summaryrefslogtreecommitdiffstats
path: root/drivers/ata
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/ata')
-rw-r--r--drivers/ata/Kconfig487
-rw-r--r--drivers/ata/Makefile62
-rw-r--r--drivers/ata/ahci.c1684
-rw-r--r--drivers/ata/ata_generic.c252
-rw-r--r--drivers/ata/ata_piix.c1256
-rw-r--r--drivers/ata/libata-core.c6176
-rw-r--r--drivers/ata/libata-eh.c2249
-rw-r--r--drivers/ata/libata-scsi.c3322
-rw-r--r--drivers/ata/libata-sff.c1121
-rw-r--r--drivers/ata/libata.h122
-rw-r--r--drivers/ata/pata_ali.c679
-rw-r--r--drivers/ata/pata_amd.c709
-rw-r--r--drivers/ata/pata_artop.c512
-rw-r--r--drivers/ata/pata_atiixp.c304
-rw-r--r--drivers/ata/pata_cmd64x.c505
-rw-r--r--drivers/ata/pata_cs5520.c334
-rw-r--r--drivers/ata/pata_cs5530.c387
-rw-r--r--drivers/ata/pata_cs5535.c291
-rw-r--r--drivers/ata/pata_cypress.c227
-rw-r--r--drivers/ata/pata_efar.c338
-rw-r--r--drivers/ata/pata_hpt366.c478
-rw-r--r--drivers/ata/pata_hpt37x.c1257
-rw-r--r--drivers/ata/pata_hpt3x2n.c597
-rw-r--r--drivers/ata/pata_hpt3x3.c226
-rw-r--r--drivers/ata/pata_isapnp.c156
-rw-r--r--drivers/ata/pata_it821x.c847
-rw-r--r--drivers/ata/pata_jmicron.c265
-rw-r--r--drivers/ata/pata_legacy.c949
-rw-r--r--drivers/ata/pata_mpiix.c310
-rw-r--r--drivers/ata/pata_netcell.c174
-rw-r--r--drivers/ata/pata_ns87410.c233
-rw-r--r--drivers/ata/pata_oldpiix.c336
-rw-r--r--drivers/ata/pata_opti.c290
-rw-r--r--drivers/ata/pata_optidma.c545
-rw-r--r--drivers/ata/pata_pcmcia.c393
-rw-r--r--drivers/ata/pata_pdc2027x.c867
-rw-r--r--drivers/ata/pata_pdc202xx_old.c423
-rw-r--r--drivers/ata/pata_qdi.c403
-rw-r--r--drivers/ata/pata_radisys.c333
-rw-r--r--drivers/ata/pata_rz1000.c205
-rw-r--r--drivers/ata/pata_sc1200.c287
-rw-r--r--drivers/ata/pata_serverworks.c591
-rw-r--r--drivers/ata/pata_sil680.c381
-rw-r--r--drivers/ata/pata_sis.c1022
-rw-r--r--drivers/ata/pata_sl82c105.c385
-rw-r--r--drivers/ata/pata_triflex.c282
-rw-r--r--drivers/ata/pata_via.c565
-rw-r--r--drivers/ata/pdc_adma.c740
-rw-r--r--drivers/ata/sata_mv.c2466
-rw-r--r--drivers/ata/sata_nv.c595
-rw-r--r--drivers/ata/sata_promise.c844
-rw-r--r--drivers/ata/sata_promise.h157
-rw-r--r--drivers/ata/sata_qstor.c730
-rw-r--r--drivers/ata/sata_sil.c728
-rw-r--r--drivers/ata/sata_sil24.c1227
-rw-r--r--drivers/ata/sata_sis.c347
-rw-r--r--drivers/ata/sata_svw.c508
-rw-r--r--drivers/ata/sata_sx4.c1502
-rw-r--r--drivers/ata/sata_uli.c300
-rw-r--r--drivers/ata/sata_via.c503
-rw-r--r--drivers/ata/sata_vsc.c482
61 files changed, 44946 insertions, 0 deletions
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
new file mode 100644
index 00000000000..3f4aa0c99ee
--- /dev/null
+++ b/drivers/ata/Kconfig
@@ -0,0 +1,487 @@
+#
+# SATA/PATA driver configuration
+#
+
+menu "Serial ATA (prod) and Parallel ATA (experimental) drivers"
+
+config ATA
+ tristate "ATA device support"
+ depends on !(M32R || M68K) || BROKEN
+ depends on !SUN4 || BROKEN
+ select SCSI
+ ---help---
+ If you want to use a ATA hard disk, ATA tape drive, ATA CD-ROM or
+ any other ATA device under Linux, say Y and make sure that you know
+ the name of your ATA host adapter (the card inside your computer
+ that "speaks" the ATA protocol, also called ATA controller),
+ because you will be asked for it.
+
+if ATA
+
+config SATA_AHCI
+ tristate "AHCI SATA support"
+ depends on PCI
+ help
+ This option enables support for AHCI Serial ATA.
+
+ If unsure, say N.
+
+config SATA_SVW
+ tristate "ServerWorks Frodo / Apple K2 SATA support"
+ depends on PCI
+ help
+ This option enables support for Broadcom/Serverworks/Apple K2
+ SATA support.
+
+ If unsure, say N.
+
+config ATA_PIIX
+ tristate "Intel PIIX/ICH SATA support"
+ depends on PCI
+ help
+ This option enables support for ICH5/6/7/8 Serial ATA.
+ If PATA support was enabled previously, this enables
+ support for select Intel PIIX/ICH PATA host controllers.
+
+ If unsure, say N.
+
+config SATA_MV
+ tristate "Marvell SATA support (HIGHLY EXPERIMENTAL)"
+ depends on PCI && EXPERIMENTAL
+ help
+ This option enables support for the Marvell Serial ATA family.
+ Currently supports 88SX[56]0[48][01] chips.
+
+ If unsure, say N.
+
+config SATA_NV
+ tristate "NVIDIA SATA support"
+ depends on PCI
+ help
+ This option enables support for NVIDIA Serial ATA.
+
+ If unsure, say N.
+
+config PDC_ADMA
+ tristate "Pacific Digital ADMA support"
+ depends on PCI
+ help
+ This option enables support for Pacific Digital ADMA controllers
+
+ If unsure, say N.
+
+config SATA_QSTOR
+ tristate "Pacific Digital SATA QStor support"
+ depends on PCI
+ help
+ This option enables support for Pacific Digital Serial ATA QStor.
+
+ If unsure, say N.
+
+config SATA_PROMISE
+ tristate "Promise SATA TX2/TX4 support"
+ depends on PCI
+ help
+ This option enables support for Promise Serial ATA TX2/TX4.
+
+ If unsure, say N.
+
+config SATA_SX4
+ tristate "Promise SATA SX4 support"
+ depends on PCI && EXPERIMENTAL
+ help
+ This option enables support for Promise Serial ATA SX4.
+
+ If unsure, say N.
+
+config SATA_SIL
+ tristate "Silicon Image SATA support"
+ depends on PCI
+ help
+ This option enables support for Silicon Image Serial ATA.
+
+ If unsure, say N.
+
+config SATA_SIL24
+ tristate "Silicon Image 3124/3132 SATA support"
+ depends on PCI
+ help
+ This option enables support for Silicon Image 3124/3132 Serial ATA.
+
+ If unsure, say N.
+
+config SATA_SIS
+ tristate "SiS 964/180 SATA support"
+ depends on PCI
+ help
+ This option enables support for SiS Serial ATA 964/180.
+
+ If unsure, say N.
+
+config SATA_ULI
+ tristate "ULi Electronics SATA support"
+ depends on PCI
+ help
+ This option enables support for ULi Electronics SATA.
+
+ If unsure, say N.
+
+config SATA_VIA
+ tristate "VIA SATA support"
+ depends on PCI
+ help
+ This option enables support for VIA Serial ATA.
+
+ If unsure, say N.
+
+config SATA_VITESSE
+ tristate "VITESSE VSC-7174 / INTEL 31244 SATA support"
+ depends on PCI
+ help
+ This option enables support for Vitesse VSC7174 and Intel 31244 Serial ATA.
+
+ If unsure, say N.
+
+config SATA_INTEL_COMBINED
+ bool
+ depends on IDE=y && !BLK_DEV_IDE_SATA && (SATA_AHCI || ATA_PIIX)
+ default y
+
+config PATA_ALI
+ tristate "ALi PATA support (Experimental)"
+ depends on PCI && EXPERIMENTAL
+ help
+ This option enables support for the ALi ATA interfaces
+ found on the many ALi chipsets.
+
+ If unsure, say N.
+
+config PATA_AMD
+ tristate "AMD/NVidia PATA support (Experimental)"
+ depends on PCI
+ help
+ This option enables support for the AMD and NVidia PATA
+ interfaces found on the chipsets for Athlon/Athlon64.
+
+ If unsure, say N.
+
+config PATA_ARTOP
+ tristate "ARTOP 6210/6260 PATA support (Experimental)"
+ depends on PCI && EXPERIMENTAL
+ help
+ This option enables support for ARTOP PATA controllers.
+
+ If unsure, say N.
+
+config PATA_ATIIXP
+ tristate "ATI PATA support (Experimental)"
+ depends on PCI && EXPERIMENTAL
+ help
+ This option enables support for the ATI ATA interfaces
+ found on the many ATI chipsets.
+
+ If unsure, say N.
+
+config PATA_CMD64X
+ tristate "CMD64x PATA support (Very Experimental)"
+ depends on PCI&& EXPERIMENTAL
+ help
+ This option enables support for the CMD64x series chips
+ except for the CMD640.
+
+ If unsure, say N.
+
+config PATA_CS5520
+ tristate "CS5510/5520 PATA support"
+ depends on PCI
+ help
+ This option enables support for the Cyrix 5510/5520
+ companion chip used with the MediaGX/Geode processor family.
+
+ If unsure, say N.
+
+config PATA_CS5530
+ tristate "CS5530 PATA support (Experimental)"
+ depends on PCI && EXPERIMENTAL
+ help
+ This option enables support for the Cyrix/NatSemi/AMD CS5530
+ companion chip used with the MediaGX/Geode processor family.
+
+ If unsure, say N.
+
+config PATA_CS5535
+ tristate "CS5535 PATA support (Experimental)"
+ depends on PCI && X86 && !X86_64 && EXPERIMENTAL
+ help
+ This option enables support for the NatSemi/AMD CS5535
+ companion chip used with the Geode processor family.
+
+ If unsure, say N.
+
+config PATA_CYPRESS
+ tristate "Cypress CY82C693 PATA support (Very Experimental)"
+ depends on PCI && EXPERIMENTAL
+ help
+ This option enables support for the Cypress/Contaq CY82C693
+ chipset found in some Alpha systems
+
+ If unsure, say N.
+
+config PATA_EFAR
+ tristate "EFAR SLC90E66 support"
+ depends on PCI
+ help
+ This option enables support for the EFAR SLC90E66
+ IDE controller found on some older machines.
+
+ If unsure, say N.
+
+config ATA_GENERIC
+ tristate "Generic ATA support"
+ depends on PCI
+ help
+ This option enables support for generic BIOS configured
+ ATA controllers via the new ATA layer
+
+ If unsure, say N.
+
+config PATA_HPT366
+ tristate "HPT 366/368 PATA support (Very Experimental)"
+ depends on PCI && EXPERIMENTAL
+ help
+ This option enables support for the HPT 366 and 368
+ PATA controllers via the new ATA layer.
+
+ If unsure, say N.
+
+config PATA_HPT37X
+ tristate "HPT 370/370A/371/372/374/302 PATA support (Very Experimental)"
+ depends on PCI && EXPERIMENTAL
+ help
+ This option enables support for the majority of the later HPT
+ PATA controllers via the new ATA layer.
+
+ If unsure, say N.
+
+config PATA_HPT3X2N
+ tristate "HPT 372N/302N PATA support (Very Experimental)"
+ depends on PCI && EXPERIMENTAL
+ help
+ This option enables support for the N variant HPT PATA
+ controllers via the new ATA layer
+
+ If unsure, say N.
+
+config PATA_HPT3X3
+ tristate "HPT 343/363 PATA support (Experimental)"
+ depends on PCI
+ help
+ This option enables support for the HPT 343/363
+ PATA controllers via the new ATA layer
+
+ If unsure, say N.
+
+config PATA_ISAPNP
+ tristate "ISA Plug and Play PATA support (Very Experimental)"
+ depends on EXPERIMENTAL && ISAPNP
+ help
+ This option enables support for ISA plug & play ATA
+ controllers such as those found on old soundcards.
+
+ If unsure, say N.
+
+config PATA_IT821X
+ tristate "IT821x PATA support (Experimental)"
+ depends on PCI && EXPERIMENTAL
+ help
+ This option enables support for the ITE 8211 and 8212
+ PATA controllers via the new ATA layer, including RAID
+ mode.
+
+ If unsure, say N.
+
+config PATA_JMICRON
+ tristate "JMicron PATA support"
+ depends on PCI
+ help
+ Enable support for the JMicron IDE controller, via the new
+ ATA layer.
+
+ If unsure, say N.
+
+config PATA_LEGACY
+ tristate "Legacy ISA PATA support (Experimental)"
+ depends on ISA && EXPERIMENTAL
+ help
+ This option enables support for ISA/VLB bus legacy PATA
+ ports and allows them to be accessed via the new ATA layer.
+
+ If unsure, say N.
+
+config PATA_TRIFLEX
+ tristate "Compaq Triflex PATA support"
+ depends on PCI
+ help
+ Enable support for the Compaq 'Triflex' IDE controller as found
+ on many Compaq Pentium-Pro systems, via the new ATA layer.
+
+ If unsure, say N.
+
+config PATA_MPIIX
+ tristate "Intel PATA MPIIX support"
+ depends on PCI
+ help
+ This option enables support for MPIIX PATA support.
+
+ If unsure, say N.
+
+config PATA_OLDPIIX
+ tristate "Intel PATA old PIIX support (Experimental)"
+ depends on PCI && EXPERIMENTAL
+ help
+ This option enables support for old(?) PIIX PATA support.
+
+ If unsure, say N.
+
+config PATA_NETCELL
+ tristate "NETCELL Revolution RAID support"
+ depends on PCI
+ help
+ This option enables support for the Netcell Revolution RAID
+ PATA controller.
+
+ If unsure, say N.
+
+config PATA_NS87410
+ tristate "Nat Semi NS87410 PATA support (Experimental)"
+ depends on PCI && EXPERIMENTAL
+ help
+ This option enables support for the National Semiconductor
+ NS87410 PCI-IDE controller.
+
+ If unsure, say N.
+
+config PATA_OPTI
+ tristate "OPTI621/6215 PATA support (Very Experimental)"
+ depends on PCI && EXPERIMENTAL
+ help
+ This option enables full PIO support for the early Opti ATA
+ controllers found on some old motherboards.
+
+ If unsure, say N.
+
+config PATA_OPTIDMA
+ tristate "OPTI FireStar PATA support (Veyr Experimental)"
+ depends on PCI && EXPERIMENTAL
+ help
+ This option enables DMA/PIO support for the later OPTi
+ controllers found on some old motherboards and in some
+ latops
+
+ If unsure, say N.
+
+config PATA_PCMCIA
+ tristate "PCMCIA PATA support"
+ depends on PCMCIA
+ help
+ This option enables support for PCMCIA ATA interfaces, including
+ compact flash card adapters via the new ATA layer.
+
+ If unsure, say N.
+
+config PATA_PDC_OLD
+ tristate "Older Promise PATA controller support (Very Experimental)"
+ depends on PCI && EXPERIMENTAL
+ help
+ This option enables support for the Promise 20246, 20262, 20263,
+ 20265 and 20267 adapters.
+
+ If unsure, say N.
+
+config PATA_QDI
+ tristate "QDI VLB PATA support"
+ depends on ISA
+ help
+ Support for QDI 6500 and 6580 PATA controllers on VESA local bus.
+
+config PATA_RADISYS
+ tristate "RADISYS 82600 PATA support (Very experimental)"
+ depends on PCI && EXPERIMENTAL
+ help
+ This option enables support for the RADISYS 82600
+ PATA controllers via the new ATA layer
+
+ If unsure, say N.
+
+config PATA_RZ1000
+ tristate "PC Tech RZ1000 PATA support"
+ depends on PCI
+ help
+ This option enables basic support for the PC Tech RZ1000/1
+ PATA controllers via the new ATA layer
+
+ If unsure, say N.
+
+config PATA_SC1200
+ tristate "SC1200 PATA support (Raving Lunatic)"
+ depends on PCI && EXPERIMENTAL
+ help
+ This option enables support for the NatSemi/AMD SC1200 SoC
+ companion chip used with the Geode processor family.
+
+ If unsure, say N.
+
+config PATA_SERVERWORKS
+ tristate "SERVERWORKS OSB4/CSB5/CSB6/HT1000 PATA support (Experimental)"
+ depends on PCI && EXPERIMENTAL
+ help
+ This option enables support for the Serverworks OSB4/CSB5/CSB6 and
+ HT1000 PATA controllers, via the new ATA layer.
+
+ If unsure, say N.
+
+config PATA_PDC2027X
+ tristate "Promise PATA 2027x support"
+ depends on PCI
+ help
+ This option enables support for Promise PATA pdc20268 to pdc20277 host adapters.
+
+ If unsure, say N.
+
+config PATA_SIL680
+ tristate "CMD / Silicon Image 680 PATA support"
+ depends on PCI
+ help
+ This option enables support for CMD / Silicon Image 680 PATA.
+
+ If unsure, say N.
+
+config PATA_SIS
+ tristate "SiS PATA support (Experimental)"
+ depends on PCI && EXPERIMENTAL
+ help
+ This option enables support for SiS PATA controllers
+
+ If unsure, say N.
+
+config PATA_VIA
+ tristate "VIA PATA support"
+ depends on PCI
+ help
+ This option enables support for the VIA PATA interfaces
+ found on the many VIA chipsets.
+
+ If unsure, say N.
+
+config PATA_WINBOND
+ tristate "Winbond SL82C105 PATA support"
+ depends on PCI
+ help
+ This option enables support for SL82C105 PATA devices found in the
+ Netwinder and some other systems
+
+ If unsure, say N.
+
+endif
+endmenu
+
diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
new file mode 100644
index 00000000000..72243a677f9
--- /dev/null
+++ b/drivers/ata/Makefile
@@ -0,0 +1,62 @@
+
+obj-$(CONFIG_ATA) += libata.o
+
+obj-$(CONFIG_SATA_AHCI) += ahci.o
+obj-$(CONFIG_SATA_SVW) += sata_svw.o
+obj-$(CONFIG_ATA_PIIX) += ata_piix.o
+obj-$(CONFIG_SATA_PROMISE) += sata_promise.o
+obj-$(CONFIG_SATA_QSTOR) += sata_qstor.o
+obj-$(CONFIG_SATA_SIL) += sata_sil.o
+obj-$(CONFIG_SATA_SIL24) += sata_sil24.o
+obj-$(CONFIG_SATA_VIA) += sata_via.o
+obj-$(CONFIG_SATA_VITESSE) += sata_vsc.o
+obj-$(CONFIG_SATA_SIS) += sata_sis.o
+obj-$(CONFIG_SATA_SX4) += sata_sx4.o
+obj-$(CONFIG_SATA_NV) += sata_nv.o
+obj-$(CONFIG_SATA_ULI) += sata_uli.o
+obj-$(CONFIG_SATA_MV) += sata_mv.o
+obj-$(CONFIG_PDC_ADMA) += pdc_adma.o
+
+obj-$(CONFIG_PATA_ALI) += pata_ali.o
+obj-$(CONFIG_PATA_AMD) += pata_amd.o
+obj-$(CONFIG_PATA_ARTOP) += pata_artop.o
+obj-$(CONFIG_PATA_ATIIXP) += pata_atiixp.o
+obj-$(CONFIG_PATA_CMD64X) += pata_cmd64x.o
+obj-$(CONFIG_PATA_CS5520) += pata_cs5520.o
+obj-$(CONFIG_PATA_CS5530) += pata_cs5530.o
+obj-$(CONFIG_PATA_CS5535) += pata_cs5535.o
+obj-$(CONFIG_PATA_CYPRESS) += pata_cypress.o
+obj-$(CONFIG_PATA_EFAR) += pata_efar.o
+obj-$(CONFIG_PATA_HPT366) += pata_hpt366.o
+obj-$(CONFIG_PATA_HPT37X) += pata_hpt37x.o
+obj-$(CONFIG_PATA_HPT3X2N) += pata_hpt3x2n.o
+obj-$(CONFIG_PATA_HPT3X3) += pata_hpt3x3.o
+obj-$(CONFIG_PATA_ISAPNP) += pata_isapnp.o
+obj-$(CONFIG_PATA_IT821X) += pata_it821x.o
+obj-$(CONFIG_PATA_JMICRON) += pata_jmicron.o
+obj-$(CONFIG_PATA_NETCELL) += pata_netcell.o
+obj-$(CONFIG_PATA_NS87410) += pata_ns87410.o
+obj-$(CONFIG_PATA_OPTI) += pata_opti.o
+obj-$(CONFIG_PATA_OPTIDMA) += pata_optidma.o
+obj-$(CONFIG_PATA_MPIIX) += pata_mpiix.o
+obj-$(CONFIG_PATA_OLDPIIX) += pata_oldpiix.o
+obj-$(CONFIG_PATA_PCMCIA) += pata_pcmcia.o
+obj-$(CONFIG_PATA_PDC2027X) += pata_pdc2027x.o
+obj-$(CONFIG_PATA_PDC_OLD) += pata_pdc202xx_old.o
+obj-$(CONFIG_PATA_QDI) += pata_qdi.o
+obj-$(CONFIG_PATA_RADISYS) += pata_radisys.o
+obj-$(CONFIG_PATA_RZ1000) += pata_rz1000.o
+obj-$(CONFIG_PATA_SC1200) += pata_sc1200.o
+obj-$(CONFIG_PATA_SERVERWORKS) += pata_serverworks.o
+obj-$(CONFIG_PATA_SIL680) += pata_sil680.o
+obj-$(CONFIG_PATA_VIA) += pata_via.o
+obj-$(CONFIG_PATA_WINBOND) += pata_sl82c105.o
+obj-$(CONFIG_PATA_SIS) += pata_sis.o
+obj-$(CONFIG_PATA_TRIFLEX) += pata_triflex.o
+# Should be last but one libata driver
+obj-$(CONFIG_ATA_GENERIC) += ata_generic.o
+# Should be last libata driver
+obj-$(CONFIG_PATA_LEGACY) += pata_legacy.o
+
+libata-objs := libata-core.o libata-scsi.o libata-sff.o libata-eh.o
+
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
new file mode 100644
index 00000000000..1aabc81d82f
--- /dev/null
+++ b/drivers/ata/ahci.c
@@ -0,0 +1,1684 @@
+/*
+ * ahci.c - AHCI SATA support
+ *
+ * Maintained by: Jeff Garzik <jgarzik@pobox.com>
+ * Please ALWAYS copy linux-ide@vger.kernel.org
+ * on emails.
+ *
+ * Copyright 2004-2005 Red Hat, Inc.
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * libata documentation is available via 'make {ps|pdf}docs',
+ * as Documentation/DocBook/libata.*
+ *
+ * AHCI hardware documentation:
+ * http://www.intel.com/technology/serialata/pdf/rev1_0.pdf
+ * http://www.intel.com/technology/serialata/pdf/rev1_1.pdf
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/dma-mapping.h>
+#include <linux/device.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_cmnd.h>
+#include <linux/libata.h>
+#include <asm/io.h>
+
+#define DRV_NAME "ahci"
+#define DRV_VERSION "2.0"
+
+
+enum {
+ AHCI_PCI_BAR = 5,
+ AHCI_MAX_SG = 168, /* hardware max is 64K */
+ AHCI_DMA_BOUNDARY = 0xffffffff,
+ AHCI_USE_CLUSTERING = 0,
+ AHCI_MAX_CMDS = 32,
+ AHCI_CMD_SZ = 32,
+ AHCI_CMD_SLOT_SZ = AHCI_MAX_CMDS * AHCI_CMD_SZ,
+ AHCI_RX_FIS_SZ = 256,
+ AHCI_CMD_TBL_CDB = 0x40,
+ AHCI_CMD_TBL_HDR_SZ = 0x80,
+ AHCI_CMD_TBL_SZ = AHCI_CMD_TBL_HDR_SZ + (AHCI_MAX_SG * 16),
+ AHCI_CMD_TBL_AR_SZ = AHCI_CMD_TBL_SZ * AHCI_MAX_CMDS,
+ AHCI_PORT_PRIV_DMA_SZ = AHCI_CMD_SLOT_SZ + AHCI_CMD_TBL_AR_SZ +
+ AHCI_RX_FIS_SZ,
+ AHCI_IRQ_ON_SG = (1 << 31),
+ AHCI_CMD_ATAPI = (1 << 5),
+ AHCI_CMD_WRITE = (1 << 6),
+ AHCI_CMD_PREFETCH = (1 << 7),
+ AHCI_CMD_RESET = (1 << 8),
+ AHCI_CMD_CLR_BUSY = (1 << 10),
+
+ RX_FIS_D2H_REG = 0x40, /* offset of D2H Register FIS data */
+ RX_FIS_UNK = 0x60, /* offset of Unknown FIS data */
+
+ board_ahci = 0,
+ board_ahci_vt8251 = 1,
+
+ /* global controller registers */
+ HOST_CAP = 0x00, /* host capabilities */
+ HOST_CTL = 0x04, /* global host control */
+ HOST_IRQ_STAT = 0x08, /* interrupt status */
+ HOST_PORTS_IMPL = 0x0c, /* bitmap of implemented ports */
+ HOST_VERSION = 0x10, /* AHCI spec. version compliancy */
+
+ /* HOST_CTL bits */
+ HOST_RESET = (1 << 0), /* reset controller; self-clear */
+ HOST_IRQ_EN = (1 << 1), /* global IRQ enable */
+ HOST_AHCI_EN = (1 << 31), /* AHCI enabled */
+
+ /* HOST_CAP bits */
+ HOST_CAP_SSC = (1 << 14), /* Slumber capable */
+ HOST_CAP_CLO = (1 << 24), /* Command List Override support */
+ HOST_CAP_SSS = (1 << 27), /* Staggered Spin-up */
+ HOST_CAP_NCQ = (1 << 30), /* Native Command Queueing */
+ HOST_CAP_64 = (1 << 31), /* PCI DAC (64-bit DMA) support */
+
+ /* registers for each SATA port */
+ PORT_LST_ADDR = 0x00, /* command list DMA addr */
+ PORT_LST_ADDR_HI = 0x04, /* command list DMA addr hi */
+ PORT_FIS_ADDR = 0x08, /* FIS rx buf addr */
+ PORT_FIS_ADDR_HI = 0x0c, /* FIS rx buf addr hi */
+ PORT_IRQ_STAT = 0x10, /* interrupt status */
+ PORT_IRQ_MASK = 0x14, /* interrupt enable/disable mask */
+ PORT_CMD = 0x18, /* port command */
+ PORT_TFDATA = 0x20, /* taskfile data */
+ PORT_SIG = 0x24, /* device TF signature */
+ PORT_CMD_ISSUE = 0x38, /* command issue */
+ PORT_SCR = 0x28, /* SATA phy register block */
+ PORT_SCR_STAT = 0x28, /* SATA phy register: SStatus */
+ PORT_SCR_CTL = 0x2c, /* SATA phy register: SControl */
+ PORT_SCR_ERR = 0x30, /* SATA phy register: SError */
+ PORT_SCR_ACT = 0x34, /* SATA phy register: SActive */
+
+ /* PORT_IRQ_{STAT,MASK} bits */
+ PORT_IRQ_COLD_PRES = (1 << 31), /* cold presence detect */
+ PORT_IRQ_TF_ERR = (1 << 30), /* task file error */
+ PORT_IRQ_HBUS_ERR = (1 << 29), /* host bus fatal error */
+ PORT_IRQ_HBUS_DATA_ERR = (1 << 28), /* host bus data error */
+ PORT_IRQ_IF_ERR = (1 << 27), /* interface fatal error */
+ PORT_IRQ_IF_NONFATAL = (1 << 26), /* interface non-fatal error */
+ PORT_IRQ_OVERFLOW = (1 << 24), /* xfer exhausted available S/G */
+ PORT_IRQ_BAD_PMP = (1 << 23), /* incorrect port multiplier */
+
+ PORT_IRQ_PHYRDY = (1 << 22), /* PhyRdy changed */
+ PORT_IRQ_DEV_ILCK = (1 << 7), /* device interlock */
+ PORT_IRQ_CONNECT = (1 << 6), /* port connect change status */
+ PORT_IRQ_SG_DONE = (1 << 5), /* descriptor processed */
+ PORT_IRQ_UNK_FIS = (1 << 4), /* unknown FIS rx'd */
+ PORT_IRQ_SDB_FIS = (1 << 3), /* Set Device Bits FIS rx'd */
+ PORT_IRQ_DMAS_FIS = (1 << 2), /* DMA Setup FIS rx'd */
+ PORT_IRQ_PIOS_FIS = (1 << 1), /* PIO Setup FIS rx'd */
+ PORT_IRQ_D2H_REG_FIS = (1 << 0), /* D2H Register FIS rx'd */
+
+ PORT_IRQ_FREEZE = PORT_IRQ_HBUS_ERR |
+ PORT_IRQ_IF_ERR |
+ PORT_IRQ_CONNECT |
+ PORT_IRQ_PHYRDY |
+ PORT_IRQ_UNK_FIS,
+ PORT_IRQ_ERROR = PORT_IRQ_FREEZE |
+ PORT_IRQ_TF_ERR |
+ PORT_IRQ_HBUS_DATA_ERR,
+ DEF_PORT_IRQ = PORT_IRQ_ERROR | PORT_IRQ_SG_DONE |
+ PORT_IRQ_SDB_FIS | PORT_IRQ_DMAS_FIS |
+ PORT_IRQ_PIOS_FIS | PORT_IRQ_D2H_REG_FIS,
+
+ /* PORT_CMD bits */
+ PORT_CMD_ATAPI = (1 << 24), /* Device is ATAPI */
+ PORT_CMD_LIST_ON = (1 << 15), /* cmd list DMA engine running */
+ PORT_CMD_FIS_ON = (1 << 14), /* FIS DMA engine running */
+ PORT_CMD_FIS_RX = (1 << 4), /* Enable FIS receive DMA engine */
+ PORT_CMD_CLO = (1 << 3), /* Command list override */
+ PORT_CMD_POWER_ON = (1 << 2), /* Power up device */
+ PORT_CMD_SPIN_UP = (1 << 1), /* Spin up device */
+ PORT_CMD_START = (1 << 0), /* Enable port DMA engine */
+
+ PORT_CMD_ICC_MASK = (0xf << 28), /* i/f ICC state mask */
+ PORT_CMD_ICC_ACTIVE = (0x1 << 28), /* Put i/f in active state */
+ PORT_CMD_ICC_PARTIAL = (0x2 << 28), /* Put i/f in partial state */
+ PORT_CMD_ICC_SLUMBER = (0x6 << 28), /* Put i/f in slumber state */
+
+ /* hpriv->flags bits */
+ AHCI_FLAG_MSI = (1 << 0),
+
+ /* ap->flags bits */
+ AHCI_FLAG_RESET_NEEDS_CLO = (1 << 24),
+ AHCI_FLAG_NO_NCQ = (1 << 25),
+};
+
+struct ahci_cmd_hdr {
+ u32 opts;
+ u32 status;
+ u32 tbl_addr;
+ u32 tbl_addr_hi;
+ u32 reserved[4];
+};
+
+struct ahci_sg {
+ u32 addr;
+ u32 addr_hi;
+ u32 reserved;
+ u32 flags_size;
+};
+
+struct ahci_host_priv {
+ unsigned long flags;
+ u32 cap; /* cache of HOST_CAP register */
+ u32 port_map; /* cache of HOST_PORTS_IMPL reg */
+};
+
+struct ahci_port_priv {
+ struct ahci_cmd_hdr *cmd_slot;
+ dma_addr_t cmd_slot_dma;
+ void *cmd_tbl;
+ dma_addr_t cmd_tbl_dma;
+ void *rx_fis;
+ dma_addr_t rx_fis_dma;
+};
+
+static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg);
+static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
+static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc);
+static irqreturn_t ahci_interrupt (int irq, void *dev_instance, struct pt_regs *regs);
+static void ahci_irq_clear(struct ata_port *ap);
+static int ahci_port_start(struct ata_port *ap);
+static void ahci_port_stop(struct ata_port *ap);
+static void ahci_tf_read(struct ata_port *ap, struct ata_taskfile *tf);
+static void ahci_qc_prep(struct ata_queued_cmd *qc);
+static u8 ahci_check_status(struct ata_port *ap);
+static void ahci_freeze(struct ata_port *ap);
+static void ahci_thaw(struct ata_port *ap);
+static void ahci_error_handler(struct ata_port *ap);
+static void ahci_post_internal_cmd(struct ata_queued_cmd *qc);
+static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg);
+static int ahci_port_resume(struct ata_port *ap);
+static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg);
+static int ahci_pci_device_resume(struct pci_dev *pdev);
+static void ahci_remove_one (struct pci_dev *pdev);
+
+static struct scsi_host_template ahci_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .change_queue_depth = ata_scsi_change_queue_depth,
+ .can_queue = AHCI_MAX_CMDS - 1,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = AHCI_MAX_SG,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = AHCI_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = AHCI_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .slave_destroy = ata_scsi_slave_destroy,
+ .bios_param = ata_std_bios_param,
+ .suspend = ata_scsi_device_suspend,
+ .resume = ata_scsi_device_resume,
+};
+
+static const struct ata_port_operations ahci_ops = {
+ .port_disable = ata_port_disable,
+
+ .check_status = ahci_check_status,
+ .check_altstatus = ahci_check_status,
+ .dev_select = ata_noop_dev_select,
+
+ .tf_read = ahci_tf_read,
+
+ .qc_prep = ahci_qc_prep,
+ .qc_issue = ahci_qc_issue,
+
+ .irq_handler = ahci_interrupt,
+ .irq_clear = ahci_irq_clear,
+
+ .scr_read = ahci_scr_read,
+ .scr_write = ahci_scr_write,
+
+ .freeze = ahci_freeze,
+ .thaw = ahci_thaw,
+
+ .error_handler = ahci_error_handler,
+ .post_internal_cmd = ahci_post_internal_cmd,
+
+ .port_suspend = ahci_port_suspend,
+ .port_resume = ahci_port_resume,
+
+ .port_start = ahci_port_start,
+ .port_stop = ahci_port_stop,
+};
+
+static const struct ata_port_info ahci_port_info[] = {
+ /* board_ahci */
+ {
+ .sht = &ahci_sht,
+ .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+ ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
+ ATA_FLAG_SKIP_D2H_BSY,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .udma_mask = 0x7f, /* udma0-6 ; FIXME */
+ .port_ops = &ahci_ops,
+ },
+ /* board_ahci_vt8251 */
+ {
+ .sht = &ahci_sht,
+ .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+ ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
+ ATA_FLAG_SKIP_D2H_BSY |
+ AHCI_FLAG_RESET_NEEDS_CLO | AHCI_FLAG_NO_NCQ,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .udma_mask = 0x7f, /* udma0-6 ; FIXME */
+ .port_ops = &ahci_ops,
+ },
+};
+
+static const struct pci_device_id ahci_pci_tbl[] = {
+ /* Intel */
+ { PCI_VENDOR_ID_INTEL, 0x2652, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ board_ahci }, /* ICH6 */
+ { PCI_VENDOR_ID_INTEL, 0x2653, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ board_ahci }, /* ICH6M */
+ { PCI_VENDOR_ID_INTEL, 0x27c1, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ board_ahci }, /* ICH7 */
+ { PCI_VENDOR_ID_INTEL, 0x27c5, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ board_ahci }, /* ICH7M */
+ { PCI_VENDOR_ID_INTEL, 0x27c3, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ board_ahci }, /* ICH7R */
+ { PCI_VENDOR_ID_AL, 0x5288, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ board_ahci }, /* ULi M5288 */
+ { PCI_VENDOR_ID_INTEL, 0x2681, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ board_ahci }, /* ESB2 */
+ { PCI_VENDOR_ID_INTEL, 0x2682, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ board_ahci }, /* ESB2 */
+ { PCI_VENDOR_ID_INTEL, 0x2683, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ board_ahci }, /* ESB2 */
+ { PCI_VENDOR_ID_INTEL, 0x27c6, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ board_ahci }, /* ICH7-M DH */
+ { PCI_VENDOR_ID_INTEL, 0x2821, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ board_ahci }, /* ICH8 */
+ { PCI_VENDOR_ID_INTEL, 0x2822, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ board_ahci }, /* ICH8 */
+ { PCI_VENDOR_ID_INTEL, 0x2824, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ board_ahci }, /* ICH8 */
+ { PCI_VENDOR_ID_INTEL, 0x2829, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ board_ahci }, /* ICH8M */
+ { PCI_VENDOR_ID_INTEL, 0x282a, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ board_ahci }, /* ICH8M */
+
+ /* JMicron */
+ { 0x197b, 0x2360, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ board_ahci }, /* JMicron JMB360 */
+ { 0x197b, 0x2361, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ board_ahci }, /* JMicron JMB361 */
+ { 0x197b, 0x2363, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ board_ahci }, /* JMicron JMB363 */
+ { 0x197b, 0x2365, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ board_ahci }, /* JMicron JMB365 */
+ { 0x197b, 0x2366, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ board_ahci }, /* JMicron JMB366 */
+
+ /* ATI */
+ { PCI_VENDOR_ID_ATI, 0x4380, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ board_ahci }, /* ATI SB600 non-raid */
+ { PCI_VENDOR_ID_ATI, 0x4381, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ board_ahci }, /* ATI SB600 raid */
+
+ /* VIA */
+ { PCI_VENDOR_ID_VIA, 0x3349, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ board_ahci_vt8251 }, /* VIA VT8251 */
+
+ /* NVIDIA */
+ { PCI_VENDOR_ID_NVIDIA, 0x044c, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ board_ahci }, /* MCP65 */
+ { PCI_VENDOR_ID_NVIDIA, 0x044d, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ board_ahci }, /* MCP65 */
+ { PCI_VENDOR_ID_NVIDIA, 0x044e, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ board_ahci }, /* MCP65 */
+ { PCI_VENDOR_ID_NVIDIA, 0x044f, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ board_ahci }, /* MCP65 */
+
+ /* SiS */
+ { PCI_VENDOR_ID_SI, 0x1184, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ board_ahci }, /* SiS 966 */
+ { PCI_VENDOR_ID_SI, 0x1185, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ board_ahci }, /* SiS 966 */
+ { PCI_VENDOR_ID_SI, 0x0186, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ board_ahci }, /* SiS 968 */
+
+ { } /* terminate list */
+};
+
+
+static struct pci_driver ahci_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = ahci_pci_tbl,
+ .probe = ahci_init_one,
+ .suspend = ahci_pci_device_suspend,
+ .resume = ahci_pci_device_resume,
+ .remove = ahci_remove_one,
+};
+
+
+static inline unsigned long ahci_port_base_ul (unsigned long base, unsigned int port)
+{
+ return base + 0x100 + (port * 0x80);
+}
+
+static inline void __iomem *ahci_port_base (void __iomem *base, unsigned int port)
+{
+ return (void __iomem *) ahci_port_base_ul((unsigned long)base, port);
+}
+
+static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg_in)
+{
+ unsigned int sc_reg;
+
+ switch (sc_reg_in) {
+ case SCR_STATUS: sc_reg = 0; break;
+ case SCR_CONTROL: sc_reg = 1; break;
+ case SCR_ERROR: sc_reg = 2; break;
+ case SCR_ACTIVE: sc_reg = 3; break;
+ default:
+ return 0xffffffffU;
+ }
+
+ return readl((void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4));
+}
+
+
+static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg_in,
+ u32 val)
+{
+ unsigned int sc_reg;
+
+ switch (sc_reg_in) {
+ case SCR_STATUS: sc_reg = 0; break;
+ case SCR_CONTROL: sc_reg = 1; break;
+ case SCR_ERROR: sc_reg = 2; break;
+ case SCR_ACTIVE: sc_reg = 3; break;
+ default:
+ return;
+ }
+
+ writel(val, (void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4));
+}
+
+static void ahci_start_engine(void __iomem *port_mmio)
+{
+ u32 tmp;
+
+ /* start DMA */
+ tmp = readl(port_mmio + PORT_CMD);
+ tmp |= PORT_CMD_START;
+ writel(tmp, port_mmio + PORT_CMD);
+ readl(port_mmio + PORT_CMD); /* flush */
+}
+
+static int ahci_stop_engine(void __iomem *port_mmio)
+{
+ u32 tmp;
+
+ tmp = readl(port_mmio + PORT_CMD);
+
+ /* check if the HBA is idle */
+ if ((tmp & (PORT_CMD_START | PORT_CMD_LIST_ON)) == 0)
+ return 0;
+
+ /* setting HBA to idle */
+ tmp &= ~PORT_CMD_START;
+ writel(tmp, port_mmio + PORT_CMD);
+
+ /* wait for engine to stop. This could be as long as 500 msec */
+ tmp = ata_wait_register(port_mmio + PORT_CMD,
+ PORT_CMD_LIST_ON, PORT_CMD_LIST_ON, 1, 500);
+ if (tmp & PORT_CMD_LIST_ON)
+ return -EIO;
+
+ return 0;
+}
+
+static void ahci_start_fis_rx(void __iomem *port_mmio, u32 cap,
+ dma_addr_t cmd_slot_dma, dma_addr_t rx_fis_dma)
+{
+ u32 tmp;
+
+ /* set FIS registers */
+ if (cap & HOST_CAP_64)
+ writel((cmd_slot_dma >> 16) >> 16, port_mmio + PORT_LST_ADDR_HI);
+ writel(cmd_slot_dma & 0xffffffff, port_mmio + PORT_LST_ADDR);
+
+ if (cap & HOST_CAP_64)
+ writel((rx_fis_dma >> 16) >> 16, port_mmio + PORT_FIS_ADDR_HI);
+ writel(rx_fis_dma & 0xffffffff, port_mmio + PORT_FIS_ADDR);
+
+ /* enable FIS reception */
+ tmp = readl(port_mmio + PORT_CMD);
+ tmp |= PORT_CMD_FIS_RX;
+ writel(tmp, port_mmio + PORT_CMD);
+
+ /* flush */
+ readl(port_mmio + PORT_CMD);
+}
+
+static int ahci_stop_fis_rx(void __iomem *port_mmio)
+{
+ u32 tmp;
+
+ /* disable FIS reception */
+ tmp = readl(port_mmio + PORT_CMD);
+ tmp &= ~PORT_CMD_FIS_RX;
+ writel(tmp, port_mmio + PORT_CMD);
+
+ /* wait for completion, spec says 500ms, give it 1000 */
+ tmp = ata_wait_register(port_mmio + PORT_CMD, PORT_CMD_FIS_ON,
+ PORT_CMD_FIS_ON, 10, 1000);
+ if (tmp & PORT_CMD_FIS_ON)
+ return -EBUSY;
+
+ return 0;
+}
+
+static void ahci_power_up(void __iomem *port_mmio, u32 cap)
+{
+ u32 cmd;
+
+ cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK;
+
+ /* spin up device */
+ if (cap & HOST_CAP_SSS) {
+ cmd |= PORT_CMD_SPIN_UP;
+ writel(cmd, port_mmio + PORT_CMD);
+ }
+
+ /* wake up link */
+ writel(cmd | PORT_CMD_ICC_ACTIVE, port_mmio + PORT_CMD);
+}
+
+static void ahci_power_down(void __iomem *port_mmio, u32 cap)
+{
+ u32 cmd, scontrol;
+
+ cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK;
+
+ if (cap & HOST_CAP_SSC) {
+ /* enable transitions to slumber mode */
+ scontrol = readl(port_mmio + PORT_SCR_CTL);
+ if ((scontrol & 0x0f00) > 0x100) {
+ scontrol &= ~0xf00;
+ writel(scontrol, port_mmio + PORT_SCR_CTL);
+ }
+
+ /* put device into slumber mode */
+ writel(cmd | PORT_CMD_ICC_SLUMBER, port_mmio + PORT_CMD);
+
+ /* wait for the transition to complete */
+ ata_wait_register(port_mmio + PORT_CMD, PORT_CMD_ICC_SLUMBER,
+ PORT_CMD_ICC_SLUMBER, 1, 50);
+ }
+
+ /* put device into listen mode */
+ if (cap & HOST_CAP_SSS) {
+ /* first set PxSCTL.DET to 0 */
+ scontrol = readl(port_mmio + PORT_SCR_CTL);
+ scontrol &= ~0xf;
+ writel(scontrol, port_mmio + PORT_SCR_CTL);
+
+ /* then set PxCMD.SUD to 0 */
+ cmd &= ~PORT_CMD_SPIN_UP;
+ writel(cmd, port_mmio + PORT_CMD);
+ }
+}
+
+static void ahci_init_port(void __iomem *port_mmio, u32 cap,
+ dma_addr_t cmd_slot_dma, dma_addr_t rx_fis_dma)
+{
+ /* power up */
+ ahci_power_up(port_mmio, cap);
+
+ /* enable FIS reception */
+ ahci_start_fis_rx(port_mmio, cap, cmd_slot_dma, rx_fis_dma);
+
+ /* enable DMA */
+ ahci_start_engine(port_mmio);
+}
+
+static int ahci_deinit_port(void __iomem *port_mmio, u32 cap, const char **emsg)
+{
+ int rc;
+
+ /* disable DMA */
+ rc = ahci_stop_engine(port_mmio);
+ if (rc) {
+ *emsg = "failed to stop engine";
+ return rc;
+ }
+
+ /* disable FIS reception */
+ rc = ahci_stop_fis_rx(port_mmio);
+ if (rc) {
+ *emsg = "failed stop FIS RX";
+ return rc;
+ }
+
+ /* put device into slumber mode */
+ ahci_power_down(port_mmio, cap);
+
+ return 0;
+}
+
+static int ahci_reset_controller(void __iomem *mmio, struct pci_dev *pdev)
+{
+ u32 cap_save, tmp;
+
+ cap_save = readl(mmio + HOST_CAP);
+ cap_save &= ( (1<<28) | (1<<17) );
+ cap_save |= (1 << 27);
+
+ /* global controller reset */
+ tmp = readl(mmio + HOST_CTL);
+ if ((tmp & HOST_RESET) == 0) {
+ writel(tmp | HOST_RESET, mmio + HOST_CTL);
+ readl(mmio + HOST_CTL); /* flush */
+ }
+
+ /* reset must complete within 1 second, or
+ * the hardware should be considered fried.
+ */
+ ssleep(1);
+
+ tmp = readl(mmio + HOST_CTL);
+ if (tmp & HOST_RESET) {
+ dev_printk(KERN_ERR, &pdev->dev,
+ "controller reset failed (0x%x)\n", tmp);
+ return -EIO;
+ }
+
+ writel(HOST_AHCI_EN, mmio + HOST_CTL);
+ (void) readl(mmio + HOST_CTL); /* flush */
+ writel(cap_save, mmio + HOST_CAP);
+ writel(0xf, mmio + HOST_PORTS_IMPL);
+ (void) readl(mmio + HOST_PORTS_IMPL); /* flush */
+
+ if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
+ u16 tmp16;
+
+ /* configure PCS */
+ pci_read_config_word(pdev, 0x92, &tmp16);
+ tmp16 |= 0xf;
+ pci_write_config_word(pdev, 0x92, tmp16);
+ }
+
+ return 0;
+}
+
+static void ahci_init_controller(void __iomem *mmio, struct pci_dev *pdev,
+ int n_ports, u32 cap)
+{
+ int i, rc;
+ u32 tmp;
+
+ for (i = 0; i < n_ports; i++) {
+ void __iomem *port_mmio = ahci_port_base(mmio, i);
+ const char *emsg = NULL;
+
+#if 0 /* BIOSen initialize this incorrectly */
+ if (!(hpriv->port_map & (1 << i)))
+ continue;
+#endif
+
+ /* make sure port is not active */
+ rc = ahci_deinit_port(port_mmio, cap, &emsg);
+ if (rc)
+ dev_printk(KERN_WARNING, &pdev->dev,
+ "%s (%d)\n", emsg, rc);
+
+ /* clear SError */
+ tmp = readl(port_mmio + PORT_SCR_ERR);
+ VPRINTK("PORT_SCR_ERR 0x%x\n", tmp);
+ writel(tmp, port_mmio + PORT_SCR_ERR);
+
+ /* clear port IRQ */
+ tmp = readl(port_mmio + PORT_IRQ_STAT);
+ VPRINTK("PORT_IRQ_STAT 0x%x\n", tmp);
+ if (tmp)
+ writel(tmp, port_mmio + PORT_IRQ_STAT);
+
+ writel(1 << i, mmio + HOST_IRQ_STAT);
+ }
+
+ tmp = readl(mmio + HOST_CTL);
+ VPRINTK("HOST_CTL 0x%x\n", tmp);
+ writel(tmp | HOST_IRQ_EN, mmio + HOST_CTL);
+ tmp = readl(mmio + HOST_CTL);
+ VPRINTK("HOST_CTL 0x%x\n", tmp);
+}
+
+static unsigned int ahci_dev_classify(struct ata_port *ap)
+{
+ void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr;
+ struct ata_taskfile tf;
+ u32 tmp;
+
+ tmp = readl(port_mmio + PORT_SIG);
+ tf.lbah = (tmp >> 24) & 0xff;
+ tf.lbam = (tmp >> 16) & 0xff;
+ tf.lbal = (tmp >> 8) & 0xff;
+ tf.nsect = (tmp) & 0xff;
+
+ return ata_dev_classify(&tf);
+}
+
+static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag,
+ u32 opts)
+{
+ dma_addr_t cmd_tbl_dma;
+
+ cmd_tbl_dma = pp->cmd_tbl_dma + tag * AHCI_CMD_TBL_SZ;
+
+ pp->cmd_slot[tag].opts = cpu_to_le32(opts);
+ pp->cmd_slot[tag].status = 0;
+ pp->cmd_slot[tag].tbl_addr = cpu_to_le32(cmd_tbl_dma & 0xffffffff);
+ pp->cmd_slot[tag].tbl_addr_hi = cpu_to_le32((cmd_tbl_dma >> 16) >> 16);
+}
+
+static int ahci_clo(struct ata_port *ap)
+{
+ void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr;
+ struct ahci_host_priv *hpriv = ap->host->private_data;
+ u32 tmp;
+
+ if (!(hpriv->cap & HOST_CAP_CLO))
+ return -EOPNOTSUPP;
+
+ tmp = readl(port_mmio + PORT_CMD);
+ tmp |= PORT_CMD_CLO;
+ writel(tmp, port_mmio + PORT_CMD);
+
+ tmp = ata_wait_register(port_mmio + PORT_CMD,
+ PORT_CMD_CLO, PORT_CMD_CLO, 1, 500);
+ if (tmp & PORT_CMD_CLO)
+ return -EIO;
+
+ return 0;
+}
+
+static int ahci_prereset(struct ata_port *ap)
+{
+ if ((ap->flags & AHCI_FLAG_RESET_NEEDS_CLO) &&
+ (ata_busy_wait(ap, ATA_BUSY, 1000) & ATA_BUSY)) {
+ /* ATA_BUSY hasn't cleared, so send a CLO */
+ ahci_clo(ap);
+ }
+
+ return ata_std_prereset(ap);
+}
+
+static int ahci_softreset(struct ata_port *ap, unsigned int *class)
+{
+ struct ahci_port_priv *pp = ap->private_data;
+ void __iomem *mmio = ap->host->mmio_base;
+ void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
+ const u32 cmd_fis_len = 5; /* five dwords */
+ const char *reason = NULL;
+ struct ata_taskfile tf;
+ u32 tmp;
+ u8 *fis;
+ int rc;
+
+ DPRINTK("ENTER\n");
+
+ if (ata_port_offline(ap)) {
+ DPRINTK("PHY reports no device\n");
+ *class = ATA_DEV_NONE;
+ return 0;
+ }
+
+ /* prepare for SRST (AHCI-1.1 10.4.1) */
+ rc = ahci_stop_engine(port_mmio);
+ if (rc) {
+ reason = "failed to stop engine";
+ goto fail_restart;
+ }
+
+ /* check BUSY/DRQ, perform Command List Override if necessary */
+ ahci_tf_read(ap, &tf);
+ if (tf.command & (ATA_BUSY | ATA_DRQ)) {
+ rc = ahci_clo(ap);
+
+ if (rc == -EOPNOTSUPP) {
+ reason = "port busy but CLO unavailable";
+ goto fail_restart;
+ } else if (rc) {
+ reason = "port busy but CLO failed";
+ goto fail_restart;
+ }
+ }
+
+ /* restart engine */
+ ahci_start_engine(port_mmio);
+
+ ata_tf_init(ap->device, &tf);
+ fis = pp->cmd_tbl;
+
+ /* issue the first D2H Register FIS */
+ ahci_fill_cmd_slot(pp, 0,
+ cmd_fis_len | AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY);
+
+ tf.ctl |= ATA_SRST;
+ ata_tf_to_fis(&tf, fis, 0);
+ fis[1] &= ~(1 << 7); /* turn off Command FIS bit */
+
+ writel(1, port_mmio + PORT_CMD_ISSUE);
+
+ tmp = ata_wait_register(port_mmio + PORT_CMD_ISSUE, 0x1, 0x1, 1, 500);
+ if (tmp & 0x1) {
+ rc = -EIO;
+ reason = "1st FIS failed";
+ goto fail;
+ }
+
+ /* spec says at least 5us, but be generous and sleep for 1ms */
+ msleep(1);
+
+ /* issue the second D2H Register FIS */
+ ahci_fill_cmd_slot(pp, 0, cmd_fis_len);
+
+ tf.ctl &= ~ATA_SRST;
+ ata_tf_to_fis(&tf, fis, 0);
+ fis[1] &= ~(1 << 7); /* turn off Command FIS bit */
+
+ writel(1, port_mmio + PORT_CMD_ISSUE);
+ readl(port_mmio + PORT_CMD_ISSUE); /* flush */
+
+ /* spec mandates ">= 2ms" before checking status.
+ * We wait 150ms, because that was the magic delay used for
+ * ATAPI devices in Hale Landis's ATADRVR, for the period of time
+ * between when the ATA command register is written, and then
+ * status is checked. Because waiting for "a while" before
+ * checking status is fine, post SRST, we perform this magic
+ * delay here as well.
+ */
+ msleep(150);
+
+ *class = ATA_DEV_NONE;
+ if (ata_port_online(ap)) {
+ if (ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT)) {
+ rc = -EIO;
+ reason = "device not ready";
+ goto fail;
+ }
+ *class = ahci_dev_classify(ap);
+ }
+
+ DPRINTK("EXIT, class=%u\n", *class);
+ return 0;
+
+ fail_restart:
+ ahci_start_engine(port_mmio);
+ fail:
+ ata_port_printk(ap, KERN_ERR, "softreset failed (%s)\n", reason);
+ return rc;
+}
+
+static int ahci_hardreset(struct ata_port *ap, unsigned int *class)
+{
+ struct ahci_port_priv *pp = ap->private_data;
+ u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
+ struct ata_taskfile tf;
+ void __iomem *mmio = ap->host->mmio_base;
+ void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
+ int rc;
+
+ DPRINTK("ENTER\n");
+
+ ahci_stop_engine(port_mmio);
+
+ /* clear D2H reception area to properly wait for D2H FIS */
+ ata_tf_init(ap->device, &tf);
+ tf.command = 0xff;
+ ata_tf_to_fis(&tf, d2h_fis, 0);
+
+ rc = sata_std_hardreset(ap, class);
+
+ ahci_start_engine(port_mmio);
+
+ if (rc == 0 && ata_port_online(ap))
+ *class = ahci_dev_classify(ap);
+ if (*class == ATA_DEV_UNKNOWN)
+ *class = ATA_DEV_NONE;
+
+ DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class);
+ return rc;
+}
+
+static void ahci_postreset(struct ata_port *ap, unsigned int *class)
+{
+ void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr;
+ u32 new_tmp, tmp;
+
+ ata_std_postreset(ap, class);
+
+ /* Make sure port's ATAPI bit is set appropriately */
+ new_tmp = tmp = readl(port_mmio + PORT_CMD);
+ if (*class == ATA_DEV_ATAPI)
+ new_tmp |= PORT_CMD_ATAPI;
+ else
+ new_tmp &= ~PORT_CMD_ATAPI;
+ if (new_tmp != tmp) {
+ writel(new_tmp, port_mmio + PORT_CMD);
+ readl(port_mmio + PORT_CMD); /* flush */
+ }
+}
+
+static u8 ahci_check_status(struct ata_port *ap)
+{
+ void __iomem *mmio = (void __iomem *) ap->ioaddr.cmd_addr;
+
+ return readl(mmio + PORT_TFDATA) & 0xFF;
+}
+
+static void ahci_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
+{
+ struct ahci_port_priv *pp = ap->private_data;
+ u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
+
+ ata_tf_from_fis(d2h_fis, tf);
+}
+
+static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl)
+{
+ struct scatterlist *sg;
+ struct ahci_sg *ahci_sg;
+ unsigned int n_sg = 0;
+
+ VPRINTK("ENTER\n");
+
+ /*
+ * Next, the S/G list.
+ */
+ ahci_sg = cmd_tbl + AHCI_CMD_TBL_HDR_SZ;
+ ata_for_each_sg(sg, qc) {
+ dma_addr_t addr = sg_dma_address(sg);
+ u32 sg_len = sg_dma_len(sg);
+
+ ahci_sg->addr = cpu_to_le32(addr & 0xffffffff);
+ ahci_sg->addr_hi = cpu_to_le32((addr >> 16) >> 16);
+ ahci_sg->flags_size = cpu_to_le32(sg_len - 1);
+
+ ahci_sg++;
+ n_sg++;
+ }
+
+ return n_sg;
+}
+
+static void ahci_qc_prep(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct ahci_port_priv *pp = ap->private_data;
+ int is_atapi = is_atapi_taskfile(&qc->tf);
+ void *cmd_tbl;
+ u32 opts;
+ const u32 cmd_fis_len = 5; /* five dwords */
+ unsigned int n_elem;
+
+ /*
+ * Fill in command table information. First, the header,
+ * a SATA Register - Host to Device command FIS.
+ */
+ cmd_tbl = pp->cmd_tbl + qc->tag * AHCI_CMD_TBL_SZ;
+
+ ata_tf_to_fis(&qc->tf, cmd_tbl, 0);
+ if (is_atapi) {
+ memset(cmd_tbl + AHCI_CMD_TBL_CDB, 0, 32);
+ memcpy(cmd_tbl + AHCI_CMD_TBL_CDB, qc->cdb, qc->dev->cdb_len);
+ }
+
+ n_elem = 0;
+ if (qc->flags & ATA_QCFLAG_DMAMAP)
+ n_elem = ahci_fill_sg(qc, cmd_tbl);
+
+ /*
+ * Fill in command slot information.
+ */
+ opts = cmd_fis_len | n_elem << 16;
+ if (qc->tf.flags & ATA_TFLAG_WRITE)
+ opts |= AHCI_CMD_WRITE;
+ if (is_atapi)
+ opts |= AHCI_CMD_ATAPI | AHCI_CMD_PREFETCH;
+
+ ahci_fill_cmd_slot(pp, qc->tag, opts);
+}
+
+static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
+{
+ struct ahci_port_priv *pp = ap->private_data;
+ struct ata_eh_info *ehi = &ap->eh_info;
+ unsigned int err_mask = 0, action = 0;
+ struct ata_queued_cmd *qc;
+ u32 serror;
+
+ ata_ehi_clear_desc(ehi);
+
+ /* AHCI needs SError cleared; otherwise, it might lock up */
+ serror = ahci_scr_read(ap, SCR_ERROR);
+ ahci_scr_write(ap, SCR_ERROR, serror);
+
+ /* analyze @irq_stat */
+ ata_ehi_push_desc(ehi, "irq_stat 0x%08x", irq_stat);
+
+ if (irq_stat & PORT_IRQ_TF_ERR)
+ err_mask |= AC_ERR_DEV;
+
+ if (irq_stat & (PORT_IRQ_HBUS_ERR | PORT_IRQ_HBUS_DATA_ERR)) {
+ err_mask |= AC_ERR_HOST_BUS;
+ action |= ATA_EH_SOFTRESET;
+ }
+
+ if (irq_stat & PORT_IRQ_IF_ERR) {
+ err_mask |= AC_ERR_ATA_BUS;
+ action |= ATA_EH_SOFTRESET;
+ ata_ehi_push_desc(ehi, ", interface fatal error");
+ }
+
+ if (irq_stat & (PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY)) {
+ ata_ehi_hotplugged(ehi);
+ ata_ehi_push_desc(ehi, ", %s", irq_stat & PORT_IRQ_CONNECT ?
+ "connection status changed" : "PHY RDY changed");
+ }
+
+ if (irq_stat & PORT_IRQ_UNK_FIS) {
+ u32 *unk = (u32 *)(pp->rx_fis + RX_FIS_UNK);
+
+ err_mask |= AC_ERR_HSM;
+ action |= ATA_EH_SOFTRESET;
+ ata_ehi_push_desc(ehi, ", unknown FIS %08x %08x %08x %08x",
+ unk[0], unk[1], unk[2], unk[3]);
+ }
+
+ /* okay, let's hand over to EH */
+ ehi->serror |= serror;
+ ehi->action |= action;
+
+ qc = ata_qc_from_tag(ap, ap->active_tag);
+ if (qc)
+ qc->err_mask |= err_mask;
+ else
+ ehi->err_mask |= err_mask;
+
+ if (irq_stat & PORT_IRQ_FREEZE)
+ ata_port_freeze(ap);
+ else
+ ata_port_abort(ap);
+}
+
+static void ahci_host_intr(struct ata_port *ap)
+{
+ void __iomem *mmio = ap->host->mmio_base;
+ void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
+ struct ata_eh_info *ehi = &ap->eh_info;
+ u32 status, qc_active;
+ int rc;
+
+ status = readl(port_mmio + PORT_IRQ_STAT);
+ writel(status, port_mmio + PORT_IRQ_STAT);
+
+ if (unlikely(status & PORT_IRQ_ERROR)) {
+ ahci_error_intr(ap, status);
+ return;
+ }
+
+ if (ap->sactive)
+ qc_active = readl(port_mmio + PORT_SCR_ACT);
+ else
+ qc_active = readl(port_mmio + PORT_CMD_ISSUE);
+
+ rc = ata_qc_complete_multiple(ap, qc_active, NULL);
+ if (rc > 0)
+ return;
+ if (rc < 0) {
+ ehi->err_mask |= AC_ERR_HSM;
+ ehi->action |= ATA_EH_SOFTRESET;
+ ata_port_freeze(ap);
+ return;
+ }
+
+ /* hmmm... a spurious interupt */
+
+ /* some devices send D2H reg with I bit set during NCQ command phase */
+ if (ap->sactive && status & PORT_IRQ_D2H_REG_FIS)
+ return;
+
+ /* ignore interim PIO setup fis interrupts */
+ if (ata_tag_valid(ap->active_tag) && (status & PORT_IRQ_PIOS_FIS))
+ return;
+
+ if (ata_ratelimit())
+ ata_port_printk(ap, KERN_INFO, "spurious interrupt "
+ "(irq_stat 0x%x active_tag %d sactive 0x%x)\n",
+ status, ap->active_tag, ap->sactive);
+}
+
+static void ahci_irq_clear(struct ata_port *ap)
+{
+ /* TODO */
+}
+
+static irqreturn_t ahci_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
+{
+ struct ata_host *host = dev_instance;
+ struct ahci_host_priv *hpriv;
+ unsigned int i, handled = 0;
+ void __iomem *mmio;
+ u32 irq_stat, irq_ack = 0;
+
+ VPRINTK("ENTER\n");
+
+ hpriv = host->private_data;
+ mmio = host->mmio_base;
+
+ /* sigh. 0xffffffff is a valid return from h/w */
+ irq_stat = readl(mmio + HOST_IRQ_STAT);
+ irq_stat &= hpriv->port_map;
+ if (!irq_stat)
+ return IRQ_NONE;
+
+ spin_lock(&host->lock);
+
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap;
+
+ if (!(irq_stat & (1 << i)))
+ continue;
+
+ ap = host->ports[i];
+ if (ap) {
+ ahci_host_intr(ap);
+ VPRINTK("port %u\n", i);
+ } else {
+ VPRINTK("port %u (no irq)\n", i);
+ if (ata_ratelimit())
+ dev_printk(KERN_WARNING, host->dev,
+ "interrupt on disabled port %u\n", i);
+ }
+
+ irq_ack |= (1 << i);
+ }
+
+ if (irq_ack) {
+ writel(irq_ack, mmio + HOST_IRQ_STAT);
+ handled = 1;
+ }
+
+ spin_unlock(&host->lock);
+
+ VPRINTK("EXIT\n");
+
+ return IRQ_RETVAL(handled);
+}
+
+static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr;
+
+ if (qc->tf.protocol == ATA_PROT_NCQ)
+ writel(1 << qc->tag, port_mmio + PORT_SCR_ACT);
+ writel(1 << qc->tag, port_mmio + PORT_CMD_ISSUE);
+ readl(port_mmio + PORT_CMD_ISSUE); /* flush */
+
+ return 0;
+}
+
+static void ahci_freeze(struct ata_port *ap)
+{
+ void __iomem *mmio = ap->host->mmio_base;
+ void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
+
+ /* turn IRQ off */
+ writel(0, port_mmio + PORT_IRQ_MASK);
+}
+
+static void ahci_thaw(struct ata_port *ap)
+{
+ void __iomem *mmio = ap->host->mmio_base;
+ void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
+ u32 tmp;
+
+ /* clear IRQ */
+ tmp = readl(port_mmio + PORT_IRQ_STAT);
+ writel(tmp, port_mmio + PORT_IRQ_STAT);
+ writel(1 << ap->id, mmio + HOST_IRQ_STAT);
+
+ /* turn IRQ back on */
+ writel(DEF_PORT_IRQ, port_mmio + PORT_IRQ_MASK);
+}
+
+static void ahci_error_handler(struct ata_port *ap)
+{
+ void __iomem *mmio = ap->host->mmio_base;
+ void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
+
+ if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
+ /* restart engine */
+ ahci_stop_engine(port_mmio);
+ ahci_start_engine(port_mmio);
+ }
+
+ /* perform recovery */
+ ata_do_eh(ap, ahci_prereset, ahci_softreset, ahci_hardreset,
+ ahci_postreset);
+}
+
+static void ahci_post_internal_cmd(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ void __iomem *mmio = ap->host->mmio_base;
+ void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
+
+ if (qc->flags & ATA_QCFLAG_FAILED)
+ qc->err_mask |= AC_ERR_OTHER;
+
+ if (qc->err_mask) {
+ /* make DMA engine forget about the failed command */
+ ahci_stop_engine(port_mmio);
+ ahci_start_engine(port_mmio);
+ }
+}
+
+static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg)
+{
+ struct ahci_host_priv *hpriv = ap->host->private_data;
+ struct ahci_port_priv *pp = ap->private_data;
+ void __iomem *mmio = ap->host->mmio_base;
+ void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
+ const char *emsg = NULL;
+ int rc;
+
+ rc = ahci_deinit_port(port_mmio, hpriv->cap, &emsg);
+ if (rc) {
+ ata_port_printk(ap, KERN_ERR, "%s (%d)\n", emsg, rc);
+ ahci_init_port(port_mmio, hpriv->cap,
+ pp->cmd_slot_dma, pp->rx_fis_dma);
+ }
+
+ return rc;
+}
+
+static int ahci_port_resume(struct ata_port *ap)
+{
+ struct ahci_port_priv *pp = ap->private_data;
+ struct ahci_host_priv *hpriv = ap->host->private_data;
+ void __iomem *mmio = ap->host->mmio_base;
+ void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
+
+ ahci_init_port(port_mmio, hpriv->cap, pp->cmd_slot_dma, pp->rx_fis_dma);
+
+ return 0;
+}
+
+static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
+{
+ struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ void __iomem *mmio = host->mmio_base;
+ u32 ctl;
+
+ if (mesg.event == PM_EVENT_SUSPEND) {
+ /* AHCI spec rev1.1 section 8.3.3:
+ * Software must disable interrupts prior to requesting a
+ * transition of the HBA to D3 state.
+ */
+ ctl = readl(mmio + HOST_CTL);
+ ctl &= ~HOST_IRQ_EN;
+ writel(ctl, mmio + HOST_CTL);
+ readl(mmio + HOST_CTL); /* flush */
+ }
+
+ return ata_pci_device_suspend(pdev, mesg);
+}
+
+static int ahci_pci_device_resume(struct pci_dev *pdev)
+{
+ struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct ahci_host_priv *hpriv = host->private_data;
+ void __iomem *mmio = host->mmio_base;
+ int rc;
+
+ ata_pci_device_do_resume(pdev);
+
+ if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) {
+ rc = ahci_reset_controller(mmio, pdev);
+ if (rc)
+ return rc;
+
+ ahci_init_controller(mmio, pdev, host->n_ports, hpriv->cap);
+ }
+
+ ata_host_resume(host);
+
+ return 0;
+}
+
+static int ahci_port_start(struct ata_port *ap)
+{
+ struct device *dev = ap->host->dev;
+ struct ahci_host_priv *hpriv = ap->host->private_data;
+ struct ahci_port_priv *pp;
+ void __iomem *mmio = ap->host->mmio_base;
+ void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
+ void *mem;
+ dma_addr_t mem_dma;
+ int rc;
+
+ pp = kmalloc(sizeof(*pp), GFP_KERNEL);
+ if (!pp)
+ return -ENOMEM;
+ memset(pp, 0, sizeof(*pp));
+
+ rc = ata_pad_alloc(ap, dev);
+ if (rc) {
+ kfree(pp);
+ return rc;
+ }
+
+ mem = dma_alloc_coherent(dev, AHCI_PORT_PRIV_DMA_SZ, &mem_dma, GFP_KERNEL);
+ if (!mem) {
+ ata_pad_free(ap, dev);
+ kfree(pp);
+ return -ENOMEM;
+ }
+ memset(mem, 0, AHCI_PORT_PRIV_DMA_SZ);
+
+ /*
+ * First item in chunk of DMA memory: 32-slot command table,
+ * 32 bytes each in size
+ */
+ pp->cmd_slot = mem;
+ pp->cmd_slot_dma = mem_dma;
+
+ mem += AHCI_CMD_SLOT_SZ;
+ mem_dma += AHCI_CMD_SLOT_SZ;
+
+ /*
+ * Second item: Received-FIS area
+ */
+ pp->rx_fis = mem;
+ pp->rx_fis_dma = mem_dma;
+
+ mem += AHCI_RX_FIS_SZ;
+ mem_dma += AHCI_RX_FIS_SZ;
+
+ /*
+ * Third item: data area for storing a single command
+ * and its scatter-gather table
+ */
+ pp->cmd_tbl = mem;
+ pp->cmd_tbl_dma = mem_dma;
+
+ ap->private_data = pp;
+
+ /* initialize port */
+ ahci_init_port(port_mmio, hpriv->cap, pp->cmd_slot_dma, pp->rx_fis_dma);
+
+ return 0;
+}
+
+static void ahci_port_stop(struct ata_port *ap)
+{
+ struct device *dev = ap->host->dev;
+ struct ahci_host_priv *hpriv = ap->host->private_data;
+ struct ahci_port_priv *pp = ap->private_data;
+ void __iomem *mmio = ap->host->mmio_base;
+ void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
+ const char *emsg = NULL;
+ int rc;
+
+ /* de-initialize port */
+ rc = ahci_deinit_port(port_mmio, hpriv->cap, &emsg);
+ if (rc)
+ ata_port_printk(ap, KERN_WARNING, "%s (%d)\n", emsg, rc);
+
+ ap->private_data = NULL;
+ dma_free_coherent(dev, AHCI_PORT_PRIV_DMA_SZ,
+ pp->cmd_slot, pp->cmd_slot_dma);
+ ata_pad_free(ap, dev);
+ kfree(pp);
+}
+
+static void ahci_setup_port(struct ata_ioports *port, unsigned long base,
+ unsigned int port_idx)
+{
+ VPRINTK("ENTER, base==0x%lx, port_idx %u\n", base, port_idx);
+ base = ahci_port_base_ul(base, port_idx);
+ VPRINTK("base now==0x%lx\n", base);
+
+ port->cmd_addr = base;
+ port->scr_addr = base + PORT_SCR;
+
+ VPRINTK("EXIT\n");
+}
+
+static int ahci_host_init(struct ata_probe_ent *probe_ent)
+{
+ struct ahci_host_priv *hpriv = probe_ent->private_data;
+ struct pci_dev *pdev = to_pci_dev(probe_ent->dev);
+ void __iomem *mmio = probe_ent->mmio_base;
+ unsigned int i, using_dac;
+ int rc;
+
+ rc = ahci_reset_controller(mmio, pdev);
+ if (rc)
+ return rc;
+
+ hpriv->cap = readl(mmio + HOST_CAP);
+ hpriv->port_map = readl(mmio + HOST_PORTS_IMPL);
+ probe_ent->n_ports = (hpriv->cap & 0x1f) + 1;
+
+ VPRINTK("cap 0x%x port_map 0x%x n_ports %d\n",
+ hpriv->cap, hpriv->port_map, probe_ent->n_ports);
+
+ using_dac = hpriv->cap & HOST_CAP_64;
+ if (using_dac &&
+ !pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
+ rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
+ if (rc) {
+ rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+ if (rc) {
+ dev_printk(KERN_ERR, &pdev->dev,
+ "64-bit DMA enable failed\n");
+ return rc;
+ }
+ }
+ } else {
+ rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+ if (rc) {
+ dev_printk(KERN_ERR, &pdev->dev,
+ "32-bit DMA enable failed\n");
+ return rc;
+ }
+ rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+ if (rc) {
+ dev_printk(KERN_ERR, &pdev->dev,
+ "32-bit consistent DMA enable failed\n");
+ return rc;
+ }
+ }
+
+ for (i = 0; i < probe_ent->n_ports; i++)
+ ahci_setup_port(&probe_ent->port[i], (unsigned long) mmio, i);
+
+ ahci_init_controller(mmio, pdev, probe_ent->n_ports, hpriv->cap);
+
+ pci_set_master(pdev);
+
+ return 0;
+}
+
+static void ahci_print_info(struct ata_probe_ent *probe_ent)
+{
+ struct ahci_host_priv *hpriv = probe_ent->private_data;
+ struct pci_dev *pdev = to_pci_dev(probe_ent->dev);
+ void __iomem *mmio = probe_ent->mmio_base;
+ u32 vers, cap, impl, speed;
+ const char *speed_s;
+ u16 cc;
+ const char *scc_s;
+
+ vers = readl(mmio + HOST_VERSION);
+ cap = hpriv->cap;
+ impl = hpriv->port_map;
+
+ speed = (cap >> 20) & 0xf;
+ if (speed == 1)
+ speed_s = "1.5";
+ else if (speed == 2)
+ speed_s = "3";
+ else
+ speed_s = "?";
+
+ pci_read_config_word(pdev, 0x0a, &cc);
+ if (cc == 0x0101)
+ scc_s = "IDE";
+ else if (cc == 0x0106)
+ scc_s = "SATA";
+ else if (cc == 0x0104)
+ scc_s = "RAID";
+ else
+ scc_s = "unknown";
+
+ dev_printk(KERN_INFO, &pdev->dev,
+ "AHCI %02x%02x.%02x%02x "
+ "%u slots %u ports %s Gbps 0x%x impl %s mode\n"
+ ,
+
+ (vers >> 24) & 0xff,
+ (vers >> 16) & 0xff,
+ (vers >> 8) & 0xff,
+ vers & 0xff,
+
+ ((cap >> 8) & 0x1f) + 1,
+ (cap & 0x1f) + 1,
+ speed_s,
+ impl,
+ scc_s);
+
+ dev_printk(KERN_INFO, &pdev->dev,
+ "flags: "
+ "%s%s%s%s%s%s"
+ "%s%s%s%s%s%s%s\n"
+ ,
+
+ cap & (1 << 31) ? "64bit " : "",
+ cap & (1 << 30) ? "ncq " : "",
+ cap & (1 << 28) ? "ilck " : "",
+ cap & (1 << 27) ? "stag " : "",
+ cap & (1 << 26) ? "pm " : "",
+ cap & (1 << 25) ? "led " : "",
+
+ cap & (1 << 24) ? "clo " : "",
+ cap & (1 << 19) ? "nz " : "",
+ cap & (1 << 18) ? "only " : "",
+ cap & (1 << 17) ? "pmp " : "",
+ cap & (1 << 15) ? "pio " : "",
+ cap & (1 << 14) ? "slum " : "",
+ cap & (1 << 13) ? "part " : ""
+ );
+}
+
+static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ static int printed_version;
+ struct ata_probe_ent *probe_ent = NULL;
+ struct ahci_host_priv *hpriv;
+ unsigned long base;
+ void __iomem *mmio_base;
+ unsigned int board_idx = (unsigned int) ent->driver_data;
+ int have_msi, pci_dev_busy = 0;
+ int rc;
+
+ VPRINTK("ENTER\n");
+
+ WARN_ON(ATA_MAX_QUEUE > AHCI_MAX_CMDS);
+
+ if (!printed_version++)
+ dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
+
+ /* JMicron-specific fixup: make sure we're in AHCI mode */
+ /* This is protected from races with ata_jmicron by the pci probe
+ locking */
+ if (pdev->vendor == PCI_VENDOR_ID_JMICRON) {
+ /* AHCI enable, AHCI on function 0 */
+ pci_write_config_byte(pdev, 0x41, 0xa1);
+ /* Function 1 is the PATA controller */
+ if (PCI_FUNC(pdev->devfn))
+ return -ENODEV;
+ }
+
+ rc = pci_enable_device(pdev);
+ if (rc)
+ return rc;
+
+ rc = pci_request_regions(pdev, DRV_NAME);
+ if (rc) {
+ pci_dev_busy = 1;
+ goto err_out;
+ }
+
+ if (pci_enable_msi(pdev) == 0)
+ have_msi = 1;
+ else {
+ pci_intx(pdev, 1);
+ have_msi = 0;
+ }
+
+ probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
+ if (probe_ent == NULL) {
+ rc = -ENOMEM;
+ goto err_out_msi;
+ }
+
+ memset(probe_ent, 0, sizeof(*probe_ent));
+ probe_ent->dev = pci_dev_to_dev(pdev);
+ INIT_LIST_HEAD(&probe_ent->node);
+
+ mmio_base = pci_iomap(pdev, AHCI_PCI_BAR, 0);
+ if (mmio_base == NULL) {
+ rc = -ENOMEM;
+ goto err_out_free_ent;
+ }
+ base = (unsigned long) mmio_base;
+
+ hpriv = kmalloc(sizeof(*hpriv), GFP_KERNEL);
+ if (!hpriv) {
+ rc = -ENOMEM;
+ goto err_out_iounmap;
+ }
+ memset(hpriv, 0, sizeof(*hpriv));
+
+ probe_ent->sht = ahci_port_info[board_idx].sht;
+ probe_ent->port_flags = ahci_port_info[board_idx].flags;
+ probe_ent->pio_mask = ahci_port_info[board_idx].pio_mask;
+ probe_ent->udma_mask = ahci_port_info[board_idx].udma_mask;
+ probe_ent->port_ops = ahci_port_info[board_idx].port_ops;
+
+ probe_ent->irq = pdev->irq;
+ probe_ent->irq_flags = IRQF_SHARED;
+ probe_ent->mmio_base = mmio_base;
+ probe_ent->private_data = hpriv;
+
+ if (have_msi)
+ hpriv->flags |= AHCI_FLAG_MSI;
+
+ /* initialize adapter */
+ rc = ahci_host_init(probe_ent);
+ if (rc)
+ goto err_out_hpriv;
+
+ if (!(probe_ent->port_flags & AHCI_FLAG_NO_NCQ) &&
+ (hpriv->cap & HOST_CAP_NCQ))
+ probe_ent->port_flags |= ATA_FLAG_NCQ;
+
+ ahci_print_info(probe_ent);
+
+ /* FIXME: check ata_device_add return value */
+ ata_device_add(probe_ent);
+ kfree(probe_ent);
+
+ return 0;
+
+err_out_hpriv:
+ kfree(hpriv);
+err_out_iounmap:
+ pci_iounmap(pdev, mmio_base);
+err_out_free_ent:
+ kfree(probe_ent);
+err_out_msi:
+ if (have_msi)
+ pci_disable_msi(pdev);
+ else
+ pci_intx(pdev, 0);
+ pci_release_regions(pdev);
+err_out:
+ if (!pci_dev_busy)
+ pci_disable_device(pdev);
+ return rc;
+}
+
+static void ahci_remove_one (struct pci_dev *pdev)
+{
+ struct device *dev = pci_dev_to_dev(pdev);
+ struct ata_host *host = dev_get_drvdata(dev);
+ struct ahci_host_priv *hpriv = host->private_data;
+ unsigned int i;
+ int have_msi;
+
+ for (i = 0; i < host->n_ports; i++)
+ ata_port_detach(host->ports[i]);
+
+ have_msi = hpriv->flags & AHCI_FLAG_MSI;
+ free_irq(host->irq, host);
+
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap = host->ports[i];
+
+ ata_scsi_release(ap->scsi_host);
+ scsi_host_put(ap->scsi_host);
+ }
+
+ kfree(hpriv);
+ pci_iounmap(pdev, host->mmio_base);
+ kfree(host);
+
+ if (have_msi)
+ pci_disable_msi(pdev);
+ else
+ pci_intx(pdev, 0);
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+ dev_set_drvdata(dev, NULL);
+}
+
+static int __init ahci_init(void)
+{
+ return pci_register_driver(&ahci_pci_driver);
+}
+
+static void __exit ahci_exit(void)
+{
+ pci_unregister_driver(&ahci_pci_driver);
+}
+
+
+MODULE_AUTHOR("Jeff Garzik");
+MODULE_DESCRIPTION("AHCI SATA low-level driver");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, ahci_pci_tbl);
+MODULE_VERSION(DRV_VERSION);
+
+module_init(ahci_init);
+module_exit(ahci_exit);
diff --git a/drivers/ata/ata_generic.c b/drivers/ata/ata_generic.c
new file mode 100644
index 00000000000..377425e7139
--- /dev/null
+++ b/drivers/ata/ata_generic.c
@@ -0,0 +1,252 @@
+/*
+ * ata_generic.c - Generic PATA/SATA controller driver.
+ * Copyright 2005 Red Hat Inc <alan@redhat.com>, all rights reserved.
+ *
+ * Elements from ide/pci/generic.c
+ * Copyright (C) 2001-2002 Andre Hedrick <andre@linux-ide.org>
+ * Portions (C) Copyright 2002 Red Hat Inc <alan@redhat.com>
+ *
+ * May be copied or modified under the terms of the GNU General Public License
+ *
+ * Driver for PCI IDE interfaces implementing the standard bus mastering
+ * interface functionality. This assumes the BIOS did the drive set up and
+ * tuning for us. By default we do not grab all IDE class devices as they
+ * may have other drivers or need fixups to avoid problems. Instead we keep
+ * a default list of stuff without documentation/driver that appears to
+ * work.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+
+#define DRV_NAME "ata_generic"
+#define DRV_VERSION "0.2.6"
+
+/*
+ * A generic parallel ATA driver using libata
+ */
+
+/**
+ * generic_pre_reset - probe begin
+ * @ap: ATA port
+ *
+ * Set up cable type and use generic probe init
+ */
+
+static int generic_pre_reset(struct ata_port *ap)
+{
+ ap->cbl = ATA_CBL_PATA80;
+ return ata_std_prereset(ap);
+}
+
+
+/**
+ * generic_error_handler - Probe specified port on PATA host controller
+ * @ap: Port to probe
+ * @classes:
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+
+static void generic_error_handler(struct ata_port *ap)
+{
+ ata_bmdma_drive_eh(ap, generic_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
+}
+
+/**
+ * generic_set_mode - mode setting
+ * @ap: interface to set up
+ *
+ * Use a non standard set_mode function. We don't want to be tuned.
+ * The BIOS configured everything. Our job is not to fiddle. We
+ * read the dma enabled bits from the PCI configuration of the device
+ * and respect them.
+ */
+
+static void generic_set_mode(struct ata_port *ap)
+{
+ int dma_enabled = 0;
+ int i;
+
+ /* Bits 5 and 6 indicate if DMA is active on master/slave */
+ if (ap->ioaddr.bmdma_addr)
+ dma_enabled = inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
+
+ for (i = 0; i < ATA_MAX_DEVICES; i++) {
+ struct ata_device *dev = &ap->device[i];
+ if (ata_dev_enabled(dev)) {
+ /* We don't really care */
+ dev->pio_mode = XFER_PIO_0;
+ dev->dma_mode = XFER_MW_DMA_0;
+ /* We do need the right mode information for DMA or PIO
+ and this comes from the current configuration flags */
+ if (dma_enabled & (1 << (5 + i))) {
+ dev->xfer_mode = XFER_MW_DMA_0;
+ dev->xfer_shift = ATA_SHIFT_MWDMA;
+ dev->flags &= ~ATA_DFLAG_PIO;
+ } else {
+ dev->xfer_mode = XFER_PIO_0;
+ dev->xfer_shift = ATA_SHIFT_PIO;
+ dev->flags |= ATA_DFLAG_PIO;
+ }
+ }
+ }
+}
+
+static struct scsi_host_template generic_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .max_sectors = ATA_MAX_SECTORS,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .bios_param = ata_std_bios_param,
+};
+
+static struct ata_port_operations generic_port_ops = {
+ .set_mode = generic_set_mode,
+
+ .port_disable = ata_port_disable,
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = generic_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+static int all_generic_ide; /* Set to claim all devices */
+
+/**
+ * ata_generic_init - attach generic IDE
+ * @dev: PCI device found
+ * @id: match entry
+ *
+ * Called each time a matching IDE interface is found. We check if the
+ * interface is one we wish to claim and if so we perform any chip
+ * specific hacks then let the ATA layer do the heavy lifting.
+ */
+
+static int ata_generic_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ u16 command;
+ static struct ata_port_info info = {
+ .sht = &generic_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x3f,
+ .port_ops = &generic_port_ops
+ };
+ static struct ata_port_info *port_info[2] = { &info, &info };
+
+ /* Don't use the generic entry unless instructed to do so */
+ if (id->driver_data == 1 && all_generic_ide == 0)
+ return -ENODEV;
+
+ /* Devices that need care */
+ if (dev->vendor == PCI_VENDOR_ID_UMC &&
+ dev->device == PCI_DEVICE_ID_UMC_UM8886A &&
+ (!(PCI_FUNC(dev->devfn) & 1)))
+ return -ENODEV;
+
+ if (dev->vendor == PCI_VENDOR_ID_OPTI &&
+ dev->device == PCI_DEVICE_ID_OPTI_82C558 &&
+ (!(PCI_FUNC(dev->devfn) & 1)))
+ return -ENODEV;
+
+ /* Don't re-enable devices in generic mode or we will break some
+ motherboards with disabled and unused IDE controllers */
+ pci_read_config_word(dev, PCI_COMMAND, &command);
+ if (!(command & PCI_COMMAND_IO))
+ return -ENODEV;
+
+ if (dev->vendor == PCI_VENDOR_ID_AL)
+ ata_pci_clear_simplex(dev);
+
+ return ata_pci_init_one(dev, port_info, 2);
+}
+
+static struct pci_device_id ata_generic[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_SAMURAI_IDE), },
+ { PCI_DEVICE(PCI_VENDOR_ID_HOLTEK, PCI_DEVICE_ID_HOLTEK_6565), },
+ { PCI_DEVICE(PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8673F), },
+ { PCI_DEVICE(PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886A), },
+ { PCI_DEVICE(PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886BF), },
+ { PCI_DEVICE(PCI_VENDOR_ID_HINT, PCI_DEVICE_ID_HINT_VXPROII_IDE), },
+ { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C561), },
+ { PCI_DEVICE(PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C558), },
+ { PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO), },
+ { PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_1), },
+ { PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_2), },
+ /* Must come last. If you add entries adjust this table appropriately */
+ { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xFFFFFF00UL, 1},
+ { 0, },
+};
+
+static struct pci_driver ata_generic_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = ata_generic,
+ .probe = ata_generic_init_one,
+ .remove = ata_pci_remove_one
+};
+
+static int __init ata_generic_init(void)
+{
+ return pci_module_init(&ata_generic_pci_driver);
+}
+
+
+static void __exit ata_generic_exit(void)
+{
+ pci_unregister_driver(&ata_generic_pci_driver);
+}
+
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("low-level driver for generic ATA");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, ata_generic);
+MODULE_VERSION(DRV_VERSION);
+
+module_init(ata_generic_init);
+module_exit(ata_generic_exit);
+
+module_param(all_generic_ide, int, 0);
diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c
new file mode 100644
index 00000000000..5719704eb0e
--- /dev/null
+++ b/drivers/ata/ata_piix.c
@@ -0,0 +1,1256 @@
+/*
+ * ata_piix.c - Intel PATA/SATA controllers
+ *
+ * Maintained by: Jeff Garzik <jgarzik@pobox.com>
+ * Please ALWAYS copy linux-ide@vger.kernel.org
+ * on emails.
+ *
+ *
+ * Copyright 2003-2005 Red Hat Inc
+ * Copyright 2003-2005 Jeff Garzik
+ *
+ *
+ * Copyright header from piix.c:
+ *
+ * Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer
+ * Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org>
+ * Copyright (C) 2003 Red Hat Inc <alan@redhat.com>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * libata documentation is available via 'make {ps|pdf}docs',
+ * as Documentation/DocBook/libata.*
+ *
+ * Hardware documentation available at http://developer.intel.com/
+ *
+ * Documentation
+ * Publically available from Intel web site. Errata documentation
+ * is also publically available. As an aide to anyone hacking on this
+ * driver the list of errata that are relevant is below.going back to
+ * PIIX4. Older device documentation is now a bit tricky to find.
+ *
+ * The chipsets all follow very much the same design. The orginal Triton
+ * series chipsets do _not_ support independant device timings, but this
+ * is fixed in Triton II. With the odd mobile exception the chips then
+ * change little except in gaining more modes until SATA arrives. This
+ * driver supports only the chips with independant timing (that is those
+ * with SITRE and the 0x44 timing register). See pata_oldpiix and pata_mpiix
+ * for the early chip drivers.
+ *
+ * Errata of note:
+ *
+ * Unfixable
+ * PIIX4 errata #9 - Only on ultra obscure hw
+ * ICH3 errata #13 - Not observed to affect real hw
+ * by Intel
+ *
+ * Things we must deal with
+ * PIIX4 errata #10 - BM IDE hang with non UDMA
+ * (must stop/start dma to recover)
+ * 440MX errata #15 - As PIIX4 errata #10
+ * PIIX4 errata #15 - Must not read control registers
+ * during a PIO transfer
+ * 440MX errata #13 - As PIIX4 errata #15
+ * ICH2 errata #21 - DMA mode 0 doesn't work right
+ * ICH0/1 errata #55 - As ICH2 errata #21
+ * ICH2 spec c #9 - Extra operations needed to handle
+ * drive hotswap [NOT YET SUPPORTED]
+ * ICH2 spec c #20 - IDE PRD must not cross a 64K boundary
+ * and must be dword aligned
+ * ICH2 spec c #24 - UDMA mode 4,5 t85/86 should be 6ns not 3.3
+ *
+ * Should have been BIOS fixed:
+ * 450NX: errata #19 - DMA hangs on old 450NX
+ * 450NX: errata #20 - DMA hangs on old 450NX
+ * 450NX: errata #25 - Corruption with DMA on old 450NX
+ * ICH3 errata #15 - IDE deadlock under high load
+ * (BIOS must set dev 31 fn 0 bit 23)
+ * ICH3 errata #18 - Don't use native mode
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+
+#define DRV_NAME "ata_piix"
+#define DRV_VERSION "2.00ac6"
+
+enum {
+ PIIX_IOCFG = 0x54, /* IDE I/O configuration register */
+ ICH5_PMR = 0x90, /* port mapping register */
+ ICH5_PCS = 0x92, /* port control and status */
+ PIIX_SCC = 0x0A, /* sub-class code register */
+
+ PIIX_FLAG_IGNORE_PCS = (1 << 25), /* ignore PCS present bits */
+ PIIX_FLAG_SCR = (1 << 26), /* SCR available */
+ PIIX_FLAG_AHCI = (1 << 27), /* AHCI possible */
+ PIIX_FLAG_CHECKINTR = (1 << 28), /* make sure PCI INTx enabled */
+
+ /* combined mode. if set, PATA is channel 0.
+ * if clear, PATA is channel 1.
+ */
+ PIIX_PORT_ENABLED = (1 << 0),
+ PIIX_PORT_PRESENT = (1 << 4),
+
+ PIIX_80C_PRI = (1 << 5) | (1 << 4),
+ PIIX_80C_SEC = (1 << 7) | (1 << 6),
+
+ /* controller IDs */
+ piix_pata_33 = 0, /* PIIX3 or 4 at 33Mhz */
+ ich_pata_33 = 1, /* ICH up to UDMA 33 only */
+ ich_pata_66 = 2, /* ICH up to 66 Mhz */
+ ich_pata_100 = 3, /* ICH up to UDMA 100 */
+ ich_pata_133 = 4, /* ICH up to UDMA 133 */
+ ich5_sata = 5,
+ esb_sata = 6,
+ ich6_sata = 7,
+ ich6_sata_ahci = 8,
+ ich6m_sata_ahci = 9,
+ ich7m_sata_ahci = 10,
+ ich8_sata_ahci = 11,
+
+ /* constants for mapping table */
+ P0 = 0, /* port 0 */
+ P1 = 1, /* port 1 */
+ P2 = 2, /* port 2 */
+ P3 = 3, /* port 3 */
+ IDE = -1, /* IDE */
+ NA = -2, /* not avaliable */
+ RV = -3, /* reserved */
+
+ PIIX_AHCI_DEVICE = 6,
+};
+
+struct piix_map_db {
+ const u32 mask;
+ const u16 port_enable;
+ const int present_shift;
+ const int map[][4];
+};
+
+struct piix_host_priv {
+ const int *map;
+ const struct piix_map_db *map_db;
+};
+
+static int piix_init_one (struct pci_dev *pdev,
+ const struct pci_device_id *ent);
+static void piix_host_stop(struct ata_host *host);
+static void piix_pata_error_handler(struct ata_port *ap);
+static void ich_pata_error_handler(struct ata_port *ap);
+static void piix_sata_error_handler(struct ata_port *ap);
+static void piix_set_piomode (struct ata_port *ap, struct ata_device *adev);
+static void piix_set_dmamode (struct ata_port *ap, struct ata_device *adev);
+static void ich_set_dmamode (struct ata_port *ap, struct ata_device *adev);
+
+static unsigned int in_module_init = 1;
+
+static const struct pci_device_id piix_pci_tbl[] = {
+#ifdef ATA_ENABLE_PATA
+ /* Intel PIIX4 for the 430TX/440BX/MX chipset: UDMA 33 */
+ /* Also PIIX4E (fn3 rev 2) and PIIX4M (fn3 rev 3) */
+ { 0x8086, 0x7111, PCI_ANY_ID, PCI_ANY_ID, 0, 0, piix_pata_33 },
+ { 0x8086, 0x24db, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
+ { 0x8086, 0x25a2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
+ /* Intel PIIX4 */
+ { 0x8086, 0x7199, PCI_ANY_ID, PCI_ANY_ID, 0, 0, piix_pata_33 },
+ /* Intel PIIX4 */
+ { 0x8086, 0x7601, PCI_ANY_ID, PCI_ANY_ID, 0, 0, piix_pata_33 },
+ /* Intel PIIX */
+ { 0x8086, 0x84CA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, piix_pata_33 },
+ /* Intel ICH (i810, i815, i840) UDMA 66*/
+ { 0x8086, 0x2411, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_66 },
+ /* Intel ICH0 : UDMA 33*/
+ { 0x8086, 0x2421, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_33 },
+ /* Intel ICH2M */
+ { 0x8086, 0x244A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
+ /* Intel ICH2 (i810E2, i845, 850, 860) UDMA 100 */
+ { 0x8086, 0x244B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
+ /* Intel ICH3M */
+ { 0x8086, 0x248A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
+ /* Intel ICH3 (E7500/1) UDMA 100 */
+ { 0x8086, 0x248B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
+ /* Intel ICH4 (i845GV, i845E, i852, i855) UDMA 100 */
+ { 0x8086, 0x24CA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
+ { 0x8086, 0x24CB, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
+ /* Intel ICH5 */
+ { 0x8086, 0x24DB, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_133 },
+ /* C-ICH (i810E2) */
+ { 0x8086, 0x245B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
+ /* ESB (855GME/875P + 6300ESB) UDMA 100 */
+ { 0x8086, 0x25A2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
+ /* ICH6 (and 6) (i915) UDMA 100 */
+ { 0x8086, 0x266F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
+ /* ICH7/7-R (i945, i975) UDMA 100*/
+ { 0x8086, 0x27DF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_133 },
+ { 0x8086, 0x269E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
+#endif
+
+ /* NOTE: The following PCI ids must be kept in sync with the
+ * list in drivers/pci/quirks.c.
+ */
+
+ /* 82801EB (ICH5) */
+ { 0x8086, 0x24d1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_sata },
+ /* 82801EB (ICH5) */
+ { 0x8086, 0x24df, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_sata },
+ /* 6300ESB (ICH5 variant with broken PCS present bits) */
+ { 0x8086, 0x25a3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, esb_sata },
+ /* 6300ESB pretending RAID */
+ { 0x8086, 0x25b0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, esb_sata },
+ /* 82801FB/FW (ICH6/ICH6W) */
+ { 0x8086, 0x2651, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata },
+ /* 82801FR/FRW (ICH6R/ICH6RW) */
+ { 0x8086, 0x2652, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_ahci },
+ /* 82801FBM ICH6M (ICH6R with only port 0 and 2 implemented) */
+ { 0x8086, 0x2653, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6m_sata_ahci },
+ /* 82801GB/GR/GH (ICH7, identical to ICH6) */
+ { 0x8086, 0x27c0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_ahci },
+ /* 2801GBM/GHM (ICH7M, identical to ICH6M) */
+ { 0x8086, 0x27c4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich7m_sata_ahci },
+ /* Enterprise Southbridge 2 (where's the datasheet?) */
+ { 0x8086, 0x2680, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_ahci },
+ /* SATA Controller 1 IDE (ICH8, no datasheet yet) */
+ { 0x8086, 0x2820, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci },
+ /* SATA Controller 2 IDE (ICH8, ditto) */
+ { 0x8086, 0x2825, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci },
+ /* Mobile SATA Controller IDE (ICH8M, ditto) */
+ { 0x8086, 0x2828, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci },
+
+ { } /* terminate list */
+};
+
+static struct pci_driver piix_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = piix_pci_tbl,
+ .probe = piix_init_one,
+ .remove = ata_pci_remove_one,
+ .suspend = ata_pci_device_suspend,
+ .resume = ata_pci_device_resume,
+};
+
+static struct scsi_host_template piix_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .slave_destroy = ata_scsi_slave_destroy,
+ .bios_param = ata_std_bios_param,
+ .resume = ata_scsi_device_resume,
+ .suspend = ata_scsi_device_suspend,
+};
+
+static const struct ata_port_operations piix_pata_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = piix_set_piomode,
+ .set_dmamode = piix_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+ .data_xfer = ata_pio_data_xfer,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = piix_pata_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = piix_host_stop,
+};
+
+static const struct ata_port_operations ich_pata_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = piix_set_piomode,
+ .set_dmamode = ich_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+ .data_xfer = ata_pio_data_xfer,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = ich_pata_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop,
+};
+
+static const struct ata_port_operations piix_sata_ops = {
+ .port_disable = ata_port_disable,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+ .data_xfer = ata_pio_data_xfer,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = piix_sata_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = piix_host_stop,
+};
+
+static const struct piix_map_db ich5_map_db = {
+ .mask = 0x7,
+ .port_enable = 0x3,
+ .present_shift = 4,
+ .map = {
+ /* PM PS SM SS MAP */
+ { P0, NA, P1, NA }, /* 000b */
+ { P1, NA, P0, NA }, /* 001b */
+ { RV, RV, RV, RV },
+ { RV, RV, RV, RV },
+ { P0, P1, IDE, IDE }, /* 100b */
+ { P1, P0, IDE, IDE }, /* 101b */
+ { IDE, IDE, P0, P1 }, /* 110b */
+ { IDE, IDE, P1, P0 }, /* 111b */
+ },
+};
+
+static const struct piix_map_db ich6_map_db = {
+ .mask = 0x3,
+ .port_enable = 0xf,
+ .present_shift = 4,
+ .map = {
+ /* PM PS SM SS MAP */
+ { P0, P2, P1, P3 }, /* 00b */
+ { IDE, IDE, P1, P3 }, /* 01b */
+ { P0, P2, IDE, IDE }, /* 10b */
+ { RV, RV, RV, RV },
+ },
+};
+
+static const struct piix_map_db ich6m_map_db = {
+ .mask = 0x3,
+ .port_enable = 0x5,
+ .present_shift = 4,
+ .map = {
+ /* PM PS SM SS MAP */
+ { P0, P2, RV, RV }, /* 00b */
+ { RV, RV, RV, RV },
+ { P0, P2, IDE, IDE }, /* 10b */
+ { RV, RV, RV, RV },
+ },
+};
+
+static const struct piix_map_db ich7m_map_db = {
+ .mask = 0x3,
+ .port_enable = 0x5,
+ .present_shift = 4,
+
+ /* Map 01b isn't specified in the doc but some notebooks use
+ * it anyway. ATM, the only case spotted carries subsystem ID
+ * 1025:0107. This is the only difference from ich6m.
+ */
+ .map = {
+ /* PM PS SM SS MAP */
+ { P0, P2, RV, RV }, /* 00b */
+ { IDE, IDE, P1, P3 }, /* 01b */
+ { P0, P2, IDE, IDE }, /* 10b */
+ { RV, RV, RV, RV },
+ },
+};
+
+static const struct piix_map_db ich8_map_db = {
+ .mask = 0x3,
+ .port_enable = 0x3,
+ .present_shift = 8,
+ .map = {
+ /* PM PS SM SS MAP */
+ { P0, NA, P1, NA }, /* 00b (hardwired) */
+ { RV, RV, RV, RV },
+ { RV, RV, RV, RV }, /* 10b (never) */
+ { RV, RV, RV, RV },
+ },
+};
+
+static const struct piix_map_db *piix_map_db_table[] = {
+ [ich5_sata] = &ich5_map_db,
+ [esb_sata] = &ich5_map_db,
+ [ich6_sata] = &ich6_map_db,
+ [ich6_sata_ahci] = &ich6_map_db,
+ [ich6m_sata_ahci] = &ich6m_map_db,
+ [ich7m_sata_ahci] = &ich7m_map_db,
+ [ich8_sata_ahci] = &ich8_map_db,
+};
+
+static struct ata_port_info piix_port_info[] = {
+ /* piix_pata_33: 0: PIIX3 or 4 at 33MHz */
+ {
+ .sht = &piix_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .mwdma_mask = 0x06, /* mwdma1-2 ?? CHECK 0 should be ok but slow */
+ .udma_mask = ATA_UDMA_MASK_40C,
+ .port_ops = &piix_pata_ops,
+ },
+
+ /* ich_pata_33: 1 ICH0 - ICH at 33Mhz*/
+ {
+ .sht = &piix_sht,
+ .flags = ATA_FLAG_SRST | ATA_FLAG_SLAVE_POSS,
+ .pio_mask = 0x1f, /* pio 0-4 */
+ .mwdma_mask = 0x06, /* Check: maybe 0x07 */
+ .udma_mask = ATA_UDMA2, /* UDMA33 */
+ .port_ops = &ich_pata_ops,
+ },
+ /* ich_pata_66: 2 ICH controllers up to 66MHz */
+ {
+ .sht = &piix_sht,
+ .flags = ATA_FLAG_SRST | ATA_FLAG_SLAVE_POSS,
+ .pio_mask = 0x1f, /* pio 0-4 */
+ .mwdma_mask = 0x06, /* MWDMA0 is broken on chip */
+ .udma_mask = ATA_UDMA4,
+ .port_ops = &ich_pata_ops,
+ },
+
+ /* ich_pata_100: 3 */
+ {
+ .sht = &piix_sht,
+ .flags = ATA_FLAG_SRST | ATA_FLAG_SLAVE_POSS | PIIX_FLAG_CHECKINTR,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .mwdma_mask = 0x06, /* mwdma1-2 */
+ .udma_mask = ATA_UDMA5, /* udma0-5 */
+ .port_ops = &ich_pata_ops,
+ },
+
+ /* ich_pata_133: 4 ICH with full UDMA6 */
+ {
+ .sht = &piix_sht,
+ .flags = ATA_FLAG_SRST | ATA_FLAG_SLAVE_POSS | PIIX_FLAG_CHECKINTR,
+ .pio_mask = 0x1f, /* pio 0-4 */
+ .mwdma_mask = 0x06, /* Check: maybe 0x07 */
+ .udma_mask = ATA_UDMA6, /* UDMA133 */
+ .port_ops = &ich_pata_ops,
+ },
+
+ /* ich5_sata: 5 */
+ {
+ .sht = &piix_sht,
+ .flags = ATA_FLAG_SATA | PIIX_FLAG_CHECKINTR |
+ PIIX_FLAG_IGNORE_PCS,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .mwdma_mask = 0x07, /* mwdma0-2 */
+ .udma_mask = 0x7f, /* udma0-6 */
+ .port_ops = &piix_sata_ops,
+ },
+
+ /* i6300esb_sata: 6 */
+ {
+ .sht = &piix_sht,
+ .flags = ATA_FLAG_SATA |
+ PIIX_FLAG_CHECKINTR | PIIX_FLAG_IGNORE_PCS,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .mwdma_mask = 0x07, /* mwdma0-2 */
+ .udma_mask = 0x7f, /* udma0-6 */
+ .port_ops = &piix_sata_ops,
+ },
+
+ /* ich6_sata: 7 */
+ {
+ .sht = &piix_sht,
+ .flags = ATA_FLAG_SATA |
+ PIIX_FLAG_CHECKINTR | PIIX_FLAG_SCR,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .mwdma_mask = 0x07, /* mwdma0-2 */
+ .udma_mask = 0x7f, /* udma0-6 */
+ .port_ops = &piix_sata_ops,
+ },
+
+ /* ich6_sata_ahci: 8 */
+ {
+ .sht = &piix_sht,
+ .flags = ATA_FLAG_SATA |
+ PIIX_FLAG_CHECKINTR | PIIX_FLAG_SCR |
+ PIIX_FLAG_AHCI,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .mwdma_mask = 0x07, /* mwdma0-2 */
+ .udma_mask = 0x7f, /* udma0-6 */
+ .port_ops = &piix_sata_ops,
+ },
+
+ /* ich6m_sata_ahci: 9 */
+ {
+ .sht = &piix_sht,
+ .flags = ATA_FLAG_SATA |
+ PIIX_FLAG_CHECKINTR | PIIX_FLAG_SCR |
+ PIIX_FLAG_AHCI,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .mwdma_mask = 0x07, /* mwdma0-2 */
+ .udma_mask = 0x7f, /* udma0-6 */
+ .port_ops = &piix_sata_ops,
+ },
+
+ /* ich7m_sata_ahci: 10 */
+ {
+ .sht = &piix_sht,
+ .flags = ATA_FLAG_SATA |
+ PIIX_FLAG_CHECKINTR | PIIX_FLAG_SCR |
+ PIIX_FLAG_AHCI,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .mwdma_mask = 0x07, /* mwdma0-2 */
+ .udma_mask = 0x7f, /* udma0-6 */
+ .port_ops = &piix_sata_ops,
+ },
+
+ /* ich8_sata_ahci: 11 */
+ {
+ .sht = &piix_sht,
+ .flags = ATA_FLAG_SATA |
+ PIIX_FLAG_CHECKINTR | PIIX_FLAG_SCR |
+ PIIX_FLAG_AHCI,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .mwdma_mask = 0x07, /* mwdma0-2 */
+ .udma_mask = 0x7f, /* udma0-6 */
+ .port_ops = &piix_sata_ops,
+ },
+
+};
+
+static struct pci_bits piix_enable_bits[] = {
+ { 0x41U, 1U, 0x80UL, 0x80UL }, /* port 0 */
+ { 0x43U, 1U, 0x80UL, 0x80UL }, /* port 1 */
+};
+
+MODULE_AUTHOR("Andre Hedrick, Alan Cox, Andrzej Krzysztofowicz, Jeff Garzik");
+MODULE_DESCRIPTION("SCSI low-level driver for Intel PIIX/ICH ATA controllers");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, piix_pci_tbl);
+MODULE_VERSION(DRV_VERSION);
+
+static int force_pcs = 0;
+module_param(force_pcs, int, 0444);
+MODULE_PARM_DESC(force_pcs, "force honoring or ignoring PCS to work around "
+ "device mis-detection (0=default, 1=ignore PCS, 2=honor PCS)");
+
+/**
+ * piix_pata_cbl_detect - Probe host controller cable detect info
+ * @ap: Port for which cable detect info is desired
+ *
+ * Read 80c cable indicator from ATA PCI device's PCI config
+ * register. This register is normally set by firmware (BIOS).
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void ich_pata_cbl_detect(struct ata_port *ap)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u8 tmp, mask;
+
+ /* no 80c support in host controller? */
+ if ((ap->udma_mask & ~ATA_UDMA_MASK_40C) == 0)
+ goto cbl40;
+
+ /* check BIOS cable detect results */
+ mask = ap->port_no == 0 ? PIIX_80C_PRI : PIIX_80C_SEC;
+ pci_read_config_byte(pdev, PIIX_IOCFG, &tmp);
+ if ((tmp & mask) == 0)
+ goto cbl40;
+
+ ap->cbl = ATA_CBL_PATA80;
+ return;
+
+cbl40:
+ ap->cbl = ATA_CBL_PATA40;
+}
+
+/**
+ * piix_pata_prereset - prereset for PATA host controller
+ * @ap: Target port
+ *
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+static int piix_pata_prereset(struct ata_port *ap)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+
+ if (!pci_test_config_bits(pdev, &piix_enable_bits[ap->port_no]))
+ return -ENOENT;
+
+ ap->cbl = ATA_CBL_PATA40;
+ return ata_std_prereset(ap);
+}
+
+static void piix_pata_error_handler(struct ata_port *ap)
+{
+ ata_bmdma_drive_eh(ap, piix_pata_prereset, ata_std_softreset, NULL,
+ ata_std_postreset);
+}
+
+
+/**
+ * ich_pata_prereset - prereset for PATA host controller
+ * @ap: Target port
+ *
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+static int ich_pata_prereset(struct ata_port *ap)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+
+ if (!pci_test_config_bits(pdev, &piix_enable_bits[ap->port_no])) {
+ ata_port_printk(ap, KERN_INFO, "port disabled. ignoring.\n");
+ ap->eh_context.i.action &= ~ATA_EH_RESET_MASK;
+ return 0;
+ }
+
+ ich_pata_cbl_detect(ap);
+
+ return ata_std_prereset(ap);
+}
+
+static void ich_pata_error_handler(struct ata_port *ap)
+{
+ ata_bmdma_drive_eh(ap, ich_pata_prereset, ata_std_softreset, NULL,
+ ata_std_postreset);
+}
+
+/**
+ * piix_sata_present_mask - determine present mask for SATA host controller
+ * @ap: Target port
+ *
+ * Reads SATA PCI device's PCI config register Port Configuration
+ * and Status (PCS) to determine port and device availability.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ *
+ * RETURNS:
+ * determined present_mask
+ */
+static unsigned int piix_sata_present_mask(struct ata_port *ap)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ struct piix_host_priv *hpriv = ap->host->private_data;
+ const unsigned int *map = hpriv->map;
+ int base = 2 * ap->port_no;
+ unsigned int present_mask = 0;
+ int port, i;
+ u16 pcs;
+
+ pci_read_config_word(pdev, ICH5_PCS, &pcs);
+ DPRINTK("ata%u: ENTER, pcs=0x%x base=%d\n", ap->id, pcs, base);
+
+ for (i = 0; i < 2; i++) {
+ port = map[base + i];
+ if (port < 0)
+ continue;
+ if ((ap->flags & PIIX_FLAG_IGNORE_PCS) ||
+ (pcs & 1 << (hpriv->map_db->present_shift + port)))
+ present_mask |= 1 << i;
+ }
+
+ DPRINTK("ata%u: LEAVE, pcs=0x%x present_mask=0x%x\n",
+ ap->id, pcs, present_mask);
+
+ return present_mask;
+}
+
+/**
+ * piix_sata_softreset - reset SATA host port via ATA SRST
+ * @ap: port to reset
+ * @classes: resulting classes of attached devices
+ *
+ * Reset SATA host port via ATA SRST. On controllers with
+ * reliable PCS present bits, the bits are used to determine
+ * device presence.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep)
+ *
+ * RETURNS:
+ * 0 on success, -errno otherwise.
+ */
+static int piix_sata_softreset(struct ata_port *ap, unsigned int *classes)
+{
+ unsigned int present_mask;
+ int i, rc;
+
+ present_mask = piix_sata_present_mask(ap);
+
+ rc = ata_std_softreset(ap, classes);
+ if (rc)
+ return rc;
+
+ for (i = 0; i < ATA_MAX_DEVICES; i++) {
+ if (!(present_mask & (1 << i)))
+ classes[i] = ATA_DEV_NONE;
+ }
+
+ return 0;
+}
+
+static void piix_sata_error_handler(struct ata_port *ap)
+{
+ ata_bmdma_drive_eh(ap, ata_std_prereset, piix_sata_softreset, NULL,
+ ata_std_postreset);
+}
+
+/**
+ * piix_set_piomode - Initialize host controller PATA PIO timings
+ * @ap: Port whose timings we are configuring
+ * @adev: um
+ *
+ * Set PIO mode for device, in host controller PCI config space.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void piix_set_piomode (struct ata_port *ap, struct ata_device *adev)
+{
+ unsigned int pio = adev->pio_mode - XFER_PIO_0;
+ struct pci_dev *dev = to_pci_dev(ap->host->dev);
+ unsigned int is_slave = (adev->devno != 0);
+ unsigned int master_port= ap->port_no ? 0x42 : 0x40;
+ unsigned int slave_port = 0x44;
+ u16 master_data;
+ u8 slave_data;
+ u8 udma_enable;
+ int control = 0;
+
+ /*
+ * See Intel Document 298600-004 for the timing programing rules
+ * for ICH controllers.
+ */
+
+ static const /* ISP RTC */
+ u8 timings[][2] = { { 0, 0 },
+ { 0, 0 },
+ { 1, 0 },
+ { 2, 1 },
+ { 2, 3 }, };
+
+ if (pio >= 2)
+ control |= 1; /* TIME1 enable */
+ if (ata_pio_need_iordy(adev))
+ control |= 2; /* IE enable */
+
+ /* Intel specifies that the PPE functionality is for disk only */
+ if (adev->class == ATA_DEV_ATA)
+ control |= 4; /* PPE enable */
+
+ pci_read_config_word(dev, master_port, &master_data);
+ if (is_slave) {
+ /* Enable SITRE (seperate slave timing register) */
+ master_data |= 0x4000;
+ /* enable PPE1, IE1 and TIME1 as needed */
+ master_data |= (control << 4);
+ pci_read_config_byte(dev, slave_port, &slave_data);
+ slave_data &= (ap->port_no ? 0x0f : 0xf0);
+ /* Load the timing nibble for this slave */
+ slave_data |= ((timings[pio][0] << 2) | timings[pio][1]) << (ap->port_no ? 4 : 0);
+ } else {
+ /* Master keeps the bits in a different format */
+ master_data &= 0xccf8;
+ /* Enable PPE, IE and TIME as appropriate */
+ master_data |= control;
+ master_data |=
+ (timings[pio][0] << 12) |
+ (timings[pio][1] << 8);
+ }
+ pci_write_config_word(dev, master_port, master_data);
+ if (is_slave)
+ pci_write_config_byte(dev, slave_port, slave_data);
+
+ /* Ensure the UDMA bit is off - it will be turned back on if
+ UDMA is selected */
+
+ if (ap->udma_mask) {
+ pci_read_config_byte(dev, 0x48, &udma_enable);
+ udma_enable &= ~(1 << (2 * ap->port_no + adev->devno));
+ pci_write_config_byte(dev, 0x48, udma_enable);
+ }
+}
+
+/**
+ * do_pata_set_dmamode - Initialize host controller PATA PIO timings
+ * @ap: Port whose timings we are configuring
+ * @adev: Drive in question
+ * @udma: udma mode, 0 - 6
+ * @isich: set if the chip is an ICH device
+ *
+ * Set UDMA mode for device, in host controller PCI config space.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void do_pata_set_dmamode (struct ata_port *ap, struct ata_device *adev, int isich)
+{
+ struct pci_dev *dev = to_pci_dev(ap->host->dev);
+ u8 master_port = ap->port_no ? 0x42 : 0x40;
+ u16 master_data;
+ u8 speed = adev->dma_mode;
+ int devid = adev->devno + 2 * ap->port_no;
+ u8 udma_enable;
+
+ static const /* ISP RTC */
+ u8 timings[][2] = { { 0, 0 },
+ { 0, 0 },
+ { 1, 0 },
+ { 2, 1 },
+ { 2, 3 }, };
+
+ pci_read_config_word(dev, master_port, &master_data);
+ pci_read_config_byte(dev, 0x48, &udma_enable);
+
+ if (speed >= XFER_UDMA_0) {
+ unsigned int udma = adev->dma_mode - XFER_UDMA_0;
+ u16 udma_timing;
+ u16 ideconf;
+ int u_clock, u_speed;
+
+ /*
+ * UDMA is handled by a combination of clock switching and
+ * selection of dividers
+ *
+ * Handy rule: Odd modes are UDMATIMx 01, even are 02
+ * except UDMA0 which is 00
+ */
+ u_speed = min(2 - (udma & 1), udma);
+ if (udma == 5)
+ u_clock = 0x1000; /* 100Mhz */
+ else if (udma > 2)
+ u_clock = 1; /* 66Mhz */
+ else
+ u_clock = 0; /* 33Mhz */
+
+ udma_enable |= (1 << devid);
+
+ /* Load the CT/RP selection */
+ pci_read_config_word(dev, 0x4A, &udma_timing);
+ udma_timing &= ~(3 << (4 * devid));
+ udma_timing |= u_speed << (4 * devid);
+ pci_write_config_word(dev, 0x4A, udma_timing);
+
+ if (isich) {
+ /* Select a 33/66/100Mhz clock */
+ pci_read_config_word(dev, 0x54, &ideconf);
+ ideconf &= ~(0x1001 << devid);
+ ideconf |= u_clock << devid;
+ /* For ICH or later we should set bit 10 for better
+ performance (WR_PingPong_En) */
+ pci_write_config_word(dev, 0x54, ideconf);
+ }
+ } else {
+ /*
+ * MWDMA is driven by the PIO timings. We must also enable
+ * IORDY unconditionally along with TIME1. PPE has already
+ * been set when the PIO timing was set.
+ */
+ unsigned int mwdma = adev->dma_mode - XFER_MW_DMA_0;
+ unsigned int control;
+ u8 slave_data;
+ const unsigned int needed_pio[3] = {
+ XFER_PIO_0, XFER_PIO_3, XFER_PIO_4
+ };
+ int pio = needed_pio[mwdma] - XFER_PIO_0;
+
+ control = 3; /* IORDY|TIME1 */
+
+ /* If the drive MWDMA is faster than it can do PIO then
+ we must force PIO into PIO0 */
+
+ if (adev->pio_mode < needed_pio[mwdma])
+ /* Enable DMA timing only */
+ control |= 8; /* PIO cycles in PIO0 */
+
+ if (adev->devno) { /* Slave */
+ master_data &= 0xFF4F; /* Mask out IORDY|TIME1|DMAONLY */
+ master_data |= control << 4;
+ pci_read_config_byte(dev, 0x44, &slave_data);
+ slave_data &= (0x0F + 0xE1 * ap->port_no);
+ /* Load the matching timing */
+ slave_data |= ((timings[pio][0] << 2) | timings[pio][1]) << (ap->port_no ? 4 : 0);
+ pci_write_config_byte(dev, 0x44, slave_data);
+ } else { /* Master */
+ master_data &= 0xCCF4; /* Mask out IORDY|TIME1|DMAONLY
+ and master timing bits */
+ master_data |= control;
+ master_data |=
+ (timings[pio][0] << 12) |
+ (timings[pio][1] << 8);
+ }
+ udma_enable &= ~(1 << devid);
+ pci_write_config_word(dev, master_port, master_data);
+ }
+ /* Don't scribble on 0x48 if the controller does not support UDMA */
+ if (ap->udma_mask)
+ pci_write_config_byte(dev, 0x48, udma_enable);
+}
+
+/**
+ * piix_set_dmamode - Initialize host controller PATA DMA timings
+ * @ap: Port whose timings we are configuring
+ * @adev: um
+ *
+ * Set MW/UDMA mode for device, in host controller PCI config space.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void piix_set_dmamode (struct ata_port *ap, struct ata_device *adev)
+{
+ do_pata_set_dmamode(ap, adev, 0);
+}
+
+/**
+ * ich_set_dmamode - Initialize host controller PATA DMA timings
+ * @ap: Port whose timings we are configuring
+ * @adev: um
+ *
+ * Set MW/UDMA mode for device, in host controller PCI config space.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void ich_set_dmamode (struct ata_port *ap, struct ata_device *adev)
+{
+ do_pata_set_dmamode(ap, adev, 1);
+}
+
+#define AHCI_PCI_BAR 5
+#define AHCI_GLOBAL_CTL 0x04
+#define AHCI_ENABLE (1 << 31)
+static int piix_disable_ahci(struct pci_dev *pdev)
+{
+ void __iomem *mmio;
+ u32 tmp;
+ int rc = 0;
+
+ /* BUG: pci_enable_device has not yet been called. This
+ * works because this device is usually set up by BIOS.
+ */
+
+ if (!pci_resource_start(pdev, AHCI_PCI_BAR) ||
+ !pci_resource_len(pdev, AHCI_PCI_BAR))
+ return 0;
+
+ mmio = pci_iomap(pdev, AHCI_PCI_BAR, 64);
+ if (!mmio)
+ return -ENOMEM;
+
+ tmp = readl(mmio + AHCI_GLOBAL_CTL);
+ if (tmp & AHCI_ENABLE) {
+ tmp &= ~AHCI_ENABLE;
+ writel(tmp, mmio + AHCI_GLOBAL_CTL);
+
+ tmp = readl(mmio + AHCI_GLOBAL_CTL);
+ if (tmp & AHCI_ENABLE)
+ rc = -EIO;
+ }
+
+ pci_iounmap(pdev, mmio);
+ return rc;
+}
+
+/**
+ * piix_check_450nx_errata - Check for problem 450NX setup
+ * @ata_dev: the PCI device to check
+ *
+ * Check for the present of 450NX errata #19 and errata #25. If
+ * they are found return an error code so we can turn off DMA
+ */
+
+static int __devinit piix_check_450nx_errata(struct pci_dev *ata_dev)
+{
+ struct pci_dev *pdev = NULL;
+ u16 cfg;
+ u8 rev;
+ int no_piix_dma = 0;
+
+ while((pdev = pci_get_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454NX, pdev)) != NULL)
+ {
+ /* Look for 450NX PXB. Check for problem configurations
+ A PCI quirk checks bit 6 already */
+ pci_read_config_byte(pdev, PCI_REVISION_ID, &rev);
+ pci_read_config_word(pdev, 0x41, &cfg);
+ /* Only on the original revision: IDE DMA can hang */
+ if (rev == 0x00)
+ no_piix_dma = 1;
+ /* On all revisions below 5 PXB bus lock must be disabled for IDE */
+ else if (cfg & (1<<14) && rev < 5)
+ no_piix_dma = 2;
+ }
+ if (no_piix_dma)
+ dev_printk(KERN_WARNING, &ata_dev->dev, "450NX errata present, disabling IDE DMA.\n");
+ if (no_piix_dma == 2)
+ dev_printk(KERN_WARNING, &ata_dev->dev, "A BIOS update may resolve this.\n");
+ return no_piix_dma;
+}
+
+static void __devinit piix_init_pcs(struct pci_dev *pdev,
+ struct ata_port_info *pinfo,
+ const struct piix_map_db *map_db)
+{
+ u16 pcs, new_pcs;
+
+ pci_read_config_word(pdev, ICH5_PCS, &pcs);
+
+ new_pcs = pcs | map_db->port_enable;
+
+ if (new_pcs != pcs) {
+ DPRINTK("updating PCS from 0x%x to 0x%x\n", pcs, new_pcs);
+ pci_write_config_word(pdev, ICH5_PCS, new_pcs);
+ msleep(150);
+ }
+
+ if (force_pcs == 1) {
+ dev_printk(KERN_INFO, &pdev->dev,
+ "force ignoring PCS (0x%x)\n", new_pcs);
+ pinfo[0].flags |= PIIX_FLAG_IGNORE_PCS;
+ pinfo[1].flags |= PIIX_FLAG_IGNORE_PCS;
+ } else if (force_pcs == 2) {
+ dev_printk(KERN_INFO, &pdev->dev,
+ "force honoring PCS (0x%x)\n", new_pcs);
+ pinfo[0].flags &= ~PIIX_FLAG_IGNORE_PCS;
+ pinfo[1].flags &= ~PIIX_FLAG_IGNORE_PCS;
+ }
+}
+
+static void __devinit piix_init_sata_map(struct pci_dev *pdev,
+ struct ata_port_info *pinfo,
+ const struct piix_map_db *map_db)
+{
+ struct piix_host_priv *hpriv = pinfo[0].private_data;
+ const unsigned int *map;
+ int i, invalid_map = 0;
+ u8 map_value;
+
+ pci_read_config_byte(pdev, ICH5_PMR, &map_value);
+
+ map = map_db->map[map_value & map_db->mask];
+
+ dev_printk(KERN_INFO, &pdev->dev, "MAP [");
+ for (i = 0; i < 4; i++) {
+ switch (map[i]) {
+ case RV:
+ invalid_map = 1;
+ printk(" XX");
+ break;
+
+ case NA:
+ printk(" --");
+ break;
+
+ case IDE:
+ WARN_ON((i & 1) || map[i + 1] != IDE);
+ pinfo[i / 2] = piix_port_info[ich_pata_100];
+ pinfo[i / 2].private_data = hpriv;
+ i++;
+ printk(" IDE IDE");
+ break;
+
+ default:
+ printk(" P%d", map[i]);
+ if (i & 1)
+ pinfo[i / 2].flags |= ATA_FLAG_SLAVE_POSS;
+ break;
+ }
+ }
+ printk(" ]\n");
+
+ if (invalid_map)
+ dev_printk(KERN_ERR, &pdev->dev,
+ "invalid MAP value %u\n", map_value);
+
+ hpriv->map = map;
+ hpriv->map_db = map_db;
+}
+
+/**
+ * piix_init_one - Register PIIX ATA PCI device with kernel services
+ * @pdev: PCI device to register
+ * @ent: Entry in piix_pci_tbl matching with @pdev
+ *
+ * Called from kernel PCI layer. We probe for combined mode (sigh),
+ * and then hand over control to libata, for it to do the rest.
+ *
+ * LOCKING:
+ * Inherited from PCI layer (may sleep).
+ *
+ * RETURNS:
+ * Zero on success, or -ERRNO value.
+ */
+
+static int piix_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ static int printed_version;
+ struct ata_port_info port_info[2];
+ struct ata_port_info *ppinfo[2] = { &port_info[0], &port_info[1] };
+ struct piix_host_priv *hpriv;
+ unsigned long port_flags;
+
+ if (!printed_version++)
+ dev_printk(KERN_DEBUG, &pdev->dev,
+ "version " DRV_VERSION "\n");
+
+ /* no hotplugging support (FIXME) */
+ if (!in_module_init)
+ return -ENODEV;
+
+ hpriv = kzalloc(sizeof(*hpriv), GFP_KERNEL);
+ if (!hpriv)
+ return -ENOMEM;
+
+ port_info[0] = piix_port_info[ent->driver_data];
+ port_info[1] = piix_port_info[ent->driver_data];
+ port_info[0].private_data = hpriv;
+ port_info[1].private_data = hpriv;
+
+ port_flags = port_info[0].flags;
+
+ if (port_flags & PIIX_FLAG_AHCI) {
+ u8 tmp;
+ pci_read_config_byte(pdev, PIIX_SCC, &tmp);
+ if (tmp == PIIX_AHCI_DEVICE) {
+ int rc = piix_disable_ahci(pdev);
+ if (rc)
+ return rc;
+ }
+ }
+
+ /* Initialize SATA map */
+ if (port_flags & ATA_FLAG_SATA) {
+ piix_init_sata_map(pdev, port_info,
+ piix_map_db_table[ent->driver_data]);
+ piix_init_pcs(pdev, port_info,
+ piix_map_db_table[ent->driver_data]);
+ }
+
+ /* On ICH5, some BIOSen disable the interrupt using the
+ * PCI_COMMAND_INTX_DISABLE bit added in PCI 2.3.
+ * On ICH6, this bit has the same effect, but only when
+ * MSI is disabled (and it is disabled, as we don't use
+ * message-signalled interrupts currently).
+ */
+ if (port_flags & PIIX_FLAG_CHECKINTR)
+ pci_intx(pdev, 1);
+
+ if (piix_check_450nx_errata(pdev)) {
+ /* This writes into the master table but it does not
+ really matter for this errata as we will apply it to
+ all the PIIX devices on the board */
+ port_info[0].mwdma_mask = 0;
+ port_info[0].udma_mask = 0;
+ port_info[1].mwdma_mask = 0;
+ port_info[1].udma_mask = 0;
+ }
+ return ata_pci_init_one(pdev, ppinfo, 2);
+}
+
+static void piix_host_stop(struct ata_host *host)
+{
+ struct piix_host_priv *hpriv = host->private_data;
+
+ ata_host_stop(host);
+
+ kfree(hpriv);
+}
+
+static int __init piix_init(void)
+{
+ int rc;
+
+ DPRINTK("pci_register_driver\n");
+ rc = pci_register_driver(&piix_pci_driver);
+ if (rc)
+ return rc;
+
+ in_module_init = 0;
+
+ DPRINTK("done\n");
+ return 0;
+}
+
+static void __exit piix_exit(void)
+{
+ pci_unregister_driver(&piix_pci_driver);
+}
+
+module_init(piix_init);
+module_exit(piix_exit);
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
new file mode 100644
index 00000000000..b4abd685036
--- /dev/null
+++ b/drivers/ata/libata-core.c
@@ -0,0 +1,6176 @@
+/*
+ * libata-core.c - helper library for ATA
+ *
+ * Maintained by: Jeff Garzik <jgarzik@pobox.com>
+ * Please ALWAYS copy linux-ide@vger.kernel.org
+ * on emails.
+ *
+ * Copyright 2003-2004 Red Hat, Inc. All rights reserved.
+ * Copyright 2003-2004 Jeff Garzik
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * libata documentation is available via 'make {ps|pdf}docs',
+ * as Documentation/DocBook/libata.*
+ *
+ * Hardware documentation available from http://www.t13.org/ and
+ * http://www.sata-io.org/
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/mm.h>
+#include <linux/highmem.h>
+#include <linux/spinlock.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/completion.h>
+#include <linux/suspend.h>
+#include <linux/workqueue.h>
+#include <linux/jiffies.h>
+#include <linux/scatterlist.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+#include <asm/io.h>
+#include <asm/semaphore.h>
+#include <asm/byteorder.h>
+
+#include "libata.h"
+
+/* debounce timing parameters in msecs { interval, duration, timeout } */
+const unsigned long sata_deb_timing_normal[] = { 5, 100, 2000 };
+const unsigned long sata_deb_timing_hotplug[] = { 25, 500, 2000 };
+const unsigned long sata_deb_timing_long[] = { 100, 2000, 5000 };
+
+static unsigned int ata_dev_init_params(struct ata_device *dev,
+ u16 heads, u16 sectors);
+static unsigned int ata_dev_set_xfermode(struct ata_device *dev);
+static void ata_dev_xfermask(struct ata_device *dev);
+
+static unsigned int ata_unique_id = 1;
+static struct workqueue_struct *ata_wq;
+
+struct workqueue_struct *ata_aux_wq;
+
+int atapi_enabled = 1;
+module_param(atapi_enabled, int, 0444);
+MODULE_PARM_DESC(atapi_enabled, "Enable discovery of ATAPI devices (0=off, 1=on)");
+
+int atapi_dmadir = 0;
+module_param(atapi_dmadir, int, 0444);
+MODULE_PARM_DESC(atapi_dmadir, "Enable ATAPI DMADIR bridge support (0=off, 1=on)");
+
+int libata_fua = 0;
+module_param_named(fua, libata_fua, int, 0444);
+MODULE_PARM_DESC(fua, "FUA support (0=off, 1=on)");
+
+static int ata_probe_timeout = ATA_TMOUT_INTERNAL / HZ;
+module_param(ata_probe_timeout, int, 0444);
+MODULE_PARM_DESC(ata_probe_timeout, "Set ATA probing timeout (seconds)");
+
+MODULE_AUTHOR("Jeff Garzik");
+MODULE_DESCRIPTION("Library module for ATA devices");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
+
+/**
+ * ata_tf_to_fis - Convert ATA taskfile to SATA FIS structure
+ * @tf: Taskfile to convert
+ * @fis: Buffer into which data will output
+ * @pmp: Port multiplier port
+ *
+ * Converts a standard ATA taskfile to a Serial ATA
+ * FIS structure (Register - Host to Device).
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+
+void ata_tf_to_fis(const struct ata_taskfile *tf, u8 *fis, u8 pmp)
+{
+ fis[0] = 0x27; /* Register - Host to Device FIS */
+ fis[1] = (pmp & 0xf) | (1 << 7); /* Port multiplier number,
+ bit 7 indicates Command FIS */
+ fis[2] = tf->command;
+ fis[3] = tf->feature;
+
+ fis[4] = tf->lbal;
+ fis[5] = tf->lbam;
+ fis[6] = tf->lbah;
+ fis[7] = tf->device;
+
+ fis[8] = tf->hob_lbal;
+ fis[9] = tf->hob_lbam;
+ fis[10] = tf->hob_lbah;
+ fis[11] = tf->hob_feature;
+
+ fis[12] = tf->nsect;
+ fis[13] = tf->hob_nsect;
+ fis[14] = 0;
+ fis[15] = tf->ctl;
+
+ fis[16] = 0;
+ fis[17] = 0;
+ fis[18] = 0;
+ fis[19] = 0;
+}
+
+/**
+ * ata_tf_from_fis - Convert SATA FIS to ATA taskfile
+ * @fis: Buffer from which data will be input
+ * @tf: Taskfile to output
+ *
+ * Converts a serial ATA FIS structure to a standard ATA taskfile.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+
+void ata_tf_from_fis(const u8 *fis, struct ata_taskfile *tf)
+{
+ tf->command = fis[2]; /* status */
+ tf->feature = fis[3]; /* error */
+
+ tf->lbal = fis[4];
+ tf->lbam = fis[5];
+ tf->lbah = fis[6];
+ tf->device = fis[7];
+
+ tf->hob_lbal = fis[8];
+ tf->hob_lbam = fis[9];
+ tf->hob_lbah = fis[10];
+
+ tf->nsect = fis[12];
+ tf->hob_nsect = fis[13];
+}
+
+static const u8 ata_rw_cmds[] = {
+ /* pio multi */
+ ATA_CMD_READ_MULTI,
+ ATA_CMD_WRITE_MULTI,
+ ATA_CMD_READ_MULTI_EXT,
+ ATA_CMD_WRITE_MULTI_EXT,
+ 0,
+ 0,
+ 0,
+ ATA_CMD_WRITE_MULTI_FUA_EXT,
+ /* pio */
+ ATA_CMD_PIO_READ,
+ ATA_CMD_PIO_WRITE,
+ ATA_CMD_PIO_READ_EXT,
+ ATA_CMD_PIO_WRITE_EXT,
+ 0,
+ 0,
+ 0,
+ 0,
+ /* dma */
+ ATA_CMD_READ,
+ ATA_CMD_WRITE,
+ ATA_CMD_READ_EXT,
+ ATA_CMD_WRITE_EXT,
+ 0,
+ 0,
+ 0,
+ ATA_CMD_WRITE_FUA_EXT
+};
+
+/**
+ * ata_rwcmd_protocol - set taskfile r/w commands and protocol
+ * @qc: command to examine and configure
+ *
+ * Examine the device configuration and tf->flags to calculate
+ * the proper read/write commands and protocol to use.
+ *
+ * LOCKING:
+ * caller.
+ */
+int ata_rwcmd_protocol(struct ata_queued_cmd *qc)
+{
+ struct ata_taskfile *tf = &qc->tf;
+ struct ata_device *dev = qc->dev;
+ u8 cmd;
+
+ int index, fua, lba48, write;
+
+ fua = (tf->flags & ATA_TFLAG_FUA) ? 4 : 0;
+ lba48 = (tf->flags & ATA_TFLAG_LBA48) ? 2 : 0;
+ write = (tf->flags & ATA_TFLAG_WRITE) ? 1 : 0;
+
+ if (dev->flags & ATA_DFLAG_PIO) {
+ tf->protocol = ATA_PROT_PIO;
+ index = dev->multi_count ? 0 : 8;
+ } else if (lba48 && (qc->ap->flags & ATA_FLAG_PIO_LBA48)) {
+ /* Unable to use DMA due to host limitation */
+ tf->protocol = ATA_PROT_PIO;
+ index = dev->multi_count ? 0 : 8;
+ } else {
+ tf->protocol = ATA_PROT_DMA;
+ index = 16;
+ }
+
+ cmd = ata_rw_cmds[index + fua + lba48 + write];
+ if (cmd) {
+ tf->command = cmd;
+ return 0;
+ }
+ return -1;
+}
+
+/**
+ * ata_pack_xfermask - Pack pio, mwdma and udma masks into xfer_mask
+ * @pio_mask: pio_mask
+ * @mwdma_mask: mwdma_mask
+ * @udma_mask: udma_mask
+ *
+ * Pack @pio_mask, @mwdma_mask and @udma_mask into a single
+ * unsigned int xfer_mask.
+ *
+ * LOCKING:
+ * None.
+ *
+ * RETURNS:
+ * Packed xfer_mask.
+ */
+static unsigned int ata_pack_xfermask(unsigned int pio_mask,
+ unsigned int mwdma_mask,
+ unsigned int udma_mask)
+{
+ return ((pio_mask << ATA_SHIFT_PIO) & ATA_MASK_PIO) |
+ ((mwdma_mask << ATA_SHIFT_MWDMA) & ATA_MASK_MWDMA) |
+ ((udma_mask << ATA_SHIFT_UDMA) & ATA_MASK_UDMA);
+}
+
+/**
+ * ata_unpack_xfermask - Unpack xfer_mask into pio, mwdma and udma masks
+ * @xfer_mask: xfer_mask to unpack
+ * @pio_mask: resulting pio_mask
+ * @mwdma_mask: resulting mwdma_mask
+ * @udma_mask: resulting udma_mask
+ *
+ * Unpack @xfer_mask into @pio_mask, @mwdma_mask and @udma_mask.
+ * Any NULL distination masks will be ignored.
+ */
+static void ata_unpack_xfermask(unsigned int xfer_mask,
+ unsigned int *pio_mask,
+ unsigned int *mwdma_mask,
+ unsigned int *udma_mask)
+{
+ if (pio_mask)
+ *pio_mask = (xfer_mask & ATA_MASK_PIO) >> ATA_SHIFT_PIO;
+ if (mwdma_mask)
+ *mwdma_mask = (xfer_mask & ATA_MASK_MWDMA) >> ATA_SHIFT_MWDMA;
+ if (udma_mask)
+ *udma_mask = (xfer_mask & ATA_MASK_UDMA) >> ATA_SHIFT_UDMA;
+}
+
+static const struct ata_xfer_ent {
+ int shift, bits;
+ u8 base;
+} ata_xfer_tbl[] = {
+ { ATA_SHIFT_PIO, ATA_BITS_PIO, XFER_PIO_0 },
+ { ATA_SHIFT_MWDMA, ATA_BITS_MWDMA, XFER_MW_DMA_0 },
+ { ATA_SHIFT_UDMA, ATA_BITS_UDMA, XFER_UDMA_0 },
+ { -1, },
+};
+
+/**
+ * ata_xfer_mask2mode - Find matching XFER_* for the given xfer_mask
+ * @xfer_mask: xfer_mask of interest
+ *
+ * Return matching XFER_* value for @xfer_mask. Only the highest
+ * bit of @xfer_mask is considered.
+ *
+ * LOCKING:
+ * None.
+ *
+ * RETURNS:
+ * Matching XFER_* value, 0 if no match found.
+ */
+static u8 ata_xfer_mask2mode(unsigned int xfer_mask)
+{
+ int highbit = fls(xfer_mask) - 1;
+ const struct ata_xfer_ent *ent;
+
+ for (ent = ata_xfer_tbl; ent->shift >= 0; ent++)
+ if (highbit >= ent->shift && highbit < ent->shift + ent->bits)
+ return ent->base + highbit - ent->shift;
+ return 0;
+}
+
+/**
+ * ata_xfer_mode2mask - Find matching xfer_mask for XFER_*
+ * @xfer_mode: XFER_* of interest
+ *
+ * Return matching xfer_mask for @xfer_mode.
+ *
+ * LOCKING:
+ * None.
+ *
+ * RETURNS:
+ * Matching xfer_mask, 0 if no match found.
+ */
+static unsigned int ata_xfer_mode2mask(u8 xfer_mode)
+{
+ const struct ata_xfer_ent *ent;
+
+ for (ent = ata_xfer_tbl; ent->shift >= 0; ent++)
+ if (xfer_mode >= ent->base && xfer_mode < ent->base + ent->bits)
+ return 1 << (ent->shift + xfer_mode - ent->base);
+ return 0;
+}
+
+/**
+ * ata_xfer_mode2shift - Find matching xfer_shift for XFER_*
+ * @xfer_mode: XFER_* of interest
+ *
+ * Return matching xfer_shift for @xfer_mode.
+ *
+ * LOCKING:
+ * None.
+ *
+ * RETURNS:
+ * Matching xfer_shift, -1 if no match found.
+ */
+static int ata_xfer_mode2shift(unsigned int xfer_mode)
+{
+ const struct ata_xfer_ent *ent;
+
+ for (ent = ata_xfer_tbl; ent->shift >= 0; ent++)
+ if (xfer_mode >= ent->base && xfer_mode < ent->base + ent->bits)
+ return ent->shift;
+ return -1;
+}
+
+/**
+ * ata_mode_string - convert xfer_mask to string
+ * @xfer_mask: mask of bits supported; only highest bit counts.
+ *
+ * Determine string which represents the highest speed
+ * (highest bit in @modemask).
+ *
+ * LOCKING:
+ * None.
+ *
+ * RETURNS:
+ * Constant C string representing highest speed listed in
+ * @mode_mask, or the constant C string "<n/a>".
+ */
+static const char *ata_mode_string(unsigned int xfer_mask)
+{
+ static const char * const xfer_mode_str[] = {
+ "PIO0",
+ "PIO1",
+ "PIO2",
+ "PIO3",
+ "PIO4",
+ "PIO5",
+ "PIO6",
+ "MWDMA0",
+ "MWDMA1",
+ "MWDMA2",
+ "MWDMA3",
+ "MWDMA4",
+ "UDMA/16",
+ "UDMA/25",
+ "UDMA/33",
+ "UDMA/44",
+ "UDMA/66",
+ "UDMA/100",
+ "UDMA/133",
+ "UDMA7",
+ };
+ int highbit;
+
+ highbit = fls(xfer_mask) - 1;
+ if (highbit >= 0 && highbit < ARRAY_SIZE(xfer_mode_str))
+ return xfer_mode_str[highbit];
+ return "<n/a>";
+}
+
+static const char *sata_spd_string(unsigned int spd)
+{
+ static const char * const spd_str[] = {
+ "1.5 Gbps",
+ "3.0 Gbps",
+ };
+
+ if (spd == 0 || (spd - 1) >= ARRAY_SIZE(spd_str))
+ return "<unknown>";
+ return spd_str[spd - 1];
+}
+
+void ata_dev_disable(struct ata_device *dev)
+{
+ if (ata_dev_enabled(dev) && ata_msg_drv(dev->ap)) {
+ ata_dev_printk(dev, KERN_WARNING, "disabled\n");
+ dev->class++;
+ }
+}
+
+/**
+ * ata_pio_devchk - PATA device presence detection
+ * @ap: ATA channel to examine
+ * @device: Device to examine (starting at zero)
+ *
+ * This technique was originally described in
+ * Hale Landis's ATADRVR (www.ata-atapi.com), and
+ * later found its way into the ATA/ATAPI spec.
+ *
+ * Write a pattern to the ATA shadow registers,
+ * and if a device is present, it will respond by
+ * correctly storing and echoing back the
+ * ATA shadow register contents.
+ *
+ * LOCKING:
+ * caller.
+ */
+
+static unsigned int ata_pio_devchk(struct ata_port *ap,
+ unsigned int device)
+{
+ struct ata_ioports *ioaddr = &ap->ioaddr;
+ u8 nsect, lbal;
+
+ ap->ops->dev_select(ap, device);
+
+ outb(0x55, ioaddr->nsect_addr);
+ outb(0xaa, ioaddr->lbal_addr);
+
+ outb(0xaa, ioaddr->nsect_addr);
+ outb(0x55, ioaddr->lbal_addr);
+
+ outb(0x55, ioaddr->nsect_addr);
+ outb(0xaa, ioaddr->lbal_addr);
+
+ nsect = inb(ioaddr->nsect_addr);
+ lbal = inb(ioaddr->lbal_addr);
+
+ if ((nsect == 0x55) && (lbal == 0xaa))
+ return 1; /* we found a device */
+
+ return 0; /* nothing found */
+}
+
+/**
+ * ata_mmio_devchk - PATA device presence detection
+ * @ap: ATA channel to examine
+ * @device: Device to examine (starting at zero)
+ *
+ * This technique was originally described in
+ * Hale Landis's ATADRVR (www.ata-atapi.com), and
+ * later found its way into the ATA/ATAPI spec.
+ *
+ * Write a pattern to the ATA shadow registers,
+ * and if a device is present, it will respond by
+ * correctly storing and echoing back the
+ * ATA shadow register contents.
+ *
+ * LOCKING:
+ * caller.
+ */
+
+static unsigned int ata_mmio_devchk(struct ata_port *ap,
+ unsigned int device)
+{
+ struct ata_ioports *ioaddr = &ap->ioaddr;
+ u8 nsect, lbal;
+
+ ap->ops->dev_select(ap, device);
+
+ writeb(0x55, (void __iomem *) ioaddr->nsect_addr);
+ writeb(0xaa, (void __iomem *) ioaddr->lbal_addr);
+
+ writeb(0xaa, (void __iomem *) ioaddr->nsect_addr);
+ writeb(0x55, (void __iomem *) ioaddr->lbal_addr);
+
+ writeb(0x55, (void __iomem *) ioaddr->nsect_addr);
+ writeb(0xaa, (void __iomem *) ioaddr->lbal_addr);
+
+ nsect = readb((void __iomem *) ioaddr->nsect_addr);
+ lbal = readb((void __iomem *) ioaddr->lbal_addr);
+
+ if ((nsect == 0x55) && (lbal == 0xaa))
+ return 1; /* we found a device */
+
+ return 0; /* nothing found */
+}
+
+/**
+ * ata_devchk - PATA device presence detection
+ * @ap: ATA channel to examine
+ * @device: Device to examine (starting at zero)
+ *
+ * Dispatch ATA device presence detection, depending
+ * on whether we are using PIO or MMIO to talk to the
+ * ATA shadow registers.
+ *
+ * LOCKING:
+ * caller.
+ */
+
+static unsigned int ata_devchk(struct ata_port *ap,
+ unsigned int device)
+{
+ if (ap->flags & ATA_FLAG_MMIO)
+ return ata_mmio_devchk(ap, device);
+ return ata_pio_devchk(ap, device);
+}
+
+/**
+ * ata_dev_classify - determine device type based on ATA-spec signature
+ * @tf: ATA taskfile register set for device to be identified
+ *
+ * Determine from taskfile register contents whether a device is
+ * ATA or ATAPI, as per "Signature and persistence" section
+ * of ATA/PI spec (volume 1, sect 5.14).
+ *
+ * LOCKING:
+ * None.
+ *
+ * RETURNS:
+ * Device type, %ATA_DEV_ATA, %ATA_DEV_ATAPI, or %ATA_DEV_UNKNOWN
+ * the event of failure.
+ */
+
+unsigned int ata_dev_classify(const struct ata_taskfile *tf)
+{
+ /* Apple's open source Darwin code hints that some devices only
+ * put a proper signature into the LBA mid/high registers,
+ * So, we only check those. It's sufficient for uniqueness.
+ */
+
+ if (((tf->lbam == 0) && (tf->lbah == 0)) ||
+ ((tf->lbam == 0x3c) && (tf->lbah == 0xc3))) {
+ DPRINTK("found ATA device by sig\n");
+ return ATA_DEV_ATA;
+ }
+
+ if (((tf->lbam == 0x14) && (tf->lbah == 0xeb)) ||
+ ((tf->lbam == 0x69) && (tf->lbah == 0x96))) {
+ DPRINTK("found ATAPI device by sig\n");
+ return ATA_DEV_ATAPI;
+ }
+
+ DPRINTK("unknown device\n");
+ return ATA_DEV_UNKNOWN;
+}
+
+/**
+ * ata_dev_try_classify - Parse returned ATA device signature
+ * @ap: ATA channel to examine
+ * @device: Device to examine (starting at zero)
+ * @r_err: Value of error register on completion
+ *
+ * After an event -- SRST, E.D.D., or SATA COMRESET -- occurs,
+ * an ATA/ATAPI-defined set of values is placed in the ATA
+ * shadow registers, indicating the results of device detection
+ * and diagnostics.
+ *
+ * Select the ATA device, and read the values from the ATA shadow
+ * registers. Then parse according to the Error register value,
+ * and the spec-defined values examined by ata_dev_classify().
+ *
+ * LOCKING:
+ * caller.
+ *
+ * RETURNS:
+ * Device type - %ATA_DEV_ATA, %ATA_DEV_ATAPI or %ATA_DEV_NONE.
+ */
+
+static unsigned int
+ata_dev_try_classify(struct ata_port *ap, unsigned int device, u8 *r_err)
+{
+ struct ata_taskfile tf;
+ unsigned int class;
+ u8 err;
+
+ ap->ops->dev_select(ap, device);
+
+ memset(&tf, 0, sizeof(tf));
+
+ ap->ops->tf_read(ap, &tf);
+ err = tf.feature;
+ if (r_err)
+ *r_err = err;
+
+ /* see if device passed diags: if master then continue and warn later */
+ if (err == 0 && device == 0)
+ /* diagnostic fail : do nothing _YET_ */
+ ap->device[device].horkage |= ATA_HORKAGE_DIAGNOSTIC;
+ else if (err == 1)
+ /* do nothing */ ;
+ else if ((device == 0) && (err == 0x81))
+ /* do nothing */ ;
+ else
+ return ATA_DEV_NONE;
+
+ /* determine if device is ATA or ATAPI */
+ class = ata_dev_classify(&tf);
+
+ if (class == ATA_DEV_UNKNOWN)
+ return ATA_DEV_NONE;
+ if ((class == ATA_DEV_ATA) && (ata_chk_status(ap) == 0))
+ return ATA_DEV_NONE;
+ return class;
+}
+
+/**
+ * ata_id_string - Convert IDENTIFY DEVICE page into string
+ * @id: IDENTIFY DEVICE results we will examine
+ * @s: string into which data is output
+ * @ofs: offset into identify device page
+ * @len: length of string to return. must be an even number.
+ *
+ * The strings in the IDENTIFY DEVICE page are broken up into
+ * 16-bit chunks. Run through the string, and output each
+ * 8-bit chunk linearly, regardless of platform.
+ *
+ * LOCKING:
+ * caller.
+ */
+
+void ata_id_string(const u16 *id, unsigned char *s,
+ unsigned int ofs, unsigned int len)
+{
+ unsigned int c;
+
+ while (len > 0) {
+ c = id[ofs] >> 8;
+ *s = c;
+ s++;
+
+ c = id[ofs] & 0xff;
+ *s = c;
+ s++;
+
+ ofs++;
+ len -= 2;
+ }
+}
+
+/**
+ * ata_id_c_string - Convert IDENTIFY DEVICE page into C string
+ * @id: IDENTIFY DEVICE results we will examine
+ * @s: string into which data is output
+ * @ofs: offset into identify device page
+ * @len: length of string to return. must be an odd number.
+ *
+ * This function is identical to ata_id_string except that it
+ * trims trailing spaces and terminates the resulting string with
+ * null. @len must be actual maximum length (even number) + 1.
+ *
+ * LOCKING:
+ * caller.
+ */
+void ata_id_c_string(const u16 *id, unsigned char *s,
+ unsigned int ofs, unsigned int len)
+{
+ unsigned char *p;
+
+ WARN_ON(!(len & 1));
+
+ ata_id_string(id, s, ofs, len - 1);
+
+ p = s + strnlen(s, len - 1);
+ while (p > s && p[-1] == ' ')
+ p--;
+ *p = '\0';
+}
+
+static u64 ata_id_n_sectors(const u16 *id)
+{
+ if (ata_id_has_lba(id)) {
+ if (ata_id_has_lba48(id))
+ return ata_id_u64(id, 100);
+ else
+ return ata_id_u32(id, 60);
+ } else {
+ if (ata_id_current_chs_valid(id))
+ return ata_id_u32(id, 57);
+ else
+ return id[1] * id[3] * id[6];
+ }
+}
+
+/**
+ * ata_noop_dev_select - Select device 0/1 on ATA bus
+ * @ap: ATA channel to manipulate
+ * @device: ATA device (numbered from zero) to select
+ *
+ * This function performs no actual function.
+ *
+ * May be used as the dev_select() entry in ata_port_operations.
+ *
+ * LOCKING:
+ * caller.
+ */
+void ata_noop_dev_select (struct ata_port *ap, unsigned int device)
+{
+}
+
+
+/**
+ * ata_std_dev_select - Select device 0/1 on ATA bus
+ * @ap: ATA channel to manipulate
+ * @device: ATA device (numbered from zero) to select
+ *
+ * Use the method defined in the ATA specification to
+ * make either device 0, or device 1, active on the
+ * ATA channel. Works with both PIO and MMIO.
+ *
+ * May be used as the dev_select() entry in ata_port_operations.
+ *
+ * LOCKING:
+ * caller.
+ */
+
+void ata_std_dev_select (struct ata_port *ap, unsigned int device)
+{
+ u8 tmp;
+
+ if (device == 0)
+ tmp = ATA_DEVICE_OBS;
+ else
+ tmp = ATA_DEVICE_OBS | ATA_DEV1;
+
+ if (ap->flags & ATA_FLAG_MMIO) {
+ writeb(tmp, (void __iomem *) ap->ioaddr.device_addr);
+ } else {
+ outb(tmp, ap->ioaddr.device_addr);
+ }
+ ata_pause(ap); /* needed; also flushes, for mmio */
+}
+
+/**
+ * ata_dev_select - Select device 0/1 on ATA bus
+ * @ap: ATA channel to manipulate
+ * @device: ATA device (numbered from zero) to select
+ * @wait: non-zero to wait for Status register BSY bit to clear
+ * @can_sleep: non-zero if context allows sleeping
+ *
+ * Use the method defined in the ATA specification to
+ * make either device 0, or device 1, active on the
+ * ATA channel.
+ *
+ * This is a high-level version of ata_std_dev_select(),
+ * which additionally provides the services of inserting
+ * the proper pauses and status polling, where needed.
+ *
+ * LOCKING:
+ * caller.
+ */
+
+void ata_dev_select(struct ata_port *ap, unsigned int device,
+ unsigned int wait, unsigned int can_sleep)
+{
+ if (ata_msg_probe(ap))
+ ata_port_printk(ap, KERN_INFO, "ata_dev_select: ENTER, ata%u: "
+ "device %u, wait %u\n", ap->id, device, wait);
+
+ if (wait)
+ ata_wait_idle(ap);
+
+ ap->ops->dev_select(ap, device);
+
+ if (wait) {
+ if (can_sleep && ap->device[device].class == ATA_DEV_ATAPI)
+ msleep(150);
+ ata_wait_idle(ap);
+ }
+}
+
+/**
+ * ata_dump_id - IDENTIFY DEVICE info debugging output
+ * @id: IDENTIFY DEVICE page to dump
+ *
+ * Dump selected 16-bit words from the given IDENTIFY DEVICE
+ * page.
+ *
+ * LOCKING:
+ * caller.
+ */
+
+static inline void ata_dump_id(const u16 *id)
+{
+ DPRINTK("49==0x%04x "
+ "53==0x%04x "
+ "63==0x%04x "
+ "64==0x%04x "
+ "75==0x%04x \n",
+ id[49],
+ id[53],
+ id[63],
+ id[64],
+ id[75]);
+ DPRINTK("80==0x%04x "
+ "81==0x%04x "
+ "82==0x%04x "
+ "83==0x%04x "
+ "84==0x%04x \n",
+ id[80],
+ id[81],
+ id[82],
+ id[83],
+ id[84]);
+ DPRINTK("88==0x%04x "
+ "93==0x%04x\n",
+ id[88],
+ id[93]);
+}
+
+/**
+ * ata_id_xfermask - Compute xfermask from the given IDENTIFY data
+ * @id: IDENTIFY data to compute xfer mask from
+ *
+ * Compute the xfermask for this device. This is not as trivial
+ * as it seems if we must consider early devices correctly.
+ *
+ * FIXME: pre IDE drive timing (do we care ?).
+ *
+ * LOCKING:
+ * None.
+ *
+ * RETURNS:
+ * Computed xfermask
+ */
+static unsigned int ata_id_xfermask(const u16 *id)
+{
+ unsigned int pio_mask, mwdma_mask, udma_mask;
+
+ /* Usual case. Word 53 indicates word 64 is valid */
+ if (id[ATA_ID_FIELD_VALID] & (1 << 1)) {
+ pio_mask = id[ATA_ID_PIO_MODES] & 0x03;
+ pio_mask <<= 3;
+ pio_mask |= 0x7;
+ } else {
+ /* If word 64 isn't valid then Word 51 high byte holds
+ * the PIO timing number for the maximum. Turn it into
+ * a mask.
+ */
+ pio_mask = (2 << (id[ATA_ID_OLD_PIO_MODES] & 0xFF)) - 1 ;
+
+ /* But wait.. there's more. Design your standards by
+ * committee and you too can get a free iordy field to
+ * process. However its the speeds not the modes that
+ * are supported... Note drivers using the timing API
+ * will get this right anyway
+ */
+ }
+
+ mwdma_mask = id[ATA_ID_MWDMA_MODES] & 0x07;
+
+ if (ata_id_is_cfa(id)) {
+ /*
+ * Process compact flash extended modes
+ */
+ int pio = id[163] & 0x7;
+ int dma = (id[163] >> 3) & 7;
+
+ if (pio)
+ pio_mask |= (1 << 5);
+ if (pio > 1)
+ pio_mask |= (1 << 6);
+ if (dma)
+ mwdma_mask |= (1 << 3);
+ if (dma > 1)
+ mwdma_mask |= (1 << 4);
+ }
+
+ udma_mask = 0;
+ if (id[ATA_ID_FIELD_VALID] & (1 << 2))
+ udma_mask = id[ATA_ID_UDMA_MODES] & 0xff;
+
+ return ata_pack_xfermask(pio_mask, mwdma_mask, udma_mask);
+}
+
+/**
+ * ata_port_queue_task - Queue port_task
+ * @ap: The ata_port to queue port_task for
+ * @fn: workqueue function to be scheduled
+ * @data: data value to pass to workqueue function
+ * @delay: delay time for workqueue function
+ *
+ * Schedule @fn(@data) for execution after @delay jiffies using
+ * port_task. There is one port_task per port and it's the
+ * user(low level driver)'s responsibility to make sure that only
+ * one task is active at any given time.
+ *
+ * libata core layer takes care of synchronization between
+ * port_task and EH. ata_port_queue_task() may be ignored for EH
+ * synchronization.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+void ata_port_queue_task(struct ata_port *ap, void (*fn)(void *), void *data,
+ unsigned long delay)
+{
+ int rc;
+
+ if (ap->pflags & ATA_PFLAG_FLUSH_PORT_TASK)
+ return;
+
+ PREPARE_WORK(&ap->port_task, fn, data);
+
+ if (!delay)
+ rc = queue_work(ata_wq, &ap->port_task);
+ else
+ rc = queue_delayed_work(ata_wq, &ap->port_task, delay);
+
+ /* rc == 0 means that another user is using port task */
+ WARN_ON(rc == 0);
+}
+
+/**
+ * ata_port_flush_task - Flush port_task
+ * @ap: The ata_port to flush port_task for
+ *
+ * After this function completes, port_task is guranteed not to
+ * be running or scheduled.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep)
+ */
+void ata_port_flush_task(struct ata_port *ap)
+{
+ unsigned long flags;
+
+ DPRINTK("ENTER\n");
+
+ spin_lock_irqsave(ap->lock, flags);
+ ap->pflags |= ATA_PFLAG_FLUSH_PORT_TASK;
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ DPRINTK("flush #1\n");
+ flush_workqueue(ata_wq);
+
+ /*
+ * At this point, if a task is running, it's guaranteed to see
+ * the FLUSH flag; thus, it will never queue pio tasks again.
+ * Cancel and flush.
+ */
+ if (!cancel_delayed_work(&ap->port_task)) {
+ if (ata_msg_ctl(ap))
+ ata_port_printk(ap, KERN_DEBUG, "%s: flush #2\n",
+ __FUNCTION__);
+ flush_workqueue(ata_wq);
+ }
+
+ spin_lock_irqsave(ap->lock, flags);
+ ap->pflags &= ~ATA_PFLAG_FLUSH_PORT_TASK;
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ if (ata_msg_ctl(ap))
+ ata_port_printk(ap, KERN_DEBUG, "%s: EXIT\n", __FUNCTION__);
+}
+
+void ata_qc_complete_internal(struct ata_queued_cmd *qc)
+{
+ struct completion *waiting = qc->private_data;
+
+ complete(waiting);
+}
+
+/**
+ * ata_exec_internal - execute libata internal command
+ * @dev: Device to which the command is sent
+ * @tf: Taskfile registers for the command and the result
+ * @cdb: CDB for packet command
+ * @dma_dir: Data tranfer direction of the command
+ * @buf: Data buffer of the command
+ * @buflen: Length of data buffer
+ *
+ * Executes libata internal command with timeout. @tf contains
+ * command on entry and result on return. Timeout and error
+ * conditions are reported via return value. No recovery action
+ * is taken after a command times out. It's caller's duty to
+ * clean up after timeout.
+ *
+ * LOCKING:
+ * None. Should be called with kernel context, might sleep.
+ *
+ * RETURNS:
+ * Zero on success, AC_ERR_* mask on failure
+ */
+unsigned ata_exec_internal(struct ata_device *dev,
+ struct ata_taskfile *tf, const u8 *cdb,
+ int dma_dir, void *buf, unsigned int buflen)
+{
+ struct ata_port *ap = dev->ap;
+ u8 command = tf->command;
+ struct ata_queued_cmd *qc;
+ unsigned int tag, preempted_tag;
+ u32 preempted_sactive, preempted_qc_active;
+ DECLARE_COMPLETION_ONSTACK(wait);
+ unsigned long flags;
+ unsigned int err_mask;
+ int rc;
+
+ spin_lock_irqsave(ap->lock, flags);
+
+ /* no internal command while frozen */
+ if (ap->pflags & ATA_PFLAG_FROZEN) {
+ spin_unlock_irqrestore(ap->lock, flags);
+ return AC_ERR_SYSTEM;
+ }
+
+ /* initialize internal qc */
+
+ /* XXX: Tag 0 is used for drivers with legacy EH as some
+ * drivers choke if any other tag is given. This breaks
+ * ata_tag_internal() test for those drivers. Don't use new
+ * EH stuff without converting to it.
+ */
+ if (ap->ops->error_handler)
+ tag = ATA_TAG_INTERNAL;
+ else
+ tag = 0;
+
+ if (test_and_set_bit(tag, &ap->qc_allocated))
+ BUG();
+ qc = __ata_qc_from_tag(ap, tag);
+
+ qc->tag = tag;
+ qc->scsicmd = NULL;
+ qc->ap = ap;
+ qc->dev = dev;
+ ata_qc_reinit(qc);
+
+ preempted_tag = ap->active_tag;
+ preempted_sactive = ap->sactive;
+ preempted_qc_active = ap->qc_active;
+ ap->active_tag = ATA_TAG_POISON;
+ ap->sactive = 0;
+ ap->qc_active = 0;
+
+ /* prepare & issue qc */
+ qc->tf = *tf;
+ if (cdb)
+ memcpy(qc->cdb, cdb, ATAPI_CDB_LEN);
+ qc->flags |= ATA_QCFLAG_RESULT_TF;
+ qc->dma_dir = dma_dir;
+ if (dma_dir != DMA_NONE) {
+ ata_sg_init_one(qc, buf, buflen);
+ qc->nsect = buflen / ATA_SECT_SIZE;
+ }
+
+ qc->private_data = &wait;
+ qc->complete_fn = ata_qc_complete_internal;
+
+ ata_qc_issue(qc);
+
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ rc = wait_for_completion_timeout(&wait, ata_probe_timeout);
+
+ ata_port_flush_task(ap);
+
+ if (!rc) {
+ spin_lock_irqsave(ap->lock, flags);
+
+ /* We're racing with irq here. If we lose, the
+ * following test prevents us from completing the qc
+ * twice. If we win, the port is frozen and will be
+ * cleaned up by ->post_internal_cmd().
+ */
+ if (qc->flags & ATA_QCFLAG_ACTIVE) {
+ qc->err_mask |= AC_ERR_TIMEOUT;
+
+ if (ap->ops->error_handler)
+ ata_port_freeze(ap);
+ else
+ ata_qc_complete(qc);
+
+ if (ata_msg_warn(ap))
+ ata_dev_printk(dev, KERN_WARNING,
+ "qc timeout (cmd 0x%x)\n", command);
+ }
+
+ spin_unlock_irqrestore(ap->lock, flags);
+ }
+
+ /* do post_internal_cmd */
+ if (ap->ops->post_internal_cmd)
+ ap->ops->post_internal_cmd(qc);
+
+ if (qc->flags & ATA_QCFLAG_FAILED && !qc->err_mask) {
+ if (ata_msg_warn(ap))
+ ata_dev_printk(dev, KERN_WARNING,
+ "zero err_mask for failed "
+ "internal command, assuming AC_ERR_OTHER\n");
+ qc->err_mask |= AC_ERR_OTHER;
+ }
+
+ /* finish up */
+ spin_lock_irqsave(ap->lock, flags);
+
+ *tf = qc->result_tf;
+ err_mask = qc->err_mask;
+
+ ata_qc_free(qc);
+ ap->active_tag = preempted_tag;
+ ap->sactive = preempted_sactive;
+ ap->qc_active = preempted_qc_active;
+
+ /* XXX - Some LLDDs (sata_mv) disable port on command failure.
+ * Until those drivers are fixed, we detect the condition
+ * here, fail the command with AC_ERR_SYSTEM and reenable the
+ * port.
+ *
+ * Note that this doesn't change any behavior as internal
+ * command failure results in disabling the device in the
+ * higher layer for LLDDs without new reset/EH callbacks.
+ *
+ * Kill the following code as soon as those drivers are fixed.
+ */
+ if (ap->flags & ATA_FLAG_DISABLED) {
+ err_mask |= AC_ERR_SYSTEM;
+ ata_port_probe(ap);
+ }
+
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ return err_mask;
+}
+
+/**
+ * ata_do_simple_cmd - execute simple internal command
+ * @dev: Device to which the command is sent
+ * @cmd: Opcode to execute
+ *
+ * Execute a 'simple' command, that only consists of the opcode
+ * 'cmd' itself, without filling any other registers
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ *
+ * RETURNS:
+ * Zero on success, AC_ERR_* mask on failure
+ */
+unsigned int ata_do_simple_cmd(struct ata_device *dev, u8 cmd)
+{
+ struct ata_taskfile tf;
+
+ ata_tf_init(dev, &tf);
+
+ tf.command = cmd;
+ tf.flags |= ATA_TFLAG_DEVICE;
+ tf.protocol = ATA_PROT_NODATA;
+
+ return ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
+}
+
+/**
+ * ata_pio_need_iordy - check if iordy needed
+ * @adev: ATA device
+ *
+ * Check if the current speed of the device requires IORDY. Used
+ * by various controllers for chip configuration.
+ */
+
+unsigned int ata_pio_need_iordy(const struct ata_device *adev)
+{
+ int pio;
+ int speed = adev->pio_mode - XFER_PIO_0;
+
+ if (speed < 2)
+ return 0;
+ if (speed > 2)
+ return 1;
+
+ /* If we have no drive specific rule, then PIO 2 is non IORDY */
+
+ if (adev->id[ATA_ID_FIELD_VALID] & 2) { /* EIDE */
+ pio = adev->id[ATA_ID_EIDE_PIO];
+ /* Is the speed faster than the drive allows non IORDY ? */
+ if (pio) {
+ /* This is cycle times not frequency - watch the logic! */
+ if (pio > 240) /* PIO2 is 240nS per cycle */
+ return 1;
+ return 0;
+ }
+ }
+ return 0;
+}
+
+/**
+ * ata_dev_read_id - Read ID data from the specified device
+ * @dev: target device
+ * @p_class: pointer to class of the target device (may be changed)
+ * @post_reset: is this read ID post-reset?
+ * @id: buffer to read IDENTIFY data into
+ *
+ * Read ID data from the specified device. ATA_CMD_ID_ATA is
+ * performed on ATA devices and ATA_CMD_ID_ATAPI on ATAPI
+ * devices. This function also issues ATA_CMD_INIT_DEV_PARAMS
+ * for pre-ATA4 drives.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep)
+ *
+ * RETURNS:
+ * 0 on success, -errno otherwise.
+ */
+int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
+ int post_reset, u16 *id)
+{
+ struct ata_port *ap = dev->ap;
+ unsigned int class = *p_class;
+ struct ata_taskfile tf;
+ unsigned int err_mask = 0;
+ const char *reason;
+ int rc;
+
+ if (ata_msg_ctl(ap))
+ ata_dev_printk(dev, KERN_DEBUG, "%s: ENTER, host %u, dev %u\n",
+ __FUNCTION__, ap->id, dev->devno);
+
+ ata_dev_select(ap, dev->devno, 1, 1); /* select device 0/1 */
+
+ retry:
+ ata_tf_init(dev, &tf);
+
+ switch (class) {
+ case ATA_DEV_ATA:
+ tf.command = ATA_CMD_ID_ATA;
+ break;
+ case ATA_DEV_ATAPI:
+ tf.command = ATA_CMD_ID_ATAPI;
+ break;
+ default:
+ rc = -ENODEV;
+ reason = "unsupported class";
+ goto err_out;
+ }
+
+ tf.protocol = ATA_PROT_PIO;
+
+ err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE,
+ id, sizeof(id[0]) * ATA_ID_WORDS);
+ if (err_mask) {
+ rc = -EIO;
+ reason = "I/O error";
+ goto err_out;
+ }
+
+ swap_buf_le16(id, ATA_ID_WORDS);
+
+ /* sanity check */
+ rc = -EINVAL;
+ reason = "device reports illegal type";
+
+ if (class == ATA_DEV_ATA) {
+ if (!ata_id_is_ata(id) && !ata_id_is_cfa(id))
+ goto err_out;
+ } else {
+ if (ata_id_is_ata(id))
+ goto err_out;
+ }
+
+ if (post_reset && class == ATA_DEV_ATA) {
+ /*
+ * The exact sequence expected by certain pre-ATA4 drives is:
+ * SRST RESET
+ * IDENTIFY
+ * INITIALIZE DEVICE PARAMETERS
+ * anything else..
+ * Some drives were very specific about that exact sequence.
+ */
+ if (ata_id_major_version(id) < 4 || !ata_id_has_lba(id)) {
+ err_mask = ata_dev_init_params(dev, id[3], id[6]);
+ if (err_mask) {
+ rc = -EIO;
+ reason = "INIT_DEV_PARAMS failed";
+ goto err_out;
+ }
+
+ /* current CHS translation info (id[53-58]) might be
+ * changed. reread the identify device info.
+ */
+ post_reset = 0;
+ goto retry;
+ }
+ }
+
+ *p_class = class;
+
+ return 0;
+
+ err_out:
+ if (ata_msg_warn(ap))
+ ata_dev_printk(dev, KERN_WARNING, "failed to IDENTIFY "
+ "(%s, err_mask=0x%x)\n", reason, err_mask);
+ return rc;
+}
+
+static inline u8 ata_dev_knobble(struct ata_device *dev)
+{
+ return ((dev->ap->cbl == ATA_CBL_SATA) && (!ata_id_is_sata(dev->id)));
+}
+
+static void ata_dev_config_ncq(struct ata_device *dev,
+ char *desc, size_t desc_sz)
+{
+ struct ata_port *ap = dev->ap;
+ int hdepth = 0, ddepth = ata_id_queue_depth(dev->id);
+
+ if (!ata_id_has_ncq(dev->id)) {
+ desc[0] = '\0';
+ return;
+ }
+
+ if (ap->flags & ATA_FLAG_NCQ) {
+ hdepth = min(ap->scsi_host->can_queue, ATA_MAX_QUEUE - 1);
+ dev->flags |= ATA_DFLAG_NCQ;
+ }
+
+ if (hdepth >= ddepth)
+ snprintf(desc, desc_sz, "NCQ (depth %d)", ddepth);
+ else
+ snprintf(desc, desc_sz, "NCQ (depth %d/%d)", hdepth, ddepth);
+}
+
+static void ata_set_port_max_cmd_len(struct ata_port *ap)
+{
+ int i;
+
+ if (ap->scsi_host) {
+ unsigned int len = 0;
+
+ for (i = 0; i < ATA_MAX_DEVICES; i++)
+ len = max(len, ap->device[i].cdb_len);
+
+ ap->scsi_host->max_cmd_len = len;
+ }
+}
+
+/**
+ * ata_dev_configure - Configure the specified ATA/ATAPI device
+ * @dev: Target device to configure
+ * @print_info: Enable device info printout
+ *
+ * Configure @dev according to @dev->id. Generic and low-level
+ * driver specific fixups are also applied.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep)
+ *
+ * RETURNS:
+ * 0 on success, -errno otherwise
+ */
+int ata_dev_configure(struct ata_device *dev, int print_info)
+{
+ struct ata_port *ap = dev->ap;
+ const u16 *id = dev->id;
+ unsigned int xfer_mask;
+ char revbuf[7]; /* XYZ-99\0 */
+ int rc;
+
+ if (!ata_dev_enabled(dev) && ata_msg_info(ap)) {
+ ata_dev_printk(dev, KERN_INFO,
+ "%s: ENTER/EXIT (host %u, dev %u) -- nodev\n",
+ __FUNCTION__, ap->id, dev->devno);
+ return 0;
+ }
+
+ if (ata_msg_probe(ap))
+ ata_dev_printk(dev, KERN_DEBUG, "%s: ENTER, host %u, dev %u\n",
+ __FUNCTION__, ap->id, dev->devno);
+
+ /* print device capabilities */
+ if (ata_msg_probe(ap))
+ ata_dev_printk(dev, KERN_DEBUG,
+ "%s: cfg 49:%04x 82:%04x 83:%04x 84:%04x "
+ "85:%04x 86:%04x 87:%04x 88:%04x\n",
+ __FUNCTION__,
+ id[49], id[82], id[83], id[84],
+ id[85], id[86], id[87], id[88]);
+
+ /* initialize to-be-configured parameters */
+ dev->flags &= ~ATA_DFLAG_CFG_MASK;
+ dev->max_sectors = 0;
+ dev->cdb_len = 0;
+ dev->n_sectors = 0;
+ dev->cylinders = 0;
+ dev->heads = 0;
+ dev->sectors = 0;
+
+ /*
+ * common ATA, ATAPI feature tests
+ */
+
+ /* find max transfer mode; for printk only */
+ xfer_mask = ata_id_xfermask(id);
+
+ if (ata_msg_probe(ap))
+ ata_dump_id(id);
+
+ /* ATA-specific feature tests */
+ if (dev->class == ATA_DEV_ATA) {
+ if (ata_id_is_cfa(id)) {
+ if (id[162] & 1) /* CPRM may make this media unusable */
+ ata_dev_printk(dev, KERN_WARNING, "ata%u: device %u supports DRM functions and may not be fully accessable.\n",
+ ap->id, dev->devno);
+ snprintf(revbuf, 7, "CFA");
+ }
+ else
+ snprintf(revbuf, 7, "ATA-%d", ata_id_major_version(id));
+
+ dev->n_sectors = ata_id_n_sectors(id);
+
+ if (ata_id_has_lba(id)) {
+ const char *lba_desc;
+ char ncq_desc[20];
+
+ lba_desc = "LBA";
+ dev->flags |= ATA_DFLAG_LBA;
+ if (ata_id_has_lba48(id)) {
+ dev->flags |= ATA_DFLAG_LBA48;
+ lba_desc = "LBA48";
+ }
+
+ /* config NCQ */
+ ata_dev_config_ncq(dev, ncq_desc, sizeof(ncq_desc));
+
+ /* print device info to dmesg */
+ if (ata_msg_drv(ap) && print_info)
+ ata_dev_printk(dev, KERN_INFO, "%s, "
+ "max %s, %Lu sectors: %s %s\n",
+ revbuf,
+ ata_mode_string(xfer_mask),
+ (unsigned long long)dev->n_sectors,
+ lba_desc, ncq_desc);
+ } else {
+ /* CHS */
+
+ /* Default translation */
+ dev->cylinders = id[1];
+ dev->heads = id[3];
+ dev->sectors = id[6];
+
+ if (ata_id_current_chs_valid(id)) {
+ /* Current CHS translation is valid. */
+ dev->cylinders = id[54];
+ dev->heads = id[55];
+ dev->sectors = id[56];
+ }
+
+ /* print device info to dmesg */
+ if (ata_msg_drv(ap) && print_info)
+ ata_dev_printk(dev, KERN_INFO, "%s, "
+ "max %s, %Lu sectors: CHS %u/%u/%u\n",
+ revbuf,
+ ata_mode_string(xfer_mask),
+ (unsigned long long)dev->n_sectors,
+ dev->cylinders, dev->heads,
+ dev->sectors);
+ }
+
+ if (dev->id[59] & 0x100) {
+ dev->multi_count = dev->id[59] & 0xff;
+ if (ata_msg_drv(ap) && print_info)
+ ata_dev_printk(dev, KERN_INFO,
+ "ata%u: dev %u multi count %u\n",
+ ap->id, dev->devno, dev->multi_count);
+ }
+
+ dev->cdb_len = 16;
+ }
+
+ /* ATAPI-specific feature tests */
+ else if (dev->class == ATA_DEV_ATAPI) {
+ char *cdb_intr_string = "";
+
+ rc = atapi_cdb_len(id);
+ if ((rc < 12) || (rc > ATAPI_CDB_LEN)) {
+ if (ata_msg_warn(ap))
+ ata_dev_printk(dev, KERN_WARNING,
+ "unsupported CDB len\n");
+ rc = -EINVAL;
+ goto err_out_nosup;
+ }
+ dev->cdb_len = (unsigned int) rc;
+
+ if (ata_id_cdb_intr(dev->id)) {
+ dev->flags |= ATA_DFLAG_CDB_INTR;
+ cdb_intr_string = ", CDB intr";
+ }
+
+ /* print device info to dmesg */
+ if (ata_msg_drv(ap) && print_info)
+ ata_dev_printk(dev, KERN_INFO, "ATAPI, max %s%s\n",
+ ata_mode_string(xfer_mask),
+ cdb_intr_string);
+ }
+
+ if (dev->horkage & ATA_HORKAGE_DIAGNOSTIC) {
+ /* Let the user know. We don't want to disallow opens for
+ rescue purposes, or in case the vendor is just a blithering
+ idiot */
+ if (print_info) {
+ ata_dev_printk(dev, KERN_WARNING,
+"Drive reports diagnostics failure. This may indicate a drive\n");
+ ata_dev_printk(dev, KERN_WARNING,
+"fault or invalid emulation. Contact drive vendor for information.\n");
+ }
+ }
+
+ ata_set_port_max_cmd_len(ap);
+
+ /* limit bridge transfers to udma5, 200 sectors */
+ if (ata_dev_knobble(dev)) {
+ if (ata_msg_drv(ap) && print_info)
+ ata_dev_printk(dev, KERN_INFO,
+ "applying bridge limits\n");
+ dev->udma_mask &= ATA_UDMA5;
+ dev->max_sectors = ATA_MAX_SECTORS;
+ }
+
+ if (ap->ops->dev_config)
+ ap->ops->dev_config(ap, dev);
+
+ if (ata_msg_probe(ap))
+ ata_dev_printk(dev, KERN_DEBUG, "%s: EXIT, drv_stat = 0x%x\n",
+ __FUNCTION__, ata_chk_status(ap));
+ return 0;
+
+err_out_nosup:
+ if (ata_msg_probe(ap))
+ ata_dev_printk(dev, KERN_DEBUG,
+ "%s: EXIT, err\n", __FUNCTION__);
+ return rc;
+}
+
+/**
+ * ata_bus_probe - Reset and probe ATA bus
+ * @ap: Bus to probe
+ *
+ * Master ATA bus probing function. Initiates a hardware-dependent
+ * bus reset, then attempts to identify any devices found on
+ * the bus.
+ *
+ * LOCKING:
+ * PCI/etc. bus probe sem.
+ *
+ * RETURNS:
+ * Zero on success, negative errno otherwise.
+ */
+
+int ata_bus_probe(struct ata_port *ap)
+{
+ unsigned int classes[ATA_MAX_DEVICES];
+ int tries[ATA_MAX_DEVICES];
+ int i, rc, down_xfermask;
+ struct ata_device *dev;
+
+ ata_port_probe(ap);
+
+ for (i = 0; i < ATA_MAX_DEVICES; i++)
+ tries[i] = ATA_PROBE_MAX_TRIES;
+
+ retry:
+ down_xfermask = 0;
+
+ /* reset and determine device classes */
+ ap->ops->phy_reset(ap);
+
+ for (i = 0; i < ATA_MAX_DEVICES; i++) {
+ dev = &ap->device[i];
+
+ if (!(ap->flags & ATA_FLAG_DISABLED) &&
+ dev->class != ATA_DEV_UNKNOWN)
+ classes[dev->devno] = dev->class;
+ else
+ classes[dev->devno] = ATA_DEV_NONE;
+
+ dev->class = ATA_DEV_UNKNOWN;
+ }
+
+ ata_port_probe(ap);
+
+ /* after the reset the device state is PIO 0 and the controller
+ state is undefined. Record the mode */
+
+ for (i = 0; i < ATA_MAX_DEVICES; i++)
+ ap->device[i].pio_mode = XFER_PIO_0;
+
+ /* read IDENTIFY page and configure devices */
+ for (i = 0; i < ATA_MAX_DEVICES; i++) {
+ dev = &ap->device[i];
+
+ if (tries[i])
+ dev->class = classes[i];
+
+ if (!ata_dev_enabled(dev))
+ continue;
+
+ rc = ata_dev_read_id(dev, &dev->class, 1, dev->id);
+ if (rc)
+ goto fail;
+
+ rc = ata_dev_configure(dev, 1);
+ if (rc)
+ goto fail;
+ }
+
+ /* configure transfer mode */
+ rc = ata_set_mode(ap, &dev);
+ if (rc) {
+ down_xfermask = 1;
+ goto fail;
+ }
+
+ for (i = 0; i < ATA_MAX_DEVICES; i++)
+ if (ata_dev_enabled(&ap->device[i]))
+ return 0;
+
+ /* no device present, disable port */
+ ata_port_disable(ap);
+ ap->ops->port_disable(ap);
+ return -ENODEV;
+
+ fail:
+ switch (rc) {
+ case -EINVAL:
+ case -ENODEV:
+ tries[dev->devno] = 0;
+ break;
+ case -EIO:
+ sata_down_spd_limit(ap);
+ /* fall through */
+ default:
+ tries[dev->devno]--;
+ if (down_xfermask &&
+ ata_down_xfermask_limit(dev, tries[dev->devno] == 1))
+ tries[dev->devno] = 0;
+ }
+
+ if (!tries[dev->devno]) {
+ ata_down_xfermask_limit(dev, 1);
+ ata_dev_disable(dev);
+ }
+
+ goto retry;
+}
+
+/**
+ * ata_port_probe - Mark port as enabled
+ * @ap: Port for which we indicate enablement
+ *
+ * Modify @ap data structure such that the system
+ * thinks that the entire port is enabled.
+ *
+ * LOCKING: host lock, or some other form of
+ * serialization.
+ */
+
+void ata_port_probe(struct ata_port *ap)
+{
+ ap->flags &= ~ATA_FLAG_DISABLED;
+}
+
+/**
+ * sata_print_link_status - Print SATA link status
+ * @ap: SATA port to printk link status about
+ *
+ * This function prints link speed and status of a SATA link.
+ *
+ * LOCKING:
+ * None.
+ */
+static void sata_print_link_status(struct ata_port *ap)
+{
+ u32 sstatus, scontrol, tmp;
+
+ if (sata_scr_read(ap, SCR_STATUS, &sstatus))
+ return;
+ sata_scr_read(ap, SCR_CONTROL, &scontrol);
+
+ if (ata_port_online(ap)) {
+ tmp = (sstatus >> 4) & 0xf;
+ ata_port_printk(ap, KERN_INFO,
+ "SATA link up %s (SStatus %X SControl %X)\n",
+ sata_spd_string(tmp), sstatus, scontrol);
+ } else {
+ ata_port_printk(ap, KERN_INFO,
+ "SATA link down (SStatus %X SControl %X)\n",
+ sstatus, scontrol);
+ }
+}
+
+/**
+ * __sata_phy_reset - Wake/reset a low-level SATA PHY
+ * @ap: SATA port associated with target SATA PHY.
+ *
+ * This function issues commands to standard SATA Sxxx
+ * PHY registers, to wake up the phy (and device), and
+ * clear any reset condition.
+ *
+ * LOCKING:
+ * PCI/etc. bus probe sem.
+ *
+ */
+void __sata_phy_reset(struct ata_port *ap)
+{
+ u32 sstatus;
+ unsigned long timeout = jiffies + (HZ * 5);
+
+ if (ap->flags & ATA_FLAG_SATA_RESET) {
+ /* issue phy wake/reset */
+ sata_scr_write_flush(ap, SCR_CONTROL, 0x301);
+ /* Couldn't find anything in SATA I/II specs, but
+ * AHCI-1.1 10.4.2 says at least 1 ms. */
+ mdelay(1);
+ }
+ /* phy wake/clear reset */
+ sata_scr_write_flush(ap, SCR_CONTROL, 0x300);
+
+ /* wait for phy to become ready, if necessary */
+ do {
+ msleep(200);
+ sata_scr_read(ap, SCR_STATUS, &sstatus);
+ if ((sstatus & 0xf) != 1)
+ break;
+ } while (time_before(jiffies, timeout));
+
+ /* print link status */
+ sata_print_link_status(ap);
+
+ /* TODO: phy layer with polling, timeouts, etc. */
+ if (!ata_port_offline(ap))
+ ata_port_probe(ap);
+ else
+ ata_port_disable(ap);
+
+ if (ap->flags & ATA_FLAG_DISABLED)
+ return;
+
+ if (ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT)) {
+ ata_port_disable(ap);
+ return;
+ }
+
+ ap->cbl = ATA_CBL_SATA;
+}
+
+/**
+ * sata_phy_reset - Reset SATA bus.
+ * @ap: SATA port associated with target SATA PHY.
+ *
+ * This function resets the SATA bus, and then probes
+ * the bus for devices.
+ *
+ * LOCKING:
+ * PCI/etc. bus probe sem.
+ *
+ */
+void sata_phy_reset(struct ata_port *ap)
+{
+ __sata_phy_reset(ap);
+ if (ap->flags & ATA_FLAG_DISABLED)
+ return;
+ ata_bus_reset(ap);
+}
+
+/**
+ * ata_dev_pair - return other device on cable
+ * @adev: device
+ *
+ * Obtain the other device on the same cable, or if none is
+ * present NULL is returned
+ */
+
+struct ata_device *ata_dev_pair(struct ata_device *adev)
+{
+ struct ata_port *ap = adev->ap;
+ struct ata_device *pair = &ap->device[1 - adev->devno];
+ if (!ata_dev_enabled(pair))
+ return NULL;
+ return pair;
+}
+
+/**
+ * ata_port_disable - Disable port.
+ * @ap: Port to be disabled.
+ *
+ * Modify @ap data structure such that the system
+ * thinks that the entire port is disabled, and should
+ * never attempt to probe or communicate with devices
+ * on this port.
+ *
+ * LOCKING: host lock, or some other form of
+ * serialization.
+ */
+
+void ata_port_disable(struct ata_port *ap)
+{
+ ap->device[0].class = ATA_DEV_NONE;
+ ap->device[1].class = ATA_DEV_NONE;
+ ap->flags |= ATA_FLAG_DISABLED;
+}
+
+/**
+ * sata_down_spd_limit - adjust SATA spd limit downward
+ * @ap: Port to adjust SATA spd limit for
+ *
+ * Adjust SATA spd limit of @ap downward. Note that this
+ * function only adjusts the limit. The change must be applied
+ * using sata_set_spd().
+ *
+ * LOCKING:
+ * Inherited from caller.
+ *
+ * RETURNS:
+ * 0 on success, negative errno on failure
+ */
+int sata_down_spd_limit(struct ata_port *ap)
+{
+ u32 sstatus, spd, mask;
+ int rc, highbit;
+
+ rc = sata_scr_read(ap, SCR_STATUS, &sstatus);
+ if (rc)
+ return rc;
+
+ mask = ap->sata_spd_limit;
+ if (mask <= 1)
+ return -EINVAL;
+ highbit = fls(mask) - 1;
+ mask &= ~(1 << highbit);
+
+ spd = (sstatus >> 4) & 0xf;
+ if (spd <= 1)
+ return -EINVAL;
+ spd--;
+ mask &= (1 << spd) - 1;
+ if (!mask)
+ return -EINVAL;
+
+ ap->sata_spd_limit = mask;
+
+ ata_port_printk(ap, KERN_WARNING, "limiting SATA link speed to %s\n",
+ sata_spd_string(fls(mask)));
+
+ return 0;
+}
+
+static int __sata_set_spd_needed(struct ata_port *ap, u32 *scontrol)
+{
+ u32 spd, limit;
+
+ if (ap->sata_spd_limit == UINT_MAX)
+ limit = 0;
+ else
+ limit = fls(ap->sata_spd_limit);
+
+ spd = (*scontrol >> 4) & 0xf;
+ *scontrol = (*scontrol & ~0xf0) | ((limit & 0xf) << 4);
+
+ return spd != limit;
+}
+
+/**
+ * sata_set_spd_needed - is SATA spd configuration needed
+ * @ap: Port in question
+ *
+ * Test whether the spd limit in SControl matches
+ * @ap->sata_spd_limit. This function is used to determine
+ * whether hardreset is necessary to apply SATA spd
+ * configuration.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ *
+ * RETURNS:
+ * 1 if SATA spd configuration is needed, 0 otherwise.
+ */
+int sata_set_spd_needed(struct ata_port *ap)
+{
+ u32 scontrol;
+
+ if (sata_scr_read(ap, SCR_CONTROL, &scontrol))
+ return 0;
+
+ return __sata_set_spd_needed(ap, &scontrol);
+}
+
+/**
+ * sata_set_spd - set SATA spd according to spd limit
+ * @ap: Port to set SATA spd for
+ *
+ * Set SATA spd of @ap according to sata_spd_limit.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ *
+ * RETURNS:
+ * 0 if spd doesn't need to be changed, 1 if spd has been
+ * changed. Negative errno if SCR registers are inaccessible.
+ */
+int sata_set_spd(struct ata_port *ap)
+{
+ u32 scontrol;
+ int rc;
+
+ if ((rc = sata_scr_read(ap, SCR_CONTROL, &scontrol)))
+ return rc;
+
+ if (!__sata_set_spd_needed(ap, &scontrol))
+ return 0;
+
+ if ((rc = sata_scr_write(ap, SCR_CONTROL, scontrol)))
+ return rc;
+
+ return 1;
+}
+
+/*
+ * This mode timing computation functionality is ported over from
+ * drivers/ide/ide-timing.h and was originally written by Vojtech Pavlik
+ */
+/*
+ * PIO 0-4, MWDMA 0-2 and UDMA 0-6 timings (in nanoseconds).
+ * These were taken from ATA/ATAPI-6 standard, rev 0a, except
+ * for UDMA6, which is currently supported only by Maxtor drives.
+ *
+ * For PIO 5/6 MWDMA 3/4 see the CFA specification 3.0.
+ */
+
+static const struct ata_timing ata_timing[] = {
+
+ { XFER_UDMA_6, 0, 0, 0, 0, 0, 0, 0, 15 },
+ { XFER_UDMA_5, 0, 0, 0, 0, 0, 0, 0, 20 },
+ { XFER_UDMA_4, 0, 0, 0, 0, 0, 0, 0, 30 },
+ { XFER_UDMA_3, 0, 0, 0, 0, 0, 0, 0, 45 },
+
+ { XFER_MW_DMA_4, 25, 0, 0, 0, 55, 20, 80, 0 },
+ { XFER_MW_DMA_3, 25, 0, 0, 0, 65, 25, 100, 0 },
+ { XFER_UDMA_2, 0, 0, 0, 0, 0, 0, 0, 60 },
+ { XFER_UDMA_1, 0, 0, 0, 0, 0, 0, 0, 80 },
+ { XFER_UDMA_0, 0, 0, 0, 0, 0, 0, 0, 120 },
+
+/* { XFER_UDMA_SLOW, 0, 0, 0, 0, 0, 0, 0, 150 }, */
+
+ { XFER_MW_DMA_2, 25, 0, 0, 0, 70, 25, 120, 0 },
+ { XFER_MW_DMA_1, 45, 0, 0, 0, 80, 50, 150, 0 },
+ { XFER_MW_DMA_0, 60, 0, 0, 0, 215, 215, 480, 0 },
+
+ { XFER_SW_DMA_2, 60, 0, 0, 0, 120, 120, 240, 0 },
+ { XFER_SW_DMA_1, 90, 0, 0, 0, 240, 240, 480, 0 },
+ { XFER_SW_DMA_0, 120, 0, 0, 0, 480, 480, 960, 0 },
+
+ { XFER_PIO_6, 10, 55, 20, 80, 55, 20, 80, 0 },
+ { XFER_PIO_5, 15, 65, 25, 100, 65, 25, 100, 0 },
+ { XFER_PIO_4, 25, 70, 25, 120, 70, 25, 120, 0 },
+ { XFER_PIO_3, 30, 80, 70, 180, 80, 70, 180, 0 },
+
+ { XFER_PIO_2, 30, 290, 40, 330, 100, 90, 240, 0 },
+ { XFER_PIO_1, 50, 290, 93, 383, 125, 100, 383, 0 },
+ { XFER_PIO_0, 70, 290, 240, 600, 165, 150, 600, 0 },
+
+/* { XFER_PIO_SLOW, 120, 290, 240, 960, 290, 240, 960, 0 }, */
+
+ { 0xFF }
+};
+
+#define ENOUGH(v,unit) (((v)-1)/(unit)+1)
+#define EZ(v,unit) ((v)?ENOUGH(v,unit):0)
+
+static void ata_timing_quantize(const struct ata_timing *t, struct ata_timing *q, int T, int UT)
+{
+ q->setup = EZ(t->setup * 1000, T);
+ q->act8b = EZ(t->act8b * 1000, T);
+ q->rec8b = EZ(t->rec8b * 1000, T);
+ q->cyc8b = EZ(t->cyc8b * 1000, T);
+ q->active = EZ(t->active * 1000, T);
+ q->recover = EZ(t->recover * 1000, T);
+ q->cycle = EZ(t->cycle * 1000, T);
+ q->udma = EZ(t->udma * 1000, UT);
+}
+
+void ata_timing_merge(const struct ata_timing *a, const struct ata_timing *b,
+ struct ata_timing *m, unsigned int what)
+{
+ if (what & ATA_TIMING_SETUP ) m->setup = max(a->setup, b->setup);
+ if (what & ATA_TIMING_ACT8B ) m->act8b = max(a->act8b, b->act8b);
+ if (what & ATA_TIMING_REC8B ) m->rec8b = max(a->rec8b, b->rec8b);
+ if (what & ATA_TIMING_CYC8B ) m->cyc8b = max(a->cyc8b, b->cyc8b);
+ if (what & ATA_TIMING_ACTIVE ) m->active = max(a->active, b->active);
+ if (what & ATA_TIMING_RECOVER) m->recover = max(a->recover, b->recover);
+ if (what & ATA_TIMING_CYCLE ) m->cycle = max(a->cycle, b->cycle);
+ if (what & ATA_TIMING_UDMA ) m->udma = max(a->udma, b->udma);
+}
+
+static const struct ata_timing* ata_timing_find_mode(unsigned short speed)
+{
+ const struct ata_timing *t;
+
+ for (t = ata_timing; t->mode != speed; t++)
+ if (t->mode == 0xFF)
+ return NULL;
+ return t;
+}
+
+int ata_timing_compute(struct ata_device *adev, unsigned short speed,
+ struct ata_timing *t, int T, int UT)
+{
+ const struct ata_timing *s;
+ struct ata_timing p;
+
+ /*
+ * Find the mode.
+ */
+
+ if (!(s = ata_timing_find_mode(speed)))
+ return -EINVAL;
+
+ memcpy(t, s, sizeof(*s));
+
+ /*
+ * If the drive is an EIDE drive, it can tell us it needs extended
+ * PIO/MW_DMA cycle timing.
+ */
+
+ if (adev->id[ATA_ID_FIELD_VALID] & 2) { /* EIDE drive */
+ memset(&p, 0, sizeof(p));
+ if(speed >= XFER_PIO_0 && speed <= XFER_SW_DMA_0) {
+ if (speed <= XFER_PIO_2) p.cycle = p.cyc8b = adev->id[ATA_ID_EIDE_PIO];
+ else p.cycle = p.cyc8b = adev->id[ATA_ID_EIDE_PIO_IORDY];
+ } else if(speed >= XFER_MW_DMA_0 && speed <= XFER_MW_DMA_2) {
+ p.cycle = adev->id[ATA_ID_EIDE_DMA_MIN];
+ }
+ ata_timing_merge(&p, t, t, ATA_TIMING_CYCLE | ATA_TIMING_CYC8B);
+ }
+
+ /*
+ * Convert the timing to bus clock counts.
+ */
+
+ ata_timing_quantize(t, t, T, UT);
+
+ /*
+ * Even in DMA/UDMA modes we still use PIO access for IDENTIFY,
+ * S.M.A.R.T * and some other commands. We have to ensure that the
+ * DMA cycle timing is slower/equal than the fastest PIO timing.
+ */
+
+ if (speed > XFER_PIO_4) {
+ ata_timing_compute(adev, adev->pio_mode, &p, T, UT);
+ ata_timing_merge(&p, t, t, ATA_TIMING_ALL);
+ }
+
+ /*
+ * Lengthen active & recovery time so that cycle time is correct.
+ */
+
+ if (t->act8b + t->rec8b < t->cyc8b) {
+ t->act8b += (t->cyc8b - (t->act8b + t->rec8b)) / 2;
+ t->rec8b = t->cyc8b - t->act8b;
+ }
+
+ if (t->active + t->recover < t->cycle) {
+ t->active += (t->cycle - (t->active + t->recover)) / 2;
+ t->recover = t->cycle - t->active;
+ }
+
+ return 0;
+}
+
+/**
+ * ata_down_xfermask_limit - adjust dev xfer masks downward
+ * @dev: Device to adjust xfer masks
+ * @force_pio0: Force PIO0
+ *
+ * Adjust xfer masks of @dev downward. Note that this function
+ * does not apply the change. Invoking ata_set_mode() afterwards
+ * will apply the limit.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ *
+ * RETURNS:
+ * 0 on success, negative errno on failure
+ */
+int ata_down_xfermask_limit(struct ata_device *dev, int force_pio0)
+{
+ unsigned long xfer_mask;
+ int highbit;
+
+ xfer_mask = ata_pack_xfermask(dev->pio_mask, dev->mwdma_mask,
+ dev->udma_mask);
+
+ if (!xfer_mask)
+ goto fail;
+ /* don't gear down to MWDMA from UDMA, go directly to PIO */
+ if (xfer_mask & ATA_MASK_UDMA)
+ xfer_mask &= ~ATA_MASK_MWDMA;
+
+ highbit = fls(xfer_mask) - 1;
+ xfer_mask &= ~(1 << highbit);
+ if (force_pio0)
+ xfer_mask &= 1 << ATA_SHIFT_PIO;
+ if (!xfer_mask)
+ goto fail;
+
+ ata_unpack_xfermask(xfer_mask, &dev->pio_mask, &dev->mwdma_mask,
+ &dev->udma_mask);
+
+ ata_dev_printk(dev, KERN_WARNING, "limiting speed to %s\n",
+ ata_mode_string(xfer_mask));
+
+ return 0;
+
+ fail:
+ return -EINVAL;
+}
+
+static int ata_dev_set_mode(struct ata_device *dev)
+{
+ unsigned int err_mask;
+ int rc;
+
+ dev->flags &= ~ATA_DFLAG_PIO;
+ if (dev->xfer_shift == ATA_SHIFT_PIO)
+ dev->flags |= ATA_DFLAG_PIO;
+
+ err_mask = ata_dev_set_xfermode(dev);
+ if (err_mask) {
+ ata_dev_printk(dev, KERN_ERR, "failed to set xfermode "
+ "(err_mask=0x%x)\n", err_mask);
+ return -EIO;
+ }
+
+ rc = ata_dev_revalidate(dev, 0);
+ if (rc)
+ return rc;
+
+ DPRINTK("xfer_shift=%u, xfer_mode=0x%x\n",
+ dev->xfer_shift, (int)dev->xfer_mode);
+
+ ata_dev_printk(dev, KERN_INFO, "configured for %s\n",
+ ata_mode_string(ata_xfer_mode2mask(dev->xfer_mode)));
+ return 0;
+}
+
+/**
+ * ata_set_mode - Program timings and issue SET FEATURES - XFER
+ * @ap: port on which timings will be programmed
+ * @r_failed_dev: out paramter for failed device
+ *
+ * Set ATA device disk transfer mode (PIO3, UDMA6, etc.). If
+ * ata_set_mode() fails, pointer to the failing device is
+ * returned in @r_failed_dev.
+ *
+ * LOCKING:
+ * PCI/etc. bus probe sem.
+ *
+ * RETURNS:
+ * 0 on success, negative errno otherwise
+ */
+int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev)
+{
+ struct ata_device *dev;
+ int i, rc = 0, used_dma = 0, found = 0;
+
+ /* has private set_mode? */
+ if (ap->ops->set_mode) {
+ /* FIXME: make ->set_mode handle no device case and
+ * return error code and failing device on failure.
+ */
+ for (i = 0; i < ATA_MAX_DEVICES; i++) {
+ if (ata_dev_ready(&ap->device[i])) {
+ ap->ops->set_mode(ap);
+ break;
+ }
+ }
+ return 0;
+ }
+
+ /* step 1: calculate xfer_mask */
+ for (i = 0; i < ATA_MAX_DEVICES; i++) {
+ unsigned int pio_mask, dma_mask;
+
+ dev = &ap->device[i];
+
+ if (!ata_dev_enabled(dev))
+ continue;
+
+ ata_dev_xfermask(dev);
+
+ pio_mask = ata_pack_xfermask(dev->pio_mask, 0, 0);
+ dma_mask = ata_pack_xfermask(0, dev->mwdma_mask, dev->udma_mask);
+ dev->pio_mode = ata_xfer_mask2mode(pio_mask);
+ dev->dma_mode = ata_xfer_mask2mode(dma_mask);
+
+ found = 1;
+ if (dev->dma_mode)
+ used_dma = 1;
+ }
+ if (!found)
+ goto out;
+
+ /* step 2: always set host PIO timings */
+ for (i = 0; i < ATA_MAX_DEVICES; i++) {
+ dev = &ap->device[i];
+ if (!ata_dev_enabled(dev))
+ continue;
+
+ if (!dev->pio_mode) {
+ ata_dev_printk(dev, KERN_WARNING, "no PIO support\n");
+ rc = -EINVAL;
+ goto out;
+ }
+
+ dev->xfer_mode = dev->pio_mode;
+ dev->xfer_shift = ATA_SHIFT_PIO;
+ if (ap->ops->set_piomode)
+ ap->ops->set_piomode(ap, dev);
+ }
+
+ /* step 3: set host DMA timings */
+ for (i = 0; i < ATA_MAX_DEVICES; i++) {
+ dev = &ap->device[i];
+
+ if (!ata_dev_enabled(dev) || !dev->dma_mode)
+ continue;
+
+ dev->xfer_mode = dev->dma_mode;
+ dev->xfer_shift = ata_xfer_mode2shift(dev->dma_mode);
+ if (ap->ops->set_dmamode)
+ ap->ops->set_dmamode(ap, dev);
+ }
+
+ /* step 4: update devices' xfer mode */
+ for (i = 0; i < ATA_MAX_DEVICES; i++) {
+ dev = &ap->device[i];
+
+ /* don't udpate suspended devices' xfer mode */
+ if (!ata_dev_ready(dev))
+ continue;
+
+ rc = ata_dev_set_mode(dev);
+ if (rc)
+ goto out;
+ }
+
+ /* Record simplex status. If we selected DMA then the other
+ * host channels are not permitted to do so.
+ */
+ if (used_dma && (ap->host->flags & ATA_HOST_SIMPLEX))
+ ap->host->simplex_claimed = 1;
+
+ /* step5: chip specific finalisation */
+ if (ap->ops->post_set_mode)
+ ap->ops->post_set_mode(ap);
+
+ out:
+ if (rc)
+ *r_failed_dev = dev;
+ return rc;
+}
+
+/**
+ * ata_tf_to_host - issue ATA taskfile to host controller
+ * @ap: port to which command is being issued
+ * @tf: ATA taskfile register set
+ *
+ * Issues ATA taskfile register set to ATA host controller,
+ * with proper synchronization with interrupt handler and
+ * other threads.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ */
+
+static inline void ata_tf_to_host(struct ata_port *ap,
+ const struct ata_taskfile *tf)
+{
+ ap->ops->tf_load(ap, tf);
+ ap->ops->exec_command(ap, tf);
+}
+
+/**
+ * ata_busy_sleep - sleep until BSY clears, or timeout
+ * @ap: port containing status register to be polled
+ * @tmout_pat: impatience timeout
+ * @tmout: overall timeout
+ *
+ * Sleep until ATA Status register bit BSY clears,
+ * or a timeout occurs.
+ *
+ * LOCKING: None.
+ */
+
+unsigned int ata_busy_sleep (struct ata_port *ap,
+ unsigned long tmout_pat, unsigned long tmout)
+{
+ unsigned long timer_start, timeout;
+ u8 status;
+
+ status = ata_busy_wait(ap, ATA_BUSY, 300);
+ timer_start = jiffies;
+ timeout = timer_start + tmout_pat;
+ while ((status & ATA_BUSY) && (time_before(jiffies, timeout))) {
+ msleep(50);
+ status = ata_busy_wait(ap, ATA_BUSY, 3);
+ }
+
+ if (status & ATA_BUSY)
+ ata_port_printk(ap, KERN_WARNING,
+ "port is slow to respond, please be patient\n");
+
+ timeout = timer_start + tmout;
+ while ((status & ATA_BUSY) && (time_before(jiffies, timeout))) {
+ msleep(50);
+ status = ata_chk_status(ap);
+ }
+
+ if (status & ATA_BUSY) {
+ ata_port_printk(ap, KERN_ERR, "port failed to respond "
+ "(%lu secs)\n", tmout / HZ);
+ return 1;
+ }
+
+ return 0;
+}
+
+static void ata_bus_post_reset(struct ata_port *ap, unsigned int devmask)
+{
+ struct ata_ioports *ioaddr = &ap->ioaddr;
+ unsigned int dev0 = devmask & (1 << 0);
+ unsigned int dev1 = devmask & (1 << 1);
+ unsigned long timeout;
+
+ /* if device 0 was found in ata_devchk, wait for its
+ * BSY bit to clear
+ */
+ if (dev0)
+ ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
+
+ /* if device 1 was found in ata_devchk, wait for
+ * register access, then wait for BSY to clear
+ */
+ timeout = jiffies + ATA_TMOUT_BOOT;
+ while (dev1) {
+ u8 nsect, lbal;
+
+ ap->ops->dev_select(ap, 1);
+ if (ap->flags & ATA_FLAG_MMIO) {
+ nsect = readb((void __iomem *) ioaddr->nsect_addr);
+ lbal = readb((void __iomem *) ioaddr->lbal_addr);
+ } else {
+ nsect = inb(ioaddr->nsect_addr);
+ lbal = inb(ioaddr->lbal_addr);
+ }
+ if ((nsect == 1) && (lbal == 1))
+ break;
+ if (time_after(jiffies, timeout)) {
+ dev1 = 0;
+ break;
+ }
+ msleep(50); /* give drive a breather */
+ }
+ if (dev1)
+ ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
+
+ /* is all this really necessary? */
+ ap->ops->dev_select(ap, 0);
+ if (dev1)
+ ap->ops->dev_select(ap, 1);
+ if (dev0)
+ ap->ops->dev_select(ap, 0);
+}
+
+static unsigned int ata_bus_softreset(struct ata_port *ap,
+ unsigned int devmask)
+{
+ struct ata_ioports *ioaddr = &ap->ioaddr;
+
+ DPRINTK("ata%u: bus reset via SRST\n", ap->id);
+
+ /* software reset. causes dev0 to be selected */
+ if (ap->flags & ATA_FLAG_MMIO) {
+ writeb(ap->ctl, (void __iomem *) ioaddr->ctl_addr);
+ udelay(20); /* FIXME: flush */
+ writeb(ap->ctl | ATA_SRST, (void __iomem *) ioaddr->ctl_addr);
+ udelay(20); /* FIXME: flush */
+ writeb(ap->ctl, (void __iomem *) ioaddr->ctl_addr);
+ } else {
+ outb(ap->ctl, ioaddr->ctl_addr);
+ udelay(10);
+ outb(ap->ctl | ATA_SRST, ioaddr->ctl_addr);
+ udelay(10);
+ outb(ap->ctl, ioaddr->ctl_addr);
+ }
+
+ /* spec mandates ">= 2ms" before checking status.
+ * We wait 150ms, because that was the magic delay used for
+ * ATAPI devices in Hale Landis's ATADRVR, for the period of time
+ * between when the ATA command register is written, and then
+ * status is checked. Because waiting for "a while" before
+ * checking status is fine, post SRST, we perform this magic
+ * delay here as well.
+ *
+ * Old drivers/ide uses the 2mS rule and then waits for ready
+ */
+ msleep(150);
+
+ /* Before we perform post reset processing we want to see if
+ * the bus shows 0xFF because the odd clown forgets the D7
+ * pulldown resistor.
+ */
+ if (ata_check_status(ap) == 0xFF) {
+ ata_port_printk(ap, KERN_ERR, "SRST failed (status 0xFF)\n");
+ return AC_ERR_OTHER;
+ }
+
+ ata_bus_post_reset(ap, devmask);
+
+ return 0;
+}
+
+/**
+ * ata_bus_reset - reset host port and associated ATA channel
+ * @ap: port to reset
+ *
+ * This is typically the first time we actually start issuing
+ * commands to the ATA channel. We wait for BSY to clear, then
+ * issue EXECUTE DEVICE DIAGNOSTIC command, polling for its
+ * result. Determine what devices, if any, are on the channel
+ * by looking at the device 0/1 error register. Look at the signature
+ * stored in each device's taskfile registers, to determine if
+ * the device is ATA or ATAPI.
+ *
+ * LOCKING:
+ * PCI/etc. bus probe sem.
+ * Obtains host lock.
+ *
+ * SIDE EFFECTS:
+ * Sets ATA_FLAG_DISABLED if bus reset fails.
+ */
+
+void ata_bus_reset(struct ata_port *ap)
+{
+ struct ata_ioports *ioaddr = &ap->ioaddr;
+ unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS;
+ u8 err;
+ unsigned int dev0, dev1 = 0, devmask = 0;
+
+ DPRINTK("ENTER, host %u, port %u\n", ap->id, ap->port_no);
+
+ /* determine if device 0/1 are present */
+ if (ap->flags & ATA_FLAG_SATA_RESET)
+ dev0 = 1;
+ else {
+ dev0 = ata_devchk(ap, 0);
+ if (slave_possible)
+ dev1 = ata_devchk(ap, 1);
+ }
+
+ if (dev0)
+ devmask |= (1 << 0);
+ if (dev1)
+ devmask |= (1 << 1);
+
+ /* select device 0 again */
+ ap->ops->dev_select(ap, 0);
+
+ /* issue bus reset */
+ if (ap->flags & ATA_FLAG_SRST)
+ if (ata_bus_softreset(ap, devmask))
+ goto err_out;
+
+ /*
+ * determine by signature whether we have ATA or ATAPI devices
+ */
+ ap->device[0].class = ata_dev_try_classify(ap, 0, &err);
+ if ((slave_possible) && (err != 0x81))
+ ap->device[1].class = ata_dev_try_classify(ap, 1, &err);
+
+ /* re-enable interrupts */
+ if (ap->ioaddr.ctl_addr) /* FIXME: hack. create a hook instead */
+ ata_irq_on(ap);
+
+ /* is double-select really necessary? */
+ if (ap->device[1].class != ATA_DEV_NONE)
+ ap->ops->dev_select(ap, 1);
+ if (ap->device[0].class != ATA_DEV_NONE)
+ ap->ops->dev_select(ap, 0);
+
+ /* if no devices were detected, disable this port */
+ if ((ap->device[0].class == ATA_DEV_NONE) &&
+ (ap->device[1].class == ATA_DEV_NONE))
+ goto err_out;
+
+ if (ap->flags & (ATA_FLAG_SATA_RESET | ATA_FLAG_SRST)) {
+ /* set up device control for ATA_FLAG_SATA_RESET */
+ if (ap->flags & ATA_FLAG_MMIO)
+ writeb(ap->ctl, (void __iomem *) ioaddr->ctl_addr);
+ else
+ outb(ap->ctl, ioaddr->ctl_addr);
+ }
+
+ DPRINTK("EXIT\n");
+ return;
+
+err_out:
+ ata_port_printk(ap, KERN_ERR, "disabling port\n");
+ ap->ops->port_disable(ap);
+
+ DPRINTK("EXIT\n");
+}
+
+/**
+ * sata_phy_debounce - debounce SATA phy status
+ * @ap: ATA port to debounce SATA phy status for
+ * @params: timing parameters { interval, duratinon, timeout } in msec
+ *
+ * Make sure SStatus of @ap reaches stable state, determined by
+ * holding the same value where DET is not 1 for @duration polled
+ * every @interval, before @timeout. Timeout constraints the
+ * beginning of the stable state. Because, after hot unplugging,
+ * DET gets stuck at 1 on some controllers, this functions waits
+ * until timeout then returns 0 if DET is stable at 1.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep)
+ *
+ * RETURNS:
+ * 0 on success, -errno on failure.
+ */
+int sata_phy_debounce(struct ata_port *ap, const unsigned long *params)
+{
+ unsigned long interval_msec = params[0];
+ unsigned long duration = params[1] * HZ / 1000;
+ unsigned long timeout = jiffies + params[2] * HZ / 1000;
+ unsigned long last_jiffies;
+ u32 last, cur;
+ int rc;
+
+ if ((rc = sata_scr_read(ap, SCR_STATUS, &cur)))
+ return rc;
+ cur &= 0xf;
+
+ last = cur;
+ last_jiffies = jiffies;
+
+ while (1) {
+ msleep(interval_msec);
+ if ((rc = sata_scr_read(ap, SCR_STATUS, &cur)))
+ return rc;
+ cur &= 0xf;
+
+ /* DET stable? */
+ if (cur == last) {
+ if (cur == 1 && time_before(jiffies, timeout))
+ continue;
+ if (time_after(jiffies, last_jiffies + duration))
+ return 0;
+ continue;
+ }
+
+ /* unstable, start over */
+ last = cur;
+ last_jiffies = jiffies;
+
+ /* check timeout */
+ if (time_after(jiffies, timeout))
+ return -EBUSY;
+ }
+}
+
+/**
+ * sata_phy_resume - resume SATA phy
+ * @ap: ATA port to resume SATA phy for
+ * @params: timing parameters { interval, duratinon, timeout } in msec
+ *
+ * Resume SATA phy of @ap and debounce it.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep)
+ *
+ * RETURNS:
+ * 0 on success, -errno on failure.
+ */
+int sata_phy_resume(struct ata_port *ap, const unsigned long *params)
+{
+ u32 scontrol;
+ int rc;
+
+ if ((rc = sata_scr_read(ap, SCR_CONTROL, &scontrol)))
+ return rc;
+
+ scontrol = (scontrol & 0x0f0) | 0x300;
+
+ if ((rc = sata_scr_write(ap, SCR_CONTROL, scontrol)))
+ return rc;
+
+ /* Some PHYs react badly if SStatus is pounded immediately
+ * after resuming. Delay 200ms before debouncing.
+ */
+ msleep(200);
+
+ return sata_phy_debounce(ap, params);
+}
+
+static void ata_wait_spinup(struct ata_port *ap)
+{
+ struct ata_eh_context *ehc = &ap->eh_context;
+ unsigned long end, secs;
+ int rc;
+
+ /* first, debounce phy if SATA */
+ if (ap->cbl == ATA_CBL_SATA) {
+ rc = sata_phy_debounce(ap, sata_deb_timing_hotplug);
+
+ /* if debounced successfully and offline, no need to wait */
+ if ((rc == 0 || rc == -EOPNOTSUPP) && ata_port_offline(ap))
+ return;
+ }
+
+ /* okay, let's give the drive time to spin up */
+ end = ehc->i.hotplug_timestamp + ATA_SPINUP_WAIT * HZ / 1000;
+ secs = ((end - jiffies) + HZ - 1) / HZ;
+
+ if (time_after(jiffies, end))
+ return;
+
+ if (secs > 5)
+ ata_port_printk(ap, KERN_INFO, "waiting for device to spin up "
+ "(%lu secs)\n", secs);
+
+ schedule_timeout_uninterruptible(end - jiffies);
+}
+
+/**
+ * ata_std_prereset - prepare for reset
+ * @ap: ATA port to be reset
+ *
+ * @ap is about to be reset. Initialize it.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep)
+ *
+ * RETURNS:
+ * 0 on success, -errno otherwise.
+ */
+int ata_std_prereset(struct ata_port *ap)
+{
+ struct ata_eh_context *ehc = &ap->eh_context;
+ const unsigned long *timing = sata_ehc_deb_timing(ehc);
+ int rc;
+
+ /* handle link resume & hotplug spinup */
+ if ((ehc->i.flags & ATA_EHI_RESUME_LINK) &&
+ (ap->flags & ATA_FLAG_HRST_TO_RESUME))
+ ehc->i.action |= ATA_EH_HARDRESET;
+
+ if ((ehc->i.flags & ATA_EHI_HOTPLUGGED) &&
+ (ap->flags & ATA_FLAG_SKIP_D2H_BSY))
+ ata_wait_spinup(ap);
+
+ /* if we're about to do hardreset, nothing more to do */
+ if (ehc->i.action & ATA_EH_HARDRESET)
+ return 0;
+
+ /* if SATA, resume phy */
+ if (ap->cbl == ATA_CBL_SATA) {
+ rc = sata_phy_resume(ap, timing);
+ if (rc && rc != -EOPNOTSUPP) {
+ /* phy resume failed */
+ ata_port_printk(ap, KERN_WARNING, "failed to resume "
+ "link for reset (errno=%d)\n", rc);
+ return rc;
+ }
+ }
+
+ /* Wait for !BSY if the controller can wait for the first D2H
+ * Reg FIS and we don't know that no device is attached.
+ */
+ if (!(ap->flags & ATA_FLAG_SKIP_D2H_BSY) && !ata_port_offline(ap))
+ ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
+
+ return 0;
+}
+
+/**
+ * ata_std_softreset - reset host port via ATA SRST
+ * @ap: port to reset
+ * @classes: resulting classes of attached devices
+ *
+ * Reset host port using ATA SRST.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep)
+ *
+ * RETURNS:
+ * 0 on success, -errno otherwise.
+ */
+int ata_std_softreset(struct ata_port *ap, unsigned int *classes)
+{
+ unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS;
+ unsigned int devmask = 0, err_mask;
+ u8 err;
+
+ DPRINTK("ENTER\n");
+
+ if (ata_port_offline(ap)) {
+ classes[0] = ATA_DEV_NONE;
+ goto out;
+ }
+
+ /* determine if device 0/1 are present */
+ if (ata_devchk(ap, 0))
+ devmask |= (1 << 0);
+ if (slave_possible && ata_devchk(ap, 1))
+ devmask |= (1 << 1);
+
+ /* select device 0 again */
+ ap->ops->dev_select(ap, 0);
+
+ /* issue bus reset */
+ DPRINTK("about to softreset, devmask=%x\n", devmask);
+ err_mask = ata_bus_softreset(ap, devmask);
+ if (err_mask) {
+ ata_port_printk(ap, KERN_ERR, "SRST failed (err_mask=0x%x)\n",
+ err_mask);
+ return -EIO;
+ }
+
+ /* determine by signature whether we have ATA or ATAPI devices */
+ classes[0] = ata_dev_try_classify(ap, 0, &err);
+ if (slave_possible && err != 0x81)
+ classes[1] = ata_dev_try_classify(ap, 1, &err);
+
+ out:
+ DPRINTK("EXIT, classes[0]=%u [1]=%u\n", classes[0], classes[1]);
+ return 0;
+}
+
+/**
+ * sata_std_hardreset - reset host port via SATA phy reset
+ * @ap: port to reset
+ * @class: resulting class of attached device
+ *
+ * SATA phy-reset host port using DET bits of SControl register.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep)
+ *
+ * RETURNS:
+ * 0 on success, -errno otherwise.
+ */
+int sata_std_hardreset(struct ata_port *ap, unsigned int *class)
+{
+ struct ata_eh_context *ehc = &ap->eh_context;
+ const unsigned long *timing = sata_ehc_deb_timing(ehc);
+ u32 scontrol;
+ int rc;
+
+ DPRINTK("ENTER\n");
+
+ if (sata_set_spd_needed(ap)) {
+ /* SATA spec says nothing about how to reconfigure
+ * spd. To be on the safe side, turn off phy during
+ * reconfiguration. This works for at least ICH7 AHCI
+ * and Sil3124.
+ */
+ if ((rc = sata_scr_read(ap, SCR_CONTROL, &scontrol)))
+ return rc;
+
+ scontrol = (scontrol & 0x0f0) | 0x304;
+
+ if ((rc = sata_scr_write(ap, SCR_CONTROL, scontrol)))
+ return rc;
+
+ sata_set_spd(ap);
+ }
+
+ /* issue phy wake/reset */
+ if ((rc = sata_scr_read(ap, SCR_CONTROL, &scontrol)))
+ return rc;
+
+ scontrol = (scontrol & 0x0f0) | 0x301;
+
+ if ((rc = sata_scr_write_flush(ap, SCR_CONTROL, scontrol)))
+ return rc;
+
+ /* Couldn't find anything in SATA I/II specs, but AHCI-1.1
+ * 10.4.2 says at least 1 ms.
+ */
+ msleep(1);
+
+ /* bring phy back */
+ sata_phy_resume(ap, timing);
+
+ /* TODO: phy layer with polling, timeouts, etc. */
+ if (ata_port_offline(ap)) {
+ *class = ATA_DEV_NONE;
+ DPRINTK("EXIT, link offline\n");
+ return 0;
+ }
+
+ if (ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT)) {
+ ata_port_printk(ap, KERN_ERR,
+ "COMRESET failed (device not ready)\n");
+ return -EIO;
+ }
+
+ ap->ops->dev_select(ap, 0); /* probably unnecessary */
+
+ *class = ata_dev_try_classify(ap, 0, NULL);
+
+ DPRINTK("EXIT, class=%u\n", *class);
+ return 0;
+}
+
+/**
+ * ata_std_postreset - standard postreset callback
+ * @ap: the target ata_port
+ * @classes: classes of attached devices
+ *
+ * This function is invoked after a successful reset. Note that
+ * the device might have been reset more than once using
+ * different reset methods before postreset is invoked.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep)
+ */
+void ata_std_postreset(struct ata_port *ap, unsigned int *classes)
+{
+ u32 serror;
+
+ DPRINTK("ENTER\n");
+
+ /* print link status */
+ sata_print_link_status(ap);
+
+ /* clear SError */
+ if (sata_scr_read(ap, SCR_ERROR, &serror) == 0)
+ sata_scr_write(ap, SCR_ERROR, serror);
+
+ /* re-enable interrupts */
+ if (!ap->ops->error_handler) {
+ /* FIXME: hack. create a hook instead */
+ if (ap->ioaddr.ctl_addr)
+ ata_irq_on(ap);
+ }
+
+ /* is double-select really necessary? */
+ if (classes[0] != ATA_DEV_NONE)
+ ap->ops->dev_select(ap, 1);
+ if (classes[1] != ATA_DEV_NONE)
+ ap->ops->dev_select(ap, 0);
+
+ /* bail out if no device is present */
+ if (classes[0] == ATA_DEV_NONE && classes[1] == ATA_DEV_NONE) {
+ DPRINTK("EXIT, no device\n");
+ return;
+ }
+
+ /* set up device control */
+ if (ap->ioaddr.ctl_addr) {
+ if (ap->flags & ATA_FLAG_MMIO)
+ writeb(ap->ctl, (void __iomem *) ap->ioaddr.ctl_addr);
+ else
+ outb(ap->ctl, ap->ioaddr.ctl_addr);
+ }
+
+ DPRINTK("EXIT\n");
+}
+
+/**
+ * ata_dev_same_device - Determine whether new ID matches configured device
+ * @dev: device to compare against
+ * @new_class: class of the new device
+ * @new_id: IDENTIFY page of the new device
+ *
+ * Compare @new_class and @new_id against @dev and determine
+ * whether @dev is the device indicated by @new_class and
+ * @new_id.
+ *
+ * LOCKING:
+ * None.
+ *
+ * RETURNS:
+ * 1 if @dev matches @new_class and @new_id, 0 otherwise.
+ */
+static int ata_dev_same_device(struct ata_device *dev, unsigned int new_class,
+ const u16 *new_id)
+{
+ const u16 *old_id = dev->id;
+ unsigned char model[2][41], serial[2][21];
+ u64 new_n_sectors;
+
+ if (dev->class != new_class) {
+ ata_dev_printk(dev, KERN_INFO, "class mismatch %d != %d\n",
+ dev->class, new_class);
+ return 0;
+ }
+
+ ata_id_c_string(old_id, model[0], ATA_ID_PROD_OFS, sizeof(model[0]));
+ ata_id_c_string(new_id, model[1], ATA_ID_PROD_OFS, sizeof(model[1]));
+ ata_id_c_string(old_id, serial[0], ATA_ID_SERNO_OFS, sizeof(serial[0]));
+ ata_id_c_string(new_id, serial[1], ATA_ID_SERNO_OFS, sizeof(serial[1]));
+ new_n_sectors = ata_id_n_sectors(new_id);
+
+ if (strcmp(model[0], model[1])) {
+ ata_dev_printk(dev, KERN_INFO, "model number mismatch "
+ "'%s' != '%s'\n", model[0], model[1]);
+ return 0;
+ }
+
+ if (strcmp(serial[0], serial[1])) {
+ ata_dev_printk(dev, KERN_INFO, "serial number mismatch "
+ "'%s' != '%s'\n", serial[0], serial[1]);
+ return 0;
+ }
+
+ if (dev->class == ATA_DEV_ATA && dev->n_sectors != new_n_sectors) {
+ ata_dev_printk(dev, KERN_INFO, "n_sectors mismatch "
+ "%llu != %llu\n",
+ (unsigned long long)dev->n_sectors,
+ (unsigned long long)new_n_sectors);
+ return 0;
+ }
+
+ return 1;
+}
+
+/**
+ * ata_dev_revalidate - Revalidate ATA device
+ * @dev: device to revalidate
+ * @post_reset: is this revalidation after reset?
+ *
+ * Re-read IDENTIFY page and make sure @dev is still attached to
+ * the port.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep)
+ *
+ * RETURNS:
+ * 0 on success, negative errno otherwise
+ */
+int ata_dev_revalidate(struct ata_device *dev, int post_reset)
+{
+ unsigned int class = dev->class;
+ u16 *id = (void *)dev->ap->sector_buf;
+ int rc;
+
+ if (!ata_dev_enabled(dev)) {
+ rc = -ENODEV;
+ goto fail;
+ }
+
+ /* read ID data */
+ rc = ata_dev_read_id(dev, &class, post_reset, id);
+ if (rc)
+ goto fail;
+
+ /* is the device still there? */
+ if (!ata_dev_same_device(dev, class, id)) {
+ rc = -ENODEV;
+ goto fail;
+ }
+
+ memcpy(dev->id, id, sizeof(id[0]) * ATA_ID_WORDS);
+
+ /* configure device according to the new ID */
+ rc = ata_dev_configure(dev, 0);
+ if (rc == 0)
+ return 0;
+
+ fail:
+ ata_dev_printk(dev, KERN_ERR, "revalidation failed (errno=%d)\n", rc);
+ return rc;
+}
+
+static const char * const ata_dma_blacklist [] = {
+ "WDC AC11000H", NULL,
+ "WDC AC22100H", NULL,
+ "WDC AC32500H", NULL,
+ "WDC AC33100H", NULL,
+ "WDC AC31600H", NULL,
+ "WDC AC32100H", "24.09P07",
+ "WDC AC23200L", "21.10N21",
+ "Compaq CRD-8241B", NULL,
+ "CRD-8400B", NULL,
+ "CRD-8480B", NULL,
+ "CRD-8482B", NULL,
+ "CRD-84", NULL,
+ "SanDisk SDP3B", NULL,
+ "SanDisk SDP3B-64", NULL,
+ "SANYO CD-ROM CRD", NULL,
+ "HITACHI CDR-8", NULL,
+ "HITACHI CDR-8335", NULL,
+ "HITACHI CDR-8435", NULL,
+ "Toshiba CD-ROM XM-6202B", NULL,
+ "TOSHIBA CD-ROM XM-1702BC", NULL,
+ "CD-532E-A", NULL,
+ "E-IDE CD-ROM CR-840", NULL,
+ "CD-ROM Drive/F5A", NULL,
+ "WPI CDD-820", NULL,
+ "SAMSUNG CD-ROM SC-148C", NULL,
+ "SAMSUNG CD-ROM SC", NULL,
+ "SanDisk SDP3B-64", NULL,
+ "ATAPI CD-ROM DRIVE 40X MAXIMUM",NULL,
+ "_NEC DV5800A", NULL,
+ "SAMSUNG CD-ROM SN-124", "N001"
+};
+
+static int ata_strim(char *s, size_t len)
+{
+ len = strnlen(s, len);
+
+ /* ATAPI specifies that empty space is blank-filled; remove blanks */
+ while ((len > 0) && (s[len - 1] == ' ')) {
+ len--;
+ s[len] = 0;
+ }
+ return len;
+}
+
+static int ata_dma_blacklisted(const struct ata_device *dev)
+{
+ unsigned char model_num[40];
+ unsigned char model_rev[16];
+ unsigned int nlen, rlen;
+ int i;
+
+ /* We don't support polling DMA.
+ * DMA blacklist those ATAPI devices with CDB-intr (and use PIO)
+ * if the LLDD handles only interrupts in the HSM_ST_LAST state.
+ */
+ if ((dev->ap->flags & ATA_FLAG_PIO_POLLING) &&
+ (dev->flags & ATA_DFLAG_CDB_INTR))
+ return 1;
+
+ ata_id_string(dev->id, model_num, ATA_ID_PROD_OFS,
+ sizeof(model_num));
+ ata_id_string(dev->id, model_rev, ATA_ID_FW_REV_OFS,
+ sizeof(model_rev));
+ nlen = ata_strim(model_num, sizeof(model_num));
+ rlen = ata_strim(model_rev, sizeof(model_rev));
+
+ for (i = 0; i < ARRAY_SIZE(ata_dma_blacklist); i += 2) {
+ if (!strncmp(ata_dma_blacklist[i], model_num, nlen)) {
+ if (ata_dma_blacklist[i+1] == NULL)
+ return 1;
+ if (!strncmp(ata_dma_blacklist[i], model_rev, rlen))
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/**
+ * ata_dev_xfermask - Compute supported xfermask of the given device
+ * @dev: Device to compute xfermask for
+ *
+ * Compute supported xfermask of @dev and store it in
+ * dev->*_mask. This function is responsible for applying all
+ * known limits including host controller limits, device
+ * blacklist, etc...
+ *
+ * LOCKING:
+ * None.
+ */
+static void ata_dev_xfermask(struct ata_device *dev)
+{
+ struct ata_port *ap = dev->ap;
+ struct ata_host *host = ap->host;
+ unsigned long xfer_mask;
+
+ /* controller modes available */
+ xfer_mask = ata_pack_xfermask(ap->pio_mask,
+ ap->mwdma_mask, ap->udma_mask);
+
+ /* Apply cable rule here. Don't apply it early because when
+ * we handle hot plug the cable type can itself change.
+ */
+ if (ap->cbl == ATA_CBL_PATA40)
+ xfer_mask &= ~(0xF8 << ATA_SHIFT_UDMA);
+
+ xfer_mask &= ata_pack_xfermask(dev->pio_mask,
+ dev->mwdma_mask, dev->udma_mask);
+ xfer_mask &= ata_id_xfermask(dev->id);
+
+ /*
+ * CFA Advanced TrueIDE timings are not allowed on a shared
+ * cable
+ */
+ if (ata_dev_pair(dev)) {
+ /* No PIO5 or PIO6 */
+ xfer_mask &= ~(0x03 << (ATA_SHIFT_PIO + 5));
+ /* No MWDMA3 or MWDMA 4 */
+ xfer_mask &= ~(0x03 << (ATA_SHIFT_MWDMA + 3));
+ }
+
+ if (ata_dma_blacklisted(dev)) {
+ xfer_mask &= ~(ATA_MASK_MWDMA | ATA_MASK_UDMA);
+ ata_dev_printk(dev, KERN_WARNING,
+ "device is on DMA blacklist, disabling DMA\n");
+ }
+
+ if ((host->flags & ATA_HOST_SIMPLEX) && host->simplex_claimed) {
+ xfer_mask &= ~(ATA_MASK_MWDMA | ATA_MASK_UDMA);
+ ata_dev_printk(dev, KERN_WARNING, "simplex DMA is claimed by "
+ "other device, disabling DMA\n");
+ }
+
+ if (ap->ops->mode_filter)
+ xfer_mask = ap->ops->mode_filter(ap, dev, xfer_mask);
+
+ ata_unpack_xfermask(xfer_mask, &dev->pio_mask,
+ &dev->mwdma_mask, &dev->udma_mask);
+}
+
+/**
+ * ata_dev_set_xfermode - Issue SET FEATURES - XFER MODE command
+ * @dev: Device to which command will be sent
+ *
+ * Issue SET FEATURES - XFER MODE command to device @dev
+ * on port @ap.
+ *
+ * LOCKING:
+ * PCI/etc. bus probe sem.
+ *
+ * RETURNS:
+ * 0 on success, AC_ERR_* mask otherwise.
+ */
+
+static unsigned int ata_dev_set_xfermode(struct ata_device *dev)
+{
+ struct ata_taskfile tf;
+ unsigned int err_mask;
+
+ /* set up set-features taskfile */
+ DPRINTK("set features - xfer mode\n");
+
+ ata_tf_init(dev, &tf);
+ tf.command = ATA_CMD_SET_FEATURES;
+ tf.feature = SETFEATURES_XFER;
+ tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
+ tf.protocol = ATA_PROT_NODATA;
+ tf.nsect = dev->xfer_mode;
+
+ err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
+
+ DPRINTK("EXIT, err_mask=%x\n", err_mask);
+ return err_mask;
+}
+
+/**
+ * ata_dev_init_params - Issue INIT DEV PARAMS command
+ * @dev: Device to which command will be sent
+ * @heads: Number of heads (taskfile parameter)
+ * @sectors: Number of sectors (taskfile parameter)
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep)
+ *
+ * RETURNS:
+ * 0 on success, AC_ERR_* mask otherwise.
+ */
+static unsigned int ata_dev_init_params(struct ata_device *dev,
+ u16 heads, u16 sectors)
+{
+ struct ata_taskfile tf;
+ unsigned int err_mask;
+
+ /* Number of sectors per track 1-255. Number of heads 1-16 */
+ if (sectors < 1 || sectors > 255 || heads < 1 || heads > 16)
+ return AC_ERR_INVALID;
+
+ /* set up init dev params taskfile */
+ DPRINTK("init dev params \n");
+
+ ata_tf_init(dev, &tf);
+ tf.command = ATA_CMD_INIT_DEV_PARAMS;
+ tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
+ tf.protocol = ATA_PROT_NODATA;
+ tf.nsect = sectors;
+ tf.device |= (heads - 1) & 0x0f; /* max head = num. of heads - 1 */
+
+ err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
+
+ DPRINTK("EXIT, err_mask=%x\n", err_mask);
+ return err_mask;
+}
+
+/**
+ * ata_sg_clean - Unmap DMA memory associated with command
+ * @qc: Command containing DMA memory to be released
+ *
+ * Unmap all mapped DMA memory associated with this command.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ */
+
+static void ata_sg_clean(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct scatterlist *sg = qc->__sg;
+ int dir = qc->dma_dir;
+ void *pad_buf = NULL;
+
+ WARN_ON(!(qc->flags & ATA_QCFLAG_DMAMAP));
+ WARN_ON(sg == NULL);
+
+ if (qc->flags & ATA_QCFLAG_SINGLE)
+ WARN_ON(qc->n_elem > 1);
+
+ VPRINTK("unmapping %u sg elements\n", qc->n_elem);
+
+ /* if we padded the buffer out to 32-bit bound, and data
+ * xfer direction is from-device, we must copy from the
+ * pad buffer back into the supplied buffer
+ */
+ if (qc->pad_len && !(qc->tf.flags & ATA_TFLAG_WRITE))
+ pad_buf = ap->pad + (qc->tag * ATA_DMA_PAD_SZ);
+
+ if (qc->flags & ATA_QCFLAG_SG) {
+ if (qc->n_elem)
+ dma_unmap_sg(ap->dev, sg, qc->n_elem, dir);
+ /* restore last sg */
+ sg[qc->orig_n_elem - 1].length += qc->pad_len;
+ if (pad_buf) {
+ struct scatterlist *psg = &qc->pad_sgent;
+ void *addr = kmap_atomic(psg->page, KM_IRQ0);
+ memcpy(addr + psg->offset, pad_buf, qc->pad_len);
+ kunmap_atomic(addr, KM_IRQ0);
+ }
+ } else {
+ if (qc->n_elem)
+ dma_unmap_single(ap->dev,
+ sg_dma_address(&sg[0]), sg_dma_len(&sg[0]),
+ dir);
+ /* restore sg */
+ sg->length += qc->pad_len;
+ if (pad_buf)
+ memcpy(qc->buf_virt + sg->length - qc->pad_len,
+ pad_buf, qc->pad_len);
+ }
+
+ qc->flags &= ~ATA_QCFLAG_DMAMAP;
+ qc->__sg = NULL;
+}
+
+/**
+ * ata_fill_sg - Fill PCI IDE PRD table
+ * @qc: Metadata associated with taskfile to be transferred
+ *
+ * Fill PCI IDE PRD (scatter-gather) table with segments
+ * associated with the current disk command.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ *
+ */
+static void ata_fill_sg(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct scatterlist *sg;
+ unsigned int idx;
+
+ WARN_ON(qc->__sg == NULL);
+ WARN_ON(qc->n_elem == 0 && qc->pad_len == 0);
+
+ idx = 0;
+ ata_for_each_sg(sg, qc) {
+ u32 addr, offset;
+ u32 sg_len, len;
+
+ /* determine if physical DMA addr spans 64K boundary.
+ * Note h/w doesn't support 64-bit, so we unconditionally
+ * truncate dma_addr_t to u32.
+ */
+ addr = (u32) sg_dma_address(sg);
+ sg_len = sg_dma_len(sg);
+
+ while (sg_len) {
+ offset = addr & 0xffff;
+ len = sg_len;
+ if ((offset + sg_len) > 0x10000)
+ len = 0x10000 - offset;
+
+ ap->prd[idx].addr = cpu_to_le32(addr);
+ ap->prd[idx].flags_len = cpu_to_le32(len & 0xffff);
+ VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", idx, addr, len);
+
+ idx++;
+ sg_len -= len;
+ addr += len;
+ }
+ }
+
+ if (idx)
+ ap->prd[idx - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT);
+}
+/**
+ * ata_check_atapi_dma - Check whether ATAPI DMA can be supported
+ * @qc: Metadata associated with taskfile to check
+ *
+ * Allow low-level driver to filter ATA PACKET commands, returning
+ * a status indicating whether or not it is OK to use DMA for the
+ * supplied PACKET command.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ *
+ * RETURNS: 0 when ATAPI DMA can be used
+ * nonzero otherwise
+ */
+int ata_check_atapi_dma(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ int rc = 0; /* Assume ATAPI DMA is OK by default */
+
+ if (ap->ops->check_atapi_dma)
+ rc = ap->ops->check_atapi_dma(qc);
+
+ return rc;
+}
+/**
+ * ata_qc_prep - Prepare taskfile for submission
+ * @qc: Metadata associated with taskfile to be prepared
+ *
+ * Prepare ATA taskfile for submission.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ */
+void ata_qc_prep(struct ata_queued_cmd *qc)
+{
+ if (!(qc->flags & ATA_QCFLAG_DMAMAP))
+ return;
+
+ ata_fill_sg(qc);
+}
+
+void ata_noop_qc_prep(struct ata_queued_cmd *qc) { }
+
+/**
+ * ata_sg_init_one - Associate command with memory buffer
+ * @qc: Command to be associated
+ * @buf: Memory buffer
+ * @buflen: Length of memory buffer, in bytes.
+ *
+ * Initialize the data-related elements of queued_cmd @qc
+ * to point to a single memory buffer, @buf of byte length @buflen.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ */
+
+void ata_sg_init_one(struct ata_queued_cmd *qc, void *buf, unsigned int buflen)
+{
+ struct scatterlist *sg;
+
+ qc->flags |= ATA_QCFLAG_SINGLE;
+
+ memset(&qc->sgent, 0, sizeof(qc->sgent));
+ qc->__sg = &qc->sgent;
+ qc->n_elem = 1;
+ qc->orig_n_elem = 1;
+ qc->buf_virt = buf;
+ qc->nbytes = buflen;
+
+ sg = qc->__sg;
+ sg_init_one(sg, buf, buflen);
+}
+
+/**
+ * ata_sg_init - Associate command with scatter-gather table.
+ * @qc: Command to be associated
+ * @sg: Scatter-gather table.
+ * @n_elem: Number of elements in s/g table.
+ *
+ * Initialize the data-related elements of queued_cmd @qc
+ * to point to a scatter-gather table @sg, containing @n_elem
+ * elements.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ */
+
+void ata_sg_init(struct ata_queued_cmd *qc, struct scatterlist *sg,
+ unsigned int n_elem)
+{
+ qc->flags |= ATA_QCFLAG_SG;
+ qc->__sg = sg;
+ qc->n_elem = n_elem;
+ qc->orig_n_elem = n_elem;
+}
+
+/**
+ * ata_sg_setup_one - DMA-map the memory buffer associated with a command.
+ * @qc: Command with memory buffer to be mapped.
+ *
+ * DMA-map the memory buffer associated with queued_cmd @qc.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ *
+ * RETURNS:
+ * Zero on success, negative on error.
+ */
+
+static int ata_sg_setup_one(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ int dir = qc->dma_dir;
+ struct scatterlist *sg = qc->__sg;
+ dma_addr_t dma_address;
+ int trim_sg = 0;
+
+ /* we must lengthen transfers to end on a 32-bit boundary */
+ qc->pad_len = sg->length & 3;
+ if (qc->pad_len) {
+ void *pad_buf = ap->pad + (qc->tag * ATA_DMA_PAD_SZ);
+ struct scatterlist *psg = &qc->pad_sgent;
+
+ WARN_ON(qc->dev->class != ATA_DEV_ATAPI);
+
+ memset(pad_buf, 0, ATA_DMA_PAD_SZ);
+
+ if (qc->tf.flags & ATA_TFLAG_WRITE)
+ memcpy(pad_buf, qc->buf_virt + sg->length - qc->pad_len,
+ qc->pad_len);
+
+ sg_dma_address(psg) = ap->pad_dma + (qc->tag * ATA_DMA_PAD_SZ);
+ sg_dma_len(psg) = ATA_DMA_PAD_SZ;
+ /* trim sg */
+ sg->length -= qc->pad_len;
+ if (sg->length == 0)
+ trim_sg = 1;
+
+ DPRINTK("padding done, sg->length=%u pad_len=%u\n",
+ sg->length, qc->pad_len);
+ }
+
+ if (trim_sg) {
+ qc->n_elem--;
+ goto skip_map;
+ }
+
+ dma_address = dma_map_single(ap->dev, qc->buf_virt,
+ sg->length, dir);
+ if (dma_mapping_error(dma_address)) {
+ /* restore sg */
+ sg->length += qc->pad_len;
+ return -1;
+ }
+
+ sg_dma_address(sg) = dma_address;
+ sg_dma_len(sg) = sg->length;
+
+skip_map:
+ DPRINTK("mapped buffer of %d bytes for %s\n", sg_dma_len(sg),
+ qc->tf.flags & ATA_TFLAG_WRITE ? "write" : "read");
+
+ return 0;
+}
+
+/**
+ * ata_sg_setup - DMA-map the scatter-gather table associated with a command.
+ * @qc: Command with scatter-gather table to be mapped.
+ *
+ * DMA-map the scatter-gather table associated with queued_cmd @qc.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ *
+ * RETURNS:
+ * Zero on success, negative on error.
+ *
+ */
+
+static int ata_sg_setup(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct scatterlist *sg = qc->__sg;
+ struct scatterlist *lsg = &sg[qc->n_elem - 1];
+ int n_elem, pre_n_elem, dir, trim_sg = 0;
+
+ VPRINTK("ENTER, ata%u\n", ap->id);
+ WARN_ON(!(qc->flags & ATA_QCFLAG_SG));
+
+ /* we must lengthen transfers to end on a 32-bit boundary */
+ qc->pad_len = lsg->length & 3;
+ if (qc->pad_len) {
+ void *pad_buf = ap->pad + (qc->tag * ATA_DMA_PAD_SZ);
+ struct scatterlist *psg = &qc->pad_sgent;
+ unsigned int offset;
+
+ WARN_ON(qc->dev->class != ATA_DEV_ATAPI);
+
+ memset(pad_buf, 0, ATA_DMA_PAD_SZ);
+
+ /*
+ * psg->page/offset are used to copy to-be-written
+ * data in this function or read data in ata_sg_clean.
+ */
+ offset = lsg->offset + lsg->length - qc->pad_len;
+ psg->page = nth_page(lsg->page, offset >> PAGE_SHIFT);
+ psg->offset = offset_in_page(offset);
+
+ if (qc->tf.flags & ATA_TFLAG_WRITE) {
+ void *addr = kmap_atomic(psg->page, KM_IRQ0);
+ memcpy(pad_buf, addr + psg->offset, qc->pad_len);
+ kunmap_atomic(addr, KM_IRQ0);
+ }
+
+ sg_dma_address(psg) = ap->pad_dma + (qc->tag * ATA_DMA_PAD_SZ);
+ sg_dma_len(psg) = ATA_DMA_PAD_SZ;
+ /* trim last sg */
+ lsg->length -= qc->pad_len;
+ if (lsg->length == 0)
+ trim_sg = 1;
+
+ DPRINTK("padding done, sg[%d].length=%u pad_len=%u\n",
+ qc->n_elem - 1, lsg->length, qc->pad_len);
+ }
+
+ pre_n_elem = qc->n_elem;
+ if (trim_sg && pre_n_elem)
+ pre_n_elem--;
+
+ if (!pre_n_elem) {
+ n_elem = 0;
+ goto skip_map;
+ }
+
+ dir = qc->dma_dir;
+ n_elem = dma_map_sg(ap->dev, sg, pre_n_elem, dir);
+ if (n_elem < 1) {
+ /* restore last sg */
+ lsg->length += qc->pad_len;
+ return -1;
+ }
+
+ DPRINTK("%d sg elements mapped\n", n_elem);
+
+skip_map:
+ qc->n_elem = n_elem;
+
+ return 0;
+}
+
+/**
+ * swap_buf_le16 - swap halves of 16-bit words in place
+ * @buf: Buffer to swap
+ * @buf_words: Number of 16-bit words in buffer.
+ *
+ * Swap halves of 16-bit words if needed to convert from
+ * little-endian byte order to native cpu byte order, or
+ * vice-versa.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+void swap_buf_le16(u16 *buf, unsigned int buf_words)
+{
+#ifdef __BIG_ENDIAN
+ unsigned int i;
+
+ for (i = 0; i < buf_words; i++)
+ buf[i] = le16_to_cpu(buf[i]);
+#endif /* __BIG_ENDIAN */
+}
+
+/**
+ * ata_mmio_data_xfer - Transfer data by MMIO
+ * @adev: device for this I/O
+ * @buf: data buffer
+ * @buflen: buffer length
+ * @write_data: read/write
+ *
+ * Transfer data from/to the device data register by MMIO.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+
+void ata_mmio_data_xfer(struct ata_device *adev, unsigned char *buf,
+ unsigned int buflen, int write_data)
+{
+ struct ata_port *ap = adev->ap;
+ unsigned int i;
+ unsigned int words = buflen >> 1;
+ u16 *buf16 = (u16 *) buf;
+ void __iomem *mmio = (void __iomem *)ap->ioaddr.data_addr;
+
+ /* Transfer multiple of 2 bytes */
+ if (write_data) {
+ for (i = 0; i < words; i++)
+ writew(le16_to_cpu(buf16[i]), mmio);
+ } else {
+ for (i = 0; i < words; i++)
+ buf16[i] = cpu_to_le16(readw(mmio));
+ }
+
+ /* Transfer trailing 1 byte, if any. */
+ if (unlikely(buflen & 0x01)) {
+ u16 align_buf[1] = { 0 };
+ unsigned char *trailing_buf = buf + buflen - 1;
+
+ if (write_data) {
+ memcpy(align_buf, trailing_buf, 1);
+ writew(le16_to_cpu(align_buf[0]), mmio);
+ } else {
+ align_buf[0] = cpu_to_le16(readw(mmio));
+ memcpy(trailing_buf, align_buf, 1);
+ }
+ }
+}
+
+/**
+ * ata_pio_data_xfer - Transfer data by PIO
+ * @adev: device to target
+ * @buf: data buffer
+ * @buflen: buffer length
+ * @write_data: read/write
+ *
+ * Transfer data from/to the device data register by PIO.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+
+void ata_pio_data_xfer(struct ata_device *adev, unsigned char *buf,
+ unsigned int buflen, int write_data)
+{
+ struct ata_port *ap = adev->ap;
+ unsigned int words = buflen >> 1;
+
+ /* Transfer multiple of 2 bytes */
+ if (write_data)
+ outsw(ap->ioaddr.data_addr, buf, words);
+ else
+ insw(ap->ioaddr.data_addr, buf, words);
+
+ /* Transfer trailing 1 byte, if any. */
+ if (unlikely(buflen & 0x01)) {
+ u16 align_buf[1] = { 0 };
+ unsigned char *trailing_buf = buf + buflen - 1;
+
+ if (write_data) {
+ memcpy(align_buf, trailing_buf, 1);
+ outw(le16_to_cpu(align_buf[0]), ap->ioaddr.data_addr);
+ } else {
+ align_buf[0] = cpu_to_le16(inw(ap->ioaddr.data_addr));
+ memcpy(trailing_buf, align_buf, 1);
+ }
+ }
+}
+
+/**
+ * ata_pio_data_xfer_noirq - Transfer data by PIO
+ * @adev: device to target
+ * @buf: data buffer
+ * @buflen: buffer length
+ * @write_data: read/write
+ *
+ * Transfer data from/to the device data register by PIO. Do the
+ * transfer with interrupts disabled.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+
+void ata_pio_data_xfer_noirq(struct ata_device *adev, unsigned char *buf,
+ unsigned int buflen, int write_data)
+{
+ unsigned long flags;
+ local_irq_save(flags);
+ ata_pio_data_xfer(adev, buf, buflen, write_data);
+ local_irq_restore(flags);
+}
+
+
+/**
+ * ata_pio_sector - Transfer ATA_SECT_SIZE (512 bytes) of data.
+ * @qc: Command on going
+ *
+ * Transfer ATA_SECT_SIZE of data from/to the ATA device.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+
+static void ata_pio_sector(struct ata_queued_cmd *qc)
+{
+ int do_write = (qc->tf.flags & ATA_TFLAG_WRITE);
+ struct scatterlist *sg = qc->__sg;
+ struct ata_port *ap = qc->ap;
+ struct page *page;
+ unsigned int offset;
+ unsigned char *buf;
+
+ if (qc->cursect == (qc->nsect - 1))
+ ap->hsm_task_state = HSM_ST_LAST;
+
+ page = sg[qc->cursg].page;
+ offset = sg[qc->cursg].offset + qc->cursg_ofs * ATA_SECT_SIZE;
+
+ /* get the current page and offset */
+ page = nth_page(page, (offset >> PAGE_SHIFT));
+ offset %= PAGE_SIZE;
+
+ DPRINTK("data %s\n", qc->tf.flags & ATA_TFLAG_WRITE ? "write" : "read");
+
+ if (PageHighMem(page)) {
+ unsigned long flags;
+
+ /* FIXME: use a bounce buffer */
+ local_irq_save(flags);
+ buf = kmap_atomic(page, KM_IRQ0);
+
+ /* do the actual data transfer */
+ ap->ops->data_xfer(qc->dev, buf + offset, ATA_SECT_SIZE, do_write);
+
+ kunmap_atomic(buf, KM_IRQ0);
+ local_irq_restore(flags);
+ } else {
+ buf = page_address(page);
+ ap->ops->data_xfer(qc->dev, buf + offset, ATA_SECT_SIZE, do_write);
+ }
+
+ qc->cursect++;
+ qc->cursg_ofs++;
+
+ if ((qc->cursg_ofs * ATA_SECT_SIZE) == (&sg[qc->cursg])->length) {
+ qc->cursg++;
+ qc->cursg_ofs = 0;
+ }
+}
+
+/**
+ * ata_pio_sectors - Transfer one or many 512-byte sectors.
+ * @qc: Command on going
+ *
+ * Transfer one or many ATA_SECT_SIZE of data from/to the
+ * ATA device for the DRQ request.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+
+static void ata_pio_sectors(struct ata_queued_cmd *qc)
+{
+ if (is_multi_taskfile(&qc->tf)) {
+ /* READ/WRITE MULTIPLE */
+ unsigned int nsect;
+
+ WARN_ON(qc->dev->multi_count == 0);
+
+ nsect = min(qc->nsect - qc->cursect, qc->dev->multi_count);
+ while (nsect--)
+ ata_pio_sector(qc);
+ } else
+ ata_pio_sector(qc);
+}
+
+/**
+ * atapi_send_cdb - Write CDB bytes to hardware
+ * @ap: Port to which ATAPI device is attached.
+ * @qc: Taskfile currently active
+ *
+ * When device has indicated its readiness to accept
+ * a CDB, this function is called. Send the CDB.
+ *
+ * LOCKING:
+ * caller.
+ */
+
+static void atapi_send_cdb(struct ata_port *ap, struct ata_queued_cmd *qc)
+{
+ /* send SCSI cdb */
+ DPRINTK("send cdb\n");
+ WARN_ON(qc->dev->cdb_len < 12);
+
+ ap->ops->data_xfer(qc->dev, qc->cdb, qc->dev->cdb_len, 1);
+ ata_altstatus(ap); /* flush */
+
+ switch (qc->tf.protocol) {
+ case ATA_PROT_ATAPI:
+ ap->hsm_task_state = HSM_ST;
+ break;
+ case ATA_PROT_ATAPI_NODATA:
+ ap->hsm_task_state = HSM_ST_LAST;
+ break;
+ case ATA_PROT_ATAPI_DMA:
+ ap->hsm_task_state = HSM_ST_LAST;
+ /* initiate bmdma */
+ ap->ops->bmdma_start(qc);
+ break;
+ }
+}
+
+/**
+ * __atapi_pio_bytes - Transfer data from/to the ATAPI device.
+ * @qc: Command on going
+ * @bytes: number of bytes
+ *
+ * Transfer Transfer data from/to the ATAPI device.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ *
+ */
+
+static void __atapi_pio_bytes(struct ata_queued_cmd *qc, unsigned int bytes)
+{
+ int do_write = (qc->tf.flags & ATA_TFLAG_WRITE);
+ struct scatterlist *sg = qc->__sg;
+ struct ata_port *ap = qc->ap;
+ struct page *page;
+ unsigned char *buf;
+ unsigned int offset, count;
+
+ if (qc->curbytes + bytes >= qc->nbytes)
+ ap->hsm_task_state = HSM_ST_LAST;
+
+next_sg:
+ if (unlikely(qc->cursg >= qc->n_elem)) {
+ /*
+ * The end of qc->sg is reached and the device expects
+ * more data to transfer. In order not to overrun qc->sg
+ * and fulfill length specified in the byte count register,
+ * - for read case, discard trailing data from the device
+ * - for write case, padding zero data to the device
+ */
+ u16 pad_buf[1] = { 0 };
+ unsigned int words = bytes >> 1;
+ unsigned int i;
+
+ if (words) /* warning if bytes > 1 */
+ ata_dev_printk(qc->dev, KERN_WARNING,
+ "%u bytes trailing data\n", bytes);
+
+ for (i = 0; i < words; i++)
+ ap->ops->data_xfer(qc->dev, (unsigned char*)pad_buf, 2, do_write);
+
+ ap->hsm_task_state = HSM_ST_LAST;
+ return;
+ }
+
+ sg = &qc->__sg[qc->cursg];
+
+ page = sg->page;
+ offset = sg->offset + qc->cursg_ofs;
+
+ /* get the current page and offset */
+ page = nth_page(page, (offset >> PAGE_SHIFT));
+ offset %= PAGE_SIZE;
+
+ /* don't overrun current sg */
+ count = min(sg->length - qc->cursg_ofs, bytes);
+
+ /* don't cross page boundaries */
+ count = min(count, (unsigned int)PAGE_SIZE - offset);
+
+ DPRINTK("data %s\n", qc->tf.flags & ATA_TFLAG_WRITE ? "write" : "read");
+
+ if (PageHighMem(page)) {
+ unsigned long flags;
+
+ /* FIXME: use bounce buffer */
+ local_irq_save(flags);
+ buf = kmap_atomic(page, KM_IRQ0);
+
+ /* do the actual data transfer */
+ ap->ops->data_xfer(qc->dev, buf + offset, count, do_write);
+
+ kunmap_atomic(buf, KM_IRQ0);
+ local_irq_restore(flags);
+ } else {
+ buf = page_address(page);
+ ap->ops->data_xfer(qc->dev, buf + offset, count, do_write);
+ }
+
+ bytes -= count;
+ qc->curbytes += count;
+ qc->cursg_ofs += count;
+
+ if (qc->cursg_ofs == sg->length) {
+ qc->cursg++;
+ qc->cursg_ofs = 0;
+ }
+
+ if (bytes)
+ goto next_sg;
+}
+
+/**
+ * atapi_pio_bytes - Transfer data from/to the ATAPI device.
+ * @qc: Command on going
+ *
+ * Transfer Transfer data from/to the ATAPI device.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+
+static void atapi_pio_bytes(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct ata_device *dev = qc->dev;
+ unsigned int ireason, bc_lo, bc_hi, bytes;
+ int i_write, do_write = (qc->tf.flags & ATA_TFLAG_WRITE) ? 1 : 0;
+
+ /* Abuse qc->result_tf for temp storage of intermediate TF
+ * here to save some kernel stack usage.
+ * For normal completion, qc->result_tf is not relevant. For
+ * error, qc->result_tf is later overwritten by ata_qc_complete().
+ * So, the correctness of qc->result_tf is not affected.
+ */
+ ap->ops->tf_read(ap, &qc->result_tf);
+ ireason = qc->result_tf.nsect;
+ bc_lo = qc->result_tf.lbam;
+ bc_hi = qc->result_tf.lbah;
+ bytes = (bc_hi << 8) | bc_lo;
+
+ /* shall be cleared to zero, indicating xfer of data */
+ if (ireason & (1 << 0))
+ goto err_out;
+
+ /* make sure transfer direction matches expected */
+ i_write = ((ireason & (1 << 1)) == 0) ? 1 : 0;
+ if (do_write != i_write)
+ goto err_out;
+
+ VPRINTK("ata%u: xfering %d bytes\n", ap->id, bytes);
+
+ __atapi_pio_bytes(qc, bytes);
+
+ return;
+
+err_out:
+ ata_dev_printk(dev, KERN_INFO, "ATAPI check failed\n");
+ qc->err_mask |= AC_ERR_HSM;
+ ap->hsm_task_state = HSM_ST_ERR;
+}
+
+/**
+ * ata_hsm_ok_in_wq - Check if the qc can be handled in the workqueue.
+ * @ap: the target ata_port
+ * @qc: qc on going
+ *
+ * RETURNS:
+ * 1 if ok in workqueue, 0 otherwise.
+ */
+
+static inline int ata_hsm_ok_in_wq(struct ata_port *ap, struct ata_queued_cmd *qc)
+{
+ if (qc->tf.flags & ATA_TFLAG_POLLING)
+ return 1;
+
+ if (ap->hsm_task_state == HSM_ST_FIRST) {
+ if (qc->tf.protocol == ATA_PROT_PIO &&
+ (qc->tf.flags & ATA_TFLAG_WRITE))
+ return 1;
+
+ if (is_atapi_taskfile(&qc->tf) &&
+ !(qc->dev->flags & ATA_DFLAG_CDB_INTR))
+ return 1;
+ }
+
+ return 0;
+}
+
+/**
+ * ata_hsm_qc_complete - finish a qc running on standard HSM
+ * @qc: Command to complete
+ * @in_wq: 1 if called from workqueue, 0 otherwise
+ *
+ * Finish @qc which is running on standard HSM.
+ *
+ * LOCKING:
+ * If @in_wq is zero, spin_lock_irqsave(host lock).
+ * Otherwise, none on entry and grabs host lock.
+ */
+static void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq)
+{
+ struct ata_port *ap = qc->ap;
+ unsigned long flags;
+
+ if (ap->ops->error_handler) {
+ if (in_wq) {
+ spin_lock_irqsave(ap->lock, flags);
+
+ /* EH might have kicked in while host lock is
+ * released.
+ */
+ qc = ata_qc_from_tag(ap, qc->tag);
+ if (qc) {
+ if (likely(!(qc->err_mask & AC_ERR_HSM))) {
+ ata_irq_on(ap);
+ ata_qc_complete(qc);
+ } else
+ ata_port_freeze(ap);
+ }
+
+ spin_unlock_irqrestore(ap->lock, flags);
+ } else {
+ if (likely(!(qc->err_mask & AC_ERR_HSM)))
+ ata_qc_complete(qc);
+ else
+ ata_port_freeze(ap);
+ }
+ } else {
+ if (in_wq) {
+ spin_lock_irqsave(ap->lock, flags);
+ ata_irq_on(ap);
+ ata_qc_complete(qc);
+ spin_unlock_irqrestore(ap->lock, flags);
+ } else
+ ata_qc_complete(qc);
+ }
+
+ ata_altstatus(ap); /* flush */
+}
+
+/**
+ * ata_hsm_move - move the HSM to the next state.
+ * @ap: the target ata_port
+ * @qc: qc on going
+ * @status: current device status
+ * @in_wq: 1 if called from workqueue, 0 otherwise
+ *
+ * RETURNS:
+ * 1 when poll next status needed, 0 otherwise.
+ */
+int ata_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc,
+ u8 status, int in_wq)
+{
+ unsigned long flags = 0;
+ int poll_next;
+
+ WARN_ON((qc->flags & ATA_QCFLAG_ACTIVE) == 0);
+
+ /* Make sure ata_qc_issue_prot() does not throw things
+ * like DMA polling into the workqueue. Notice that
+ * in_wq is not equivalent to (qc->tf.flags & ATA_TFLAG_POLLING).
+ */
+ WARN_ON(in_wq != ata_hsm_ok_in_wq(ap, qc));
+
+fsm_start:
+ DPRINTK("ata%u: protocol %d task_state %d (dev_stat 0x%X)\n",
+ ap->id, qc->tf.protocol, ap->hsm_task_state, status);
+
+ switch (ap->hsm_task_state) {
+ case HSM_ST_FIRST:
+ /* Send first data block or PACKET CDB */
+
+ /* If polling, we will stay in the work queue after
+ * sending the data. Otherwise, interrupt handler
+ * takes over after sending the data.
+ */
+ poll_next = (qc->tf.flags & ATA_TFLAG_POLLING);
+
+ /* check device status */
+ if (unlikely((status & ATA_DRQ) == 0)) {
+ /* handle BSY=0, DRQ=0 as error */
+ if (likely(status & (ATA_ERR | ATA_DF)))
+ /* device stops HSM for abort/error */
+ qc->err_mask |= AC_ERR_DEV;
+ else
+ /* HSM violation. Let EH handle this */
+ qc->err_mask |= AC_ERR_HSM;
+
+ ap->hsm_task_state = HSM_ST_ERR;
+ goto fsm_start;
+ }
+
+ /* Device should not ask for data transfer (DRQ=1)
+ * when it finds something wrong.
+ * We ignore DRQ here and stop the HSM by
+ * changing hsm_task_state to HSM_ST_ERR and
+ * let the EH abort the command or reset the device.
+ */
+ if (unlikely(status & (ATA_ERR | ATA_DF))) {
+ printk(KERN_WARNING "ata%d: DRQ=1 with device error, dev_stat 0x%X\n",
+ ap->id, status);
+ qc->err_mask |= AC_ERR_HSM;
+ ap->hsm_task_state = HSM_ST_ERR;
+ goto fsm_start;
+ }
+
+ /* Send the CDB (atapi) or the first data block (ata pio out).
+ * During the state transition, interrupt handler shouldn't
+ * be invoked before the data transfer is complete and
+ * hsm_task_state is changed. Hence, the following locking.
+ */
+ if (in_wq)
+ spin_lock_irqsave(ap->lock, flags);
+
+ if (qc->tf.protocol == ATA_PROT_PIO) {
+ /* PIO data out protocol.
+ * send first data block.
+ */
+
+ /* ata_pio_sectors() might change the state
+ * to HSM_ST_LAST. so, the state is changed here
+ * before ata_pio_sectors().
+ */
+ ap->hsm_task_state = HSM_ST;
+ ata_pio_sectors(qc);
+ ata_altstatus(ap); /* flush */
+ } else
+ /* send CDB */
+ atapi_send_cdb(ap, qc);
+
+ if (in_wq)
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ /* if polling, ata_pio_task() handles the rest.
+ * otherwise, interrupt handler takes over from here.
+ */
+ break;
+
+ case HSM_ST:
+ /* complete command or read/write the data register */
+ if (qc->tf.protocol == ATA_PROT_ATAPI) {
+ /* ATAPI PIO protocol */
+ if ((status & ATA_DRQ) == 0) {
+ /* No more data to transfer or device error.
+ * Device error will be tagged in HSM_ST_LAST.
+ */
+ ap->hsm_task_state = HSM_ST_LAST;
+ goto fsm_start;
+ }
+
+ /* Device should not ask for data transfer (DRQ=1)
+ * when it finds something wrong.
+ * We ignore DRQ here and stop the HSM by
+ * changing hsm_task_state to HSM_ST_ERR and
+ * let the EH abort the command or reset the device.
+ */
+ if (unlikely(status & (ATA_ERR | ATA_DF))) {
+ printk(KERN_WARNING "ata%d: DRQ=1 with device error, dev_stat 0x%X\n",
+ ap->id, status);
+ qc->err_mask |= AC_ERR_HSM;
+ ap->hsm_task_state = HSM_ST_ERR;
+ goto fsm_start;
+ }
+
+ atapi_pio_bytes(qc);
+
+ if (unlikely(ap->hsm_task_state == HSM_ST_ERR))
+ /* bad ireason reported by device */
+ goto fsm_start;
+
+ } else {
+ /* ATA PIO protocol */
+ if (unlikely((status & ATA_DRQ) == 0)) {
+ /* handle BSY=0, DRQ=0 as error */
+ if (likely(status & (ATA_ERR | ATA_DF)))
+ /* device stops HSM for abort/error */
+ qc->err_mask |= AC_ERR_DEV;
+ else
+ /* HSM violation. Let EH handle this */
+ qc->err_mask |= AC_ERR_HSM;
+
+ ap->hsm_task_state = HSM_ST_ERR;
+ goto fsm_start;
+ }
+
+ /* For PIO reads, some devices may ask for
+ * data transfer (DRQ=1) alone with ERR=1.
+ * We respect DRQ here and transfer one
+ * block of junk data before changing the
+ * hsm_task_state to HSM_ST_ERR.
+ *
+ * For PIO writes, ERR=1 DRQ=1 doesn't make
+ * sense since the data block has been
+ * transferred to the device.
+ */
+ if (unlikely(status & (ATA_ERR | ATA_DF))) {
+ /* data might be corrputed */
+ qc->err_mask |= AC_ERR_DEV;
+
+ if (!(qc->tf.flags & ATA_TFLAG_WRITE)) {
+ ata_pio_sectors(qc);
+ ata_altstatus(ap);
+ status = ata_wait_idle(ap);
+ }
+
+ if (status & (ATA_BUSY | ATA_DRQ))
+ qc->err_mask |= AC_ERR_HSM;
+
+ /* ata_pio_sectors() might change the
+ * state to HSM_ST_LAST. so, the state
+ * is changed after ata_pio_sectors().
+ */
+ ap->hsm_task_state = HSM_ST_ERR;
+ goto fsm_start;
+ }
+
+ ata_pio_sectors(qc);
+
+ if (ap->hsm_task_state == HSM_ST_LAST &&
+ (!(qc->tf.flags & ATA_TFLAG_WRITE))) {
+ /* all data read */
+ ata_altstatus(ap);
+ status = ata_wait_idle(ap);
+ goto fsm_start;
+ }
+ }
+
+ ata_altstatus(ap); /* flush */
+ poll_next = 1;
+ break;
+
+ case HSM_ST_LAST:
+ if (unlikely(!ata_ok(status))) {
+ qc->err_mask |= __ac_err_mask(status);
+ ap->hsm_task_state = HSM_ST_ERR;
+ goto fsm_start;
+ }
+
+ /* no more data to transfer */
+ DPRINTK("ata%u: dev %u command complete, drv_stat 0x%x\n",
+ ap->id, qc->dev->devno, status);
+
+ WARN_ON(qc->err_mask);
+
+ ap->hsm_task_state = HSM_ST_IDLE;
+
+ /* complete taskfile transaction */
+ ata_hsm_qc_complete(qc, in_wq);
+
+ poll_next = 0;
+ break;
+
+ case HSM_ST_ERR:
+ /* make sure qc->err_mask is available to
+ * know what's wrong and recover
+ */
+ WARN_ON(qc->err_mask == 0);
+
+ ap->hsm_task_state = HSM_ST_IDLE;
+
+ /* complete taskfile transaction */
+ ata_hsm_qc_complete(qc, in_wq);
+
+ poll_next = 0;
+ break;
+ default:
+ poll_next = 0;
+ BUG();
+ }
+
+ return poll_next;
+}
+
+static void ata_pio_task(void *_data)
+{
+ struct ata_queued_cmd *qc = _data;
+ struct ata_port *ap = qc->ap;
+ u8 status;
+ int poll_next;
+
+fsm_start:
+ WARN_ON(ap->hsm_task_state == HSM_ST_IDLE);
+
+ /*
+ * This is purely heuristic. This is a fast path.
+ * Sometimes when we enter, BSY will be cleared in
+ * a chk-status or two. If not, the drive is probably seeking
+ * or something. Snooze for a couple msecs, then
+ * chk-status again. If still busy, queue delayed work.
+ */
+ status = ata_busy_wait(ap, ATA_BUSY, 5);
+ if (status & ATA_BUSY) {
+ msleep(2);
+ status = ata_busy_wait(ap, ATA_BUSY, 10);
+ if (status & ATA_BUSY) {
+ ata_port_queue_task(ap, ata_pio_task, qc, ATA_SHORT_PAUSE);
+ return;
+ }
+ }
+
+ /* move the HSM */
+ poll_next = ata_hsm_move(ap, qc, status, 1);
+
+ /* another command or interrupt handler
+ * may be running at this point.
+ */
+ if (poll_next)
+ goto fsm_start;
+}
+
+/**
+ * ata_qc_new - Request an available ATA command, for queueing
+ * @ap: Port associated with device @dev
+ * @dev: Device from whom we request an available command structure
+ *
+ * LOCKING:
+ * None.
+ */
+
+static struct ata_queued_cmd *ata_qc_new(struct ata_port *ap)
+{
+ struct ata_queued_cmd *qc = NULL;
+ unsigned int i;
+
+ /* no command while frozen */
+ if (unlikely(ap->pflags & ATA_PFLAG_FROZEN))
+ return NULL;
+
+ /* the last tag is reserved for internal command. */
+ for (i = 0; i < ATA_MAX_QUEUE - 1; i++)
+ if (!test_and_set_bit(i, &ap->qc_allocated)) {
+ qc = __ata_qc_from_tag(ap, i);
+ break;
+ }
+
+ if (qc)
+ qc->tag = i;
+
+ return qc;
+}
+
+/**
+ * ata_qc_new_init - Request an available ATA command, and initialize it
+ * @dev: Device from whom we request an available command structure
+ *
+ * LOCKING:
+ * None.
+ */
+
+struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev)
+{
+ struct ata_port *ap = dev->ap;
+ struct ata_queued_cmd *qc;
+
+ qc = ata_qc_new(ap);
+ if (qc) {
+ qc->scsicmd = NULL;
+ qc->ap = ap;
+ qc->dev = dev;
+
+ ata_qc_reinit(qc);
+ }
+
+ return qc;
+}
+
+/**
+ * ata_qc_free - free unused ata_queued_cmd
+ * @qc: Command to complete
+ *
+ * Designed to free unused ata_queued_cmd object
+ * in case something prevents using it.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ */
+void ata_qc_free(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ unsigned int tag;
+
+ WARN_ON(qc == NULL); /* ata_qc_from_tag _might_ return NULL */
+
+ qc->flags = 0;
+ tag = qc->tag;
+ if (likely(ata_tag_valid(tag))) {
+ qc->tag = ATA_TAG_POISON;
+ clear_bit(tag, &ap->qc_allocated);
+ }
+}
+
+void __ata_qc_complete(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+
+ WARN_ON(qc == NULL); /* ata_qc_from_tag _might_ return NULL */
+ WARN_ON(!(qc->flags & ATA_QCFLAG_ACTIVE));
+
+ if (likely(qc->flags & ATA_QCFLAG_DMAMAP))
+ ata_sg_clean(qc);
+
+ /* command should be marked inactive atomically with qc completion */
+ if (qc->tf.protocol == ATA_PROT_NCQ)
+ ap->sactive &= ~(1 << qc->tag);
+ else
+ ap->active_tag = ATA_TAG_POISON;
+
+ /* atapi: mark qc as inactive to prevent the interrupt handler
+ * from completing the command twice later, before the error handler
+ * is called. (when rc != 0 and atapi request sense is needed)
+ */
+ qc->flags &= ~ATA_QCFLAG_ACTIVE;
+ ap->qc_active &= ~(1 << qc->tag);
+
+ /* call completion callback */
+ qc->complete_fn(qc);
+}
+
+/**
+ * ata_qc_complete - Complete an active ATA command
+ * @qc: Command to complete
+ * @err_mask: ATA Status register contents
+ *
+ * Indicate to the mid and upper layers that an ATA
+ * command has completed, with either an ok or not-ok status.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ */
+void ata_qc_complete(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+
+ /* XXX: New EH and old EH use different mechanisms to
+ * synchronize EH with regular execution path.
+ *
+ * In new EH, a failed qc is marked with ATA_QCFLAG_FAILED.
+ * Normal execution path is responsible for not accessing a
+ * failed qc. libata core enforces the rule by returning NULL
+ * from ata_qc_from_tag() for failed qcs.
+ *
+ * Old EH depends on ata_qc_complete() nullifying completion
+ * requests if ATA_QCFLAG_EH_SCHEDULED is set. Old EH does
+ * not synchronize with interrupt handler. Only PIO task is
+ * taken care of.
+ */
+ if (ap->ops->error_handler) {
+ WARN_ON(ap->pflags & ATA_PFLAG_FROZEN);
+
+ if (unlikely(qc->err_mask))
+ qc->flags |= ATA_QCFLAG_FAILED;
+
+ if (unlikely(qc->flags & ATA_QCFLAG_FAILED)) {
+ if (!ata_tag_internal(qc->tag)) {
+ /* always fill result TF for failed qc */
+ ap->ops->tf_read(ap, &qc->result_tf);
+ ata_qc_schedule_eh(qc);
+ return;
+ }
+ }
+
+ /* read result TF if requested */
+ if (qc->flags & ATA_QCFLAG_RESULT_TF)
+ ap->ops->tf_read(ap, &qc->result_tf);
+
+ __ata_qc_complete(qc);
+ } else {
+ if (qc->flags & ATA_QCFLAG_EH_SCHEDULED)
+ return;
+
+ /* read result TF if failed or requested */
+ if (qc->err_mask || qc->flags & ATA_QCFLAG_RESULT_TF)
+ ap->ops->tf_read(ap, &qc->result_tf);
+
+ __ata_qc_complete(qc);
+ }
+}
+
+/**
+ * ata_qc_complete_multiple - Complete multiple qcs successfully
+ * @ap: port in question
+ * @qc_active: new qc_active mask
+ * @finish_qc: LLDD callback invoked before completing a qc
+ *
+ * Complete in-flight commands. This functions is meant to be
+ * called from low-level driver's interrupt routine to complete
+ * requests normally. ap->qc_active and @qc_active is compared
+ * and commands are completed accordingly.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ *
+ * RETURNS:
+ * Number of completed commands on success, -errno otherwise.
+ */
+int ata_qc_complete_multiple(struct ata_port *ap, u32 qc_active,
+ void (*finish_qc)(struct ata_queued_cmd *))
+{
+ int nr_done = 0;
+ u32 done_mask;
+ int i;
+
+ done_mask = ap->qc_active ^ qc_active;
+
+ if (unlikely(done_mask & qc_active)) {
+ ata_port_printk(ap, KERN_ERR, "illegal qc_active transition "
+ "(%08x->%08x)\n", ap->qc_active, qc_active);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < ATA_MAX_QUEUE; i++) {
+ struct ata_queued_cmd *qc;
+
+ if (!(done_mask & (1 << i)))
+ continue;
+
+ if ((qc = ata_qc_from_tag(ap, i))) {
+ if (finish_qc)
+ finish_qc(qc);
+ ata_qc_complete(qc);
+ nr_done++;
+ }
+ }
+
+ return nr_done;
+}
+
+static inline int ata_should_dma_map(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+
+ switch (qc->tf.protocol) {
+ case ATA_PROT_NCQ:
+ case ATA_PROT_DMA:
+ case ATA_PROT_ATAPI_DMA:
+ return 1;
+
+ case ATA_PROT_ATAPI:
+ case ATA_PROT_PIO:
+ if (ap->flags & ATA_FLAG_PIO_DMA)
+ return 1;
+
+ /* fall through */
+
+ default:
+ return 0;
+ }
+
+ /* never reached */
+}
+
+/**
+ * ata_qc_issue - issue taskfile to device
+ * @qc: command to issue to device
+ *
+ * Prepare an ATA command to submission to device.
+ * This includes mapping the data into a DMA-able
+ * area, filling in the S/G table, and finally
+ * writing the taskfile to hardware, starting the command.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ */
+void ata_qc_issue(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+
+ /* Make sure only one non-NCQ command is outstanding. The
+ * check is skipped for old EH because it reuses active qc to
+ * request ATAPI sense.
+ */
+ WARN_ON(ap->ops->error_handler && ata_tag_valid(ap->active_tag));
+
+ if (qc->tf.protocol == ATA_PROT_NCQ) {
+ WARN_ON(ap->sactive & (1 << qc->tag));
+ ap->sactive |= 1 << qc->tag;
+ } else {
+ WARN_ON(ap->sactive);
+ ap->active_tag = qc->tag;
+ }
+
+ qc->flags |= ATA_QCFLAG_ACTIVE;
+ ap->qc_active |= 1 << qc->tag;
+
+ if (ata_should_dma_map(qc)) {
+ if (qc->flags & ATA_QCFLAG_SG) {
+ if (ata_sg_setup(qc))
+ goto sg_err;
+ } else if (qc->flags & ATA_QCFLAG_SINGLE) {
+ if (ata_sg_setup_one(qc))
+ goto sg_err;
+ }
+ } else {
+ qc->flags &= ~ATA_QCFLAG_DMAMAP;
+ }
+
+ ap->ops->qc_prep(qc);
+
+ qc->err_mask |= ap->ops->qc_issue(qc);
+ if (unlikely(qc->err_mask))
+ goto err;
+ return;
+
+sg_err:
+ qc->flags &= ~ATA_QCFLAG_DMAMAP;
+ qc->err_mask |= AC_ERR_SYSTEM;
+err:
+ ata_qc_complete(qc);
+}
+
+/**
+ * ata_qc_issue_prot - issue taskfile to device in proto-dependent manner
+ * @qc: command to issue to device
+ *
+ * Using various libata functions and hooks, this function
+ * starts an ATA command. ATA commands are grouped into
+ * classes called "protocols", and issuing each type of protocol
+ * is slightly different.
+ *
+ * May be used as the qc_issue() entry in ata_port_operations.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ *
+ * RETURNS:
+ * Zero on success, AC_ERR_* mask on failure
+ */
+
+unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+
+ /* Use polling pio if the LLD doesn't handle
+ * interrupt driven pio and atapi CDB interrupt.
+ */
+ if (ap->flags & ATA_FLAG_PIO_POLLING) {
+ switch (qc->tf.protocol) {
+ case ATA_PROT_PIO:
+ case ATA_PROT_ATAPI:
+ case ATA_PROT_ATAPI_NODATA:
+ qc->tf.flags |= ATA_TFLAG_POLLING;
+ break;
+ case ATA_PROT_ATAPI_DMA:
+ if (qc->dev->flags & ATA_DFLAG_CDB_INTR)
+ /* see ata_dma_blacklisted() */
+ BUG();
+ break;
+ default:
+ break;
+ }
+ }
+
+ /* select the device */
+ ata_dev_select(ap, qc->dev->devno, 1, 0);
+
+ /* start the command */
+ switch (qc->tf.protocol) {
+ case ATA_PROT_NODATA:
+ if (qc->tf.flags & ATA_TFLAG_POLLING)
+ ata_qc_set_polling(qc);
+
+ ata_tf_to_host(ap, &qc->tf);
+ ap->hsm_task_state = HSM_ST_LAST;
+
+ if (qc->tf.flags & ATA_TFLAG_POLLING)
+ ata_port_queue_task(ap, ata_pio_task, qc, 0);
+
+ break;
+
+ case ATA_PROT_DMA:
+ WARN_ON(qc->tf.flags & ATA_TFLAG_POLLING);
+
+ ap->ops->tf_load(ap, &qc->tf); /* load tf registers */
+ ap->ops->bmdma_setup(qc); /* set up bmdma */
+ ap->ops->bmdma_start(qc); /* initiate bmdma */
+ ap->hsm_task_state = HSM_ST_LAST;
+ break;
+
+ case ATA_PROT_PIO:
+ if (qc->tf.flags & ATA_TFLAG_POLLING)
+ ata_qc_set_polling(qc);
+
+ ata_tf_to_host(ap, &qc->tf);
+
+ if (qc->tf.flags & ATA_TFLAG_WRITE) {
+ /* PIO data out protocol */
+ ap->hsm_task_state = HSM_ST_FIRST;
+ ata_port_queue_task(ap, ata_pio_task, qc, 0);
+
+ /* always send first data block using
+ * the ata_pio_task() codepath.
+ */
+ } else {
+ /* PIO data in protocol */
+ ap->hsm_task_state = HSM_ST;
+
+ if (qc->tf.flags & ATA_TFLAG_POLLING)
+ ata_port_queue_task(ap, ata_pio_task, qc, 0);
+
+ /* if polling, ata_pio_task() handles the rest.
+ * otherwise, interrupt handler takes over from here.
+ */
+ }
+
+ break;
+
+ case ATA_PROT_ATAPI:
+ case ATA_PROT_ATAPI_NODATA:
+ if (qc->tf.flags & ATA_TFLAG_POLLING)
+ ata_qc_set_polling(qc);
+
+ ata_tf_to_host(ap, &qc->tf);
+
+ ap->hsm_task_state = HSM_ST_FIRST;
+
+ /* send cdb by polling if no cdb interrupt */
+ if ((!(qc->dev->flags & ATA_DFLAG_CDB_INTR)) ||
+ (qc->tf.flags & ATA_TFLAG_POLLING))
+ ata_port_queue_task(ap, ata_pio_task, qc, 0);
+ break;
+
+ case ATA_PROT_ATAPI_DMA:
+ WARN_ON(qc->tf.flags & ATA_TFLAG_POLLING);
+
+ ap->ops->tf_load(ap, &qc->tf); /* load tf registers */
+ ap->ops->bmdma_setup(qc); /* set up bmdma */
+ ap->hsm_task_state = HSM_ST_FIRST;
+
+ /* send cdb by polling if no cdb interrupt */
+ if (!(qc->dev->flags & ATA_DFLAG_CDB_INTR))
+ ata_port_queue_task(ap, ata_pio_task, qc, 0);
+ break;
+
+ default:
+ WARN_ON(1);
+ return AC_ERR_SYSTEM;
+ }
+
+ return 0;
+}
+
+/**
+ * ata_host_intr - Handle host interrupt for given (port, task)
+ * @ap: Port on which interrupt arrived (possibly...)
+ * @qc: Taskfile currently active in engine
+ *
+ * Handle host interrupt for given queued command. Currently,
+ * only DMA interrupts are handled. All other commands are
+ * handled via polling with interrupts disabled (nIEN bit).
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ *
+ * RETURNS:
+ * One if interrupt was handled, zero if not (shared irq).
+ */
+
+inline unsigned int ata_host_intr (struct ata_port *ap,
+ struct ata_queued_cmd *qc)
+{
+ u8 status, host_stat = 0;
+
+ VPRINTK("ata%u: protocol %d task_state %d\n",
+ ap->id, qc->tf.protocol, ap->hsm_task_state);
+
+ /* Check whether we are expecting interrupt in this state */
+ switch (ap->hsm_task_state) {
+ case HSM_ST_FIRST:
+ /* Some pre-ATAPI-4 devices assert INTRQ
+ * at this state when ready to receive CDB.
+ */
+
+ /* Check the ATA_DFLAG_CDB_INTR flag is enough here.
+ * The flag was turned on only for atapi devices.
+ * No need to check is_atapi_taskfile(&qc->tf) again.
+ */
+ if (!(qc->dev->flags & ATA_DFLAG_CDB_INTR))
+ goto idle_irq;
+ break;
+ case HSM_ST_LAST:
+ if (qc->tf.protocol == ATA_PROT_DMA ||
+ qc->tf.protocol == ATA_PROT_ATAPI_DMA) {
+ /* check status of DMA engine */
+ host_stat = ap->ops->bmdma_status(ap);
+ VPRINTK("ata%u: host_stat 0x%X\n", ap->id, host_stat);
+
+ /* if it's not our irq... */
+ if (!(host_stat & ATA_DMA_INTR))
+ goto idle_irq;
+
+ /* before we do anything else, clear DMA-Start bit */
+ ap->ops->bmdma_stop(qc);
+
+ if (unlikely(host_stat & ATA_DMA_ERR)) {
+ /* error when transfering data to/from memory */
+ qc->err_mask |= AC_ERR_HOST_BUS;
+ ap->hsm_task_state = HSM_ST_ERR;
+ }
+ }
+ break;
+ case HSM_ST:
+ break;
+ default:
+ goto idle_irq;
+ }
+
+ /* check altstatus */
+ status = ata_altstatus(ap);
+ if (status & ATA_BUSY)
+ goto idle_irq;
+
+ /* check main status, clearing INTRQ */
+ status = ata_chk_status(ap);
+ if (unlikely(status & ATA_BUSY))
+ goto idle_irq;
+
+ /* ack bmdma irq events */
+ ap->ops->irq_clear(ap);
+
+ ata_hsm_move(ap, qc, status, 0);
+ return 1; /* irq handled */
+
+idle_irq:
+ ap->stats.idle_irq++;
+
+#ifdef ATA_IRQ_TRAP
+ if ((ap->stats.idle_irq % 1000) == 0) {
+ ata_irq_ack(ap, 0); /* debug trap */
+ ata_port_printk(ap, KERN_WARNING, "irq trap\n");
+ return 1;
+ }
+#endif
+ return 0; /* irq not handled */
+}
+
+/**
+ * ata_interrupt - Default ATA host interrupt handler
+ * @irq: irq line (unused)
+ * @dev_instance: pointer to our ata_host information structure
+ * @regs: unused
+ *
+ * Default interrupt handler for PCI IDE devices. Calls
+ * ata_host_intr() for each port that is not disabled.
+ *
+ * LOCKING:
+ * Obtains host lock during operation.
+ *
+ * RETURNS:
+ * IRQ_NONE or IRQ_HANDLED.
+ */
+
+irqreturn_t ata_interrupt (int irq, void *dev_instance, struct pt_regs *regs)
+{
+ struct ata_host *host = dev_instance;
+ unsigned int i;
+ unsigned int handled = 0;
+ unsigned long flags;
+
+ /* TODO: make _irqsave conditional on x86 PCI IDE legacy mode */
+ spin_lock_irqsave(&host->lock, flags);
+
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap;
+
+ ap = host->ports[i];
+ if (ap &&
+ !(ap->flags & ATA_FLAG_DISABLED)) {
+ struct ata_queued_cmd *qc;
+
+ qc = ata_qc_from_tag(ap, ap->active_tag);
+ if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)) &&
+ (qc->flags & ATA_QCFLAG_ACTIVE))
+ handled |= ata_host_intr(ap, qc);
+ }
+ }
+
+ spin_unlock_irqrestore(&host->lock, flags);
+
+ return IRQ_RETVAL(handled);
+}
+
+/**
+ * sata_scr_valid - test whether SCRs are accessible
+ * @ap: ATA port to test SCR accessibility for
+ *
+ * Test whether SCRs are accessible for @ap.
+ *
+ * LOCKING:
+ * None.
+ *
+ * RETURNS:
+ * 1 if SCRs are accessible, 0 otherwise.
+ */
+int sata_scr_valid(struct ata_port *ap)
+{
+ return ap->cbl == ATA_CBL_SATA && ap->ops->scr_read;
+}
+
+/**
+ * sata_scr_read - read SCR register of the specified port
+ * @ap: ATA port to read SCR for
+ * @reg: SCR to read
+ * @val: Place to store read value
+ *
+ * Read SCR register @reg of @ap into *@val. This function is
+ * guaranteed to succeed if the cable type of the port is SATA
+ * and the port implements ->scr_read.
+ *
+ * LOCKING:
+ * None.
+ *
+ * RETURNS:
+ * 0 on success, negative errno on failure.
+ */
+int sata_scr_read(struct ata_port *ap, int reg, u32 *val)
+{
+ if (sata_scr_valid(ap)) {
+ *val = ap->ops->scr_read(ap, reg);
+ return 0;
+ }
+ return -EOPNOTSUPP;
+}
+
+/**
+ * sata_scr_write - write SCR register of the specified port
+ * @ap: ATA port to write SCR for
+ * @reg: SCR to write
+ * @val: value to write
+ *
+ * Write @val to SCR register @reg of @ap. This function is
+ * guaranteed to succeed if the cable type of the port is SATA
+ * and the port implements ->scr_read.
+ *
+ * LOCKING:
+ * None.
+ *
+ * RETURNS:
+ * 0 on success, negative errno on failure.
+ */
+int sata_scr_write(struct ata_port *ap, int reg, u32 val)
+{
+ if (sata_scr_valid(ap)) {
+ ap->ops->scr_write(ap, reg, val);
+ return 0;
+ }
+ return -EOPNOTSUPP;
+}
+
+/**
+ * sata_scr_write_flush - write SCR register of the specified port and flush
+ * @ap: ATA port to write SCR for
+ * @reg: SCR to write
+ * @val: value to write
+ *
+ * This function is identical to sata_scr_write() except that this
+ * function performs flush after writing to the register.
+ *
+ * LOCKING:
+ * None.
+ *
+ * RETURNS:
+ * 0 on success, negative errno on failure.
+ */
+int sata_scr_write_flush(struct ata_port *ap, int reg, u32 val)
+{
+ if (sata_scr_valid(ap)) {
+ ap->ops->scr_write(ap, reg, val);
+ ap->ops->scr_read(ap, reg);
+ return 0;
+ }
+ return -EOPNOTSUPP;
+}
+
+/**
+ * ata_port_online - test whether the given port is online
+ * @ap: ATA port to test
+ *
+ * Test whether @ap is online. Note that this function returns 0
+ * if online status of @ap cannot be obtained, so
+ * ata_port_online(ap) != !ata_port_offline(ap).
+ *
+ * LOCKING:
+ * None.
+ *
+ * RETURNS:
+ * 1 if the port online status is available and online.
+ */
+int ata_port_online(struct ata_port *ap)
+{
+ u32 sstatus;
+
+ if (!sata_scr_read(ap, SCR_STATUS, &sstatus) && (sstatus & 0xf) == 0x3)
+ return 1;
+ return 0;
+}
+
+/**
+ * ata_port_offline - test whether the given port is offline
+ * @ap: ATA port to test
+ *
+ * Test whether @ap is offline. Note that this function returns
+ * 0 if offline status of @ap cannot be obtained, so
+ * ata_port_online(ap) != !ata_port_offline(ap).
+ *
+ * LOCKING:
+ * None.
+ *
+ * RETURNS:
+ * 1 if the port offline status is available and offline.
+ */
+int ata_port_offline(struct ata_port *ap)
+{
+ u32 sstatus;
+
+ if (!sata_scr_read(ap, SCR_STATUS, &sstatus) && (sstatus & 0xf) != 0x3)
+ return 1;
+ return 0;
+}
+
+int ata_flush_cache(struct ata_device *dev)
+{
+ unsigned int err_mask;
+ u8 cmd;
+
+ if (!ata_try_flush_cache(dev))
+ return 0;
+
+ if (ata_id_has_flush_ext(dev->id))
+ cmd = ATA_CMD_FLUSH_EXT;
+ else
+ cmd = ATA_CMD_FLUSH;
+
+ err_mask = ata_do_simple_cmd(dev, cmd);
+ if (err_mask) {
+ ata_dev_printk(dev, KERN_ERR, "failed to flush cache\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int ata_host_request_pm(struct ata_host *host, pm_message_t mesg,
+ unsigned int action, unsigned int ehi_flags,
+ int wait)
+{
+ unsigned long flags;
+ int i, rc;
+
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap = host->ports[i];
+
+ /* Previous resume operation might still be in
+ * progress. Wait for PM_PENDING to clear.
+ */
+ if (ap->pflags & ATA_PFLAG_PM_PENDING) {
+ ata_port_wait_eh(ap);
+ WARN_ON(ap->pflags & ATA_PFLAG_PM_PENDING);
+ }
+
+ /* request PM ops to EH */
+ spin_lock_irqsave(ap->lock, flags);
+
+ ap->pm_mesg = mesg;
+ if (wait) {
+ rc = 0;
+ ap->pm_result = &rc;
+ }
+
+ ap->pflags |= ATA_PFLAG_PM_PENDING;
+ ap->eh_info.action |= action;
+ ap->eh_info.flags |= ehi_flags;
+
+ ata_port_schedule_eh(ap);
+
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ /* wait and check result */
+ if (wait) {
+ ata_port_wait_eh(ap);
+ WARN_ON(ap->pflags & ATA_PFLAG_PM_PENDING);
+ if (rc)
+ return rc;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * ata_host_suspend - suspend host
+ * @host: host to suspend
+ * @mesg: PM message
+ *
+ * Suspend @host. Actual operation is performed by EH. This
+ * function requests EH to perform PM operations and waits for EH
+ * to finish.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, -errno on failure.
+ */
+int ata_host_suspend(struct ata_host *host, pm_message_t mesg)
+{
+ int i, j, rc;
+
+ rc = ata_host_request_pm(host, mesg, 0, ATA_EHI_QUIET, 1);
+ if (rc)
+ goto fail;
+
+ /* EH is quiescent now. Fail if we have any ready device.
+ * This happens if hotplug occurs between completion of device
+ * suspension and here.
+ */
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap = host->ports[i];
+
+ for (j = 0; j < ATA_MAX_DEVICES; j++) {
+ struct ata_device *dev = &ap->device[j];
+
+ if (ata_dev_ready(dev)) {
+ ata_port_printk(ap, KERN_WARNING,
+ "suspend failed, device %d "
+ "still active\n", dev->devno);
+ rc = -EBUSY;
+ goto fail;
+ }
+ }
+ }
+
+ host->dev->power.power_state = mesg;
+ return 0;
+
+ fail:
+ ata_host_resume(host);
+ return rc;
+}
+
+/**
+ * ata_host_resume - resume host
+ * @host: host to resume
+ *
+ * Resume @host. Actual operation is performed by EH. This
+ * function requests EH to perform PM operations and returns.
+ * Note that all resume operations are performed parallely.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ */
+void ata_host_resume(struct ata_host *host)
+{
+ ata_host_request_pm(host, PMSG_ON, ATA_EH_SOFTRESET,
+ ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET, 0);
+ host->dev->power.power_state = PMSG_ON;
+}
+
+/**
+ * ata_port_start - Set port up for dma.
+ * @ap: Port to initialize
+ *
+ * Called just after data structures for each port are
+ * initialized. Allocates space for PRD table.
+ *
+ * May be used as the port_start() entry in ata_port_operations.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+
+int ata_port_start (struct ata_port *ap)
+{
+ struct device *dev = ap->dev;
+ int rc;
+
+ ap->prd = dma_alloc_coherent(dev, ATA_PRD_TBL_SZ, &ap->prd_dma, GFP_KERNEL);
+ if (!ap->prd)
+ return -ENOMEM;
+
+ rc = ata_pad_alloc(ap, dev);
+ if (rc) {
+ dma_free_coherent(dev, ATA_PRD_TBL_SZ, ap->prd, ap->prd_dma);
+ return rc;
+ }
+
+ DPRINTK("prd alloc, virt %p, dma %llx\n", ap->prd, (unsigned long long) ap->prd_dma);
+
+ return 0;
+}
+
+
+/**
+ * ata_port_stop - Undo ata_port_start()
+ * @ap: Port to shut down
+ *
+ * Frees the PRD table.
+ *
+ * May be used as the port_stop() entry in ata_port_operations.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+
+void ata_port_stop (struct ata_port *ap)
+{
+ struct device *dev = ap->dev;
+
+ dma_free_coherent(dev, ATA_PRD_TBL_SZ, ap->prd, ap->prd_dma);
+ ata_pad_free(ap, dev);
+}
+
+void ata_host_stop (struct ata_host *host)
+{
+ if (host->mmio_base)
+ iounmap(host->mmio_base);
+}
+
+/**
+ * ata_dev_init - Initialize an ata_device structure
+ * @dev: Device structure to initialize
+ *
+ * Initialize @dev in preparation for probing.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+void ata_dev_init(struct ata_device *dev)
+{
+ struct ata_port *ap = dev->ap;
+ unsigned long flags;
+
+ /* SATA spd limit is bound to the first device */
+ ap->sata_spd_limit = ap->hw_sata_spd_limit;
+
+ /* High bits of dev->flags are used to record warm plug
+ * requests which occur asynchronously. Synchronize using
+ * host lock.
+ */
+ spin_lock_irqsave(ap->lock, flags);
+ dev->flags &= ~ATA_DFLAG_INIT_MASK;
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ memset((void *)dev + ATA_DEVICE_CLEAR_OFFSET, 0,
+ sizeof(*dev) - ATA_DEVICE_CLEAR_OFFSET);
+ dev->pio_mask = UINT_MAX;
+ dev->mwdma_mask = UINT_MAX;
+ dev->udma_mask = UINT_MAX;
+}
+
+/**
+ * ata_port_init - Initialize an ata_port structure
+ * @ap: Structure to initialize
+ * @host: Collection of hosts to which @ap belongs
+ * @ent: Probe information provided by low-level driver
+ * @port_no: Port number associated with this ata_port
+ *
+ * Initialize a new ata_port structure.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+void ata_port_init(struct ata_port *ap, struct ata_host *host,
+ const struct ata_probe_ent *ent, unsigned int port_no)
+{
+ unsigned int i;
+
+ ap->lock = &host->lock;
+ ap->flags = ATA_FLAG_DISABLED;
+ ap->id = ata_unique_id++;
+ ap->ctl = ATA_DEVCTL_OBS;
+ ap->host = host;
+ ap->dev = ent->dev;
+ ap->port_no = port_no;
+ if (port_no == 1 && ent->pinfo2) {
+ ap->pio_mask = ent->pinfo2->pio_mask;
+ ap->mwdma_mask = ent->pinfo2->mwdma_mask;
+ ap->udma_mask = ent->pinfo2->udma_mask;
+ ap->flags |= ent->pinfo2->flags;
+ ap->ops = ent->pinfo2->port_ops;
+ } else {
+ ap->pio_mask = ent->pio_mask;
+ ap->mwdma_mask = ent->mwdma_mask;
+ ap->udma_mask = ent->udma_mask;
+ ap->flags |= ent->port_flags;
+ ap->ops = ent->port_ops;
+ }
+ ap->hw_sata_spd_limit = UINT_MAX;
+ ap->active_tag = ATA_TAG_POISON;
+ ap->last_ctl = 0xFF;
+
+#if defined(ATA_VERBOSE_DEBUG)
+ /* turn on all debugging levels */
+ ap->msg_enable = 0x00FF;
+#elif defined(ATA_DEBUG)
+ ap->msg_enable = ATA_MSG_DRV | ATA_MSG_INFO | ATA_MSG_CTL | ATA_MSG_WARN | ATA_MSG_ERR;
+#else
+ ap->msg_enable = ATA_MSG_DRV | ATA_MSG_ERR | ATA_MSG_WARN;
+#endif
+
+ INIT_WORK(&ap->port_task, NULL, NULL);
+ INIT_WORK(&ap->hotplug_task, ata_scsi_hotplug, ap);
+ INIT_WORK(&ap->scsi_rescan_task, ata_scsi_dev_rescan, ap);
+ INIT_LIST_HEAD(&ap->eh_done_q);
+ init_waitqueue_head(&ap->eh_wait_q);
+
+ /* set cable type */
+ ap->cbl = ATA_CBL_NONE;
+ if (ap->flags & ATA_FLAG_SATA)
+ ap->cbl = ATA_CBL_SATA;
+
+ for (i = 0; i < ATA_MAX_DEVICES; i++) {
+ struct ata_device *dev = &ap->device[i];
+ dev->ap = ap;
+ dev->devno = i;
+ ata_dev_init(dev);
+ }
+
+#ifdef ATA_IRQ_TRAP
+ ap->stats.unhandled_irq = 1;
+ ap->stats.idle_irq = 1;
+#endif
+
+ memcpy(&ap->ioaddr, &ent->port[port_no], sizeof(struct ata_ioports));
+}
+
+/**
+ * ata_port_init_shost - Initialize SCSI host associated with ATA port
+ * @ap: ATA port to initialize SCSI host for
+ * @shost: SCSI host associated with @ap
+ *
+ * Initialize SCSI host @shost associated with ATA port @ap.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+static void ata_port_init_shost(struct ata_port *ap, struct Scsi_Host *shost)
+{
+ ap->scsi_host = shost;
+
+ shost->unique_id = ap->id;
+ shost->max_id = 16;
+ shost->max_lun = 1;
+ shost->max_channel = 1;
+ shost->max_cmd_len = 12;
+}
+
+/**
+ * ata_port_add - Attach low-level ATA driver to system
+ * @ent: Information provided by low-level driver
+ * @host: Collections of ports to which we add
+ * @port_no: Port number associated with this host
+ *
+ * Attach low-level ATA driver to system.
+ *
+ * LOCKING:
+ * PCI/etc. bus probe sem.
+ *
+ * RETURNS:
+ * New ata_port on success, for NULL on error.
+ */
+static struct ata_port * ata_port_add(const struct ata_probe_ent *ent,
+ struct ata_host *host,
+ unsigned int port_no)
+{
+ struct Scsi_Host *shost;
+ struct ata_port *ap;
+
+ DPRINTK("ENTER\n");
+
+ if (!ent->port_ops->error_handler &&
+ !(ent->port_flags & (ATA_FLAG_SATA_RESET | ATA_FLAG_SRST))) {
+ printk(KERN_ERR "ata%u: no reset mechanism available\n",
+ port_no);
+ return NULL;
+ }
+
+ shost = scsi_host_alloc(ent->sht, sizeof(struct ata_port));
+ if (!shost)
+ return NULL;
+
+ shost->transportt = &ata_scsi_transport_template;
+
+ ap = ata_shost_to_port(shost);
+
+ ata_port_init(ap, host, ent, port_no);
+ ata_port_init_shost(ap, shost);
+
+ return ap;
+}
+
+/**
+ * ata_sas_host_init - Initialize a host struct
+ * @host: host to initialize
+ * @dev: device host is attached to
+ * @flags: host flags
+ * @ops: port_ops
+ *
+ * LOCKING:
+ * PCI/etc. bus probe sem.
+ *
+ */
+
+void ata_host_init(struct ata_host *host, struct device *dev,
+ unsigned long flags, const struct ata_port_operations *ops)
+{
+ spin_lock_init(&host->lock);
+ host->dev = dev;
+ host->flags = flags;
+ host->ops = ops;
+}
+
+/**
+ * ata_device_add - Register hardware device with ATA and SCSI layers
+ * @ent: Probe information describing hardware device to be registered
+ *
+ * This function processes the information provided in the probe
+ * information struct @ent, allocates the necessary ATA and SCSI
+ * host information structures, initializes them, and registers
+ * everything with requisite kernel subsystems.
+ *
+ * This function requests irqs, probes the ATA bus, and probes
+ * the SCSI bus.
+ *
+ * LOCKING:
+ * PCI/etc. bus probe sem.
+ *
+ * RETURNS:
+ * Number of ports registered. Zero on error (no ports registered).
+ */
+int ata_device_add(const struct ata_probe_ent *ent)
+{
+ unsigned int i;
+ struct device *dev = ent->dev;
+ struct ata_host *host;
+ int rc;
+
+ DPRINTK("ENTER\n");
+
+ if (ent->irq == 0) {
+ dev_printk(KERN_ERR, dev, "is not available: No interrupt assigned.\n");
+ return 0;
+ }
+ /* alloc a container for our list of ATA ports (buses) */
+ host = kzalloc(sizeof(struct ata_host) +
+ (ent->n_ports * sizeof(void *)), GFP_KERNEL);
+ if (!host)
+ return 0;
+
+ ata_host_init(host, dev, ent->_host_flags, ent->port_ops);
+ host->n_ports = ent->n_ports;
+ host->irq = ent->irq;
+ host->irq2 = ent->irq2;
+ host->mmio_base = ent->mmio_base;
+ host->private_data = ent->private_data;
+
+ /* register each port bound to this device */
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap;
+ unsigned long xfer_mode_mask;
+ int irq_line = ent->irq;
+
+ ap = ata_port_add(ent, host, i);
+ if (!ap)
+ goto err_out;
+
+ host->ports[i] = ap;
+
+ /* dummy? */
+ if (ent->dummy_port_mask & (1 << i)) {
+ ata_port_printk(ap, KERN_INFO, "DUMMY\n");
+ ap->ops = &ata_dummy_port_ops;
+ continue;
+ }
+
+ /* start port */
+ rc = ap->ops->port_start(ap);
+ if (rc) {
+ host->ports[i] = NULL;
+ scsi_host_put(ap->scsi_host);
+ goto err_out;
+ }
+
+ /* Report the secondary IRQ for second channel legacy */
+ if (i == 1 && ent->irq2)
+ irq_line = ent->irq2;
+
+ xfer_mode_mask =(ap->udma_mask << ATA_SHIFT_UDMA) |
+ (ap->mwdma_mask << ATA_SHIFT_MWDMA) |
+ (ap->pio_mask << ATA_SHIFT_PIO);
+
+ /* print per-port info to dmesg */
+ ata_port_printk(ap, KERN_INFO, "%cATA max %s cmd 0x%lX "
+ "ctl 0x%lX bmdma 0x%lX irq %d\n",
+ ap->flags & ATA_FLAG_SATA ? 'S' : 'P',
+ ata_mode_string(xfer_mode_mask),
+ ap->ioaddr.cmd_addr,
+ ap->ioaddr.ctl_addr,
+ ap->ioaddr.bmdma_addr,
+ irq_line);
+
+ ata_chk_status(ap);
+ host->ops->irq_clear(ap);
+ ata_eh_freeze_port(ap); /* freeze port before requesting IRQ */
+ }
+
+ /* obtain irq, that may be shared between channels */
+ rc = request_irq(ent->irq, ent->port_ops->irq_handler, ent->irq_flags,
+ DRV_NAME, host);
+ if (rc) {
+ dev_printk(KERN_ERR, dev, "irq %lu request failed: %d\n",
+ ent->irq, rc);
+ goto err_out;
+ }
+
+ /* do we have a second IRQ for the other channel, eg legacy mode */
+ if (ent->irq2) {
+ /* We will get weird core code crashes later if this is true
+ so trap it now */
+ BUG_ON(ent->irq == ent->irq2);
+
+ rc = request_irq(ent->irq2, ent->port_ops->irq_handler, ent->irq_flags,
+ DRV_NAME, host);
+ if (rc) {
+ dev_printk(KERN_ERR, dev, "irq %lu request failed: %d\n",
+ ent->irq2, rc);
+ goto err_out_free_irq;
+ }
+ }
+
+ /* perform each probe synchronously */
+ DPRINTK("probe begin\n");
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap = host->ports[i];
+ u32 scontrol;
+ int rc;
+
+ /* init sata_spd_limit to the current value */
+ if (sata_scr_read(ap, SCR_CONTROL, &scontrol) == 0) {
+ int spd = (scontrol >> 4) & 0xf;
+ ap->hw_sata_spd_limit &= (1 << spd) - 1;
+ }
+ ap->sata_spd_limit = ap->hw_sata_spd_limit;
+
+ rc = scsi_add_host(ap->scsi_host, dev);
+ if (rc) {
+ ata_port_printk(ap, KERN_ERR, "scsi_add_host failed\n");
+ /* FIXME: do something useful here */
+ /* FIXME: handle unconditional calls to
+ * scsi_scan_host and ata_host_remove, below,
+ * at the very least
+ */
+ }
+
+ if (ap->ops->error_handler) {
+ struct ata_eh_info *ehi = &ap->eh_info;
+ unsigned long flags;
+
+ ata_port_probe(ap);
+
+ /* kick EH for boot probing */
+ spin_lock_irqsave(ap->lock, flags);
+
+ ehi->probe_mask = (1 << ATA_MAX_DEVICES) - 1;
+ ehi->action |= ATA_EH_SOFTRESET;
+ ehi->flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET;
+
+ ap->pflags |= ATA_PFLAG_LOADING;
+ ata_port_schedule_eh(ap);
+
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ /* wait for EH to finish */
+ ata_port_wait_eh(ap);
+ } else {
+ DPRINTK("ata%u: bus probe begin\n", ap->id);
+ rc = ata_bus_probe(ap);
+ DPRINTK("ata%u: bus probe end\n", ap->id);
+
+ if (rc) {
+ /* FIXME: do something useful here?
+ * Current libata behavior will
+ * tear down everything when
+ * the module is removed
+ * or the h/w is unplugged.
+ */
+ }
+ }
+ }
+
+ /* probes are done, now scan each port's disk(s) */
+ DPRINTK("host probe begin\n");
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap = host->ports[i];
+
+ ata_scsi_scan_host(ap);
+ }
+
+ dev_set_drvdata(dev, host);
+
+ VPRINTK("EXIT, returning %u\n", ent->n_ports);
+ return ent->n_ports; /* success */
+
+err_out_free_irq:
+ free_irq(ent->irq, host);
+err_out:
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap = host->ports[i];
+ if (ap) {
+ ap->ops->port_stop(ap);
+ scsi_host_put(ap->scsi_host);
+ }
+ }
+
+ kfree(host);
+ VPRINTK("EXIT, returning 0\n");
+ return 0;
+}
+
+/**
+ * ata_port_detach - Detach ATA port in prepration of device removal
+ * @ap: ATA port to be detached
+ *
+ * Detach all ATA devices and the associated SCSI devices of @ap;
+ * then, remove the associated SCSI host. @ap is guaranteed to
+ * be quiescent on return from this function.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ */
+void ata_port_detach(struct ata_port *ap)
+{
+ unsigned long flags;
+ int i;
+
+ if (!ap->ops->error_handler)
+ goto skip_eh;
+
+ /* tell EH we're leaving & flush EH */
+ spin_lock_irqsave(ap->lock, flags);
+ ap->pflags |= ATA_PFLAG_UNLOADING;
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ ata_port_wait_eh(ap);
+
+ /* EH is now guaranteed to see UNLOADING, so no new device
+ * will be attached. Disable all existing devices.
+ */
+ spin_lock_irqsave(ap->lock, flags);
+
+ for (i = 0; i < ATA_MAX_DEVICES; i++)
+ ata_dev_disable(&ap->device[i]);
+
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ /* Final freeze & EH. All in-flight commands are aborted. EH
+ * will be skipped and retrials will be terminated with bad
+ * target.
+ */
+ spin_lock_irqsave(ap->lock, flags);
+ ata_port_freeze(ap); /* won't be thawed */
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ ata_port_wait_eh(ap);
+
+ /* Flush hotplug task. The sequence is similar to
+ * ata_port_flush_task().
+ */
+ flush_workqueue(ata_aux_wq);
+ cancel_delayed_work(&ap->hotplug_task);
+ flush_workqueue(ata_aux_wq);
+
+ skip_eh:
+ /* remove the associated SCSI host */
+ scsi_remove_host(ap->scsi_host);
+}
+
+/**
+ * ata_host_remove - PCI layer callback for device removal
+ * @host: ATA host set that was removed
+ *
+ * Unregister all objects associated with this host set. Free those
+ * objects.
+ *
+ * LOCKING:
+ * Inherited from calling layer (may sleep).
+ */
+
+void ata_host_remove(struct ata_host *host)
+{
+ unsigned int i;
+
+ for (i = 0; i < host->n_ports; i++)
+ ata_port_detach(host->ports[i]);
+
+ free_irq(host->irq, host);
+ if (host->irq2)
+ free_irq(host->irq2, host);
+
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap = host->ports[i];
+
+ ata_scsi_release(ap->scsi_host);
+
+ if ((ap->flags & ATA_FLAG_NO_LEGACY) == 0) {
+ struct ata_ioports *ioaddr = &ap->ioaddr;
+
+ /* FIXME: Add -ac IDE pci mods to remove these special cases */
+ if (ioaddr->cmd_addr == ATA_PRIMARY_CMD)
+ release_region(ATA_PRIMARY_CMD, 8);
+ else if (ioaddr->cmd_addr == ATA_SECONDARY_CMD)
+ release_region(ATA_SECONDARY_CMD, 8);
+ }
+
+ scsi_host_put(ap->scsi_host);
+ }
+
+ if (host->ops->host_stop)
+ host->ops->host_stop(host);
+
+ kfree(host);
+}
+
+/**
+ * ata_scsi_release - SCSI layer callback hook for host unload
+ * @host: libata host to be unloaded
+ *
+ * Performs all duties necessary to shut down a libata port...
+ * Kill port kthread, disable port, and release resources.
+ *
+ * LOCKING:
+ * Inherited from SCSI layer.
+ *
+ * RETURNS:
+ * One.
+ */
+
+int ata_scsi_release(struct Scsi_Host *shost)
+{
+ struct ata_port *ap = ata_shost_to_port(shost);
+
+ DPRINTK("ENTER\n");
+
+ ap->ops->port_disable(ap);
+ ap->ops->port_stop(ap);
+
+ DPRINTK("EXIT\n");
+ return 1;
+}
+
+struct ata_probe_ent *
+ata_probe_ent_alloc(struct device *dev, const struct ata_port_info *port)
+{
+ struct ata_probe_ent *probe_ent;
+
+ probe_ent = kzalloc(sizeof(*probe_ent), GFP_KERNEL);
+ if (!probe_ent) {
+ printk(KERN_ERR DRV_NAME "(%s): out of memory\n",
+ kobject_name(&(dev->kobj)));
+ return NULL;
+ }
+
+ INIT_LIST_HEAD(&probe_ent->node);
+ probe_ent->dev = dev;
+
+ probe_ent->sht = port->sht;
+ probe_ent->port_flags = port->flags;
+ probe_ent->pio_mask = port->pio_mask;
+ probe_ent->mwdma_mask = port->mwdma_mask;
+ probe_ent->udma_mask = port->udma_mask;
+ probe_ent->port_ops = port->port_ops;
+
+ return probe_ent;
+}
+
+/**
+ * ata_std_ports - initialize ioaddr with standard port offsets.
+ * @ioaddr: IO address structure to be initialized
+ *
+ * Utility function which initializes data_addr, error_addr,
+ * feature_addr, nsect_addr, lbal_addr, lbam_addr, lbah_addr,
+ * device_addr, status_addr, and command_addr to standard offsets
+ * relative to cmd_addr.
+ *
+ * Does not set ctl_addr, altstatus_addr, bmdma_addr, or scr_addr.
+ */
+
+void ata_std_ports(struct ata_ioports *ioaddr)
+{
+ ioaddr->data_addr = ioaddr->cmd_addr + ATA_REG_DATA;
+ ioaddr->error_addr = ioaddr->cmd_addr + ATA_REG_ERR;
+ ioaddr->feature_addr = ioaddr->cmd_addr + ATA_REG_FEATURE;
+ ioaddr->nsect_addr = ioaddr->cmd_addr + ATA_REG_NSECT;
+ ioaddr->lbal_addr = ioaddr->cmd_addr + ATA_REG_LBAL;
+ ioaddr->lbam_addr = ioaddr->cmd_addr + ATA_REG_LBAM;
+ ioaddr->lbah_addr = ioaddr->cmd_addr + ATA_REG_LBAH;
+ ioaddr->device_addr = ioaddr->cmd_addr + ATA_REG_DEVICE;
+ ioaddr->status_addr = ioaddr->cmd_addr + ATA_REG_STATUS;
+ ioaddr->command_addr = ioaddr->cmd_addr + ATA_REG_CMD;
+}
+
+
+#ifdef CONFIG_PCI
+
+void ata_pci_host_stop (struct ata_host *host)
+{
+ struct pci_dev *pdev = to_pci_dev(host->dev);
+
+ pci_iounmap(pdev, host->mmio_base);
+}
+
+/**
+ * ata_pci_remove_one - PCI layer callback for device removal
+ * @pdev: PCI device that was removed
+ *
+ * PCI layer indicates to libata via this hook that
+ * hot-unplug or module unload event has occurred.
+ * Handle this by unregistering all objects associated
+ * with this PCI device. Free those objects. Then finally
+ * release PCI resources and disable device.
+ *
+ * LOCKING:
+ * Inherited from PCI layer (may sleep).
+ */
+
+void ata_pci_remove_one (struct pci_dev *pdev)
+{
+ struct device *dev = pci_dev_to_dev(pdev);
+ struct ata_host *host = dev_get_drvdata(dev);
+
+ ata_host_remove(host);
+
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+ dev_set_drvdata(dev, NULL);
+}
+
+/* move to PCI subsystem */
+int pci_test_config_bits(struct pci_dev *pdev, const struct pci_bits *bits)
+{
+ unsigned long tmp = 0;
+
+ switch (bits->width) {
+ case 1: {
+ u8 tmp8 = 0;
+ pci_read_config_byte(pdev, bits->reg, &tmp8);
+ tmp = tmp8;
+ break;
+ }
+ case 2: {
+ u16 tmp16 = 0;
+ pci_read_config_word(pdev, bits->reg, &tmp16);
+ tmp = tmp16;
+ break;
+ }
+ case 4: {
+ u32 tmp32 = 0;
+ pci_read_config_dword(pdev, bits->reg, &tmp32);
+ tmp = tmp32;
+ break;
+ }
+
+ default:
+ return -EINVAL;
+ }
+
+ tmp &= bits->mask;
+
+ return (tmp == bits->val) ? 1 : 0;
+}
+
+void ata_pci_device_do_suspend(struct pci_dev *pdev, pm_message_t mesg)
+{
+ pci_save_state(pdev);
+
+ if (mesg.event == PM_EVENT_SUSPEND) {
+ pci_disable_device(pdev);
+ pci_set_power_state(pdev, PCI_D3hot);
+ }
+}
+
+void ata_pci_device_do_resume(struct pci_dev *pdev)
+{
+ pci_set_power_state(pdev, PCI_D0);
+ pci_restore_state(pdev);
+ pci_enable_device(pdev);
+ pci_set_master(pdev);
+}
+
+int ata_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
+{
+ struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ int rc = 0;
+
+ rc = ata_host_suspend(host, mesg);
+ if (rc)
+ return rc;
+
+ ata_pci_device_do_suspend(pdev, mesg);
+
+ return 0;
+}
+
+int ata_pci_device_resume(struct pci_dev *pdev)
+{
+ struct ata_host *host = dev_get_drvdata(&pdev->dev);
+
+ ata_pci_device_do_resume(pdev);
+ ata_host_resume(host);
+ return 0;
+}
+#endif /* CONFIG_PCI */
+
+
+static int __init ata_init(void)
+{
+ ata_probe_timeout *= HZ;
+ ata_wq = create_workqueue("ata");
+ if (!ata_wq)
+ return -ENOMEM;
+
+ ata_aux_wq = create_singlethread_workqueue("ata_aux");
+ if (!ata_aux_wq) {
+ destroy_workqueue(ata_wq);
+ return -ENOMEM;
+ }
+
+ printk(KERN_DEBUG "libata version " DRV_VERSION " loaded.\n");
+ return 0;
+}
+
+static void __exit ata_exit(void)
+{
+ destroy_workqueue(ata_wq);
+ destroy_workqueue(ata_aux_wq);
+}
+
+module_init(ata_init);
+module_exit(ata_exit);
+
+static unsigned long ratelimit_time;
+static DEFINE_SPINLOCK(ata_ratelimit_lock);
+
+int ata_ratelimit(void)
+{
+ int rc;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ata_ratelimit_lock, flags);
+
+ if (time_after(jiffies, ratelimit_time)) {
+ rc = 1;
+ ratelimit_time = jiffies + (HZ/5);
+ } else
+ rc = 0;
+
+ spin_unlock_irqrestore(&ata_ratelimit_lock, flags);
+
+ return rc;
+}
+
+/**
+ * ata_wait_register - wait until register value changes
+ * @reg: IO-mapped register
+ * @mask: Mask to apply to read register value
+ * @val: Wait condition
+ * @interval_msec: polling interval in milliseconds
+ * @timeout_msec: timeout in milliseconds
+ *
+ * Waiting for some bits of register to change is a common
+ * operation for ATA controllers. This function reads 32bit LE
+ * IO-mapped register @reg and tests for the following condition.
+ *
+ * (*@reg & mask) != val
+ *
+ * If the condition is met, it returns; otherwise, the process is
+ * repeated after @interval_msec until timeout.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep)
+ *
+ * RETURNS:
+ * The final register value.
+ */
+u32 ata_wait_register(void __iomem *reg, u32 mask, u32 val,
+ unsigned long interval_msec,
+ unsigned long timeout_msec)
+{
+ unsigned long timeout;
+ u32 tmp;
+
+ tmp = ioread32(reg);
+
+ /* Calculate timeout _after_ the first read to make sure
+ * preceding writes reach the controller before starting to
+ * eat away the timeout.
+ */
+ timeout = jiffies + (timeout_msec * HZ) / 1000;
+
+ while ((tmp & mask) == val && time_before(jiffies, timeout)) {
+ msleep(interval_msec);
+ tmp = ioread32(reg);
+ }
+
+ return tmp;
+}
+
+/*
+ * Dummy port_ops
+ */
+static void ata_dummy_noret(struct ata_port *ap) { }
+static int ata_dummy_ret0(struct ata_port *ap) { return 0; }
+static void ata_dummy_qc_noret(struct ata_queued_cmd *qc) { }
+
+static u8 ata_dummy_check_status(struct ata_port *ap)
+{
+ return ATA_DRDY;
+}
+
+static unsigned int ata_dummy_qc_issue(struct ata_queued_cmd *qc)
+{
+ return AC_ERR_SYSTEM;
+}
+
+const struct ata_port_operations ata_dummy_port_ops = {
+ .port_disable = ata_port_disable,
+ .check_status = ata_dummy_check_status,
+ .check_altstatus = ata_dummy_check_status,
+ .dev_select = ata_noop_dev_select,
+ .qc_prep = ata_noop_qc_prep,
+ .qc_issue = ata_dummy_qc_issue,
+ .freeze = ata_dummy_noret,
+ .thaw = ata_dummy_noret,
+ .error_handler = ata_dummy_noret,
+ .post_internal_cmd = ata_dummy_qc_noret,
+ .irq_clear = ata_dummy_noret,
+ .port_start = ata_dummy_ret0,
+ .port_stop = ata_dummy_noret,
+};
+
+/*
+ * libata is essentially a library of internal helper functions for
+ * low-level ATA host controller drivers. As such, the API/ABI is
+ * likely to change as new drivers are added and updated.
+ * Do not depend on ABI/API stability.
+ */
+
+EXPORT_SYMBOL_GPL(sata_deb_timing_normal);
+EXPORT_SYMBOL_GPL(sata_deb_timing_hotplug);
+EXPORT_SYMBOL_GPL(sata_deb_timing_long);
+EXPORT_SYMBOL_GPL(ata_dummy_port_ops);
+EXPORT_SYMBOL_GPL(ata_std_bios_param);
+EXPORT_SYMBOL_GPL(ata_std_ports);
+EXPORT_SYMBOL_GPL(ata_host_init);
+EXPORT_SYMBOL_GPL(ata_device_add);
+EXPORT_SYMBOL_GPL(ata_port_detach);
+EXPORT_SYMBOL_GPL(ata_host_remove);
+EXPORT_SYMBOL_GPL(ata_sg_init);
+EXPORT_SYMBOL_GPL(ata_sg_init_one);
+EXPORT_SYMBOL_GPL(ata_hsm_move);
+EXPORT_SYMBOL_GPL(ata_qc_complete);
+EXPORT_SYMBOL_GPL(ata_qc_complete_multiple);
+EXPORT_SYMBOL_GPL(ata_qc_issue_prot);
+EXPORT_SYMBOL_GPL(ata_tf_load);
+EXPORT_SYMBOL_GPL(ata_tf_read);
+EXPORT_SYMBOL_GPL(ata_noop_dev_select);
+EXPORT_SYMBOL_GPL(ata_std_dev_select);
+EXPORT_SYMBOL_GPL(ata_tf_to_fis);
+EXPORT_SYMBOL_GPL(ata_tf_from_fis);
+EXPORT_SYMBOL_GPL(ata_check_status);
+EXPORT_SYMBOL_GPL(ata_altstatus);
+EXPORT_SYMBOL_GPL(ata_exec_command);
+EXPORT_SYMBOL_GPL(ata_port_start);
+EXPORT_SYMBOL_GPL(ata_port_stop);
+EXPORT_SYMBOL_GPL(ata_host_stop);
+EXPORT_SYMBOL_GPL(ata_interrupt);
+EXPORT_SYMBOL_GPL(ata_mmio_data_xfer);
+EXPORT_SYMBOL_GPL(ata_pio_data_xfer);
+EXPORT_SYMBOL_GPL(ata_pio_data_xfer_noirq);
+EXPORT_SYMBOL_GPL(ata_qc_prep);
+EXPORT_SYMBOL_GPL(ata_noop_qc_prep);
+EXPORT_SYMBOL_GPL(ata_bmdma_setup);
+EXPORT_SYMBOL_GPL(ata_bmdma_start);
+EXPORT_SYMBOL_GPL(ata_bmdma_irq_clear);
+EXPORT_SYMBOL_GPL(ata_bmdma_status);
+EXPORT_SYMBOL_GPL(ata_bmdma_stop);
+EXPORT_SYMBOL_GPL(ata_bmdma_freeze);
+EXPORT_SYMBOL_GPL(ata_bmdma_thaw);
+EXPORT_SYMBOL_GPL(ata_bmdma_drive_eh);
+EXPORT_SYMBOL_GPL(ata_bmdma_error_handler);
+EXPORT_SYMBOL_GPL(ata_bmdma_post_internal_cmd);
+EXPORT_SYMBOL_GPL(ata_port_probe);
+EXPORT_SYMBOL_GPL(sata_set_spd);
+EXPORT_SYMBOL_GPL(sata_phy_debounce);
+EXPORT_SYMBOL_GPL(sata_phy_resume);
+EXPORT_SYMBOL_GPL(sata_phy_reset);
+EXPORT_SYMBOL_GPL(__sata_phy_reset);
+EXPORT_SYMBOL_GPL(ata_bus_reset);
+EXPORT_SYMBOL_GPL(ata_std_prereset);
+EXPORT_SYMBOL_GPL(ata_std_softreset);
+EXPORT_SYMBOL_GPL(sata_std_hardreset);
+EXPORT_SYMBOL_GPL(ata_std_postreset);
+EXPORT_SYMBOL_GPL(ata_dev_revalidate);
+EXPORT_SYMBOL_GPL(ata_dev_classify);
+EXPORT_SYMBOL_GPL(ata_dev_pair);
+EXPORT_SYMBOL_GPL(ata_port_disable);
+EXPORT_SYMBOL_GPL(ata_ratelimit);
+EXPORT_SYMBOL_GPL(ata_wait_register);
+EXPORT_SYMBOL_GPL(ata_busy_sleep);
+EXPORT_SYMBOL_GPL(ata_port_queue_task);
+EXPORT_SYMBOL_GPL(ata_scsi_ioctl);
+EXPORT_SYMBOL_GPL(ata_scsi_queuecmd);
+EXPORT_SYMBOL_GPL(ata_scsi_slave_config);
+EXPORT_SYMBOL_GPL(ata_scsi_slave_destroy);
+EXPORT_SYMBOL_GPL(ata_scsi_change_queue_depth);
+EXPORT_SYMBOL_GPL(ata_scsi_release);
+EXPORT_SYMBOL_GPL(ata_host_intr);
+EXPORT_SYMBOL_GPL(sata_scr_valid);
+EXPORT_SYMBOL_GPL(sata_scr_read);
+EXPORT_SYMBOL_GPL(sata_scr_write);
+EXPORT_SYMBOL_GPL(sata_scr_write_flush);
+EXPORT_SYMBOL_GPL(ata_port_online);
+EXPORT_SYMBOL_GPL(ata_port_offline);
+EXPORT_SYMBOL_GPL(ata_host_suspend);
+EXPORT_SYMBOL_GPL(ata_host_resume);
+EXPORT_SYMBOL_GPL(ata_id_string);
+EXPORT_SYMBOL_GPL(ata_id_c_string);
+EXPORT_SYMBOL_GPL(ata_scsi_simulate);
+
+EXPORT_SYMBOL_GPL(ata_pio_need_iordy);
+EXPORT_SYMBOL_GPL(ata_timing_compute);
+EXPORT_SYMBOL_GPL(ata_timing_merge);
+
+#ifdef CONFIG_PCI
+EXPORT_SYMBOL_GPL(pci_test_config_bits);
+EXPORT_SYMBOL_GPL(ata_pci_host_stop);
+EXPORT_SYMBOL_GPL(ata_pci_init_native_mode);
+EXPORT_SYMBOL_GPL(ata_pci_init_one);
+EXPORT_SYMBOL_GPL(ata_pci_remove_one);
+EXPORT_SYMBOL_GPL(ata_pci_device_do_suspend);
+EXPORT_SYMBOL_GPL(ata_pci_device_do_resume);
+EXPORT_SYMBOL_GPL(ata_pci_device_suspend);
+EXPORT_SYMBOL_GPL(ata_pci_device_resume);
+EXPORT_SYMBOL_GPL(ata_pci_default_filter);
+EXPORT_SYMBOL_GPL(ata_pci_clear_simplex);
+#endif /* CONFIG_PCI */
+
+EXPORT_SYMBOL_GPL(ata_scsi_device_suspend);
+EXPORT_SYMBOL_GPL(ata_scsi_device_resume);
+
+EXPORT_SYMBOL_GPL(ata_eng_timeout);
+EXPORT_SYMBOL_GPL(ata_port_schedule_eh);
+EXPORT_SYMBOL_GPL(ata_port_abort);
+EXPORT_SYMBOL_GPL(ata_port_freeze);
+EXPORT_SYMBOL_GPL(ata_eh_freeze_port);
+EXPORT_SYMBOL_GPL(ata_eh_thaw_port);
+EXPORT_SYMBOL_GPL(ata_eh_qc_complete);
+EXPORT_SYMBOL_GPL(ata_eh_qc_retry);
+EXPORT_SYMBOL_GPL(ata_do_eh);
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
new file mode 100644
index 00000000000..02b2b2787d9
--- /dev/null
+++ b/drivers/ata/libata-eh.c
@@ -0,0 +1,2249 @@
+/*
+ * libata-eh.c - libata error handling
+ *
+ * Maintained by: Jeff Garzik <jgarzik@pobox.com>
+ * Please ALWAYS copy linux-ide@vger.kernel.org
+ * on emails.
+ *
+ * Copyright 2006 Tejun Heo <htejun@gmail.com>
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139,
+ * USA.
+ *
+ *
+ * libata documentation is available via 'make {ps|pdf}docs',
+ * as Documentation/DocBook/libata.*
+ *
+ * Hardware documentation available from http://www.t13.org/ and
+ * http://www.sata-io.org/
+ *
+ */
+
+#include <linux/kernel.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_eh.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_cmnd.h>
+#include "../scsi/scsi_transport_api.h"
+
+#include <linux/libata.h>
+
+#include "libata.h"
+
+static void __ata_port_freeze(struct ata_port *ap);
+static void ata_eh_finish(struct ata_port *ap);
+static void ata_eh_handle_port_suspend(struct ata_port *ap);
+static void ata_eh_handle_port_resume(struct ata_port *ap);
+
+static void ata_ering_record(struct ata_ering *ering, int is_io,
+ unsigned int err_mask)
+{
+ struct ata_ering_entry *ent;
+
+ WARN_ON(!err_mask);
+
+ ering->cursor++;
+ ering->cursor %= ATA_ERING_SIZE;
+
+ ent = &ering->ring[ering->cursor];
+ ent->is_io = is_io;
+ ent->err_mask = err_mask;
+ ent->timestamp = get_jiffies_64();
+}
+
+static struct ata_ering_entry * ata_ering_top(struct ata_ering *ering)
+{
+ struct ata_ering_entry *ent = &ering->ring[ering->cursor];
+ if (!ent->err_mask)
+ return NULL;
+ return ent;
+}
+
+static int ata_ering_map(struct ata_ering *ering,
+ int (*map_fn)(struct ata_ering_entry *, void *),
+ void *arg)
+{
+ int idx, rc = 0;
+ struct ata_ering_entry *ent;
+
+ idx = ering->cursor;
+ do {
+ ent = &ering->ring[idx];
+ if (!ent->err_mask)
+ break;
+ rc = map_fn(ent, arg);
+ if (rc)
+ break;
+ idx = (idx - 1 + ATA_ERING_SIZE) % ATA_ERING_SIZE;
+ } while (idx != ering->cursor);
+
+ return rc;
+}
+
+static unsigned int ata_eh_dev_action(struct ata_device *dev)
+{
+ struct ata_eh_context *ehc = &dev->ap->eh_context;
+
+ return ehc->i.action | ehc->i.dev_action[dev->devno];
+}
+
+static void ata_eh_clear_action(struct ata_device *dev,
+ struct ata_eh_info *ehi, unsigned int action)
+{
+ int i;
+
+ if (!dev) {
+ ehi->action &= ~action;
+ for (i = 0; i < ATA_MAX_DEVICES; i++)
+ ehi->dev_action[i] &= ~action;
+ } else {
+ /* doesn't make sense for port-wide EH actions */
+ WARN_ON(!(action & ATA_EH_PERDEV_MASK));
+
+ /* break ehi->action into ehi->dev_action */
+ if (ehi->action & action) {
+ for (i = 0; i < ATA_MAX_DEVICES; i++)
+ ehi->dev_action[i] |= ehi->action & action;
+ ehi->action &= ~action;
+ }
+
+ /* turn off the specified per-dev action */
+ ehi->dev_action[dev->devno] &= ~action;
+ }
+}
+
+/**
+ * ata_scsi_timed_out - SCSI layer time out callback
+ * @cmd: timed out SCSI command
+ *
+ * Handles SCSI layer timeout. We race with normal completion of
+ * the qc for @cmd. If the qc is already gone, we lose and let
+ * the scsi command finish (EH_HANDLED). Otherwise, the qc has
+ * timed out and EH should be invoked. Prevent ata_qc_complete()
+ * from finishing it by setting EH_SCHEDULED and return
+ * EH_NOT_HANDLED.
+ *
+ * TODO: kill this function once old EH is gone.
+ *
+ * LOCKING:
+ * Called from timer context
+ *
+ * RETURNS:
+ * EH_HANDLED or EH_NOT_HANDLED
+ */
+enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd)
+{
+ struct Scsi_Host *host = cmd->device->host;
+ struct ata_port *ap = ata_shost_to_port(host);
+ unsigned long flags;
+ struct ata_queued_cmd *qc;
+ enum scsi_eh_timer_return ret;
+
+ DPRINTK("ENTER\n");
+
+ if (ap->ops->error_handler) {
+ ret = EH_NOT_HANDLED;
+ goto out;
+ }
+
+ ret = EH_HANDLED;
+ spin_lock_irqsave(ap->lock, flags);
+ qc = ata_qc_from_tag(ap, ap->active_tag);
+ if (qc) {
+ WARN_ON(qc->scsicmd != cmd);
+ qc->flags |= ATA_QCFLAG_EH_SCHEDULED;
+ qc->err_mask |= AC_ERR_TIMEOUT;
+ ret = EH_NOT_HANDLED;
+ }
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ out:
+ DPRINTK("EXIT, ret=%d\n", ret);
+ return ret;
+}
+
+/**
+ * ata_scsi_error - SCSI layer error handler callback
+ * @host: SCSI host on which error occurred
+ *
+ * Handles SCSI-layer-thrown error events.
+ *
+ * LOCKING:
+ * Inherited from SCSI layer (none, can sleep)
+ *
+ * RETURNS:
+ * Zero.
+ */
+void ata_scsi_error(struct Scsi_Host *host)
+{
+ struct ata_port *ap = ata_shost_to_port(host);
+ int i, repeat_cnt = ATA_EH_MAX_REPEAT;
+ unsigned long flags;
+
+ DPRINTK("ENTER\n");
+
+ /* synchronize with port task */
+ ata_port_flush_task(ap);
+
+ /* synchronize with host lock and sort out timeouts */
+
+ /* For new EH, all qcs are finished in one of three ways -
+ * normal completion, error completion, and SCSI timeout.
+ * Both cmpletions can race against SCSI timeout. When normal
+ * completion wins, the qc never reaches EH. When error
+ * completion wins, the qc has ATA_QCFLAG_FAILED set.
+ *
+ * When SCSI timeout wins, things are a bit more complex.
+ * Normal or error completion can occur after the timeout but
+ * before this point. In such cases, both types of
+ * completions are honored. A scmd is determined to have
+ * timed out iff its associated qc is active and not failed.
+ */
+ if (ap->ops->error_handler) {
+ struct scsi_cmnd *scmd, *tmp;
+ int nr_timedout = 0;
+
+ spin_lock_irqsave(ap->lock, flags);
+
+ list_for_each_entry_safe(scmd, tmp, &host->eh_cmd_q, eh_entry) {
+ struct ata_queued_cmd *qc;
+
+ for (i = 0; i < ATA_MAX_QUEUE; i++) {
+ qc = __ata_qc_from_tag(ap, i);
+ if (qc->flags & ATA_QCFLAG_ACTIVE &&
+ qc->scsicmd == scmd)
+ break;
+ }
+
+ if (i < ATA_MAX_QUEUE) {
+ /* the scmd has an associated qc */
+ if (!(qc->flags & ATA_QCFLAG_FAILED)) {
+ /* which hasn't failed yet, timeout */
+ qc->err_mask |= AC_ERR_TIMEOUT;
+ qc->flags |= ATA_QCFLAG_FAILED;
+ nr_timedout++;
+ }
+ } else {
+ /* Normal completion occurred after
+ * SCSI timeout but before this point.
+ * Successfully complete it.
+ */
+ scmd->retries = scmd->allowed;
+ scsi_eh_finish_cmd(scmd, &ap->eh_done_q);
+ }
+ }
+
+ /* If we have timed out qcs. They belong to EH from
+ * this point but the state of the controller is
+ * unknown. Freeze the port to make sure the IRQ
+ * handler doesn't diddle with those qcs. This must
+ * be done atomically w.r.t. setting QCFLAG_FAILED.
+ */
+ if (nr_timedout)
+ __ata_port_freeze(ap);
+
+ spin_unlock_irqrestore(ap->lock, flags);
+ } else
+ spin_unlock_wait(ap->lock);
+
+ repeat:
+ /* invoke error handler */
+ if (ap->ops->error_handler) {
+ /* process port resume request */
+ ata_eh_handle_port_resume(ap);
+
+ /* fetch & clear EH info */
+ spin_lock_irqsave(ap->lock, flags);
+
+ memset(&ap->eh_context, 0, sizeof(ap->eh_context));
+ ap->eh_context.i = ap->eh_info;
+ memset(&ap->eh_info, 0, sizeof(ap->eh_info));
+
+ ap->pflags |= ATA_PFLAG_EH_IN_PROGRESS;
+ ap->pflags &= ~ATA_PFLAG_EH_PENDING;
+
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ /* invoke EH, skip if unloading or suspended */
+ if (!(ap->pflags & (ATA_PFLAG_UNLOADING | ATA_PFLAG_SUSPENDED)))
+ ap->ops->error_handler(ap);
+ else
+ ata_eh_finish(ap);
+
+ /* process port suspend request */
+ ata_eh_handle_port_suspend(ap);
+
+ /* Exception might have happend after ->error_handler
+ * recovered the port but before this point. Repeat
+ * EH in such case.
+ */
+ spin_lock_irqsave(ap->lock, flags);
+
+ if (ap->pflags & ATA_PFLAG_EH_PENDING) {
+ if (--repeat_cnt) {
+ ata_port_printk(ap, KERN_INFO,
+ "EH pending after completion, "
+ "repeating EH (cnt=%d)\n", repeat_cnt);
+ spin_unlock_irqrestore(ap->lock, flags);
+ goto repeat;
+ }
+ ata_port_printk(ap, KERN_ERR, "EH pending after %d "
+ "tries, giving up\n", ATA_EH_MAX_REPEAT);
+ }
+
+ /* this run is complete, make sure EH info is clear */
+ memset(&ap->eh_info, 0, sizeof(ap->eh_info));
+
+ /* Clear host_eh_scheduled while holding ap->lock such
+ * that if exception occurs after this point but
+ * before EH completion, SCSI midlayer will
+ * re-initiate EH.
+ */
+ host->host_eh_scheduled = 0;
+
+ spin_unlock_irqrestore(ap->lock, flags);
+ } else {
+ WARN_ON(ata_qc_from_tag(ap, ap->active_tag) == NULL);
+ ap->ops->eng_timeout(ap);
+ }
+
+ /* finish or retry handled scmd's and clean up */
+ WARN_ON(host->host_failed || !list_empty(&host->eh_cmd_q));
+
+ scsi_eh_flush_done_q(&ap->eh_done_q);
+
+ /* clean up */
+ spin_lock_irqsave(ap->lock, flags);
+
+ if (ap->pflags & ATA_PFLAG_LOADING)
+ ap->pflags &= ~ATA_PFLAG_LOADING;
+ else if (ap->pflags & ATA_PFLAG_SCSI_HOTPLUG)
+ queue_work(ata_aux_wq, &ap->hotplug_task);
+
+ if (ap->pflags & ATA_PFLAG_RECOVERED)
+ ata_port_printk(ap, KERN_INFO, "EH complete\n");
+
+ ap->pflags &= ~(ATA_PFLAG_SCSI_HOTPLUG | ATA_PFLAG_RECOVERED);
+
+ /* tell wait_eh that we're done */
+ ap->pflags &= ~ATA_PFLAG_EH_IN_PROGRESS;
+ wake_up_all(&ap->eh_wait_q);
+
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ DPRINTK("EXIT\n");
+}
+
+/**
+ * ata_port_wait_eh - Wait for the currently pending EH to complete
+ * @ap: Port to wait EH for
+ *
+ * Wait until the currently pending EH is complete.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ */
+void ata_port_wait_eh(struct ata_port *ap)
+{
+ unsigned long flags;
+ DEFINE_WAIT(wait);
+
+ retry:
+ spin_lock_irqsave(ap->lock, flags);
+
+ while (ap->pflags & (ATA_PFLAG_EH_PENDING | ATA_PFLAG_EH_IN_PROGRESS)) {
+ prepare_to_wait(&ap->eh_wait_q, &wait, TASK_UNINTERRUPTIBLE);
+ spin_unlock_irqrestore(ap->lock, flags);
+ schedule();
+ spin_lock_irqsave(ap->lock, flags);
+ }
+ finish_wait(&ap->eh_wait_q, &wait);
+
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ /* make sure SCSI EH is complete */
+ if (scsi_host_in_recovery(ap->scsi_host)) {
+ msleep(10);
+ goto retry;
+ }
+}
+
+/**
+ * ata_qc_timeout - Handle timeout of queued command
+ * @qc: Command that timed out
+ *
+ * Some part of the kernel (currently, only the SCSI layer)
+ * has noticed that the active command on port @ap has not
+ * completed after a specified length of time. Handle this
+ * condition by disabling DMA (if necessary) and completing
+ * transactions, with error if necessary.
+ *
+ * This also handles the case of the "lost interrupt", where
+ * for some reason (possibly hardware bug, possibly driver bug)
+ * an interrupt was not delivered to the driver, even though the
+ * transaction completed successfully.
+ *
+ * TODO: kill this function once old EH is gone.
+ *
+ * LOCKING:
+ * Inherited from SCSI layer (none, can sleep)
+ */
+static void ata_qc_timeout(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ u8 host_stat = 0, drv_stat;
+ unsigned long flags;
+
+ DPRINTK("ENTER\n");
+
+ ap->hsm_task_state = HSM_ST_IDLE;
+
+ spin_lock_irqsave(ap->lock, flags);
+
+ switch (qc->tf.protocol) {
+
+ case ATA_PROT_DMA:
+ case ATA_PROT_ATAPI_DMA:
+ host_stat = ap->ops->bmdma_status(ap);
+
+ /* before we do anything else, clear DMA-Start bit */
+ ap->ops->bmdma_stop(qc);
+
+ /* fall through */
+
+ default:
+ ata_altstatus(ap);
+ drv_stat = ata_chk_status(ap);
+
+ /* ack bmdma irq events */
+ ap->ops->irq_clear(ap);
+
+ ata_dev_printk(qc->dev, KERN_ERR, "command 0x%x timeout, "
+ "stat 0x%x host_stat 0x%x\n",
+ qc->tf.command, drv_stat, host_stat);
+
+ /* complete taskfile transaction */
+ qc->err_mask |= AC_ERR_TIMEOUT;
+ break;
+ }
+
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ ata_eh_qc_complete(qc);
+
+ DPRINTK("EXIT\n");
+}
+
+/**
+ * ata_eng_timeout - Handle timeout of queued command
+ * @ap: Port on which timed-out command is active
+ *
+ * Some part of the kernel (currently, only the SCSI layer)
+ * has noticed that the active command on port @ap has not
+ * completed after a specified length of time. Handle this
+ * condition by disabling DMA (if necessary) and completing
+ * transactions, with error if necessary.
+ *
+ * This also handles the case of the "lost interrupt", where
+ * for some reason (possibly hardware bug, possibly driver bug)
+ * an interrupt was not delivered to the driver, even though the
+ * transaction completed successfully.
+ *
+ * TODO: kill this function once old EH is gone.
+ *
+ * LOCKING:
+ * Inherited from SCSI layer (none, can sleep)
+ */
+void ata_eng_timeout(struct ata_port *ap)
+{
+ DPRINTK("ENTER\n");
+
+ ata_qc_timeout(ata_qc_from_tag(ap, ap->active_tag));
+
+ DPRINTK("EXIT\n");
+}
+
+/**
+ * ata_qc_schedule_eh - schedule qc for error handling
+ * @qc: command to schedule error handling for
+ *
+ * Schedule error handling for @qc. EH will kick in as soon as
+ * other commands are drained.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ */
+void ata_qc_schedule_eh(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+
+ WARN_ON(!ap->ops->error_handler);
+
+ qc->flags |= ATA_QCFLAG_FAILED;
+ qc->ap->pflags |= ATA_PFLAG_EH_PENDING;
+
+ /* The following will fail if timeout has already expired.
+ * ata_scsi_error() takes care of such scmds on EH entry.
+ * Note that ATA_QCFLAG_FAILED is unconditionally set after
+ * this function completes.
+ */
+ scsi_req_abort_cmd(qc->scsicmd);
+}
+
+/**
+ * ata_port_schedule_eh - schedule error handling without a qc
+ * @ap: ATA port to schedule EH for
+ *
+ * Schedule error handling for @ap. EH will kick in as soon as
+ * all commands are drained.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ */
+void ata_port_schedule_eh(struct ata_port *ap)
+{
+ WARN_ON(!ap->ops->error_handler);
+
+ ap->pflags |= ATA_PFLAG_EH_PENDING;
+ scsi_schedule_eh(ap->scsi_host);
+
+ DPRINTK("port EH scheduled\n");
+}
+
+/**
+ * ata_port_abort - abort all qc's on the port
+ * @ap: ATA port to abort qc's for
+ *
+ * Abort all active qc's of @ap and schedule EH.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ *
+ * RETURNS:
+ * Number of aborted qc's.
+ */
+int ata_port_abort(struct ata_port *ap)
+{
+ int tag, nr_aborted = 0;
+
+ WARN_ON(!ap->ops->error_handler);
+
+ for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
+ struct ata_queued_cmd *qc = ata_qc_from_tag(ap, tag);
+
+ if (qc) {
+ qc->flags |= ATA_QCFLAG_FAILED;
+ ata_qc_complete(qc);
+ nr_aborted++;
+ }
+ }
+
+ if (!nr_aborted)
+ ata_port_schedule_eh(ap);
+
+ return nr_aborted;
+}
+
+/**
+ * __ata_port_freeze - freeze port
+ * @ap: ATA port to freeze
+ *
+ * This function is called when HSM violation or some other
+ * condition disrupts normal operation of the port. Frozen port
+ * is not allowed to perform any operation until the port is
+ * thawed, which usually follows a successful reset.
+ *
+ * ap->ops->freeze() callback can be used for freezing the port
+ * hardware-wise (e.g. mask interrupt and stop DMA engine). If a
+ * port cannot be frozen hardware-wise, the interrupt handler
+ * must ack and clear interrupts unconditionally while the port
+ * is frozen.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ */
+static void __ata_port_freeze(struct ata_port *ap)
+{
+ WARN_ON(!ap->ops->error_handler);
+
+ if (ap->ops->freeze)
+ ap->ops->freeze(ap);
+
+ ap->pflags |= ATA_PFLAG_FROZEN;
+
+ DPRINTK("ata%u port frozen\n", ap->id);
+}
+
+/**
+ * ata_port_freeze - abort & freeze port
+ * @ap: ATA port to freeze
+ *
+ * Abort and freeze @ap.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ *
+ * RETURNS:
+ * Number of aborted commands.
+ */
+int ata_port_freeze(struct ata_port *ap)
+{
+ int nr_aborted;
+
+ WARN_ON(!ap->ops->error_handler);
+
+ nr_aborted = ata_port_abort(ap);
+ __ata_port_freeze(ap);
+
+ return nr_aborted;
+}
+
+/**
+ * ata_eh_freeze_port - EH helper to freeze port
+ * @ap: ATA port to freeze
+ *
+ * Freeze @ap.
+ *
+ * LOCKING:
+ * None.
+ */
+void ata_eh_freeze_port(struct ata_port *ap)
+{
+ unsigned long flags;
+
+ if (!ap->ops->error_handler)
+ return;
+
+ spin_lock_irqsave(ap->lock, flags);
+ __ata_port_freeze(ap);
+ spin_unlock_irqrestore(ap->lock, flags);
+}
+
+/**
+ * ata_port_thaw_port - EH helper to thaw port
+ * @ap: ATA port to thaw
+ *
+ * Thaw frozen port @ap.
+ *
+ * LOCKING:
+ * None.
+ */
+void ata_eh_thaw_port(struct ata_port *ap)
+{
+ unsigned long flags;
+
+ if (!ap->ops->error_handler)
+ return;
+
+ spin_lock_irqsave(ap->lock, flags);
+
+ ap->pflags &= ~ATA_PFLAG_FROZEN;
+
+ if (ap->ops->thaw)
+ ap->ops->thaw(ap);
+
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ DPRINTK("ata%u port thawed\n", ap->id);
+}
+
+static void ata_eh_scsidone(struct scsi_cmnd *scmd)
+{
+ /* nada */
+}
+
+static void __ata_eh_qc_complete(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct scsi_cmnd *scmd = qc->scsicmd;
+ unsigned long flags;
+
+ spin_lock_irqsave(ap->lock, flags);
+ qc->scsidone = ata_eh_scsidone;
+ __ata_qc_complete(qc);
+ WARN_ON(ata_tag_valid(qc->tag));
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ scsi_eh_finish_cmd(scmd, &ap->eh_done_q);
+}
+
+/**
+ * ata_eh_qc_complete - Complete an active ATA command from EH
+ * @qc: Command to complete
+ *
+ * Indicate to the mid and upper layers that an ATA command has
+ * completed. To be used from EH.
+ */
+void ata_eh_qc_complete(struct ata_queued_cmd *qc)
+{
+ struct scsi_cmnd *scmd = qc->scsicmd;
+ scmd->retries = scmd->allowed;
+ __ata_eh_qc_complete(qc);
+}
+
+/**
+ * ata_eh_qc_retry - Tell midlayer to retry an ATA command after EH
+ * @qc: Command to retry
+ *
+ * Indicate to the mid and upper layers that an ATA command
+ * should be retried. To be used from EH.
+ *
+ * SCSI midlayer limits the number of retries to scmd->allowed.
+ * scmd->retries is decremented for commands which get retried
+ * due to unrelated failures (qc->err_mask is zero).
+ */
+void ata_eh_qc_retry(struct ata_queued_cmd *qc)
+{
+ struct scsi_cmnd *scmd = qc->scsicmd;
+ if (!qc->err_mask && scmd->retries)
+ scmd->retries--;
+ __ata_eh_qc_complete(qc);
+}
+
+/**
+ * ata_eh_detach_dev - detach ATA device
+ * @dev: ATA device to detach
+ *
+ * Detach @dev.
+ *
+ * LOCKING:
+ * None.
+ */
+static void ata_eh_detach_dev(struct ata_device *dev)
+{
+ struct ata_port *ap = dev->ap;
+ unsigned long flags;
+
+ ata_dev_disable(dev);
+
+ spin_lock_irqsave(ap->lock, flags);
+
+ dev->flags &= ~ATA_DFLAG_DETACH;
+
+ if (ata_scsi_offline_dev(dev)) {
+ dev->flags |= ATA_DFLAG_DETACHED;
+ ap->pflags |= ATA_PFLAG_SCSI_HOTPLUG;
+ }
+
+ /* clear per-dev EH actions */
+ ata_eh_clear_action(dev, &ap->eh_info, ATA_EH_PERDEV_MASK);
+ ata_eh_clear_action(dev, &ap->eh_context.i, ATA_EH_PERDEV_MASK);
+
+ spin_unlock_irqrestore(ap->lock, flags);
+}
+
+/**
+ * ata_eh_about_to_do - about to perform eh_action
+ * @ap: target ATA port
+ * @dev: target ATA dev for per-dev action (can be NULL)
+ * @action: action about to be performed
+ *
+ * Called just before performing EH actions to clear related bits
+ * in @ap->eh_info such that eh actions are not unnecessarily
+ * repeated.
+ *
+ * LOCKING:
+ * None.
+ */
+static void ata_eh_about_to_do(struct ata_port *ap, struct ata_device *dev,
+ unsigned int action)
+{
+ unsigned long flags;
+ struct ata_eh_info *ehi = &ap->eh_info;
+ struct ata_eh_context *ehc = &ap->eh_context;
+
+ spin_lock_irqsave(ap->lock, flags);
+
+ /* Reset is represented by combination of actions and EHI
+ * flags. Suck in all related bits before clearing eh_info to
+ * avoid losing requested action.
+ */
+ if (action & ATA_EH_RESET_MASK) {
+ ehc->i.action |= ehi->action & ATA_EH_RESET_MASK;
+ ehc->i.flags |= ehi->flags & ATA_EHI_RESET_MODIFIER_MASK;
+
+ /* make sure all reset actions are cleared & clear EHI flags */
+ action |= ATA_EH_RESET_MASK;
+ ehi->flags &= ~ATA_EHI_RESET_MODIFIER_MASK;
+ }
+
+ ata_eh_clear_action(dev, ehi, action);
+
+ if (!(ehc->i.flags & ATA_EHI_QUIET))
+ ap->pflags |= ATA_PFLAG_RECOVERED;
+
+ spin_unlock_irqrestore(ap->lock, flags);
+}
+
+/**
+ * ata_eh_done - EH action complete
+ * @ap: target ATA port
+ * @dev: target ATA dev for per-dev action (can be NULL)
+ * @action: action just completed
+ *
+ * Called right after performing EH actions to clear related bits
+ * in @ap->eh_context.
+ *
+ * LOCKING:
+ * None.
+ */
+static void ata_eh_done(struct ata_port *ap, struct ata_device *dev,
+ unsigned int action)
+{
+ /* if reset is complete, clear all reset actions & reset modifier */
+ if (action & ATA_EH_RESET_MASK) {
+ action |= ATA_EH_RESET_MASK;
+ ap->eh_context.i.flags &= ~ATA_EHI_RESET_MODIFIER_MASK;
+ }
+
+ ata_eh_clear_action(dev, &ap->eh_context.i, action);
+}
+
+/**
+ * ata_err_string - convert err_mask to descriptive string
+ * @err_mask: error mask to convert to string
+ *
+ * Convert @err_mask to descriptive string. Errors are
+ * prioritized according to severity and only the most severe
+ * error is reported.
+ *
+ * LOCKING:
+ * None.
+ *
+ * RETURNS:
+ * Descriptive string for @err_mask
+ */
+static const char * ata_err_string(unsigned int err_mask)
+{
+ if (err_mask & AC_ERR_HOST_BUS)
+ return "host bus error";
+ if (err_mask & AC_ERR_ATA_BUS)
+ return "ATA bus error";
+ if (err_mask & AC_ERR_TIMEOUT)
+ return "timeout";
+ if (err_mask & AC_ERR_HSM)
+ return "HSM violation";
+ if (err_mask & AC_ERR_SYSTEM)
+ return "internal error";
+ if (err_mask & AC_ERR_MEDIA)
+ return "media error";
+ if (err_mask & AC_ERR_INVALID)
+ return "invalid argument";
+ if (err_mask & AC_ERR_DEV)
+ return "device error";
+ return "unknown error";
+}
+
+/**
+ * ata_read_log_page - read a specific log page
+ * @dev: target device
+ * @page: page to read
+ * @buf: buffer to store read page
+ * @sectors: number of sectors to read
+ *
+ * Read log page using READ_LOG_EXT command.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, AC_ERR_* mask otherwise.
+ */
+static unsigned int ata_read_log_page(struct ata_device *dev,
+ u8 page, void *buf, unsigned int sectors)
+{
+ struct ata_taskfile tf;
+ unsigned int err_mask;
+
+ DPRINTK("read log page - page %d\n", page);
+
+ ata_tf_init(dev, &tf);
+ tf.command = ATA_CMD_READ_LOG_EXT;
+ tf.lbal = page;
+ tf.nsect = sectors;
+ tf.hob_nsect = sectors >> 8;
+ tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_LBA48 | ATA_TFLAG_DEVICE;
+ tf.protocol = ATA_PROT_PIO;
+
+ err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE,
+ buf, sectors * ATA_SECT_SIZE);
+
+ DPRINTK("EXIT, err_mask=%x\n", err_mask);
+ return err_mask;
+}
+
+/**
+ * ata_eh_read_log_10h - Read log page 10h for NCQ error details
+ * @dev: Device to read log page 10h from
+ * @tag: Resulting tag of the failed command
+ * @tf: Resulting taskfile registers of the failed command
+ *
+ * Read log page 10h to obtain NCQ error details and clear error
+ * condition.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, -errno otherwise.
+ */
+static int ata_eh_read_log_10h(struct ata_device *dev,
+ int *tag, struct ata_taskfile *tf)
+{
+ u8 *buf = dev->ap->sector_buf;
+ unsigned int err_mask;
+ u8 csum;
+ int i;
+
+ err_mask = ata_read_log_page(dev, ATA_LOG_SATA_NCQ, buf, 1);
+ if (err_mask)
+ return -EIO;
+
+ csum = 0;
+ for (i = 0; i < ATA_SECT_SIZE; i++)
+ csum += buf[i];
+ if (csum)
+ ata_dev_printk(dev, KERN_WARNING,
+ "invalid checksum 0x%x on log page 10h\n", csum);
+
+ if (buf[0] & 0x80)
+ return -ENOENT;
+
+ *tag = buf[0] & 0x1f;
+
+ tf->command = buf[2];
+ tf->feature = buf[3];
+ tf->lbal = buf[4];
+ tf->lbam = buf[5];
+ tf->lbah = buf[6];
+ tf->device = buf[7];
+ tf->hob_lbal = buf[8];
+ tf->hob_lbam = buf[9];
+ tf->hob_lbah = buf[10];
+ tf->nsect = buf[12];
+ tf->hob_nsect = buf[13];
+
+ return 0;
+}
+
+/**
+ * atapi_eh_request_sense - perform ATAPI REQUEST_SENSE
+ * @dev: device to perform REQUEST_SENSE to
+ * @sense_buf: result sense data buffer (SCSI_SENSE_BUFFERSIZE bytes long)
+ *
+ * Perform ATAPI REQUEST_SENSE after the device reported CHECK
+ * SENSE. This function is EH helper.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, AC_ERR_* mask on failure
+ */
+static unsigned int atapi_eh_request_sense(struct ata_device *dev,
+ unsigned char *sense_buf)
+{
+ struct ata_port *ap = dev->ap;
+ struct ata_taskfile tf;
+ u8 cdb[ATAPI_CDB_LEN];
+
+ DPRINTK("ATAPI request sense\n");
+
+ ata_tf_init(dev, &tf);
+
+ /* FIXME: is this needed? */
+ memset(sense_buf, 0, SCSI_SENSE_BUFFERSIZE);
+
+ /* XXX: why tf_read here? */
+ ap->ops->tf_read(ap, &tf);
+
+ /* fill these in, for the case where they are -not- overwritten */
+ sense_buf[0] = 0x70;
+ sense_buf[2] = tf.feature >> 4;
+
+ memset(cdb, 0, ATAPI_CDB_LEN);
+ cdb[0] = REQUEST_SENSE;
+ cdb[4] = SCSI_SENSE_BUFFERSIZE;
+
+ tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
+ tf.command = ATA_CMD_PACKET;
+
+ /* is it pointless to prefer PIO for "safety reasons"? */
+ if (ap->flags & ATA_FLAG_PIO_DMA) {
+ tf.protocol = ATA_PROT_ATAPI_DMA;
+ tf.feature |= ATAPI_PKT_DMA;
+ } else {
+ tf.protocol = ATA_PROT_ATAPI;
+ tf.lbam = (8 * 1024) & 0xff;
+ tf.lbah = (8 * 1024) >> 8;
+ }
+
+ return ata_exec_internal(dev, &tf, cdb, DMA_FROM_DEVICE,
+ sense_buf, SCSI_SENSE_BUFFERSIZE);
+}
+
+/**
+ * ata_eh_analyze_serror - analyze SError for a failed port
+ * @ap: ATA port to analyze SError for
+ *
+ * Analyze SError if available and further determine cause of
+ * failure.
+ *
+ * LOCKING:
+ * None.
+ */
+static void ata_eh_analyze_serror(struct ata_port *ap)
+{
+ struct ata_eh_context *ehc = &ap->eh_context;
+ u32 serror = ehc->i.serror;
+ unsigned int err_mask = 0, action = 0;
+
+ if (serror & SERR_PERSISTENT) {
+ err_mask |= AC_ERR_ATA_BUS;
+ action |= ATA_EH_HARDRESET;
+ }
+ if (serror &
+ (SERR_DATA_RECOVERED | SERR_COMM_RECOVERED | SERR_DATA)) {
+ err_mask |= AC_ERR_ATA_BUS;
+ action |= ATA_EH_SOFTRESET;
+ }
+ if (serror & SERR_PROTOCOL) {
+ err_mask |= AC_ERR_HSM;
+ action |= ATA_EH_SOFTRESET;
+ }
+ if (serror & SERR_INTERNAL) {
+ err_mask |= AC_ERR_SYSTEM;
+ action |= ATA_EH_SOFTRESET;
+ }
+ if (serror & (SERR_PHYRDY_CHG | SERR_DEV_XCHG))
+ ata_ehi_hotplugged(&ehc->i);
+
+ ehc->i.err_mask |= err_mask;
+ ehc->i.action |= action;
+}
+
+/**
+ * ata_eh_analyze_ncq_error - analyze NCQ error
+ * @ap: ATA port to analyze NCQ error for
+ *
+ * Read log page 10h, determine the offending qc and acquire
+ * error status TF. For NCQ device errors, all LLDDs have to do
+ * is setting AC_ERR_DEV in ehi->err_mask. This function takes
+ * care of the rest.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ */
+static void ata_eh_analyze_ncq_error(struct ata_port *ap)
+{
+ struct ata_eh_context *ehc = &ap->eh_context;
+ struct ata_device *dev = ap->device;
+ struct ata_queued_cmd *qc;
+ struct ata_taskfile tf;
+ int tag, rc;
+
+ /* if frozen, we can't do much */
+ if (ap->pflags & ATA_PFLAG_FROZEN)
+ return;
+
+ /* is it NCQ device error? */
+ if (!ap->sactive || !(ehc->i.err_mask & AC_ERR_DEV))
+ return;
+
+ /* has LLDD analyzed already? */
+ for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
+ qc = __ata_qc_from_tag(ap, tag);
+
+ if (!(qc->flags & ATA_QCFLAG_FAILED))
+ continue;
+
+ if (qc->err_mask)
+ return;
+ }
+
+ /* okay, this error is ours */
+ rc = ata_eh_read_log_10h(dev, &tag, &tf);
+ if (rc) {
+ ata_port_printk(ap, KERN_ERR, "failed to read log page 10h "
+ "(errno=%d)\n", rc);
+ return;
+ }
+
+ if (!(ap->sactive & (1 << tag))) {
+ ata_port_printk(ap, KERN_ERR, "log page 10h reported "
+ "inactive tag %d\n", tag);
+ return;
+ }
+
+ /* we've got the perpetrator, condemn it */
+ qc = __ata_qc_from_tag(ap, tag);
+ memcpy(&qc->result_tf, &tf, sizeof(tf));
+ qc->err_mask |= AC_ERR_DEV;
+ ehc->i.err_mask &= ~AC_ERR_DEV;
+}
+
+/**
+ * ata_eh_analyze_tf - analyze taskfile of a failed qc
+ * @qc: qc to analyze
+ * @tf: Taskfile registers to analyze
+ *
+ * Analyze taskfile of @qc and further determine cause of
+ * failure. This function also requests ATAPI sense data if
+ * avaliable.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ *
+ * RETURNS:
+ * Determined recovery action
+ */
+static unsigned int ata_eh_analyze_tf(struct ata_queued_cmd *qc,
+ const struct ata_taskfile *tf)
+{
+ unsigned int tmp, action = 0;
+ u8 stat = tf->command, err = tf->feature;
+
+ if ((stat & (ATA_BUSY | ATA_DRQ | ATA_DRDY)) != ATA_DRDY) {
+ qc->err_mask |= AC_ERR_HSM;
+ return ATA_EH_SOFTRESET;
+ }
+
+ if (!(qc->err_mask & AC_ERR_DEV))
+ return 0;
+
+ switch (qc->dev->class) {
+ case ATA_DEV_ATA:
+ if (err & ATA_ICRC)
+ qc->err_mask |= AC_ERR_ATA_BUS;
+ if (err & ATA_UNC)
+ qc->err_mask |= AC_ERR_MEDIA;
+ if (err & ATA_IDNF)
+ qc->err_mask |= AC_ERR_INVALID;
+ break;
+
+ case ATA_DEV_ATAPI:
+ tmp = atapi_eh_request_sense(qc->dev,
+ qc->scsicmd->sense_buffer);
+ if (!tmp) {
+ /* ATA_QCFLAG_SENSE_VALID is used to tell
+ * atapi_qc_complete() that sense data is
+ * already valid.
+ *
+ * TODO: interpret sense data and set
+ * appropriate err_mask.
+ */
+ qc->flags |= ATA_QCFLAG_SENSE_VALID;
+ } else
+ qc->err_mask |= tmp;
+ }
+
+ if (qc->err_mask & (AC_ERR_HSM | AC_ERR_TIMEOUT | AC_ERR_ATA_BUS))
+ action |= ATA_EH_SOFTRESET;
+
+ return action;
+}
+
+static int ata_eh_categorize_ering_entry(struct ata_ering_entry *ent)
+{
+ if (ent->err_mask & (AC_ERR_ATA_BUS | AC_ERR_TIMEOUT))
+ return 1;
+
+ if (ent->is_io) {
+ if (ent->err_mask & AC_ERR_HSM)
+ return 1;
+ if ((ent->err_mask &
+ (AC_ERR_DEV|AC_ERR_MEDIA|AC_ERR_INVALID)) == AC_ERR_DEV)
+ return 2;
+ }
+
+ return 0;
+}
+
+struct speed_down_needed_arg {
+ u64 since;
+ int nr_errors[3];
+};
+
+static int speed_down_needed_cb(struct ata_ering_entry *ent, void *void_arg)
+{
+ struct speed_down_needed_arg *arg = void_arg;
+
+ if (ent->timestamp < arg->since)
+ return -1;
+
+ arg->nr_errors[ata_eh_categorize_ering_entry(ent)]++;
+ return 0;
+}
+
+/**
+ * ata_eh_speed_down_needed - Determine wheter speed down is necessary
+ * @dev: Device of interest
+ *
+ * This function examines error ring of @dev and determines
+ * whether speed down is necessary. Speed down is necessary if
+ * there have been more than 3 of Cat-1 errors or 10 of Cat-2
+ * errors during last 15 minutes.
+ *
+ * Cat-1 errors are ATA_BUS, TIMEOUT for any command and HSM
+ * violation for known supported commands.
+ *
+ * Cat-2 errors are unclassified DEV error for known supported
+ * command.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ *
+ * RETURNS:
+ * 1 if speed down is necessary, 0 otherwise
+ */
+static int ata_eh_speed_down_needed(struct ata_device *dev)
+{
+ const u64 interval = 15LLU * 60 * HZ;
+ static const int err_limits[3] = { -1, 3, 10 };
+ struct speed_down_needed_arg arg;
+ struct ata_ering_entry *ent;
+ int err_cat;
+ u64 j64;
+
+ ent = ata_ering_top(&dev->ering);
+ if (!ent)
+ return 0;
+
+ err_cat = ata_eh_categorize_ering_entry(ent);
+ if (err_cat == 0)
+ return 0;
+
+ memset(&arg, 0, sizeof(arg));
+
+ j64 = get_jiffies_64();
+ if (j64 >= interval)
+ arg.since = j64 - interval;
+ else
+ arg.since = 0;
+
+ ata_ering_map(&dev->ering, speed_down_needed_cb, &arg);
+
+ return arg.nr_errors[err_cat] > err_limits[err_cat];
+}
+
+/**
+ * ata_eh_speed_down - record error and speed down if necessary
+ * @dev: Failed device
+ * @is_io: Did the device fail during normal IO?
+ * @err_mask: err_mask of the error
+ *
+ * Record error and examine error history to determine whether
+ * adjusting transmission speed is necessary. It also sets
+ * transmission limits appropriately if such adjustment is
+ * necessary.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, -errno otherwise
+ */
+static int ata_eh_speed_down(struct ata_device *dev, int is_io,
+ unsigned int err_mask)
+{
+ if (!err_mask)
+ return 0;
+
+ /* record error and determine whether speed down is necessary */
+ ata_ering_record(&dev->ering, is_io, err_mask);
+
+ if (!ata_eh_speed_down_needed(dev))
+ return 0;
+
+ /* speed down SATA link speed if possible */
+ if (sata_down_spd_limit(dev->ap) == 0)
+ return ATA_EH_HARDRESET;
+
+ /* lower transfer mode */
+ if (ata_down_xfermask_limit(dev, 0) == 0)
+ return ATA_EH_SOFTRESET;
+
+ ata_dev_printk(dev, KERN_ERR,
+ "speed down requested but no transfer mode left\n");
+ return 0;
+}
+
+/**
+ * ata_eh_autopsy - analyze error and determine recovery action
+ * @ap: ATA port to perform autopsy on
+ *
+ * Analyze why @ap failed and determine which recovery action is
+ * needed. This function also sets more detailed AC_ERR_* values
+ * and fills sense data for ATAPI CHECK SENSE.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ */
+static void ata_eh_autopsy(struct ata_port *ap)
+{
+ struct ata_eh_context *ehc = &ap->eh_context;
+ unsigned int all_err_mask = 0;
+ int tag, is_io = 0;
+ u32 serror;
+ int rc;
+
+ DPRINTK("ENTER\n");
+
+ if (ehc->i.flags & ATA_EHI_NO_AUTOPSY)
+ return;
+
+ /* obtain and analyze SError */
+ rc = sata_scr_read(ap, SCR_ERROR, &serror);
+ if (rc == 0) {
+ ehc->i.serror |= serror;
+ ata_eh_analyze_serror(ap);
+ } else if (rc != -EOPNOTSUPP)
+ ehc->i.action |= ATA_EH_HARDRESET;
+
+ /* analyze NCQ failure */
+ ata_eh_analyze_ncq_error(ap);
+
+ /* any real error trumps AC_ERR_OTHER */
+ if (ehc->i.err_mask & ~AC_ERR_OTHER)
+ ehc->i.err_mask &= ~AC_ERR_OTHER;
+
+ all_err_mask |= ehc->i.err_mask;
+
+ for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
+ struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag);
+
+ if (!(qc->flags & ATA_QCFLAG_FAILED))
+ continue;
+
+ /* inherit upper level err_mask */
+ qc->err_mask |= ehc->i.err_mask;
+
+ /* analyze TF */
+ ehc->i.action |= ata_eh_analyze_tf(qc, &qc->result_tf);
+
+ /* DEV errors are probably spurious in case of ATA_BUS error */
+ if (qc->err_mask & AC_ERR_ATA_BUS)
+ qc->err_mask &= ~(AC_ERR_DEV | AC_ERR_MEDIA |
+ AC_ERR_INVALID);
+
+ /* any real error trumps unknown error */
+ if (qc->err_mask & ~AC_ERR_OTHER)
+ qc->err_mask &= ~AC_ERR_OTHER;
+
+ /* SENSE_VALID trumps dev/unknown error and revalidation */
+ if (qc->flags & ATA_QCFLAG_SENSE_VALID) {
+ qc->err_mask &= ~(AC_ERR_DEV | AC_ERR_OTHER);
+ ehc->i.action &= ~ATA_EH_REVALIDATE;
+ }
+
+ /* accumulate error info */
+ ehc->i.dev = qc->dev;
+ all_err_mask |= qc->err_mask;
+ if (qc->flags & ATA_QCFLAG_IO)
+ is_io = 1;
+ }
+
+ /* enforce default EH actions */
+ if (ap->pflags & ATA_PFLAG_FROZEN ||
+ all_err_mask & (AC_ERR_HSM | AC_ERR_TIMEOUT))
+ ehc->i.action |= ATA_EH_SOFTRESET;
+ else if (all_err_mask)
+ ehc->i.action |= ATA_EH_REVALIDATE;
+
+ /* if we have offending qcs and the associated failed device */
+ if (ehc->i.dev) {
+ /* speed down */
+ ehc->i.action |= ata_eh_speed_down(ehc->i.dev, is_io,
+ all_err_mask);
+
+ /* perform per-dev EH action only on the offending device */
+ ehc->i.dev_action[ehc->i.dev->devno] |=
+ ehc->i.action & ATA_EH_PERDEV_MASK;
+ ehc->i.action &= ~ATA_EH_PERDEV_MASK;
+ }
+
+ DPRINTK("EXIT\n");
+}
+
+/**
+ * ata_eh_report - report error handling to user
+ * @ap: ATA port EH is going on
+ *
+ * Report EH to user.
+ *
+ * LOCKING:
+ * None.
+ */
+static void ata_eh_report(struct ata_port *ap)
+{
+ struct ata_eh_context *ehc = &ap->eh_context;
+ const char *frozen, *desc;
+ int tag, nr_failed = 0;
+
+ desc = NULL;
+ if (ehc->i.desc[0] != '\0')
+ desc = ehc->i.desc;
+
+ for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
+ struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag);
+
+ if (!(qc->flags & ATA_QCFLAG_FAILED))
+ continue;
+ if (qc->flags & ATA_QCFLAG_SENSE_VALID && !qc->err_mask)
+ continue;
+
+ nr_failed++;
+ }
+
+ if (!nr_failed && !ehc->i.err_mask)
+ return;
+
+ frozen = "";
+ if (ap->pflags & ATA_PFLAG_FROZEN)
+ frozen = " frozen";
+
+ if (ehc->i.dev) {
+ ata_dev_printk(ehc->i.dev, KERN_ERR, "exception Emask 0x%x "
+ "SAct 0x%x SErr 0x%x action 0x%x%s\n",
+ ehc->i.err_mask, ap->sactive, ehc->i.serror,
+ ehc->i.action, frozen);
+ if (desc)
+ ata_dev_printk(ehc->i.dev, KERN_ERR, "(%s)\n", desc);
+ } else {
+ ata_port_printk(ap, KERN_ERR, "exception Emask 0x%x "
+ "SAct 0x%x SErr 0x%x action 0x%x%s\n",
+ ehc->i.err_mask, ap->sactive, ehc->i.serror,
+ ehc->i.action, frozen);
+ if (desc)
+ ata_port_printk(ap, KERN_ERR, "(%s)\n", desc);
+ }
+
+ for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
+ struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag);
+
+ if (!(qc->flags & ATA_QCFLAG_FAILED) || !qc->err_mask)
+ continue;
+
+ ata_dev_printk(qc->dev, KERN_ERR, "tag %d cmd 0x%x "
+ "Emask 0x%x stat 0x%x err 0x%x (%s)\n",
+ qc->tag, qc->tf.command, qc->err_mask,
+ qc->result_tf.command, qc->result_tf.feature,
+ ata_err_string(qc->err_mask));
+ }
+}
+
+static int ata_do_reset(struct ata_port *ap, ata_reset_fn_t reset,
+ unsigned int *classes)
+{
+ int i, rc;
+
+ for (i = 0; i < ATA_MAX_DEVICES; i++)
+ classes[i] = ATA_DEV_UNKNOWN;
+
+ rc = reset(ap, classes);
+ if (rc)
+ return rc;
+
+ /* If any class isn't ATA_DEV_UNKNOWN, consider classification
+ * is complete and convert all ATA_DEV_UNKNOWN to
+ * ATA_DEV_NONE.
+ */
+ for (i = 0; i < ATA_MAX_DEVICES; i++)
+ if (classes[i] != ATA_DEV_UNKNOWN)
+ break;
+
+ if (i < ATA_MAX_DEVICES)
+ for (i = 0; i < ATA_MAX_DEVICES; i++)
+ if (classes[i] == ATA_DEV_UNKNOWN)
+ classes[i] = ATA_DEV_NONE;
+
+ return 0;
+}
+
+static int ata_eh_followup_srst_needed(int rc, int classify,
+ const unsigned int *classes)
+{
+ if (rc == -EAGAIN)
+ return 1;
+ if (rc != 0)
+ return 0;
+ if (classify && classes[0] == ATA_DEV_UNKNOWN)
+ return 1;
+ return 0;
+}
+
+static int ata_eh_reset(struct ata_port *ap, int classify,
+ ata_prereset_fn_t prereset, ata_reset_fn_t softreset,
+ ata_reset_fn_t hardreset, ata_postreset_fn_t postreset)
+{
+ struct ata_eh_context *ehc = &ap->eh_context;
+ unsigned int *classes = ehc->classes;
+ int tries = ATA_EH_RESET_TRIES;
+ int verbose = !(ehc->i.flags & ATA_EHI_QUIET);
+ unsigned int action;
+ ata_reset_fn_t reset;
+ int i, did_followup_srst, rc;
+
+ /* about to reset */
+ ata_eh_about_to_do(ap, NULL, ehc->i.action & ATA_EH_RESET_MASK);
+
+ /* Determine which reset to use and record in ehc->i.action.
+ * prereset() may examine and modify it.
+ */
+ action = ehc->i.action;
+ ehc->i.action &= ~ATA_EH_RESET_MASK;
+ if (softreset && (!hardreset || (!sata_set_spd_needed(ap) &&
+ !(action & ATA_EH_HARDRESET))))
+ ehc->i.action |= ATA_EH_SOFTRESET;
+ else
+ ehc->i.action |= ATA_EH_HARDRESET;
+
+ if (prereset) {
+ rc = prereset(ap);
+ if (rc) {
+ if (rc == -ENOENT) {
+ ata_port_printk(ap, KERN_DEBUG, "port disabled. ignoring.\n");
+ ap->eh_context.i.action &= ~ATA_EH_RESET_MASK;
+ } else
+ ata_port_printk(ap, KERN_ERR,
+ "prereset failed (errno=%d)\n", rc);
+ return rc;
+ }
+ }
+
+ /* prereset() might have modified ehc->i.action */
+ if (ehc->i.action & ATA_EH_HARDRESET)
+ reset = hardreset;
+ else if (ehc->i.action & ATA_EH_SOFTRESET)
+ reset = softreset;
+ else {
+ /* prereset told us not to reset, bang classes and return */
+ for (i = 0; i < ATA_MAX_DEVICES; i++)
+ classes[i] = ATA_DEV_NONE;
+ return 0;
+ }
+
+ /* did prereset() screw up? if so, fix up to avoid oopsing */
+ if (!reset) {
+ ata_port_printk(ap, KERN_ERR, "BUG: prereset() requested "
+ "invalid reset type\n");
+ if (softreset)
+ reset = softreset;
+ else
+ reset = hardreset;
+ }
+
+ retry:
+ /* shut up during boot probing */
+ if (verbose)
+ ata_port_printk(ap, KERN_INFO, "%s resetting port\n",
+ reset == softreset ? "soft" : "hard");
+
+ /* mark that this EH session started with reset */
+ ehc->i.flags |= ATA_EHI_DID_RESET;
+
+ rc = ata_do_reset(ap, reset, classes);
+
+ did_followup_srst = 0;
+ if (reset == hardreset &&
+ ata_eh_followup_srst_needed(rc, classify, classes)) {
+ /* okay, let's do follow-up softreset */
+ did_followup_srst = 1;
+ reset = softreset;
+
+ if (!reset) {
+ ata_port_printk(ap, KERN_ERR,
+ "follow-up softreset required "
+ "but no softreset avaliable\n");
+ return -EINVAL;
+ }
+
+ ata_eh_about_to_do(ap, NULL, ATA_EH_RESET_MASK);
+ rc = ata_do_reset(ap, reset, classes);
+
+ if (rc == 0 && classify &&
+ classes[0] == ATA_DEV_UNKNOWN) {
+ ata_port_printk(ap, KERN_ERR,
+ "classification failed\n");
+ return -EINVAL;
+ }
+ }
+
+ if (rc && --tries) {
+ const char *type;
+
+ if (reset == softreset) {
+ if (did_followup_srst)
+ type = "follow-up soft";
+ else
+ type = "soft";
+ } else
+ type = "hard";
+
+ ata_port_printk(ap, KERN_WARNING,
+ "%sreset failed, retrying in 5 secs\n", type);
+ ssleep(5);
+
+ if (reset == hardreset)
+ sata_down_spd_limit(ap);
+ if (hardreset)
+ reset = hardreset;
+ goto retry;
+ }
+
+ if (rc == 0) {
+ /* After the reset, the device state is PIO 0 and the
+ * controller state is undefined. Record the mode.
+ */
+ for (i = 0; i < ATA_MAX_DEVICES; i++)
+ ap->device[i].pio_mode = XFER_PIO_0;
+
+ if (postreset)
+ postreset(ap, classes);
+
+ /* reset successful, schedule revalidation */
+ ata_eh_done(ap, NULL, ehc->i.action & ATA_EH_RESET_MASK);
+ ehc->i.action |= ATA_EH_REVALIDATE;
+ }
+
+ return rc;
+}
+
+static int ata_eh_revalidate_and_attach(struct ata_port *ap,
+ struct ata_device **r_failed_dev)
+{
+ struct ata_eh_context *ehc = &ap->eh_context;
+ struct ata_device *dev;
+ unsigned long flags;
+ int i, rc = 0;
+
+ DPRINTK("ENTER\n");
+
+ for (i = 0; i < ATA_MAX_DEVICES; i++) {
+ unsigned int action;
+
+ dev = &ap->device[i];
+ action = ata_eh_dev_action(dev);
+
+ if (action & ATA_EH_REVALIDATE && ata_dev_ready(dev)) {
+ if (ata_port_offline(ap)) {
+ rc = -EIO;
+ break;
+ }
+
+ ata_eh_about_to_do(ap, dev, ATA_EH_REVALIDATE);
+ rc = ata_dev_revalidate(dev,
+ ehc->i.flags & ATA_EHI_DID_RESET);
+ if (rc)
+ break;
+
+ ata_eh_done(ap, dev, ATA_EH_REVALIDATE);
+
+ /* schedule the scsi_rescan_device() here */
+ queue_work(ata_aux_wq, &(ap->scsi_rescan_task));
+ } else if (dev->class == ATA_DEV_UNKNOWN &&
+ ehc->tries[dev->devno] &&
+ ata_class_enabled(ehc->classes[dev->devno])) {
+ dev->class = ehc->classes[dev->devno];
+
+ rc = ata_dev_read_id(dev, &dev->class, 1, dev->id);
+ if (rc == 0)
+ rc = ata_dev_configure(dev, 1);
+
+ if (rc) {
+ dev->class = ATA_DEV_UNKNOWN;
+ break;
+ }
+
+ spin_lock_irqsave(ap->lock, flags);
+ ap->pflags |= ATA_PFLAG_SCSI_HOTPLUG;
+ spin_unlock_irqrestore(ap->lock, flags);
+ }
+ }
+
+ if (rc)
+ *r_failed_dev = dev;
+
+ DPRINTK("EXIT\n");
+ return rc;
+}
+
+/**
+ * ata_eh_suspend - handle suspend EH action
+ * @ap: target host port
+ * @r_failed_dev: result parameter to indicate failing device
+ *
+ * Handle suspend EH action. Disk devices are spinned down and
+ * other types of devices are just marked suspended. Once
+ * suspended, no EH action to the device is allowed until it is
+ * resumed.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, -errno otherwise
+ */
+static int ata_eh_suspend(struct ata_port *ap, struct ata_device **r_failed_dev)
+{
+ struct ata_device *dev;
+ int i, rc = 0;
+
+ DPRINTK("ENTER\n");
+
+ for (i = 0; i < ATA_MAX_DEVICES; i++) {
+ unsigned long flags;
+ unsigned int action, err_mask;
+
+ dev = &ap->device[i];
+ action = ata_eh_dev_action(dev);
+
+ if (!ata_dev_enabled(dev) || !(action & ATA_EH_SUSPEND))
+ continue;
+
+ WARN_ON(dev->flags & ATA_DFLAG_SUSPENDED);
+
+ ata_eh_about_to_do(ap, dev, ATA_EH_SUSPEND);
+
+ if (dev->class == ATA_DEV_ATA && !(action & ATA_EH_PM_FREEZE)) {
+ /* flush cache */
+ rc = ata_flush_cache(dev);
+ if (rc)
+ break;
+
+ /* spin down */
+ err_mask = ata_do_simple_cmd(dev, ATA_CMD_STANDBYNOW1);
+ if (err_mask) {
+ ata_dev_printk(dev, KERN_ERR, "failed to "
+ "spin down (err_mask=0x%x)\n",
+ err_mask);
+ rc = -EIO;
+ break;
+ }
+ }
+
+ spin_lock_irqsave(ap->lock, flags);
+ dev->flags |= ATA_DFLAG_SUSPENDED;
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ ata_eh_done(ap, dev, ATA_EH_SUSPEND);
+ }
+
+ if (rc)
+ *r_failed_dev = dev;
+
+ DPRINTK("EXIT\n");
+ return 0;
+}
+
+/**
+ * ata_eh_prep_resume - prep for resume EH action
+ * @ap: target host port
+ *
+ * Clear SUSPENDED in preparation for scheduled resume actions.
+ * This allows other parts of EH to access the devices being
+ * resumed.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ */
+static void ata_eh_prep_resume(struct ata_port *ap)
+{
+ struct ata_device *dev;
+ unsigned long flags;
+ int i;
+
+ DPRINTK("ENTER\n");
+
+ for (i = 0; i < ATA_MAX_DEVICES; i++) {
+ unsigned int action;
+
+ dev = &ap->device[i];
+ action = ata_eh_dev_action(dev);
+
+ if (!ata_dev_enabled(dev) || !(action & ATA_EH_RESUME))
+ continue;
+
+ spin_lock_irqsave(ap->lock, flags);
+ dev->flags &= ~ATA_DFLAG_SUSPENDED;
+ spin_unlock_irqrestore(ap->lock, flags);
+ }
+
+ DPRINTK("EXIT\n");
+}
+
+/**
+ * ata_eh_resume - handle resume EH action
+ * @ap: target host port
+ * @r_failed_dev: result parameter to indicate failing device
+ *
+ * Handle resume EH action. Target devices are already reset and
+ * revalidated. Spinning up is the only operation left.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, -errno otherwise
+ */
+static int ata_eh_resume(struct ata_port *ap, struct ata_device **r_failed_dev)
+{
+ struct ata_device *dev;
+ int i, rc = 0;
+
+ DPRINTK("ENTER\n");
+
+ for (i = 0; i < ATA_MAX_DEVICES; i++) {
+ unsigned int action, err_mask;
+
+ dev = &ap->device[i];
+ action = ata_eh_dev_action(dev);
+
+ if (!ata_dev_enabled(dev) || !(action & ATA_EH_RESUME))
+ continue;
+
+ ata_eh_about_to_do(ap, dev, ATA_EH_RESUME);
+
+ if (dev->class == ATA_DEV_ATA && !(action & ATA_EH_PM_FREEZE)) {
+ err_mask = ata_do_simple_cmd(dev,
+ ATA_CMD_IDLEIMMEDIATE);
+ if (err_mask) {
+ ata_dev_printk(dev, KERN_ERR, "failed to "
+ "spin up (err_mask=0x%x)\n",
+ err_mask);
+ rc = -EIO;
+ break;
+ }
+ }
+
+ ata_eh_done(ap, dev, ATA_EH_RESUME);
+ }
+
+ if (rc)
+ *r_failed_dev = dev;
+
+ DPRINTK("EXIT\n");
+ return 0;
+}
+
+static int ata_port_nr_enabled(struct ata_port *ap)
+{
+ int i, cnt = 0;
+
+ for (i = 0; i < ATA_MAX_DEVICES; i++)
+ if (ata_dev_enabled(&ap->device[i]))
+ cnt++;
+ return cnt;
+}
+
+static int ata_port_nr_vacant(struct ata_port *ap)
+{
+ int i, cnt = 0;
+
+ for (i = 0; i < ATA_MAX_DEVICES; i++)
+ if (ap->device[i].class == ATA_DEV_UNKNOWN)
+ cnt++;
+ return cnt;
+}
+
+static int ata_eh_skip_recovery(struct ata_port *ap)
+{
+ struct ata_eh_context *ehc = &ap->eh_context;
+ int i;
+
+ /* skip if all possible devices are suspended */
+ for (i = 0; i < ata_port_max_devices(ap); i++) {
+ struct ata_device *dev = &ap->device[i];
+
+ if (!(dev->flags & ATA_DFLAG_SUSPENDED))
+ break;
+ }
+
+ if (i == ata_port_max_devices(ap))
+ return 1;
+
+ /* thaw frozen port, resume link and recover failed devices */
+ if ((ap->pflags & ATA_PFLAG_FROZEN) ||
+ (ehc->i.flags & ATA_EHI_RESUME_LINK) || ata_port_nr_enabled(ap))
+ return 0;
+
+ /* skip if class codes for all vacant slots are ATA_DEV_NONE */
+ for (i = 0; i < ATA_MAX_DEVICES; i++) {
+ struct ata_device *dev = &ap->device[i];
+
+ if (dev->class == ATA_DEV_UNKNOWN &&
+ ehc->classes[dev->devno] != ATA_DEV_NONE)
+ return 0;
+ }
+
+ return 1;
+}
+
+/**
+ * ata_eh_recover - recover host port after error
+ * @ap: host port to recover
+ * @prereset: prereset method (can be NULL)
+ * @softreset: softreset method (can be NULL)
+ * @hardreset: hardreset method (can be NULL)
+ * @postreset: postreset method (can be NULL)
+ *
+ * This is the alpha and omega, eum and yang, heart and soul of
+ * libata exception handling. On entry, actions required to
+ * recover the port and hotplug requests are recorded in
+ * eh_context. This function executes all the operations with
+ * appropriate retrials and fallbacks to resurrect failed
+ * devices, detach goners and greet newcomers.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, -errno on failure.
+ */
+static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
+ ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
+ ata_postreset_fn_t postreset)
+{
+ struct ata_eh_context *ehc = &ap->eh_context;
+ struct ata_device *dev;
+ int down_xfermask, i, rc;
+
+ DPRINTK("ENTER\n");
+
+ /* prep for recovery */
+ for (i = 0; i < ATA_MAX_DEVICES; i++) {
+ dev = &ap->device[i];
+
+ ehc->tries[dev->devno] = ATA_EH_DEV_TRIES;
+
+ /* process hotplug request */
+ if (dev->flags & ATA_DFLAG_DETACH)
+ ata_eh_detach_dev(dev);
+
+ if (!ata_dev_enabled(dev) &&
+ ((ehc->i.probe_mask & (1 << dev->devno)) &&
+ !(ehc->did_probe_mask & (1 << dev->devno)))) {
+ ata_eh_detach_dev(dev);
+ ata_dev_init(dev);
+ ehc->did_probe_mask |= (1 << dev->devno);
+ ehc->i.action |= ATA_EH_SOFTRESET;
+ }
+ }
+
+ retry:
+ down_xfermask = 0;
+ rc = 0;
+
+ /* if UNLOADING, finish immediately */
+ if (ap->pflags & ATA_PFLAG_UNLOADING)
+ goto out;
+
+ /* prep for resume */
+ ata_eh_prep_resume(ap);
+
+ /* skip EH if possible. */
+ if (ata_eh_skip_recovery(ap))
+ ehc->i.action = 0;
+
+ for (i = 0; i < ATA_MAX_DEVICES; i++)
+ ehc->classes[i] = ATA_DEV_UNKNOWN;
+
+ /* reset */
+ if (ehc->i.action & ATA_EH_RESET_MASK) {
+ ata_eh_freeze_port(ap);
+
+ rc = ata_eh_reset(ap, ata_port_nr_vacant(ap), prereset,
+ softreset, hardreset, postreset);
+ if (rc) {
+ ata_port_printk(ap, KERN_ERR,
+ "reset failed, giving up\n");
+ goto out;
+ }
+
+ ata_eh_thaw_port(ap);
+ }
+
+ /* revalidate existing devices and attach new ones */
+ rc = ata_eh_revalidate_and_attach(ap, &dev);
+ if (rc)
+ goto dev_fail;
+
+ /* resume devices */
+ rc = ata_eh_resume(ap, &dev);
+ if (rc)
+ goto dev_fail;
+
+ /* configure transfer mode if the port has been reset */
+ if (ehc->i.flags & ATA_EHI_DID_RESET) {
+ rc = ata_set_mode(ap, &dev);
+ if (rc) {
+ down_xfermask = 1;
+ goto dev_fail;
+ }
+ }
+
+ /* suspend devices */
+ rc = ata_eh_suspend(ap, &dev);
+ if (rc)
+ goto dev_fail;
+
+ goto out;
+
+ dev_fail:
+ switch (rc) {
+ case -ENODEV:
+ /* device missing, schedule probing */
+ ehc->i.probe_mask |= (1 << dev->devno);
+ case -EINVAL:
+ ehc->tries[dev->devno] = 0;
+ break;
+ case -EIO:
+ sata_down_spd_limit(ap);
+ default:
+ ehc->tries[dev->devno]--;
+ if (down_xfermask &&
+ ata_down_xfermask_limit(dev, ehc->tries[dev->devno] == 1))
+ ehc->tries[dev->devno] = 0;
+ }
+
+ if (ata_dev_enabled(dev) && !ehc->tries[dev->devno]) {
+ /* disable device if it has used up all its chances */
+ ata_dev_disable(dev);
+
+ /* detach if offline */
+ if (ata_port_offline(ap))
+ ata_eh_detach_dev(dev);
+
+ /* probe if requested */
+ if ((ehc->i.probe_mask & (1 << dev->devno)) &&
+ !(ehc->did_probe_mask & (1 << dev->devno))) {
+ ata_eh_detach_dev(dev);
+ ata_dev_init(dev);
+
+ ehc->tries[dev->devno] = ATA_EH_DEV_TRIES;
+ ehc->did_probe_mask |= (1 << dev->devno);
+ ehc->i.action |= ATA_EH_SOFTRESET;
+ }
+ } else {
+ /* soft didn't work? be haaaaard */
+ if (ehc->i.flags & ATA_EHI_DID_RESET)
+ ehc->i.action |= ATA_EH_HARDRESET;
+ else
+ ehc->i.action |= ATA_EH_SOFTRESET;
+ }
+
+ if (ata_port_nr_enabled(ap)) {
+ ata_port_printk(ap, KERN_WARNING, "failed to recover some "
+ "devices, retrying in 5 secs\n");
+ ssleep(5);
+ } else {
+ /* no device left, repeat fast */
+ msleep(500);
+ }
+
+ goto retry;
+
+ out:
+ if (rc) {
+ for (i = 0; i < ATA_MAX_DEVICES; i++)
+ ata_dev_disable(&ap->device[i]);
+ }
+
+ DPRINTK("EXIT, rc=%d\n", rc);
+ return rc;
+}
+
+/**
+ * ata_eh_finish - finish up EH
+ * @ap: host port to finish EH for
+ *
+ * Recovery is complete. Clean up EH states and retry or finish
+ * failed qcs.
+ *
+ * LOCKING:
+ * None.
+ */
+static void ata_eh_finish(struct ata_port *ap)
+{
+ int tag;
+
+ /* retry or finish qcs */
+ for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
+ struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag);
+
+ if (!(qc->flags & ATA_QCFLAG_FAILED))
+ continue;
+
+ if (qc->err_mask) {
+ /* FIXME: Once EH migration is complete,
+ * generate sense data in this function,
+ * considering both err_mask and tf.
+ */
+ if (qc->err_mask & AC_ERR_INVALID)
+ ata_eh_qc_complete(qc);
+ else
+ ata_eh_qc_retry(qc);
+ } else {
+ if (qc->flags & ATA_QCFLAG_SENSE_VALID) {
+ ata_eh_qc_complete(qc);
+ } else {
+ /* feed zero TF to sense generation */
+ memset(&qc->result_tf, 0, sizeof(qc->result_tf));
+ ata_eh_qc_retry(qc);
+ }
+ }
+ }
+}
+
+/**
+ * ata_do_eh - do standard error handling
+ * @ap: host port to handle error for
+ * @prereset: prereset method (can be NULL)
+ * @softreset: softreset method (can be NULL)
+ * @hardreset: hardreset method (can be NULL)
+ * @postreset: postreset method (can be NULL)
+ *
+ * Perform standard error handling sequence.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ */
+void ata_do_eh(struct ata_port *ap, ata_prereset_fn_t prereset,
+ ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
+ ata_postreset_fn_t postreset)
+{
+ ata_eh_autopsy(ap);
+ ata_eh_report(ap);
+ ata_eh_recover(ap, prereset, softreset, hardreset, postreset);
+ ata_eh_finish(ap);
+}
+
+/**
+ * ata_eh_handle_port_suspend - perform port suspend operation
+ * @ap: port to suspend
+ *
+ * Suspend @ap.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ */
+static void ata_eh_handle_port_suspend(struct ata_port *ap)
+{
+ unsigned long flags;
+ int rc = 0;
+
+ /* are we suspending? */
+ spin_lock_irqsave(ap->lock, flags);
+ if (!(ap->pflags & ATA_PFLAG_PM_PENDING) ||
+ ap->pm_mesg.event == PM_EVENT_ON) {
+ spin_unlock_irqrestore(ap->lock, flags);
+ return;
+ }
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ WARN_ON(ap->pflags & ATA_PFLAG_SUSPENDED);
+
+ /* suspend */
+ ata_eh_freeze_port(ap);
+
+ if (ap->ops->port_suspend)
+ rc = ap->ops->port_suspend(ap, ap->pm_mesg);
+
+ /* report result */
+ spin_lock_irqsave(ap->lock, flags);
+
+ ap->pflags &= ~ATA_PFLAG_PM_PENDING;
+ if (rc == 0)
+ ap->pflags |= ATA_PFLAG_SUSPENDED;
+ else
+ ata_port_schedule_eh(ap);
+
+ if (ap->pm_result) {
+ *ap->pm_result = rc;
+ ap->pm_result = NULL;
+ }
+
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ return;
+}
+
+/**
+ * ata_eh_handle_port_resume - perform port resume operation
+ * @ap: port to resume
+ *
+ * Resume @ap.
+ *
+ * This function also waits upto one second until all devices
+ * hanging off this port requests resume EH action. This is to
+ * prevent invoking EH and thus reset multiple times on resume.
+ *
+ * On DPM resume, where some of devices might not be resumed
+ * together, this may delay port resume upto one second, but such
+ * DPM resumes are rare and 1 sec delay isn't too bad.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ */
+static void ata_eh_handle_port_resume(struct ata_port *ap)
+{
+ unsigned long timeout;
+ unsigned long flags;
+ int i, rc = 0;
+
+ /* are we resuming? */
+ spin_lock_irqsave(ap->lock, flags);
+ if (!(ap->pflags & ATA_PFLAG_PM_PENDING) ||
+ ap->pm_mesg.event != PM_EVENT_ON) {
+ spin_unlock_irqrestore(ap->lock, flags);
+ return;
+ }
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ /* spurious? */
+ if (!(ap->pflags & ATA_PFLAG_SUSPENDED))
+ goto done;
+
+ if (ap->ops->port_resume)
+ rc = ap->ops->port_resume(ap);
+
+ /* give devices time to request EH */
+ timeout = jiffies + HZ; /* 1s max */
+ while (1) {
+ for (i = 0; i < ATA_MAX_DEVICES; i++) {
+ struct ata_device *dev = &ap->device[i];
+ unsigned int action = ata_eh_dev_action(dev);
+
+ if ((dev->flags & ATA_DFLAG_SUSPENDED) &&
+ !(action & ATA_EH_RESUME))
+ break;
+ }
+
+ if (i == ATA_MAX_DEVICES || time_after(jiffies, timeout))
+ break;
+ msleep(10);
+ }
+
+ done:
+ spin_lock_irqsave(ap->lock, flags);
+ ap->pflags &= ~(ATA_PFLAG_PM_PENDING | ATA_PFLAG_SUSPENDED);
+ if (ap->pm_result) {
+ *ap->pm_result = rc;
+ ap->pm_result = NULL;
+ }
+ spin_unlock_irqrestore(ap->lock, flags);
+}
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
new file mode 100644
index 00000000000..3986ec8741b
--- /dev/null
+++ b/drivers/ata/libata-scsi.c
@@ -0,0 +1,3322 @@
+/*
+ * libata-scsi.c - helper library for ATA
+ *
+ * Maintained by: Jeff Garzik <jgarzik@pobox.com>
+ * Please ALWAYS copy linux-ide@vger.kernel.org
+ * on emails.
+ *
+ * Copyright 2003-2004 Red Hat, Inc. All rights reserved.
+ * Copyright 2003-2004 Jeff Garzik
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * libata documentation is available via 'make {ps|pdf}docs',
+ * as Documentation/DocBook/libata.*
+ *
+ * Hardware documentation available from
+ * - http://www.t10.org/
+ * - http://www.t13.org/
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/blkdev.h>
+#include <linux/spinlock.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_eh.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_tcq.h>
+#include <scsi/scsi_transport.h>
+#include <linux/libata.h>
+#include <linux/hdreg.h>
+#include <asm/uaccess.h>
+
+#include "libata.h"
+
+#define SECTOR_SIZE 512
+
+typedef unsigned int (*ata_xlat_func_t)(struct ata_queued_cmd *qc, const u8 *scsicmd);
+
+static struct ata_device * __ata_scsi_find_dev(struct ata_port *ap,
+ const struct scsi_device *scsidev);
+static struct ata_device * ata_scsi_find_dev(struct ata_port *ap,
+ const struct scsi_device *scsidev);
+static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel,
+ unsigned int id, unsigned int lun);
+
+
+#define RW_RECOVERY_MPAGE 0x1
+#define RW_RECOVERY_MPAGE_LEN 12
+#define CACHE_MPAGE 0x8
+#define CACHE_MPAGE_LEN 20
+#define CONTROL_MPAGE 0xa
+#define CONTROL_MPAGE_LEN 12
+#define ALL_MPAGES 0x3f
+#define ALL_SUB_MPAGES 0xff
+
+
+static const u8 def_rw_recovery_mpage[] = {
+ RW_RECOVERY_MPAGE,
+ RW_RECOVERY_MPAGE_LEN - 2,
+ (1 << 7) | /* AWRE, sat-r06 say it shall be 0 */
+ (1 << 6), /* ARRE (auto read reallocation) */
+ 0, /* read retry count */
+ 0, 0, 0, 0,
+ 0, /* write retry count */
+ 0, 0, 0
+};
+
+static const u8 def_cache_mpage[CACHE_MPAGE_LEN] = {
+ CACHE_MPAGE,
+ CACHE_MPAGE_LEN - 2,
+ 0, /* contains WCE, needs to be 0 for logic */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, /* contains DRA, needs to be 0 for logic */
+ 0, 0, 0, 0, 0, 0, 0
+};
+
+static const u8 def_control_mpage[CONTROL_MPAGE_LEN] = {
+ CONTROL_MPAGE,
+ CONTROL_MPAGE_LEN - 2,
+ 2, /* DSENSE=0, GLTSD=1 */
+ 0, /* [QAM+QERR may be 1, see 05-359r1] */
+ 0, 0, 0, 0, 0xff, 0xff,
+ 0, 30 /* extended self test time, see 05-359r1 */
+};
+
+/*
+ * libata transport template. libata doesn't do real transport stuff.
+ * It just needs the eh_timed_out hook.
+ */
+struct scsi_transport_template ata_scsi_transport_template = {
+ .eh_strategy_handler = ata_scsi_error,
+ .eh_timed_out = ata_scsi_timed_out,
+ .user_scan = ata_scsi_user_scan,
+};
+
+
+static void ata_scsi_invalid_field(struct scsi_cmnd *cmd,
+ void (*done)(struct scsi_cmnd *))
+{
+ ata_scsi_set_sense(cmd, ILLEGAL_REQUEST, 0x24, 0x0);
+ /* "Invalid field in cbd" */
+ done(cmd);
+}
+
+/**
+ * ata_std_bios_param - generic bios head/sector/cylinder calculator used by sd.
+ * @sdev: SCSI device for which BIOS geometry is to be determined
+ * @bdev: block device associated with @sdev
+ * @capacity: capacity of SCSI device
+ * @geom: location to which geometry will be output
+ *
+ * Generic bios head/sector/cylinder calculator
+ * used by sd. Most BIOSes nowadays expect a XXX/255/16 (CHS)
+ * mapping. Some situations may arise where the disk is not
+ * bootable if this is not used.
+ *
+ * LOCKING:
+ * Defined by the SCSI layer. We don't really care.
+ *
+ * RETURNS:
+ * Zero.
+ */
+int ata_std_bios_param(struct scsi_device *sdev, struct block_device *bdev,
+ sector_t capacity, int geom[])
+{
+ geom[0] = 255;
+ geom[1] = 63;
+ sector_div(capacity, 255*63);
+ geom[2] = capacity;
+
+ return 0;
+}
+
+/**
+ * ata_cmd_ioctl - Handler for HDIO_DRIVE_CMD ioctl
+ * @scsidev: Device to which we are issuing command
+ * @arg: User provided data for issuing command
+ *
+ * LOCKING:
+ * Defined by the SCSI layer. We don't really care.
+ *
+ * RETURNS:
+ * Zero on success, negative errno on error.
+ */
+
+int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg)
+{
+ int rc = 0;
+ u8 scsi_cmd[MAX_COMMAND_SIZE];
+ u8 args[4], *argbuf = NULL;
+ int argsize = 0;
+ struct scsi_sense_hdr sshdr;
+ enum dma_data_direction data_dir;
+
+ if (arg == NULL)
+ return -EINVAL;
+
+ if (copy_from_user(args, arg, sizeof(args)))
+ return -EFAULT;
+
+ memset(scsi_cmd, 0, sizeof(scsi_cmd));
+
+ if (args[3]) {
+ argsize = SECTOR_SIZE * args[3];
+ argbuf = kmalloc(argsize, GFP_KERNEL);
+ if (argbuf == NULL) {
+ rc = -ENOMEM;
+ goto error;
+ }
+
+ scsi_cmd[1] = (4 << 1); /* PIO Data-in */
+ scsi_cmd[2] = 0x0e; /* no off.line or cc, read from dev,
+ block count in sector count field */
+ data_dir = DMA_FROM_DEVICE;
+ } else {
+ scsi_cmd[1] = (3 << 1); /* Non-data */
+ /* scsi_cmd[2] is already 0 -- no off.line, cc, or data xfer */
+ data_dir = DMA_NONE;
+ }
+
+ scsi_cmd[0] = ATA_16;
+
+ scsi_cmd[4] = args[2];
+ if (args[0] == WIN_SMART) { /* hack -- ide driver does this too... */
+ scsi_cmd[6] = args[3];
+ scsi_cmd[8] = args[1];
+ scsi_cmd[10] = 0x4f;
+ scsi_cmd[12] = 0xc2;
+ } else {
+ scsi_cmd[6] = args[1];
+ }
+ scsi_cmd[14] = args[0];
+
+ /* Good values for timeout and retries? Values below
+ from scsi_ioctl_send_command() for default case... */
+ if (scsi_execute_req(scsidev, scsi_cmd, data_dir, argbuf, argsize,
+ &sshdr, (10*HZ), 5)) {
+ rc = -EIO;
+ goto error;
+ }
+
+ /* Need code to retrieve data from check condition? */
+
+ if ((argbuf)
+ && copy_to_user(arg + sizeof(args), argbuf, argsize))
+ rc = -EFAULT;
+error:
+ kfree(argbuf);
+ return rc;
+}
+
+/**
+ * ata_task_ioctl - Handler for HDIO_DRIVE_TASK ioctl
+ * @scsidev: Device to which we are issuing command
+ * @arg: User provided data for issuing command
+ *
+ * LOCKING:
+ * Defined by the SCSI layer. We don't really care.
+ *
+ * RETURNS:
+ * Zero on success, negative errno on error.
+ */
+int ata_task_ioctl(struct scsi_device *scsidev, void __user *arg)
+{
+ int rc = 0;
+ u8 scsi_cmd[MAX_COMMAND_SIZE];
+ u8 args[7];
+ struct scsi_sense_hdr sshdr;
+
+ if (arg == NULL)
+ return -EINVAL;
+
+ if (copy_from_user(args, arg, sizeof(args)))
+ return -EFAULT;
+
+ memset(scsi_cmd, 0, sizeof(scsi_cmd));
+ scsi_cmd[0] = ATA_16;
+ scsi_cmd[1] = (3 << 1); /* Non-data */
+ /* scsi_cmd[2] is already 0 -- no off.line, cc, or data xfer */
+ scsi_cmd[4] = args[1];
+ scsi_cmd[6] = args[2];
+ scsi_cmd[8] = args[3];
+ scsi_cmd[10] = args[4];
+ scsi_cmd[12] = args[5];
+ scsi_cmd[14] = args[0];
+
+ /* Good values for timeout and retries? Values below
+ from scsi_ioctl_send_command() for default case... */
+ if (scsi_execute_req(scsidev, scsi_cmd, DMA_NONE, NULL, 0, &sshdr,
+ (10*HZ), 5))
+ rc = -EIO;
+
+ /* Need code to retrieve data from check condition? */
+ return rc;
+}
+
+int ata_scsi_ioctl(struct scsi_device *scsidev, int cmd, void __user *arg)
+{
+ int val = -EINVAL, rc = -EINVAL;
+
+ switch (cmd) {
+ case ATA_IOC_GET_IO32:
+ val = 0;
+ if (copy_to_user(arg, &val, 1))
+ return -EFAULT;
+ return 0;
+
+ case ATA_IOC_SET_IO32:
+ val = (unsigned long) arg;
+ if (val != 0)
+ return -EINVAL;
+ return 0;
+
+ case HDIO_DRIVE_CMD:
+ if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
+ return -EACCES;
+ return ata_cmd_ioctl(scsidev, arg);
+
+ case HDIO_DRIVE_TASK:
+ if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
+ return -EACCES;
+ return ata_task_ioctl(scsidev, arg);
+
+ default:
+ rc = -ENOTTY;
+ break;
+ }
+
+ return rc;
+}
+
+/**
+ * ata_scsi_qc_new - acquire new ata_queued_cmd reference
+ * @dev: ATA device to which the new command is attached
+ * @cmd: SCSI command that originated this ATA command
+ * @done: SCSI command completion function
+ *
+ * Obtain a reference to an unused ata_queued_cmd structure,
+ * which is the basic libata structure representing a single
+ * ATA command sent to the hardware.
+ *
+ * If a command was available, fill in the SCSI-specific
+ * portions of the structure with information on the
+ * current command.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ *
+ * RETURNS:
+ * Command allocated, or %NULL if none available.
+ */
+struct ata_queued_cmd *ata_scsi_qc_new(struct ata_device *dev,
+ struct scsi_cmnd *cmd,
+ void (*done)(struct scsi_cmnd *))
+{
+ struct ata_queued_cmd *qc;
+
+ qc = ata_qc_new_init(dev);
+ if (qc) {
+ qc->scsicmd = cmd;
+ qc->scsidone = done;
+
+ if (cmd->use_sg) {
+ qc->__sg = (struct scatterlist *) cmd->request_buffer;
+ qc->n_elem = cmd->use_sg;
+ } else {
+ qc->__sg = &qc->sgent;
+ qc->n_elem = 1;
+ }
+ } else {
+ cmd->result = (DID_OK << 16) | (QUEUE_FULL << 1);
+ done(cmd);
+ }
+
+ return qc;
+}
+
+/**
+ * ata_dump_status - user friendly display of error info
+ * @id: id of the port in question
+ * @tf: ptr to filled out taskfile
+ *
+ * Decode and dump the ATA error/status registers for the user so
+ * that they have some idea what really happened at the non
+ * make-believe layer.
+ *
+ * LOCKING:
+ * inherited from caller
+ */
+void ata_dump_status(unsigned id, struct ata_taskfile *tf)
+{
+ u8 stat = tf->command, err = tf->feature;
+
+ printk(KERN_WARNING "ata%u: status=0x%02x { ", id, stat);
+ if (stat & ATA_BUSY) {
+ printk("Busy }\n"); /* Data is not valid in this case */
+ } else {
+ if (stat & 0x40) printk("DriveReady ");
+ if (stat & 0x20) printk("DeviceFault ");
+ if (stat & 0x10) printk("SeekComplete ");
+ if (stat & 0x08) printk("DataRequest ");
+ if (stat & 0x04) printk("CorrectedError ");
+ if (stat & 0x02) printk("Index ");
+ if (stat & 0x01) printk("Error ");
+ printk("}\n");
+
+ if (err) {
+ printk(KERN_WARNING "ata%u: error=0x%02x { ", id, err);
+ if (err & 0x04) printk("DriveStatusError ");
+ if (err & 0x80) {
+ if (err & 0x04) printk("BadCRC ");
+ else printk("Sector ");
+ }
+ if (err & 0x40) printk("UncorrectableError ");
+ if (err & 0x10) printk("SectorIdNotFound ");
+ if (err & 0x02) printk("TrackZeroNotFound ");
+ if (err & 0x01) printk("AddrMarkNotFound ");
+ printk("}\n");
+ }
+ }
+}
+
+/**
+ * ata_scsi_device_suspend - suspend ATA device associated with sdev
+ * @sdev: the SCSI device to suspend
+ * @mesg: target power management message
+ *
+ * Request suspend EH action on the ATA device associated with
+ * @sdev and wait for the operation to complete.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, -errno otherwise.
+ */
+int ata_scsi_device_suspend(struct scsi_device *sdev, pm_message_t mesg)
+{
+ struct ata_port *ap = ata_shost_to_port(sdev->host);
+ struct ata_device *dev = ata_scsi_find_dev(ap, sdev);
+ unsigned long flags;
+ unsigned int action;
+ int rc = 0;
+
+ if (!dev)
+ goto out;
+
+ spin_lock_irqsave(ap->lock, flags);
+
+ /* wait for the previous resume to complete */
+ while (dev->flags & ATA_DFLAG_SUSPENDED) {
+ spin_unlock_irqrestore(ap->lock, flags);
+ ata_port_wait_eh(ap);
+ spin_lock_irqsave(ap->lock, flags);
+ }
+
+ /* if @sdev is already detached, nothing to do */
+ if (sdev->sdev_state == SDEV_OFFLINE ||
+ sdev->sdev_state == SDEV_CANCEL || sdev->sdev_state == SDEV_DEL)
+ goto out_unlock;
+
+ /* request suspend */
+ action = ATA_EH_SUSPEND;
+ if (mesg.event != PM_EVENT_SUSPEND)
+ action |= ATA_EH_PM_FREEZE;
+ ap->eh_info.dev_action[dev->devno] |= action;
+ ap->eh_info.flags |= ATA_EHI_QUIET;
+ ata_port_schedule_eh(ap);
+
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ /* wait for EH to do the job */
+ ata_port_wait_eh(ap);
+
+ spin_lock_irqsave(ap->lock, flags);
+
+ /* If @sdev is still attached but the associated ATA device
+ * isn't suspended, the operation failed.
+ */
+ if (sdev->sdev_state != SDEV_OFFLINE &&
+ sdev->sdev_state != SDEV_CANCEL && sdev->sdev_state != SDEV_DEL &&
+ !(dev->flags & ATA_DFLAG_SUSPENDED))
+ rc = -EIO;
+
+ out_unlock:
+ spin_unlock_irqrestore(ap->lock, flags);
+ out:
+ if (rc == 0)
+ sdev->sdev_gendev.power.power_state = mesg;
+ return rc;
+}
+
+/**
+ * ata_scsi_device_resume - resume ATA device associated with sdev
+ * @sdev: the SCSI device to resume
+ *
+ * Request resume EH action on the ATA device associated with
+ * @sdev and return immediately. This enables parallel
+ * wakeup/spinup of devices.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ *
+ * RETURNS:
+ * 0.
+ */
+int ata_scsi_device_resume(struct scsi_device *sdev)
+{
+ struct ata_port *ap = ata_shost_to_port(sdev->host);
+ struct ata_device *dev = ata_scsi_find_dev(ap, sdev);
+ struct ata_eh_info *ehi = &ap->eh_info;
+ unsigned long flags;
+ unsigned int action;
+
+ if (!dev)
+ goto out;
+
+ spin_lock_irqsave(ap->lock, flags);
+
+ /* if @sdev is already detached, nothing to do */
+ if (sdev->sdev_state == SDEV_OFFLINE ||
+ sdev->sdev_state == SDEV_CANCEL || sdev->sdev_state == SDEV_DEL)
+ goto out_unlock;
+
+ /* request resume */
+ action = ATA_EH_RESUME;
+ if (sdev->sdev_gendev.power.power_state.event == PM_EVENT_SUSPEND)
+ __ata_ehi_hotplugged(ehi);
+ else
+ action |= ATA_EH_PM_FREEZE | ATA_EH_SOFTRESET;
+ ehi->dev_action[dev->devno] |= action;
+
+ /* We don't want autopsy and verbose EH messages. Disable
+ * those if we're the only device on this link.
+ */
+ if (ata_port_max_devices(ap) == 1)
+ ehi->flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET;
+
+ ata_port_schedule_eh(ap);
+
+ out_unlock:
+ spin_unlock_irqrestore(ap->lock, flags);
+ out:
+ sdev->sdev_gendev.power.power_state = PMSG_ON;
+ return 0;
+}
+
+/**
+ * ata_to_sense_error - convert ATA error to SCSI error
+ * @id: ATA device number
+ * @drv_stat: value contained in ATA status register
+ * @drv_err: value contained in ATA error register
+ * @sk: the sense key we'll fill out
+ * @asc: the additional sense code we'll fill out
+ * @ascq: the additional sense code qualifier we'll fill out
+ * @verbose: be verbose
+ *
+ * Converts an ATA error into a SCSI error. Fill out pointers to
+ * SK, ASC, and ASCQ bytes for later use in fixed or descriptor
+ * format sense blocks.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ */
+void ata_to_sense_error(unsigned id, u8 drv_stat, u8 drv_err, u8 *sk, u8 *asc,
+ u8 *ascq, int verbose)
+{
+ int i;
+
+ /* Based on the 3ware driver translation table */
+ static const unsigned char sense_table[][4] = {
+ /* BBD|ECC|ID|MAR */
+ {0xd1, ABORTED_COMMAND, 0x00, 0x00}, // Device busy Aborted command
+ /* BBD|ECC|ID */
+ {0xd0, ABORTED_COMMAND, 0x00, 0x00}, // Device busy Aborted command
+ /* ECC|MC|MARK */
+ {0x61, HARDWARE_ERROR, 0x00, 0x00}, // Device fault Hardware error
+ /* ICRC|ABRT */ /* NB: ICRC & !ABRT is BBD */
+ {0x84, ABORTED_COMMAND, 0x47, 0x00}, // Data CRC error SCSI parity error
+ /* MC|ID|ABRT|TRK0|MARK */
+ {0x37, NOT_READY, 0x04, 0x00}, // Unit offline Not ready
+ /* MCR|MARK */
+ {0x09, NOT_READY, 0x04, 0x00}, // Unrecovered disk error Not ready
+ /* Bad address mark */
+ {0x01, MEDIUM_ERROR, 0x13, 0x00}, // Address mark not found Address mark not found for data field
+ /* TRK0 */
+ {0x02, HARDWARE_ERROR, 0x00, 0x00}, // Track 0 not found Hardware error
+ /* Abort & !ICRC */
+ {0x04, ABORTED_COMMAND, 0x00, 0x00}, // Aborted command Aborted command
+ /* Media change request */
+ {0x08, NOT_READY, 0x04, 0x00}, // Media change request FIXME: faking offline
+ /* SRV */
+ {0x10, ABORTED_COMMAND, 0x14, 0x00}, // ID not found Recorded entity not found
+ /* Media change */
+ {0x08, NOT_READY, 0x04, 0x00}, // Media change FIXME: faking offline
+ /* ECC */
+ {0x40, MEDIUM_ERROR, 0x11, 0x04}, // Uncorrectable ECC error Unrecovered read error
+ /* BBD - block marked bad */
+ {0x80, MEDIUM_ERROR, 0x11, 0x04}, // Block marked bad Medium error, unrecovered read error
+ {0xFF, 0xFF, 0xFF, 0xFF}, // END mark
+ };
+ static const unsigned char stat_table[][4] = {
+ /* Must be first because BUSY means no other bits valid */
+ {0x80, ABORTED_COMMAND, 0x47, 0x00}, // Busy, fake parity for now
+ {0x20, HARDWARE_ERROR, 0x00, 0x00}, // Device fault
+ {0x08, ABORTED_COMMAND, 0x47, 0x00}, // Timed out in xfer, fake parity for now
+ {0x04, RECOVERED_ERROR, 0x11, 0x00}, // Recovered ECC error Medium error, recovered
+ {0xFF, 0xFF, 0xFF, 0xFF}, // END mark
+ };
+
+ /*
+ * Is this an error we can process/parse
+ */
+ if (drv_stat & ATA_BUSY) {
+ drv_err = 0; /* Ignore the err bits, they're invalid */
+ }
+
+ if (drv_err) {
+ /* Look for drv_err */
+ for (i = 0; sense_table[i][0] != 0xFF; i++) {
+ /* Look for best matches first */
+ if ((sense_table[i][0] & drv_err) ==
+ sense_table[i][0]) {
+ *sk = sense_table[i][1];
+ *asc = sense_table[i][2];
+ *ascq = sense_table[i][3];
+ goto translate_done;
+ }
+ }
+ /* No immediate match */
+ if (verbose)
+ printk(KERN_WARNING "ata%u: no sense translation for "
+ "error 0x%02x\n", id, drv_err);
+ }
+
+ /* Fall back to interpreting status bits */
+ for (i = 0; stat_table[i][0] != 0xFF; i++) {
+ if (stat_table[i][0] & drv_stat) {
+ *sk = stat_table[i][1];
+ *asc = stat_table[i][2];
+ *ascq = stat_table[i][3];
+ goto translate_done;
+ }
+ }
+ /* No error? Undecoded? */
+ if (verbose)
+ printk(KERN_WARNING "ata%u: no sense translation for "
+ "status: 0x%02x\n", id, drv_stat);
+
+ /* We need a sensible error return here, which is tricky, and one
+ that won't cause people to do things like return a disk wrongly */
+ *sk = ABORTED_COMMAND;
+ *asc = 0x00;
+ *ascq = 0x00;
+
+ translate_done:
+ if (verbose)
+ printk(KERN_ERR "ata%u: translated ATA stat/err 0x%02x/%02x "
+ "to SCSI SK/ASC/ASCQ 0x%x/%02x/%02x\n",
+ id, drv_stat, drv_err, *sk, *asc, *ascq);
+ return;
+}
+
+/*
+ * ata_gen_ata_desc_sense - Generate check condition sense block.
+ * @qc: Command that completed.
+ *
+ * This function is specific to the ATA descriptor format sense
+ * 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.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ */
+void ata_gen_ata_desc_sense(struct ata_queued_cmd *qc)
+{
+ struct scsi_cmnd *cmd = qc->scsicmd;
+ struct ata_taskfile *tf = &qc->result_tf;
+ unsigned char *sb = cmd->sense_buffer;
+ unsigned char *desc = sb + 8;
+ int verbose = qc->ap->ops->error_handler == NULL;
+
+ memset(sb, 0, SCSI_SENSE_BUFFERSIZE);
+
+ cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
+
+ /*
+ * Use ata_to_sense_error() to map status register bits
+ * onto sense key, asc & ascq.
+ */
+ if (qc->err_mask ||
+ tf->command & (ATA_BUSY | ATA_DF | ATA_ERR | ATA_DRQ)) {
+ ata_to_sense_error(qc->ap->id, tf->command, tf->feature,
+ &sb[1], &sb[2], &sb[3], verbose);
+ sb[1] &= 0x0f;
+ }
+
+ /*
+ * Sense data is current and format is descriptor.
+ */
+ sb[0] = 0x72;
+
+ desc[0] = 0x09;
+
+ /*
+ * Set length of additional sense data.
+ * Since we only populate descriptor 0, the total
+ * length is the same (fixed) length as descriptor 0.
+ */
+ desc[1] = sb[7] = 14;
+
+ /*
+ * Copy registers into sense buffer.
+ */
+ desc[2] = 0x00;
+ desc[3] = tf->feature; /* == error reg */
+ desc[5] = tf->nsect;
+ desc[7] = tf->lbal;
+ desc[9] = tf->lbam;
+ desc[11] = tf->lbah;
+ desc[12] = tf->device;
+ desc[13] = tf->command; /* == status reg */
+
+ /*
+ * Fill in Extend bit, and the high order bytes
+ * if applicable.
+ */
+ if (tf->flags & ATA_TFLAG_LBA48) {
+ desc[2] |= 0x01;
+ desc[4] = tf->hob_nsect;
+ desc[6] = tf->hob_lbal;
+ desc[8] = tf->hob_lbam;
+ desc[10] = tf->hob_lbah;
+ }
+}
+
+/**
+ * ata_gen_fixed_sense - generate a SCSI fixed sense block
+ * @qc: Command that we are erroring out
+ *
+ * Leverage ata_to_sense_error() to give us the codes. Fit our
+ * LBA in here if there's room.
+ *
+ * LOCKING:
+ * inherited from caller
+ */
+void ata_gen_fixed_sense(struct ata_queued_cmd *qc)
+{
+ struct scsi_cmnd *cmd = qc->scsicmd;
+ struct ata_taskfile *tf = &qc->result_tf;
+ unsigned char *sb = cmd->sense_buffer;
+ int verbose = qc->ap->ops->error_handler == NULL;
+
+ memset(sb, 0, SCSI_SENSE_BUFFERSIZE);
+
+ cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
+
+ /*
+ * Use ata_to_sense_error() to map status register bits
+ * onto sense key, asc & ascq.
+ */
+ if (qc->err_mask ||
+ tf->command & (ATA_BUSY | ATA_DF | ATA_ERR | ATA_DRQ)) {
+ ata_to_sense_error(qc->ap->id, tf->command, tf->feature,
+ &sb[2], &sb[12], &sb[13], verbose);
+ sb[2] &= 0x0f;
+ }
+
+ sb[0] = 0x70;
+ sb[7] = 0x0a;
+
+ if (tf->flags & ATA_TFLAG_LBA48) {
+ /* TODO: find solution for LBA48 descriptors */
+ }
+
+ else if (tf->flags & ATA_TFLAG_LBA) {
+ /* A small (28b) LBA will fit in the 32b info field */
+ sb[0] |= 0x80; /* set valid bit */
+ sb[3] = tf->device & 0x0f;
+ sb[4] = tf->lbah;
+ sb[5] = tf->lbam;
+ sb[6] = tf->lbal;
+ }
+
+ else {
+ /* TODO: C/H/S */
+ }
+}
+
+static void ata_scsi_sdev_config(struct scsi_device *sdev)
+{
+ sdev->use_10_for_rw = 1;
+ sdev->use_10_for_ms = 1;
+}
+
+static void ata_scsi_dev_config(struct scsi_device *sdev,
+ struct ata_device *dev)
+{
+ unsigned int max_sectors;
+
+ /* TODO: 2048 is an arbitrary number, not the
+ * hardware maximum. This should be increased to
+ * 65534 when Jens Axboe's patch for dynamically
+ * determining max_sectors is merged.
+ */
+ max_sectors = ATA_MAX_SECTORS;
+ if (dev->flags & ATA_DFLAG_LBA48)
+ max_sectors = ATA_MAX_SECTORS_LBA48;
+ if (dev->max_sectors)
+ max_sectors = dev->max_sectors;
+
+ blk_queue_max_sectors(sdev->request_queue, max_sectors);
+
+ /*
+ * SATA DMA transfers must be multiples of 4 byte, so
+ * we need to pad ATAPI transfers using an extra sg.
+ * Decrement max hw segments accordingly.
+ */
+ if (dev->class == ATA_DEV_ATAPI) {
+ request_queue_t *q = sdev->request_queue;
+ blk_queue_max_hw_segments(q, q->max_hw_segments - 1);
+ }
+
+ if (dev->flags & ATA_DFLAG_NCQ) {
+ int depth;
+
+ depth = min(sdev->host->can_queue, ata_id_queue_depth(dev->id));
+ depth = min(ATA_MAX_QUEUE - 1, depth);
+ scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, depth);
+ }
+}
+
+/**
+ * ata_scsi_slave_config - Set SCSI device attributes
+ * @sdev: SCSI device to examine
+ *
+ * This is called before we actually start reading
+ * and writing to the device, to configure certain
+ * SCSI mid-layer behaviors.
+ *
+ * LOCKING:
+ * Defined by SCSI layer. We don't really care.
+ */
+
+int ata_scsi_slave_config(struct scsi_device *sdev)
+{
+ struct ata_port *ap = ata_shost_to_port(sdev->host);
+ struct ata_device *dev = __ata_scsi_find_dev(ap, sdev);
+
+ ata_scsi_sdev_config(sdev);
+
+ blk_queue_max_phys_segments(sdev->request_queue, LIBATA_MAX_PRD);
+
+ if (dev)
+ ata_scsi_dev_config(sdev, dev);
+
+ return 0; /* scsi layer doesn't check return value, sigh */
+}
+
+/**
+ * ata_scsi_slave_destroy - SCSI device is about to be destroyed
+ * @sdev: SCSI device to be destroyed
+ *
+ * @sdev is about to be destroyed for hot/warm unplugging. If
+ * this unplugging was initiated by libata as indicated by NULL
+ * dev->sdev, this function doesn't have to do anything.
+ * Otherwise, SCSI layer initiated warm-unplug is in progress.
+ * Clear dev->sdev, schedule the device for ATA detach and invoke
+ * EH.
+ *
+ * LOCKING:
+ * Defined by SCSI layer. We don't really care.
+ */
+void ata_scsi_slave_destroy(struct scsi_device *sdev)
+{
+ struct ata_port *ap = ata_shost_to_port(sdev->host);
+ unsigned long flags;
+ struct ata_device *dev;
+
+ if (!ap->ops->error_handler)
+ return;
+
+ spin_lock_irqsave(ap->lock, flags);
+ dev = __ata_scsi_find_dev(ap, sdev);
+ if (dev && dev->sdev) {
+ /* SCSI device already in CANCEL state, no need to offline it */
+ dev->sdev = NULL;
+ dev->flags |= ATA_DFLAG_DETACH;
+ ata_port_schedule_eh(ap);
+ }
+ spin_unlock_irqrestore(ap->lock, flags);
+}
+
+/**
+ * ata_scsi_change_queue_depth - SCSI callback for queue depth config
+ * @sdev: SCSI device to configure queue depth for
+ * @queue_depth: new queue depth
+ *
+ * This is libata standard hostt->change_queue_depth callback.
+ * SCSI will call into this callback when user tries to set queue
+ * depth via sysfs.
+ *
+ * LOCKING:
+ * SCSI layer (we don't care)
+ *
+ * RETURNS:
+ * Newly configured queue depth.
+ */
+int ata_scsi_change_queue_depth(struct scsi_device *sdev, int queue_depth)
+{
+ struct ata_port *ap = ata_shost_to_port(sdev->host);
+ struct ata_device *dev;
+ int max_depth;
+
+ if (queue_depth < 1)
+ return sdev->queue_depth;
+
+ dev = ata_scsi_find_dev(ap, sdev);
+ if (!dev || !ata_dev_enabled(dev))
+ return sdev->queue_depth;
+
+ max_depth = min(sdev->host->can_queue, ata_id_queue_depth(dev->id));
+ max_depth = min(ATA_MAX_QUEUE - 1, max_depth);
+ if (queue_depth > max_depth)
+ queue_depth = max_depth;
+
+ scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, queue_depth);
+ return queue_depth;
+}
+
+/**
+ * ata_scsi_start_stop_xlat - Translate SCSI START STOP UNIT command
+ * @qc: Storage for translated ATA taskfile
+ * @scsicmd: SCSI command to translate
+ *
+ * Sets up an ATA taskfile to issue STANDBY (to stop) or READ VERIFY
+ * (to start). Perhaps these commands should be preceded by
+ * CHECK POWER MODE to see what power mode the device is already in.
+ * [See SAT revision 5 at www.t10.org]
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ *
+ * RETURNS:
+ * Zero on success, non-zero on error.
+ */
+
+static unsigned int ata_scsi_start_stop_xlat(struct ata_queued_cmd *qc,
+ const u8 *scsicmd)
+{
+ struct ata_taskfile *tf = &qc->tf;
+
+ tf->flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR;
+ tf->protocol = ATA_PROT_NODATA;
+ if (scsicmd[1] & 0x1) {
+ ; /* ignore IMMED bit, violates sat-r05 */
+ }
+ if (scsicmd[4] & 0x2)
+ goto invalid_fld; /* LOEJ bit set not supported */
+ if (((scsicmd[4] >> 4) & 0xf) != 0)
+ goto invalid_fld; /* power conditions not supported */
+ if (scsicmd[4] & 0x1) {
+ tf->nsect = 1; /* 1 sector, lba=0 */
+
+ if (qc->dev->flags & ATA_DFLAG_LBA) {
+ tf->flags |= ATA_TFLAG_LBA;
+
+ tf->lbah = 0x0;
+ tf->lbam = 0x0;
+ tf->lbal = 0x0;
+ tf->device |= ATA_LBA;
+ } else {
+ /* CHS */
+ tf->lbal = 0x1; /* sect */
+ tf->lbam = 0x0; /* cyl low */
+ tf->lbah = 0x0; /* cyl high */
+ }
+
+ tf->command = ATA_CMD_VERIFY; /* READ VERIFY */
+ } else {
+ tf->nsect = 0; /* time period value (0 implies now) */
+ tf->command = ATA_CMD_STANDBY;
+ /* Consider: ATA STANDBY IMMEDIATE command */
+ }
+ /*
+ * Standby and Idle condition timers could be implemented but that
+ * would require libata to implement the Power condition mode page
+ * and allow the user to change it. Changing mode pages requires
+ * MODE SELECT to be implemented.
+ */
+
+ return 0;
+
+invalid_fld:
+ ata_scsi_set_sense(qc->scsicmd, ILLEGAL_REQUEST, 0x24, 0x0);
+ /* "Invalid field in cbd" */
+ return 1;
+}
+
+
+/**
+ * ata_scsi_flush_xlat - Translate SCSI SYNCHRONIZE CACHE command
+ * @qc: Storage for translated ATA taskfile
+ * @scsicmd: SCSI command to translate (ignored)
+ *
+ * Sets up an ATA taskfile to issue FLUSH CACHE or
+ * FLUSH CACHE EXT.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ *
+ * RETURNS:
+ * Zero on success, non-zero on error.
+ */
+
+static unsigned int ata_scsi_flush_xlat(struct ata_queued_cmd *qc, const u8 *scsicmd)
+{
+ struct ata_taskfile *tf = &qc->tf;
+
+ tf->flags |= ATA_TFLAG_DEVICE;
+ tf->protocol = ATA_PROT_NODATA;
+
+ if ((qc->dev->flags & ATA_DFLAG_LBA48) &&
+ (ata_id_has_flush_ext(qc->dev->id)))
+ tf->command = ATA_CMD_FLUSH_EXT;
+ else
+ tf->command = ATA_CMD_FLUSH;
+
+ return 0;
+}
+
+/**
+ * scsi_6_lba_len - Get LBA and transfer length
+ * @scsicmd: SCSI command to translate
+ *
+ * Calculate LBA and transfer length for 6-byte commands.
+ *
+ * RETURNS:
+ * @plba: the LBA
+ * @plen: the transfer length
+ */
+
+static void scsi_6_lba_len(const u8 *scsicmd, u64 *plba, u32 *plen)
+{
+ u64 lba = 0;
+ u32 len = 0;
+
+ VPRINTK("six-byte command\n");
+
+ lba |= ((u64)scsicmd[2]) << 8;
+ lba |= ((u64)scsicmd[3]);
+
+ len |= ((u32)scsicmd[4]);
+
+ *plba = lba;
+ *plen = len;
+}
+
+/**
+ * scsi_10_lba_len - Get LBA and transfer length
+ * @scsicmd: SCSI command to translate
+ *
+ * Calculate LBA and transfer length for 10-byte commands.
+ *
+ * RETURNS:
+ * @plba: the LBA
+ * @plen: the transfer length
+ */
+
+static void scsi_10_lba_len(const u8 *scsicmd, u64 *plba, u32 *plen)
+{
+ u64 lba = 0;
+ u32 len = 0;
+
+ VPRINTK("ten-byte command\n");
+
+ lba |= ((u64)scsicmd[2]) << 24;
+ lba |= ((u64)scsicmd[3]) << 16;
+ lba |= ((u64)scsicmd[4]) << 8;
+ lba |= ((u64)scsicmd[5]);
+
+ len |= ((u32)scsicmd[7]) << 8;
+ len |= ((u32)scsicmd[8]);
+
+ *plba = lba;
+ *plen = len;
+}
+
+/**
+ * scsi_16_lba_len - Get LBA and transfer length
+ * @scsicmd: SCSI command to translate
+ *
+ * Calculate LBA and transfer length for 16-byte commands.
+ *
+ * RETURNS:
+ * @plba: the LBA
+ * @plen: the transfer length
+ */
+
+static void scsi_16_lba_len(const u8 *scsicmd, u64 *plba, u32 *plen)
+{
+ u64 lba = 0;
+ u32 len = 0;
+
+ VPRINTK("sixteen-byte command\n");
+
+ lba |= ((u64)scsicmd[2]) << 56;
+ lba |= ((u64)scsicmd[3]) << 48;
+ lba |= ((u64)scsicmd[4]) << 40;
+ lba |= ((u64)scsicmd[5]) << 32;
+ lba |= ((u64)scsicmd[6]) << 24;
+ lba |= ((u64)scsicmd[7]) << 16;
+ lba |= ((u64)scsicmd[8]) << 8;
+ lba |= ((u64)scsicmd[9]);
+
+ len |= ((u32)scsicmd[10]) << 24;
+ len |= ((u32)scsicmd[11]) << 16;
+ len |= ((u32)scsicmd[12]) << 8;
+ len |= ((u32)scsicmd[13]);
+
+ *plba = lba;
+ *plen = len;
+}
+
+/**
+ * ata_scsi_verify_xlat - Translate SCSI VERIFY command into an ATA one
+ * @qc: Storage for translated ATA taskfile
+ * @scsicmd: SCSI command to translate
+ *
+ * Converts SCSI VERIFY command to an ATA READ VERIFY command.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ *
+ * RETURNS:
+ * Zero on success, non-zero on error.
+ */
+
+static unsigned int ata_scsi_verify_xlat(struct ata_queued_cmd *qc, const u8 *scsicmd)
+{
+ struct ata_taskfile *tf = &qc->tf;
+ struct ata_device *dev = qc->dev;
+ u64 dev_sectors = qc->dev->n_sectors;
+ u64 block;
+ u32 n_block;
+
+ tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
+ tf->protocol = ATA_PROT_NODATA;
+
+ if (scsicmd[0] == VERIFY)
+ scsi_10_lba_len(scsicmd, &block, &n_block);
+ else if (scsicmd[0] == VERIFY_16)
+ scsi_16_lba_len(scsicmd, &block, &n_block);
+ else
+ goto invalid_fld;
+
+ if (!n_block)
+ goto nothing_to_do;
+ if (block >= dev_sectors)
+ goto out_of_range;
+ if ((block + n_block) > dev_sectors)
+ goto out_of_range;
+
+ if (dev->flags & ATA_DFLAG_LBA) {
+ tf->flags |= ATA_TFLAG_LBA;
+
+ if (lba_28_ok(block, n_block)) {
+ /* use LBA28 */
+ tf->command = ATA_CMD_VERIFY;
+ tf->device |= (block >> 24) & 0xf;
+ } else if (lba_48_ok(block, n_block)) {
+ if (!(dev->flags & ATA_DFLAG_LBA48))
+ goto out_of_range;
+
+ /* use LBA48 */
+ tf->flags |= ATA_TFLAG_LBA48;
+ tf->command = ATA_CMD_VERIFY_EXT;
+
+ tf->hob_nsect = (n_block >> 8) & 0xff;
+
+ tf->hob_lbah = (block >> 40) & 0xff;
+ tf->hob_lbam = (block >> 32) & 0xff;
+ tf->hob_lbal = (block >> 24) & 0xff;
+ } else
+ /* request too large even for LBA48 */
+ goto out_of_range;
+
+ tf->nsect = n_block & 0xff;
+
+ tf->lbah = (block >> 16) & 0xff;
+ tf->lbam = (block >> 8) & 0xff;
+ tf->lbal = block & 0xff;
+
+ tf->device |= ATA_LBA;
+ } else {
+ /* CHS */
+ u32 sect, head, cyl, track;
+
+ if (!lba_28_ok(block, n_block))
+ goto out_of_range;
+
+ /* Convert LBA to CHS */
+ track = (u32)block / dev->sectors;
+ cyl = track / dev->heads;
+ head = track % dev->heads;
+ sect = (u32)block % dev->sectors + 1;
+
+ DPRINTK("block %u track %u cyl %u head %u sect %u\n",
+ (u32)block, track, cyl, head, sect);
+
+ /* Check whether the converted CHS can fit.
+ Cylinder: 0-65535
+ Head: 0-15
+ Sector: 1-255*/
+ if ((cyl >> 16) || (head >> 4) || (sect >> 8) || (!sect))
+ goto out_of_range;
+
+ tf->command = ATA_CMD_VERIFY;
+ tf->nsect = n_block & 0xff; /* Sector count 0 means 256 sectors */
+ tf->lbal = sect;
+ tf->lbam = cyl;
+ tf->lbah = cyl >> 8;
+ tf->device |= head;
+ }
+
+ return 0;
+
+invalid_fld:
+ ata_scsi_set_sense(qc->scsicmd, ILLEGAL_REQUEST, 0x24, 0x0);
+ /* "Invalid field in cbd" */
+ return 1;
+
+out_of_range:
+ ata_scsi_set_sense(qc->scsicmd, ILLEGAL_REQUEST, 0x21, 0x0);
+ /* "Logical Block Address out of range" */
+ return 1;
+
+nothing_to_do:
+ qc->scsicmd->result = SAM_STAT_GOOD;
+ return 1;
+}
+
+/**
+ * ata_scsi_rw_xlat - Translate SCSI r/w command into an ATA one
+ * @qc: Storage for translated ATA taskfile
+ * @scsicmd: SCSI command to translate
+ *
+ * Converts any of six SCSI read/write commands into the
+ * ATA counterpart, including starting sector (LBA),
+ * sector count, and taking into account the device's LBA48
+ * support.
+ *
+ * Commands %READ_6, %READ_10, %READ_16, %WRITE_6, %WRITE_10, and
+ * %WRITE_16 are currently supported.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ *
+ * RETURNS:
+ * Zero on success, non-zero on error.
+ */
+
+static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, const u8 *scsicmd)
+{
+ struct ata_taskfile *tf = &qc->tf;
+ struct ata_device *dev = qc->dev;
+ u64 block;
+ u32 n_block;
+
+ qc->flags |= ATA_QCFLAG_IO;
+ tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
+
+ if (scsicmd[0] == WRITE_10 || scsicmd[0] == WRITE_6 ||
+ scsicmd[0] == WRITE_16)
+ tf->flags |= ATA_TFLAG_WRITE;
+
+ /* Calculate the SCSI LBA, transfer length and FUA. */
+ switch (scsicmd[0]) {
+ case READ_10:
+ case WRITE_10:
+ scsi_10_lba_len(scsicmd, &block, &n_block);
+ if (unlikely(scsicmd[1] & (1 << 3)))
+ tf->flags |= ATA_TFLAG_FUA;
+ break;
+ case READ_6:
+ case WRITE_6:
+ scsi_6_lba_len(scsicmd, &block, &n_block);
+
+ /* for 6-byte r/w commands, transfer length 0
+ * means 256 blocks of data, not 0 block.
+ */
+ if (!n_block)
+ n_block = 256;
+ break;
+ case READ_16:
+ case WRITE_16:
+ scsi_16_lba_len(scsicmd, &block, &n_block);
+ if (unlikely(scsicmd[1] & (1 << 3)))
+ tf->flags |= ATA_TFLAG_FUA;
+ break;
+ default:
+ DPRINTK("no-byte command\n");
+ goto invalid_fld;
+ }
+
+ /* Check and compose ATA command */
+ if (!n_block)
+ /* For 10-byte and 16-byte SCSI R/W commands, transfer
+ * length 0 means transfer 0 block of data.
+ * However, for ATA R/W commands, sector count 0 means
+ * 256 or 65536 sectors, not 0 sectors as in SCSI.
+ *
+ * WARNING: one or two older ATA drives treat 0 as 0...
+ */
+ goto nothing_to_do;
+
+ if ((dev->flags & (ATA_DFLAG_PIO | ATA_DFLAG_NCQ)) == ATA_DFLAG_NCQ) {
+ /* yay, NCQ */
+ if (!lba_48_ok(block, n_block))
+ goto out_of_range;
+
+ tf->protocol = ATA_PROT_NCQ;
+ tf->flags |= ATA_TFLAG_LBA | ATA_TFLAG_LBA48;
+
+ if (tf->flags & ATA_TFLAG_WRITE)
+ tf->command = ATA_CMD_FPDMA_WRITE;
+ else
+ tf->command = ATA_CMD_FPDMA_READ;
+
+ qc->nsect = n_block;
+
+ tf->nsect = qc->tag << 3;
+ tf->hob_feature = (n_block >> 8) & 0xff;
+ tf->feature = n_block & 0xff;
+
+ tf->hob_lbah = (block >> 40) & 0xff;
+ tf->hob_lbam = (block >> 32) & 0xff;
+ tf->hob_lbal = (block >> 24) & 0xff;
+ tf->lbah = (block >> 16) & 0xff;
+ tf->lbam = (block >> 8) & 0xff;
+ tf->lbal = block & 0xff;
+
+ tf->device = 1 << 6;
+ if (tf->flags & ATA_TFLAG_FUA)
+ tf->device |= 1 << 7;
+ } else if (dev->flags & ATA_DFLAG_LBA) {
+ tf->flags |= ATA_TFLAG_LBA;
+
+ if (lba_28_ok(block, n_block)) {
+ /* use LBA28 */
+ tf->device |= (block >> 24) & 0xf;
+ } else if (lba_48_ok(block, n_block)) {
+ if (!(dev->flags & ATA_DFLAG_LBA48))
+ goto out_of_range;
+
+ /* use LBA48 */
+ tf->flags |= ATA_TFLAG_LBA48;
+
+ tf->hob_nsect = (n_block >> 8) & 0xff;
+
+ tf->hob_lbah = (block >> 40) & 0xff;
+ tf->hob_lbam = (block >> 32) & 0xff;
+ tf->hob_lbal = (block >> 24) & 0xff;
+ } else
+ /* request too large even for LBA48 */
+ goto out_of_range;
+
+ if (unlikely(ata_rwcmd_protocol(qc) < 0))
+ goto invalid_fld;
+
+ qc->nsect = n_block;
+ tf->nsect = n_block & 0xff;
+
+ tf->lbah = (block >> 16) & 0xff;
+ tf->lbam = (block >> 8) & 0xff;
+ tf->lbal = block & 0xff;
+
+ tf->device |= ATA_LBA;
+ } else {
+ /* CHS */
+ u32 sect, head, cyl, track;
+
+ /* The request -may- be too large for CHS addressing. */
+ if (!lba_28_ok(block, n_block))
+ goto out_of_range;
+
+ if (unlikely(ata_rwcmd_protocol(qc) < 0))
+ goto invalid_fld;
+
+ /* Convert LBA to CHS */
+ track = (u32)block / dev->sectors;
+ cyl = track / dev->heads;
+ head = track % dev->heads;
+ sect = (u32)block % dev->sectors + 1;
+
+ DPRINTK("block %u track %u cyl %u head %u sect %u\n",
+ (u32)block, track, cyl, head, sect);
+
+ /* Check whether the converted CHS can fit.
+ Cylinder: 0-65535
+ Head: 0-15
+ Sector: 1-255*/
+ if ((cyl >> 16) || (head >> 4) || (sect >> 8) || (!sect))
+ goto out_of_range;
+
+ qc->nsect = n_block;
+ tf->nsect = n_block & 0xff; /* Sector count 0 means 256 sectors */
+ tf->lbal = sect;
+ tf->lbam = cyl;
+ tf->lbah = cyl >> 8;
+ tf->device |= head;
+ }
+
+ return 0;
+
+invalid_fld:
+ ata_scsi_set_sense(qc->scsicmd, ILLEGAL_REQUEST, 0x24, 0x0);
+ /* "Invalid field in cbd" */
+ return 1;
+
+out_of_range:
+ ata_scsi_set_sense(qc->scsicmd, ILLEGAL_REQUEST, 0x21, 0x0);
+ /* "Logical Block Address out of range" */
+ return 1;
+
+nothing_to_do:
+ qc->scsicmd->result = SAM_STAT_GOOD;
+ return 1;
+}
+
+static void ata_scsi_qc_complete(struct ata_queued_cmd *qc)
+{
+ struct scsi_cmnd *cmd = qc->scsicmd;
+ u8 *cdb = cmd->cmnd;
+ int need_sense = (qc->err_mask != 0);
+
+ /* We snoop the SET_FEATURES - Write Cache ON/OFF command, and
+ * schedule EH_REVALIDATE operation to update the IDENTIFY DEVICE
+ * cache
+ */
+ if (!need_sense && (qc->tf.command == ATA_CMD_SET_FEATURES) &&
+ ((qc->tf.feature == SETFEATURES_WC_ON) ||
+ (qc->tf.feature == SETFEATURES_WC_OFF))) {
+ qc->ap->eh_info.action |= ATA_EH_REVALIDATE;
+ ata_port_schedule_eh(qc->ap);
+ }
+
+ /* 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
+ * whether the command completed successfully or not. If there
+ * was no error, SK, ASC and ASCQ will all be zero.
+ */
+ if (((cdb[0] == ATA_16) || (cdb[0] == ATA_12)) &&
+ ((cdb[2] & 0x20) || need_sense)) {
+ ata_gen_ata_desc_sense(qc);
+ } else {
+ if (!need_sense) {
+ cmd->result = SAM_STAT_GOOD;
+ } else {
+ /* TODO: decide which descriptor format to use
+ * for 48b LBA devices and call that here
+ * instead of the fixed desc, which is only
+ * good for smaller LBA (and maybe CHS?)
+ * devices.
+ */
+ ata_gen_fixed_sense(qc);
+ }
+ }
+
+ if (need_sense && !qc->ap->ops->error_handler)
+ ata_dump_status(qc->ap->id, &qc->result_tf);
+
+ qc->scsidone(cmd);
+
+ ata_qc_free(qc);
+}
+
+/**
+ * ata_scmd_need_defer - Check whether we need to defer scmd
+ * @dev: ATA device to which the command is addressed
+ * @is_io: Is the command IO (and thus possibly NCQ)?
+ *
+ * NCQ and non-NCQ commands cannot run together. As upper layer
+ * only knows the queue depth, we are responsible for maintaining
+ * exclusion. This function checks whether a new command can be
+ * issued to @dev.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ *
+ * RETURNS:
+ * 1 if deferring is needed, 0 otherwise.
+ */
+static int ata_scmd_need_defer(struct ata_device *dev, int is_io)
+{
+ struct ata_port *ap = dev->ap;
+
+ if (!(dev->flags & ATA_DFLAG_NCQ))
+ return 0;
+
+ if (is_io) {
+ if (!ata_tag_valid(ap->active_tag))
+ return 0;
+ } else {
+ if (!ata_tag_valid(ap->active_tag) && !ap->sactive)
+ return 0;
+ }
+ return 1;
+}
+
+/**
+ * ata_scsi_translate - Translate then issue SCSI command to ATA device
+ * @dev: ATA device to which the command is addressed
+ * @cmd: SCSI command to execute
+ * @done: SCSI command completion function
+ * @xlat_func: Actor which translates @cmd to an ATA taskfile
+ *
+ * Our ->queuecommand() function has decided that the SCSI
+ * command issued can be directly translated into an ATA
+ * command, rather than handled internally.
+ *
+ * This function sets up an ata_queued_cmd structure for the
+ * SCSI command, and sends that ata_queued_cmd to the hardware.
+ *
+ * The xlat_func argument (actor) returns 0 if ready to execute
+ * ATA command, else 1 to finish translation. If 1 is returned
+ * then cmd->result (and possibly cmd->sense_buffer) are assumed
+ * to be set reflecting an error condition or clean (early)
+ * termination.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ *
+ * RETURNS:
+ * 0 on success, SCSI_ML_QUEUE_DEVICE_BUSY if the command
+ * needs to be deferred.
+ */
+static int ata_scsi_translate(struct ata_device *dev, struct scsi_cmnd *cmd,
+ void (*done)(struct scsi_cmnd *),
+ ata_xlat_func_t xlat_func)
+{
+ struct ata_queued_cmd *qc;
+ u8 *scsicmd = cmd->cmnd;
+ int is_io = xlat_func == ata_scsi_rw_xlat;
+
+ VPRINTK("ENTER\n");
+
+ if (unlikely(ata_scmd_need_defer(dev, is_io)))
+ goto defer;
+
+ qc = ata_scsi_qc_new(dev, cmd, done);
+ if (!qc)
+ goto err_mem;
+
+ /* data is present; dma-map it */
+ if (cmd->sc_data_direction == DMA_FROM_DEVICE ||
+ cmd->sc_data_direction == DMA_TO_DEVICE) {
+ if (unlikely(cmd->request_bufflen < 1)) {
+ ata_dev_printk(dev, KERN_WARNING,
+ "WARNING: zero len r/w req\n");
+ goto err_did;
+ }
+
+ if (cmd->use_sg)
+ ata_sg_init(qc, cmd->request_buffer, cmd->use_sg);
+ else
+ ata_sg_init_one(qc, cmd->request_buffer,
+ cmd->request_bufflen);
+
+ qc->dma_dir = cmd->sc_data_direction;
+ }
+
+ qc->complete_fn = ata_scsi_qc_complete;
+
+ if (xlat_func(qc, scsicmd))
+ goto early_finish;
+
+ /* select device, send command to hardware */
+ ata_qc_issue(qc);
+
+ VPRINTK("EXIT\n");
+ return 0;
+
+early_finish:
+ ata_qc_free(qc);
+ done(cmd);
+ DPRINTK("EXIT - early finish (good or error)\n");
+ return 0;
+
+err_did:
+ ata_qc_free(qc);
+err_mem:
+ cmd->result = (DID_ERROR << 16);
+ done(cmd);
+ DPRINTK("EXIT - internal\n");
+ return 0;
+
+defer:
+ DPRINTK("EXIT - defer\n");
+ return SCSI_MLQUEUE_DEVICE_BUSY;
+}
+
+/**
+ * ata_scsi_rbuf_get - Map response buffer.
+ * @cmd: SCSI command containing buffer to be mapped.
+ * @buf_out: Pointer to mapped area.
+ *
+ * Maps buffer contained within SCSI command @cmd.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ *
+ * RETURNS:
+ * Length of response buffer.
+ */
+
+static unsigned int ata_scsi_rbuf_get(struct scsi_cmnd *cmd, u8 **buf_out)
+{
+ u8 *buf;
+ unsigned int buflen;
+
+ if (cmd->use_sg) {
+ struct scatterlist *sg;
+
+ sg = (struct scatterlist *) cmd->request_buffer;
+ buf = kmap_atomic(sg->page, KM_USER0) + sg->offset;
+ buflen = sg->length;
+ } else {
+ buf = cmd->request_buffer;
+ buflen = cmd->request_bufflen;
+ }
+
+ *buf_out = buf;
+ return buflen;
+}
+
+/**
+ * ata_scsi_rbuf_put - Unmap response buffer.
+ * @cmd: SCSI command containing buffer to be unmapped.
+ * @buf: buffer to unmap
+ *
+ * Unmaps response buffer contained within @cmd.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ */
+
+static inline void ata_scsi_rbuf_put(struct scsi_cmnd *cmd, u8 *buf)
+{
+ if (cmd->use_sg) {
+ struct scatterlist *sg;
+
+ sg = (struct scatterlist *) cmd->request_buffer;
+ kunmap_atomic(buf - sg->offset, KM_USER0);
+ }
+}
+
+/**
+ * ata_scsi_rbuf_fill - wrapper for SCSI command simulators
+ * @args: device IDENTIFY data / SCSI command of interest.
+ * @actor: Callback hook for desired SCSI command simulator
+ *
+ * Takes care of the hard work of simulating a SCSI command...
+ * Mapping the response buffer, calling the command's handler,
+ * and handling the handler's return value. This return value
+ * indicates whether the handler wishes the SCSI command to be
+ * completed successfully (0), or not (in which case cmd->result
+ * and sense buffer are assumed to be set).
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ */
+
+void ata_scsi_rbuf_fill(struct ata_scsi_args *args,
+ unsigned int (*actor) (struct ata_scsi_args *args,
+ u8 *rbuf, unsigned int buflen))
+{
+ u8 *rbuf;
+ unsigned int buflen, rc;
+ struct scsi_cmnd *cmd = args->cmd;
+
+ buflen = ata_scsi_rbuf_get(cmd, &rbuf);
+ memset(rbuf, 0, buflen);
+ rc = actor(args, rbuf, buflen);
+ ata_scsi_rbuf_put(cmd, rbuf);
+
+ if (rc == 0)
+ cmd->result = SAM_STAT_GOOD;
+ args->done(cmd);
+}
+
+/**
+ * ata_scsiop_inq_std - Simulate INQUIRY command
+ * @args: device IDENTIFY data / SCSI command of interest.
+ * @rbuf: Response buffer, to which simulated SCSI cmd output is sent.
+ * @buflen: Response buffer length.
+ *
+ * Returns standard device identification data associated
+ * with non-VPD INQUIRY command output.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ */
+
+unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf,
+ unsigned int buflen)
+{
+ u8 hdr[] = {
+ TYPE_DISK,
+ 0,
+ 0x5, /* claim SPC-3 version compatibility */
+ 2,
+ 95 - 4
+ };
+
+ /* set scsi removeable (RMB) bit per ata bit */
+ if (ata_id_removeable(args->id))
+ hdr[1] |= (1 << 7);
+
+ VPRINTK("ENTER\n");
+
+ memcpy(rbuf, hdr, sizeof(hdr));
+
+ if (buflen > 35) {
+ memcpy(&rbuf[8], "ATA ", 8);
+ ata_id_string(args->id, &rbuf[16], ATA_ID_PROD_OFS, 16);
+ ata_id_string(args->id, &rbuf[32], ATA_ID_FW_REV_OFS, 4);
+ if (rbuf[32] == 0 || rbuf[32] == ' ')
+ memcpy(&rbuf[32], "n/a ", 4);
+ }
+
+ if (buflen > 63) {
+ const u8 versions[] = {
+ 0x60, /* SAM-3 (no version claimed) */
+
+ 0x03,
+ 0x20, /* SBC-2 (no version claimed) */
+
+ 0x02,
+ 0x60 /* SPC-3 (no version claimed) */
+ };
+
+ memcpy(rbuf + 59, versions, sizeof(versions));
+ }
+
+ return 0;
+}
+
+/**
+ * ata_scsiop_inq_00 - Simulate INQUIRY VPD page 0, list of pages
+ * @args: device IDENTIFY data / SCSI command of interest.
+ * @rbuf: Response buffer, to which simulated SCSI cmd output is sent.
+ * @buflen: Response buffer length.
+ *
+ * Returns list of inquiry VPD pages available.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ */
+
+unsigned int ata_scsiop_inq_00(struct ata_scsi_args *args, u8 *rbuf,
+ unsigned int buflen)
+{
+ const u8 pages[] = {
+ 0x00, /* page 0x00, this page */
+ 0x80, /* page 0x80, unit serial no page */
+ 0x83 /* page 0x83, device ident page */
+ };
+ rbuf[3] = sizeof(pages); /* number of supported VPD pages */
+
+ if (buflen > 6)
+ memcpy(rbuf + 4, pages, sizeof(pages));
+
+ return 0;
+}
+
+/**
+ * ata_scsiop_inq_80 - Simulate INQUIRY VPD page 80, device serial number
+ * @args: device IDENTIFY data / SCSI command of interest.
+ * @rbuf: Response buffer, to which simulated SCSI cmd output is sent.
+ * @buflen: Response buffer length.
+ *
+ * Returns ATA device serial number.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ */
+
+unsigned int ata_scsiop_inq_80(struct ata_scsi_args *args, u8 *rbuf,
+ unsigned int buflen)
+{
+ const u8 hdr[] = {
+ 0,
+ 0x80, /* this page code */
+ 0,
+ ATA_SERNO_LEN, /* page len */
+ };
+ memcpy(rbuf, hdr, sizeof(hdr));
+
+ if (buflen > (ATA_SERNO_LEN + 4 - 1))
+ ata_id_string(args->id, (unsigned char *) &rbuf[4],
+ ATA_ID_SERNO_OFS, ATA_SERNO_LEN);
+
+ return 0;
+}
+
+/**
+ * ata_scsiop_inq_83 - Simulate INQUIRY VPD page 83, device identity
+ * @args: device IDENTIFY data / SCSI command of interest.
+ * @rbuf: Response buffer, to which simulated SCSI cmd output is sent.
+ * @buflen: Response buffer length.
+ *
+ * Yields two logical unit device identification designators:
+ * - vendor specific ASCII containing the ATA serial number
+ * - SAT defined "t10 vendor id based" containing ASCII vendor
+ * name ("ATA "), model and serial numbers.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ */
+
+unsigned int ata_scsiop_inq_83(struct ata_scsi_args *args, u8 *rbuf,
+ unsigned int buflen)
+{
+ int num;
+ const int sat_model_serial_desc_len = 68;
+ const int ata_model_byte_len = 40;
+
+ rbuf[1] = 0x83; /* this page code */
+ num = 4;
+
+ if (buflen > (ATA_SERNO_LEN + num + 3)) {
+ /* piv=0, assoc=lu, code_set=ACSII, designator=vendor */
+ rbuf[num + 0] = 2;
+ rbuf[num + 3] = ATA_SERNO_LEN;
+ num += 4;
+ ata_id_string(args->id, (unsigned char *) rbuf + num,
+ ATA_ID_SERNO_OFS, ATA_SERNO_LEN);
+ num += ATA_SERNO_LEN;
+ }
+ if (buflen > (sat_model_serial_desc_len + num + 3)) {
+ /* SAT defined lu model and serial numbers descriptor */
+ /* piv=0, assoc=lu, code_set=ACSII, designator=t10 vendor id */
+ rbuf[num + 0] = 2;
+ rbuf[num + 1] = 1;
+ rbuf[num + 3] = sat_model_serial_desc_len;
+ num += 4;
+ memcpy(rbuf + num, "ATA ", 8);
+ num += 8;
+ ata_id_string(args->id, (unsigned char *) rbuf + num,
+ ATA_ID_PROD_OFS, ata_model_byte_len);
+ num += ata_model_byte_len;
+ ata_id_string(args->id, (unsigned char *) rbuf + num,
+ ATA_ID_SERNO_OFS, ATA_SERNO_LEN);
+ num += ATA_SERNO_LEN;
+ }
+ rbuf[3] = num - 4; /* page len (assume less than 256 bytes) */
+ return 0;
+}
+
+/**
+ * ata_scsiop_noop - Command handler that simply returns success.
+ * @args: device IDENTIFY data / SCSI command of interest.
+ * @rbuf: Response buffer, to which simulated SCSI cmd output is sent.
+ * @buflen: Response buffer length.
+ *
+ * No operation. Simply returns success to caller, to indicate
+ * that the caller should successfully complete this SCSI command.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ */
+
+unsigned int ata_scsiop_noop(struct ata_scsi_args *args, u8 *rbuf,
+ unsigned int buflen)
+{
+ VPRINTK("ENTER\n");
+ return 0;
+}
+
+/**
+ * ata_msense_push - Push data onto MODE SENSE data output buffer
+ * @ptr_io: (input/output) Location to store more output data
+ * @last: End of output data buffer
+ * @buf: Pointer to BLOB being added to output buffer
+ * @buflen: Length of BLOB
+ *
+ * Store MODE SENSE data on an output buffer.
+ *
+ * LOCKING:
+ * None.
+ */
+
+static void ata_msense_push(u8 **ptr_io, const u8 *last,
+ const u8 *buf, unsigned int buflen)
+{
+ u8 *ptr = *ptr_io;
+
+ if ((ptr + buflen - 1) > last)
+ return;
+
+ memcpy(ptr, buf, buflen);
+
+ ptr += buflen;
+
+ *ptr_io = ptr;
+}
+
+/**
+ * ata_msense_caching - Simulate MODE SENSE caching info page
+ * @id: device IDENTIFY data
+ * @ptr_io: (input/output) Location to store more output data
+ * @last: End of output data buffer
+ *
+ * Generate a caching info page, which conditionally indicates
+ * write caching to the SCSI layer, depending on device
+ * capabilities.
+ *
+ * LOCKING:
+ * None.
+ */
+
+static unsigned int ata_msense_caching(u16 *id, u8 **ptr_io,
+ const u8 *last)
+{
+ u8 page[CACHE_MPAGE_LEN];
+
+ memcpy(page, def_cache_mpage, sizeof(page));
+ if (ata_id_wcache_enabled(id))
+ page[2] |= (1 << 2); /* write cache enable */
+ if (!ata_id_rahead_enabled(id))
+ page[12] |= (1 << 5); /* disable read ahead */
+
+ ata_msense_push(ptr_io, last, page, sizeof(page));
+ return sizeof(page);
+}
+
+/**
+ * ata_msense_ctl_mode - Simulate MODE SENSE control mode page
+ * @dev: Device associated with this MODE SENSE command
+ * @ptr_io: (input/output) Location to store more output data
+ * @last: End of output data buffer
+ *
+ * Generate a generic MODE SENSE control mode page.
+ *
+ * LOCKING:
+ * None.
+ */
+
+static unsigned int ata_msense_ctl_mode(u8 **ptr_io, const u8 *last)
+{
+ ata_msense_push(ptr_io, last, def_control_mpage,
+ sizeof(def_control_mpage));
+ return sizeof(def_control_mpage);
+}
+
+/**
+ * ata_msense_rw_recovery - Simulate MODE SENSE r/w error recovery page
+ * @dev: Device associated with this MODE SENSE command
+ * @ptr_io: (input/output) Location to store more output data
+ * @last: End of output data buffer
+ *
+ * Generate a generic MODE SENSE r/w error recovery page.
+ *
+ * LOCKING:
+ * None.
+ */
+
+static unsigned int ata_msense_rw_recovery(u8 **ptr_io, const u8 *last)
+{
+
+ ata_msense_push(ptr_io, last, def_rw_recovery_mpage,
+ sizeof(def_rw_recovery_mpage));
+ return sizeof(def_rw_recovery_mpage);
+}
+
+/*
+ * We can turn this into a real blacklist if it's needed, for now just
+ * blacklist any Maxtor BANC1G10 revision firmware
+ */
+static int ata_dev_supports_fua(u16 *id)
+{
+ unsigned char model[41], fw[9];
+
+ if (!libata_fua)
+ return 0;
+ if (!ata_id_has_fua(id))
+ return 0;
+
+ ata_id_c_string(id, model, ATA_ID_PROD_OFS, sizeof(model));
+ ata_id_c_string(id, fw, ATA_ID_FW_REV_OFS, sizeof(fw));
+
+ if (strcmp(model, "Maxtor"))
+ return 1;
+ if (strcmp(fw, "BANC1G10"))
+ return 1;
+
+ return 0; /* blacklisted */
+}
+
+/**
+ * ata_scsiop_mode_sense - Simulate MODE SENSE 6, 10 commands
+ * @args: device IDENTIFY data / SCSI command of interest.
+ * @rbuf: Response buffer, to which simulated SCSI cmd output is sent.
+ * @buflen: Response buffer length.
+ *
+ * Simulate MODE SENSE commands. Assume this is invoked for direct
+ * access devices (e.g. disks) only. There should be no block
+ * descriptor for other device types.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ */
+
+unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf,
+ unsigned int buflen)
+{
+ struct ata_device *dev = args->dev;
+ u8 *scsicmd = args->cmd->cmnd, *p, *last;
+ const u8 sat_blk_desc[] = {
+ 0, 0, 0, 0, /* number of blocks: sat unspecified */
+ 0,
+ 0, 0x2, 0x0 /* block length: 512 bytes */
+ };
+ u8 pg, spg;
+ unsigned int ebd, page_control, six_byte, output_len, alloc_len, minlen;
+ u8 dpofua;
+
+ VPRINTK("ENTER\n");
+
+ six_byte = (scsicmd[0] == MODE_SENSE);
+ ebd = !(scsicmd[1] & 0x8); /* dbd bit inverted == edb */
+ /*
+ * LLBA bit in msense(10) ignored (compliant)
+ */
+
+ page_control = scsicmd[2] >> 6;
+ switch (page_control) {
+ case 0: /* current */
+ break; /* supported */
+ case 3: /* saved */
+ goto saving_not_supp;
+ case 1: /* changeable */
+ case 2: /* defaults */
+ default:
+ goto invalid_fld;
+ }
+
+ if (six_byte) {
+ output_len = 4 + (ebd ? 8 : 0);
+ alloc_len = scsicmd[4];
+ } else {
+ output_len = 8 + (ebd ? 8 : 0);
+ alloc_len = (scsicmd[7] << 8) + scsicmd[8];
+ }
+ minlen = (alloc_len < buflen) ? alloc_len : buflen;
+
+ p = rbuf + output_len;
+ last = rbuf + minlen - 1;
+
+ pg = scsicmd[2] & 0x3f;
+ spg = scsicmd[3];
+ /*
+ * No mode subpages supported (yet) but asking for _all_
+ * subpages may be valid
+ */
+ if (spg && (spg != ALL_SUB_MPAGES))
+ goto invalid_fld;
+
+ switch(pg) {
+ case RW_RECOVERY_MPAGE:
+ output_len += ata_msense_rw_recovery(&p, last);
+ break;
+
+ case CACHE_MPAGE:
+ output_len += ata_msense_caching(args->id, &p, last);
+ break;
+
+ case CONTROL_MPAGE: {
+ output_len += ata_msense_ctl_mode(&p, last);
+ break;
+ }
+
+ case ALL_MPAGES:
+ output_len += ata_msense_rw_recovery(&p, last);
+ output_len += ata_msense_caching(args->id, &p, last);
+ output_len += ata_msense_ctl_mode(&p, last);
+ break;
+
+ default: /* invalid page code */
+ goto invalid_fld;
+ }
+
+ if (minlen < 1)
+ return 0;
+
+ dpofua = 0;
+ if (ata_dev_supports_fua(args->id) && (dev->flags & ATA_DFLAG_LBA48) &&
+ (!(dev->flags & ATA_DFLAG_PIO) || dev->multi_count))
+ dpofua = 1 << 4;
+
+ if (six_byte) {
+ output_len--;
+ rbuf[0] = output_len;
+ if (minlen > 2)
+ rbuf[2] |= dpofua;
+ if (ebd) {
+ if (minlen > 3)
+ rbuf[3] = sizeof(sat_blk_desc);
+ if (minlen > 11)
+ memcpy(rbuf + 4, sat_blk_desc,
+ sizeof(sat_blk_desc));
+ }
+ } else {
+ output_len -= 2;
+ rbuf[0] = output_len >> 8;
+ if (minlen > 1)
+ rbuf[1] = output_len;
+ if (minlen > 3)
+ rbuf[3] |= dpofua;
+ if (ebd) {
+ if (minlen > 7)
+ rbuf[7] = sizeof(sat_blk_desc);
+ if (minlen > 15)
+ memcpy(rbuf + 8, sat_blk_desc,
+ sizeof(sat_blk_desc));
+ }
+ }
+ return 0;
+
+invalid_fld:
+ ata_scsi_set_sense(args->cmd, ILLEGAL_REQUEST, 0x24, 0x0);
+ /* "Invalid field in cbd" */
+ return 1;
+
+saving_not_supp:
+ ata_scsi_set_sense(args->cmd, ILLEGAL_REQUEST, 0x39, 0x0);
+ /* "Saving parameters not supported" */
+ return 1;
+}
+
+/**
+ * ata_scsiop_read_cap - Simulate READ CAPACITY[ 16] commands
+ * @args: device IDENTIFY data / SCSI command of interest.
+ * @rbuf: Response buffer, to which simulated SCSI cmd output is sent.
+ * @buflen: Response buffer length.
+ *
+ * Simulate READ CAPACITY commands.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ */
+
+unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf,
+ unsigned int buflen)
+{
+ u64 n_sectors;
+ u32 tmp;
+
+ VPRINTK("ENTER\n");
+
+ if (ata_id_has_lba(args->id)) {
+ if (ata_id_has_lba48(args->id))
+ n_sectors = ata_id_u64(args->id, 100);
+ else
+ n_sectors = ata_id_u32(args->id, 60);
+ } else {
+ /* CHS default translation */
+ n_sectors = args->id[1] * args->id[3] * args->id[6];
+
+ if (ata_id_current_chs_valid(args->id))
+ /* CHS current translation */
+ n_sectors = ata_id_u32(args->id, 57);
+ }
+
+ n_sectors--; /* ATA TotalUserSectors - 1 */
+
+ if (args->cmd->cmnd[0] == READ_CAPACITY) {
+ if( n_sectors >= 0xffffffffULL )
+ tmp = 0xffffffff ; /* Return max count on overflow */
+ else
+ tmp = n_sectors ;
+
+ /* sector count, 32-bit */
+ rbuf[0] = tmp >> (8 * 3);
+ rbuf[1] = tmp >> (8 * 2);
+ rbuf[2] = tmp >> (8 * 1);
+ rbuf[3] = tmp;
+
+ /* sector size */
+ tmp = ATA_SECT_SIZE;
+ rbuf[6] = tmp >> 8;
+ rbuf[7] = tmp;
+
+ } else {
+ /* sector count, 64-bit */
+ tmp = n_sectors >> (8 * 4);
+ rbuf[2] = tmp >> (8 * 3);
+ rbuf[3] = tmp >> (8 * 2);
+ rbuf[4] = tmp >> (8 * 1);
+ rbuf[5] = tmp;
+ tmp = n_sectors;
+ rbuf[6] = tmp >> (8 * 3);
+ rbuf[7] = tmp >> (8 * 2);
+ rbuf[8] = tmp >> (8 * 1);
+ rbuf[9] = tmp;
+
+ /* sector size */
+ tmp = ATA_SECT_SIZE;
+ rbuf[12] = tmp >> 8;
+ rbuf[13] = tmp;
+ }
+
+ return 0;
+}
+
+/**
+ * ata_scsiop_report_luns - Simulate REPORT LUNS command
+ * @args: device IDENTIFY data / SCSI command of interest.
+ * @rbuf: Response buffer, to which simulated SCSI cmd output is sent.
+ * @buflen: Response buffer length.
+ *
+ * Simulate REPORT LUNS command.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ */
+
+unsigned int ata_scsiop_report_luns(struct ata_scsi_args *args, u8 *rbuf,
+ unsigned int buflen)
+{
+ VPRINTK("ENTER\n");
+ rbuf[3] = 8; /* just one lun, LUN 0, size 8 bytes */
+
+ return 0;
+}
+
+/**
+ * ata_scsi_set_sense - Set SCSI sense data and status
+ * @cmd: SCSI request to be handled
+ * @sk: SCSI-defined sense key
+ * @asc: SCSI-defined additional sense code
+ * @ascq: SCSI-defined additional sense code qualifier
+ *
+ * Helper function that builds a valid fixed format, current
+ * response code and the given sense key (sk), additional sense
+ * code (asc) and additional sense code qualifier (ascq) with
+ * a SCSI command status of %SAM_STAT_CHECK_CONDITION and
+ * DRIVER_SENSE set in the upper bits of scsi_cmnd::result .
+ *
+ * LOCKING:
+ * Not required
+ */
+
+void ata_scsi_set_sense(struct scsi_cmnd *cmd, u8 sk, u8 asc, u8 ascq)
+{
+ cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
+
+ cmd->sense_buffer[0] = 0x70; /* fixed format, current */
+ cmd->sense_buffer[2] = sk;
+ cmd->sense_buffer[7] = 18 - 8; /* additional sense length */
+ cmd->sense_buffer[12] = asc;
+ cmd->sense_buffer[13] = ascq;
+}
+
+/**
+ * ata_scsi_badcmd - End a SCSI request with an error
+ * @cmd: SCSI request to be handled
+ * @done: SCSI command completion function
+ * @asc: SCSI-defined additional sense code
+ * @ascq: SCSI-defined additional sense code qualifier
+ *
+ * Helper function that completes a SCSI command with
+ * %SAM_STAT_CHECK_CONDITION, with a sense key %ILLEGAL_REQUEST
+ * and the specified additional sense codes.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ */
+
+void ata_scsi_badcmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *), u8 asc, u8 ascq)
+{
+ DPRINTK("ENTER\n");
+ ata_scsi_set_sense(cmd, ILLEGAL_REQUEST, asc, ascq);
+
+ done(cmd);
+}
+
+static void atapi_sense_complete(struct ata_queued_cmd *qc)
+{
+ if (qc->err_mask && ((qc->err_mask & AC_ERR_DEV) == 0)) {
+ /* FIXME: not quite right; we don't want the
+ * translation of taskfile registers into
+ * a sense descriptors, since that's only
+ * correct for ATA, not ATAPI
+ */
+ ata_gen_ata_desc_sense(qc);
+ }
+
+ qc->scsidone(qc->scsicmd);
+ ata_qc_free(qc);
+}
+
+/* is it pointless to prefer PIO for "safety reasons"? */
+static inline int ata_pio_use_silly(struct ata_port *ap)
+{
+ return (ap->flags & ATA_FLAG_PIO_DMA);
+}
+
+static void atapi_request_sense(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct scsi_cmnd *cmd = qc->scsicmd;
+
+ DPRINTK("ATAPI request sense\n");
+
+ /* FIXME: is this needed? */
+ memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
+
+ ap->ops->tf_read(ap, &qc->tf);
+
+ /* fill these in, for the case where they are -not- overwritten */
+ cmd->sense_buffer[0] = 0x70;
+ cmd->sense_buffer[2] = qc->tf.feature >> 4;
+
+ ata_qc_reinit(qc);
+
+ ata_sg_init_one(qc, cmd->sense_buffer, sizeof(cmd->sense_buffer));
+ qc->dma_dir = DMA_FROM_DEVICE;
+
+ memset(&qc->cdb, 0, qc->dev->cdb_len);
+ qc->cdb[0] = REQUEST_SENSE;
+ qc->cdb[4] = SCSI_SENSE_BUFFERSIZE;
+
+ qc->tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
+ qc->tf.command = ATA_CMD_PACKET;
+
+ if (ata_pio_use_silly(ap)) {
+ qc->tf.protocol = ATA_PROT_ATAPI_DMA;
+ qc->tf.feature |= ATAPI_PKT_DMA;
+ } else {
+ qc->tf.protocol = ATA_PROT_ATAPI;
+ qc->tf.lbam = (8 * 1024) & 0xff;
+ qc->tf.lbah = (8 * 1024) >> 8;
+ }
+ qc->nbytes = SCSI_SENSE_BUFFERSIZE;
+
+ qc->complete_fn = atapi_sense_complete;
+
+ ata_qc_issue(qc);
+
+ DPRINTK("EXIT\n");
+}
+
+static void atapi_qc_complete(struct ata_queued_cmd *qc)
+{
+ struct scsi_cmnd *cmd = qc->scsicmd;
+ unsigned int err_mask = qc->err_mask;
+
+ VPRINTK("ENTER, err_mask 0x%X\n", err_mask);
+
+ /* handle completion from new EH */
+ if (unlikely(qc->ap->ops->error_handler &&
+ (err_mask || qc->flags & ATA_QCFLAG_SENSE_VALID))) {
+
+ if (!(qc->flags & ATA_QCFLAG_SENSE_VALID)) {
+ /* FIXME: not quite right; we don't want the
+ * translation of taskfile registers into a
+ * sense descriptors, since that's only
+ * correct for ATA, not ATAPI
+ */
+ ata_gen_ata_desc_sense(qc);
+ }
+
+ /* SCSI EH automatically locks door if sdev->locked is
+ * set. Sometimes door lock request continues to
+ * fail, for example, when no media is present. This
+ * creates a loop - SCSI EH issues door lock which
+ * fails and gets invoked again to acquire sense data
+ * for the failed command.
+ *
+ * If door lock fails, always clear sdev->locked to
+ * avoid this infinite loop.
+ */
+ if (qc->cdb[0] == ALLOW_MEDIUM_REMOVAL)
+ qc->dev->sdev->locked = 0;
+
+ qc->scsicmd->result = SAM_STAT_CHECK_CONDITION;
+ qc->scsidone(cmd);
+ ata_qc_free(qc);
+ return;
+ }
+
+ /* successful completion or old EH failure path */
+ if (unlikely(err_mask & AC_ERR_DEV)) {
+ cmd->result = SAM_STAT_CHECK_CONDITION;
+ atapi_request_sense(qc);
+ return;
+ } else if (unlikely(err_mask)) {
+ /* FIXME: not quite right; we don't want the
+ * translation of taskfile registers into
+ * a sense descriptors, since that's only
+ * correct for ATA, not ATAPI
+ */
+ ata_gen_ata_desc_sense(qc);
+ } else {
+ u8 *scsicmd = cmd->cmnd;
+
+ if ((scsicmd[0] == INQUIRY) && ((scsicmd[1] & 0x03) == 0)) {
+ u8 *buf = NULL;
+ unsigned int buflen;
+
+ buflen = ata_scsi_rbuf_get(cmd, &buf);
+
+ /* ATAPI devices typically report zero for their SCSI version,
+ * and sometimes deviate from the spec WRT response data
+ * format. If SCSI version is reported as zero like normal,
+ * then we make the following fixups: 1) Fake MMC-5 version,
+ * to indicate to the Linux scsi midlayer this is a modern
+ * device. 2) Ensure response data format / ATAPI information
+ * are always correct.
+ */
+ if (buf[2] == 0) {
+ buf[2] = 0x5;
+ buf[3] = 0x32;
+ }
+
+ ata_scsi_rbuf_put(cmd, buf);
+ }
+
+ cmd->result = SAM_STAT_GOOD;
+ }
+
+ qc->scsidone(cmd);
+ ata_qc_free(qc);
+}
+/**
+ * atapi_xlat - Initialize PACKET taskfile
+ * @qc: command structure to be initialized
+ * @scsicmd: SCSI CDB associated with this PACKET command
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ *
+ * RETURNS:
+ * Zero on success, non-zero on failure.
+ */
+
+static unsigned int atapi_xlat(struct ata_queued_cmd *qc, const u8 *scsicmd)
+{
+ struct scsi_cmnd *cmd = qc->scsicmd;
+ struct ata_device *dev = qc->dev;
+ int using_pio = (dev->flags & ATA_DFLAG_PIO);
+ int nodata = (cmd->sc_data_direction == DMA_NONE);
+
+ if (!using_pio)
+ /* Check whether ATAPI DMA is safe */
+ if (ata_check_atapi_dma(qc))
+ using_pio = 1;
+
+ memcpy(&qc->cdb, scsicmd, dev->cdb_len);
+
+ qc->complete_fn = atapi_qc_complete;
+
+ qc->tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
+ if (cmd->sc_data_direction == DMA_TO_DEVICE) {
+ qc->tf.flags |= ATA_TFLAG_WRITE;
+ DPRINTK("direction: write\n");
+ }
+
+ qc->tf.command = ATA_CMD_PACKET;
+
+ /* no data, or PIO data xfer */
+ if (using_pio || nodata) {
+ if (nodata)
+ qc->tf.protocol = ATA_PROT_ATAPI_NODATA;
+ else
+ qc->tf.protocol = ATA_PROT_ATAPI;
+ qc->tf.lbam = (8 * 1024) & 0xff;
+ qc->tf.lbah = (8 * 1024) >> 8;
+ }
+
+ /* DMA data xfer */
+ else {
+ qc->tf.protocol = ATA_PROT_ATAPI_DMA;
+ qc->tf.feature |= ATAPI_PKT_DMA;
+
+ if (atapi_dmadir && (cmd->sc_data_direction != DMA_TO_DEVICE))
+ /* some SATA bridges need us to indicate data xfer direction */
+ qc->tf.feature |= ATAPI_DMADIR;
+ }
+
+ qc->nbytes = cmd->request_bufflen;
+
+ return 0;
+}
+
+static struct ata_device * ata_find_dev(struct ata_port *ap, int id)
+{
+ if (likely(id < ATA_MAX_DEVICES))
+ return &ap->device[id];
+ return NULL;
+}
+
+static struct ata_device * __ata_scsi_find_dev(struct ata_port *ap,
+ const struct scsi_device *scsidev)
+{
+ /* skip commands not addressed to targets we simulate */
+ if (unlikely(scsidev->channel || scsidev->lun))
+ return NULL;
+
+ return ata_find_dev(ap, scsidev->id);
+}
+
+/**
+ * ata_scsi_dev_enabled - determine if device is enabled
+ * @dev: ATA device
+ *
+ * Determine if commands should be sent to the specified device.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ *
+ * RETURNS:
+ * 0 if commands are not allowed / 1 if commands are allowed
+ */
+
+static int ata_scsi_dev_enabled(struct ata_device *dev)
+{
+ if (unlikely(!ata_dev_enabled(dev)))
+ return 0;
+
+ if (!atapi_enabled || (dev->ap->flags & ATA_FLAG_NO_ATAPI)) {
+ if (unlikely(dev->class == ATA_DEV_ATAPI)) {
+ ata_dev_printk(dev, KERN_WARNING,
+ "WARNING: ATAPI is %s, device ignored.\n",
+ atapi_enabled ? "not supported with this driver" : "disabled");
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+/**
+ * ata_scsi_find_dev - lookup ata_device from scsi_cmnd
+ * @ap: ATA port to which the device is attached
+ * @scsidev: SCSI device from which we derive the ATA device
+ *
+ * Given various information provided in struct scsi_cmnd,
+ * map that onto an ATA bus, and using that mapping
+ * determine which ata_device is associated with the
+ * SCSI command to be sent.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ *
+ * RETURNS:
+ * Associated ATA device, or %NULL if not found.
+ */
+static struct ata_device *
+ata_scsi_find_dev(struct ata_port *ap, const struct scsi_device *scsidev)
+{
+ struct ata_device *dev = __ata_scsi_find_dev(ap, scsidev);
+
+ if (unlikely(!dev || !ata_scsi_dev_enabled(dev)))
+ return NULL;
+
+ return dev;
+}
+
+/*
+ * ata_scsi_map_proto - Map pass-thru protocol value to taskfile value.
+ * @byte1: Byte 1 from pass-thru CDB.
+ *
+ * RETURNS:
+ * ATA_PROT_UNKNOWN if mapping failed/unimplemented, protocol otherwise.
+ */
+static u8
+ata_scsi_map_proto(u8 byte1)
+{
+ switch((byte1 & 0x1e) >> 1) {
+ case 3: /* Non-data */
+ return ATA_PROT_NODATA;
+
+ case 6: /* DMA */
+ return ATA_PROT_DMA;
+
+ case 4: /* PIO Data-in */
+ case 5: /* PIO Data-out */
+ return ATA_PROT_PIO;
+
+ case 10: /* Device Reset */
+ case 0: /* Hard Reset */
+ case 1: /* SRST */
+ case 2: /* Bus Idle */
+ case 7: /* Packet */
+ case 8: /* DMA Queued */
+ case 9: /* Device Diagnostic */
+ case 11: /* UDMA Data-in */
+ case 12: /* UDMA Data-Out */
+ case 13: /* FPDMA */
+ default: /* Reserved */
+ break;
+ }
+
+ return ATA_PROT_UNKNOWN;
+}
+
+/**
+ * ata_scsi_pass_thru - convert ATA pass-thru CDB to taskfile
+ * @qc: command structure to be initialized
+ * @scsicmd: SCSI command to convert
+ *
+ * Handles either 12 or 16-byte versions of the CDB.
+ *
+ * RETURNS:
+ * Zero on success, non-zero on failure.
+ */
+static unsigned int
+ata_scsi_pass_thru(struct ata_queued_cmd *qc, const u8 *scsicmd)
+{
+ struct ata_taskfile *tf = &(qc->tf);
+ struct scsi_cmnd *cmd = qc->scsicmd;
+ struct ata_device *dev = qc->dev;
+
+ if ((tf->protocol = ata_scsi_map_proto(scsicmd[1])) == ATA_PROT_UNKNOWN)
+ goto invalid_fld;
+
+ /* We may not issue DMA commands if no DMA mode is set */
+ if (tf->protocol == ATA_PROT_DMA && dev->dma_mode == 0)
+ goto invalid_fld;
+
+ if (scsicmd[1] & 0xe0)
+ /* PIO multi not supported yet */
+ goto invalid_fld;
+
+ /*
+ * 12 and 16 byte CDBs use different offsets to
+ * provide the various register values.
+ */
+ if (scsicmd[0] == ATA_16) {
+ /*
+ * 16-byte CDB - may contain extended commands.
+ *
+ * If that is the case, copy the upper byte register values.
+ */
+ if (scsicmd[1] & 0x01) {
+ tf->hob_feature = scsicmd[3];
+ tf->hob_nsect = scsicmd[5];
+ tf->hob_lbal = scsicmd[7];
+ tf->hob_lbam = scsicmd[9];
+ tf->hob_lbah = scsicmd[11];
+ tf->flags |= ATA_TFLAG_LBA48;
+ } else
+ tf->flags &= ~ATA_TFLAG_LBA48;
+
+ /*
+ * Always copy low byte, device and command registers.
+ */
+ tf->feature = scsicmd[4];
+ tf->nsect = scsicmd[6];
+ tf->lbal = scsicmd[8];
+ tf->lbam = scsicmd[10];
+ tf->lbah = scsicmd[12];
+ tf->device = scsicmd[13];
+ tf->command = scsicmd[14];
+ } else {
+ /*
+ * 12-byte CDB - incapable of extended commands.
+ */
+ tf->flags &= ~ATA_TFLAG_LBA48;
+
+ tf->feature = scsicmd[3];
+ tf->nsect = scsicmd[4];
+ tf->lbal = scsicmd[5];
+ tf->lbam = scsicmd[6];
+ tf->lbah = scsicmd[7];
+ tf->device = scsicmd[8];
+ tf->command = scsicmd[9];
+ }
+ /*
+ * If slave is possible, enforce correct master/slave bit
+ */
+ if (qc->ap->flags & ATA_FLAG_SLAVE_POSS)
+ tf->device = qc->dev->devno ?
+ tf->device | ATA_DEV1 : tf->device & ~ATA_DEV1;
+
+ /*
+ * Filter SET_FEATURES - XFER MODE command -- otherwise,
+ * SET_FEATURES - XFER MODE must be preceded/succeeded
+ * by an update to hardware-specific registers for each
+ * controller (i.e. the reason for ->set_piomode(),
+ * ->set_dmamode(), and ->post_set_mode() hooks).
+ */
+ if ((tf->command == ATA_CMD_SET_FEATURES)
+ && (tf->feature == SETFEATURES_XFER))
+ goto invalid_fld;
+
+ /*
+ * Set flags so that all registers will be written,
+ * and pass on write indication (used for PIO/DMA
+ * setup.)
+ */
+ tf->flags |= (ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE);
+
+ if (cmd->sc_data_direction == DMA_TO_DEVICE)
+ tf->flags |= ATA_TFLAG_WRITE;
+
+ /*
+ * Set transfer length.
+ *
+ * TODO: find out if we need to do more here to
+ * cover scatter/gather case.
+ */
+ qc->nsect = cmd->request_bufflen / ATA_SECT_SIZE;
+
+ /* request result TF */
+ qc->flags |= ATA_QCFLAG_RESULT_TF;
+
+ return 0;
+
+ invalid_fld:
+ ata_scsi_set_sense(qc->scsicmd, ILLEGAL_REQUEST, 0x24, 0x00);
+ /* "Invalid field in cdb" */
+ return 1;
+}
+
+/**
+ * ata_get_xlat_func - check if SCSI to ATA translation is possible
+ * @dev: ATA device
+ * @cmd: SCSI command opcode to consider
+ *
+ * Look up the SCSI command given, and determine whether the
+ * SCSI command is to be translated or simulated.
+ *
+ * RETURNS:
+ * Pointer to translation function if possible, %NULL if not.
+ */
+
+static inline ata_xlat_func_t ata_get_xlat_func(struct ata_device *dev, u8 cmd)
+{
+ switch (cmd) {
+ case READ_6:
+ case READ_10:
+ case READ_16:
+
+ case WRITE_6:
+ case WRITE_10:
+ case WRITE_16:
+ return ata_scsi_rw_xlat;
+
+ case SYNCHRONIZE_CACHE:
+ if (ata_try_flush_cache(dev))
+ return ata_scsi_flush_xlat;
+ break;
+
+ case VERIFY:
+ case VERIFY_16:
+ return ata_scsi_verify_xlat;
+
+ case ATA_12:
+ case ATA_16:
+ return ata_scsi_pass_thru;
+
+ case START_STOP:
+ return ata_scsi_start_stop_xlat;
+ }
+
+ return NULL;
+}
+
+/**
+ * ata_scsi_dump_cdb - dump SCSI command contents to dmesg
+ * @ap: ATA port to which the command was being sent
+ * @cmd: SCSI command to dump
+ *
+ * Prints the contents of a SCSI command via printk().
+ */
+
+static inline void ata_scsi_dump_cdb(struct ata_port *ap,
+ struct scsi_cmnd *cmd)
+{
+#ifdef ATA_DEBUG
+ struct scsi_device *scsidev = cmd->device;
+ u8 *scsicmd = cmd->cmnd;
+
+ DPRINTK("CDB (%u:%d,%d,%d) %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
+ ap->id,
+ scsidev->channel, scsidev->id, scsidev->lun,
+ scsicmd[0], scsicmd[1], scsicmd[2], scsicmd[3],
+ scsicmd[4], scsicmd[5], scsicmd[6], scsicmd[7],
+ scsicmd[8]);
+#endif
+}
+
+static inline int __ata_scsi_queuecmd(struct scsi_cmnd *cmd,
+ void (*done)(struct scsi_cmnd *),
+ struct ata_device *dev)
+{
+ int rc = 0;
+
+ if (dev->class == ATA_DEV_ATA) {
+ ata_xlat_func_t xlat_func = ata_get_xlat_func(dev,
+ cmd->cmnd[0]);
+
+ if (xlat_func)
+ rc = ata_scsi_translate(dev, cmd, done, xlat_func);
+ else
+ ata_scsi_simulate(dev, cmd, done);
+ } else
+ rc = ata_scsi_translate(dev, cmd, done, atapi_xlat);
+
+ return rc;
+}
+
+/**
+ * ata_scsi_queuecmd - Issue SCSI cdb to libata-managed device
+ * @cmd: SCSI command to be sent
+ * @done: Completion function, called when command is complete
+ *
+ * In some cases, this function translates SCSI commands into
+ * ATA taskfiles, and queues the taskfiles to be sent to
+ * hardware. In other cases, this function simulates a
+ * SCSI device by evaluating and responding to certain
+ * SCSI commands. This creates the overall effect of
+ * ATA and ATAPI devices appearing as SCSI devices.
+ *
+ * LOCKING:
+ * Releases scsi-layer-held lock, and obtains host lock.
+ *
+ * RETURNS:
+ * Return value from __ata_scsi_queuecmd() if @cmd can be queued,
+ * 0 otherwise.
+ */
+int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
+{
+ struct ata_port *ap;
+ struct ata_device *dev;
+ struct scsi_device *scsidev = cmd->device;
+ struct Scsi_Host *shost = scsidev->host;
+ int rc = 0;
+
+ ap = ata_shost_to_port(shost);
+
+ spin_unlock(shost->host_lock);
+ spin_lock(ap->lock);
+
+ ata_scsi_dump_cdb(ap, cmd);
+
+ dev = ata_scsi_find_dev(ap, scsidev);
+ if (likely(dev))
+ rc = __ata_scsi_queuecmd(cmd, done, dev);
+ else {
+ cmd->result = (DID_BAD_TARGET << 16);
+ done(cmd);
+ }
+
+ spin_unlock(ap->lock);
+ spin_lock(shost->host_lock);
+ return rc;
+}
+
+/**
+ * ata_scsi_simulate - simulate SCSI command on ATA device
+ * @dev: the target device
+ * @cmd: SCSI command being sent to device.
+ * @done: SCSI command completion function.
+ *
+ * Interprets and directly executes a select list of SCSI commands
+ * that can be handled internally.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ */
+
+void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd,
+ void (*done)(struct scsi_cmnd *))
+{
+ struct ata_scsi_args args;
+ const u8 *scsicmd = cmd->cmnd;
+
+ args.dev = dev;
+ args.id = dev->id;
+ args.cmd = cmd;
+ args.done = done;
+
+ switch(scsicmd[0]) {
+ /* no-op's, complete with success */
+ case SYNCHRONIZE_CACHE:
+ case REZERO_UNIT:
+ case SEEK_6:
+ case SEEK_10:
+ case TEST_UNIT_READY:
+ case FORMAT_UNIT: /* FIXME: correct? */
+ case SEND_DIAGNOSTIC: /* FIXME: correct? */
+ ata_scsi_rbuf_fill(&args, ata_scsiop_noop);
+ break;
+
+ case INQUIRY:
+ if (scsicmd[1] & 2) /* is CmdDt set? */
+ ata_scsi_invalid_field(cmd, done);
+ else if ((scsicmd[1] & 1) == 0) /* is EVPD clear? */
+ ata_scsi_rbuf_fill(&args, ata_scsiop_inq_std);
+ else if (scsicmd[2] == 0x00)
+ ata_scsi_rbuf_fill(&args, ata_scsiop_inq_00);
+ else if (scsicmd[2] == 0x80)
+ ata_scsi_rbuf_fill(&args, ata_scsiop_inq_80);
+ else if (scsicmd[2] == 0x83)
+ ata_scsi_rbuf_fill(&args, ata_scsiop_inq_83);
+ else
+ ata_scsi_invalid_field(cmd, done);
+ break;
+
+ case MODE_SENSE:
+ case MODE_SENSE_10:
+ ata_scsi_rbuf_fill(&args, ata_scsiop_mode_sense);
+ break;
+
+ case MODE_SELECT: /* unconditionally return */
+ case MODE_SELECT_10: /* bad-field-in-cdb */
+ ata_scsi_invalid_field(cmd, done);
+ break;
+
+ case READ_CAPACITY:
+ ata_scsi_rbuf_fill(&args, ata_scsiop_read_cap);
+ break;
+
+ case SERVICE_ACTION_IN:
+ if ((scsicmd[1] & 0x1f) == SAI_READ_CAPACITY_16)
+ ata_scsi_rbuf_fill(&args, ata_scsiop_read_cap);
+ else
+ ata_scsi_invalid_field(cmd, done);
+ break;
+
+ case REPORT_LUNS:
+ ata_scsi_rbuf_fill(&args, ata_scsiop_report_luns);
+ break;
+
+ /* mandatory commands we haven't implemented yet */
+ case REQUEST_SENSE:
+
+ /* all other commands */
+ default:
+ ata_scsi_set_sense(cmd, ILLEGAL_REQUEST, 0x20, 0x0);
+ /* "Invalid command operation code" */
+ done(cmd);
+ break;
+ }
+}
+
+void ata_scsi_scan_host(struct ata_port *ap)
+{
+ unsigned int i;
+
+ if (ap->flags & ATA_FLAG_DISABLED)
+ return;
+
+ for (i = 0; i < ATA_MAX_DEVICES; i++) {
+ struct ata_device *dev = &ap->device[i];
+ struct scsi_device *sdev;
+
+ if (!ata_dev_enabled(dev) || dev->sdev)
+ continue;
+
+ sdev = __scsi_add_device(ap->scsi_host, 0, i, 0, NULL);
+ if (!IS_ERR(sdev)) {
+ dev->sdev = sdev;
+ scsi_device_put(sdev);
+ }
+ }
+}
+
+/**
+ * ata_scsi_offline_dev - offline attached SCSI device
+ * @dev: ATA device to offline attached SCSI device for
+ *
+ * This function is called from ata_eh_hotplug() and responsible
+ * for taking the SCSI device attached to @dev offline. This
+ * function is called with host lock which protects dev->sdev
+ * against clearing.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ *
+ * RETURNS:
+ * 1 if attached SCSI device exists, 0 otherwise.
+ */
+int ata_scsi_offline_dev(struct ata_device *dev)
+{
+ if (dev->sdev) {
+ scsi_device_set_state(dev->sdev, SDEV_OFFLINE);
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * ata_scsi_remove_dev - remove attached SCSI device
+ * @dev: ATA device to remove attached SCSI device for
+ *
+ * This function is called from ata_eh_scsi_hotplug() and
+ * responsible for removing the SCSI device attached to @dev.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ */
+static void ata_scsi_remove_dev(struct ata_device *dev)
+{
+ struct ata_port *ap = dev->ap;
+ struct scsi_device *sdev;
+ unsigned long flags;
+
+ /* Alas, we need to grab scan_mutex to ensure SCSI device
+ * state doesn't change underneath us and thus
+ * scsi_device_get() always succeeds. The mutex locking can
+ * be removed if there is __scsi_device_get() interface which
+ * increments reference counts regardless of device state.
+ */
+ mutex_lock(&ap->scsi_host->scan_mutex);
+ spin_lock_irqsave(ap->lock, flags);
+
+ /* clearing dev->sdev is protected by host lock */
+ sdev = dev->sdev;
+ dev->sdev = NULL;
+
+ if (sdev) {
+ /* If user initiated unplug races with us, sdev can go
+ * away underneath us after the host lock and
+ * scan_mutex are released. Hold onto it.
+ */
+ if (scsi_device_get(sdev) == 0) {
+ /* The following ensures the attached sdev is
+ * offline on return from ata_scsi_offline_dev()
+ * regardless it wins or loses the race
+ * against this function.
+ */
+ scsi_device_set_state(sdev, SDEV_OFFLINE);
+ } else {
+ WARN_ON(1);
+ sdev = NULL;
+ }
+ }
+
+ spin_unlock_irqrestore(ap->lock, flags);
+ mutex_unlock(&ap->scsi_host->scan_mutex);
+
+ if (sdev) {
+ ata_dev_printk(dev, KERN_INFO, "detaching (SCSI %s)\n",
+ sdev->sdev_gendev.bus_id);
+
+ scsi_remove_device(sdev);
+ scsi_device_put(sdev);
+ }
+}
+
+/**
+ * ata_scsi_hotplug - SCSI part of hotplug
+ * @data: Pointer to ATA port to perform SCSI hotplug on
+ *
+ * Perform SCSI part of hotplug. It's executed from a separate
+ * workqueue after EH completes. This is necessary because SCSI
+ * hot plugging requires working EH and hot unplugging is
+ * synchronized with hot plugging with a mutex.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ */
+void ata_scsi_hotplug(void *data)
+{
+ struct ata_port *ap = data;
+ int i;
+
+ if (ap->pflags & ATA_PFLAG_UNLOADING) {
+ DPRINTK("ENTER/EXIT - unloading\n");
+ return;
+ }
+
+ DPRINTK("ENTER\n");
+
+ /* unplug detached devices */
+ for (i = 0; i < ATA_MAX_DEVICES; i++) {
+ struct ata_device *dev = &ap->device[i];
+ unsigned long flags;
+
+ if (!(dev->flags & ATA_DFLAG_DETACHED))
+ continue;
+
+ spin_lock_irqsave(ap->lock, flags);
+ dev->flags &= ~ATA_DFLAG_DETACHED;
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ ata_scsi_remove_dev(dev);
+ }
+
+ /* scan for new ones */
+ ata_scsi_scan_host(ap);
+
+ /* If we scanned while EH was in progress, scan would have
+ * failed silently. Requeue if there are enabled but
+ * unattached devices.
+ */
+ for (i = 0; i < ATA_MAX_DEVICES; i++) {
+ struct ata_device *dev = &ap->device[i];
+ if (ata_dev_enabled(dev) && !dev->sdev) {
+ queue_delayed_work(ata_aux_wq, &ap->hotplug_task, HZ);
+ break;
+ }
+ }
+
+ DPRINTK("EXIT\n");
+}
+
+/**
+ * ata_scsi_user_scan - indication for user-initiated bus scan
+ * @shost: SCSI host to scan
+ * @channel: Channel to scan
+ * @id: ID to scan
+ * @lun: LUN to scan
+ *
+ * This function is called when user explicitly requests bus
+ * scan. Set probe pending flag and invoke EH.
+ *
+ * LOCKING:
+ * SCSI layer (we don't care)
+ *
+ * RETURNS:
+ * Zero.
+ */
+static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel,
+ unsigned int id, unsigned int lun)
+{
+ struct ata_port *ap = ata_shost_to_port(shost);
+ unsigned long flags;
+ int rc = 0;
+
+ if (!ap->ops->error_handler)
+ return -EOPNOTSUPP;
+
+ if ((channel != SCAN_WILD_CARD && channel != 0) ||
+ (lun != SCAN_WILD_CARD && lun != 0))
+ return -EINVAL;
+
+ spin_lock_irqsave(ap->lock, flags);
+
+ if (id == SCAN_WILD_CARD) {
+ ap->eh_info.probe_mask |= (1 << ATA_MAX_DEVICES) - 1;
+ ap->eh_info.action |= ATA_EH_SOFTRESET;
+ } else {
+ struct ata_device *dev = ata_find_dev(ap, id);
+
+ if (dev) {
+ ap->eh_info.probe_mask |= 1 << dev->devno;
+ ap->eh_info.action |= ATA_EH_SOFTRESET;
+ ap->eh_info.flags |= ATA_EHI_RESUME_LINK;
+ } else
+ rc = -EINVAL;
+ }
+
+ if (rc == 0)
+ ata_port_schedule_eh(ap);
+
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ return rc;
+}
+
+/**
+ * ata_scsi_dev_rescan - initiate scsi_rescan_device()
+ * @data: Pointer to ATA port to perform scsi_rescan_device()
+ *
+ * After ATA pass thru (SAT) commands are executed successfully,
+ * libata need to propagate the changes to SCSI layer. This
+ * function must be executed from ata_aux_wq such that sdev
+ * attach/detach don't race with rescan.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ */
+void ata_scsi_dev_rescan(void *data)
+{
+ struct ata_port *ap = data;
+ struct ata_device *dev;
+ unsigned int i;
+
+ for (i = 0; i < ATA_MAX_DEVICES; i++) {
+ dev = &ap->device[i];
+
+ if (ata_dev_enabled(dev) && dev->sdev)
+ scsi_rescan_device(&(dev->sdev->sdev_gendev));
+ }
+}
+
+/**
+ * ata_sas_port_alloc - Allocate port for a SAS attached SATA device
+ * @pdev: PCI device that the scsi device is attached to
+ * @port_info: Information from low-level host driver
+ * @shost: SCSI host that the scsi device is attached to
+ *
+ * LOCKING:
+ * PCI/etc. bus probe sem.
+ *
+ * RETURNS:
+ * ata_port pointer on success / NULL on failure.
+ */
+
+struct ata_port *ata_sas_port_alloc(struct ata_host *host,
+ struct ata_port_info *port_info,
+ struct Scsi_Host *shost)
+{
+ struct ata_port *ap = kzalloc(sizeof(*ap), GFP_KERNEL);
+ struct ata_probe_ent *ent;
+
+ if (!ap)
+ return NULL;
+
+ ent = ata_probe_ent_alloc(host->dev, port_info);
+ if (!ent) {
+ kfree(ap);
+ return NULL;
+ }
+
+ ata_port_init(ap, host, ent, 0);
+ ap->lock = shost->host_lock;
+ kfree(ent);
+ return ap;
+}
+EXPORT_SYMBOL_GPL(ata_sas_port_alloc);
+
+/**
+ * ata_sas_port_start - Set port up for dma.
+ * @ap: Port to initialize
+ *
+ * Called just after data structures for each port are
+ * initialized. Allocates DMA pad.
+ *
+ * May be used as the port_start() entry in ata_port_operations.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+int ata_sas_port_start(struct ata_port *ap)
+{
+ return ata_pad_alloc(ap, ap->dev);
+}
+EXPORT_SYMBOL_GPL(ata_sas_port_start);
+
+/**
+ * ata_port_stop - Undo ata_sas_port_start()
+ * @ap: Port to shut down
+ *
+ * Frees the DMA pad.
+ *
+ * May be used as the port_stop() entry in ata_port_operations.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+
+void ata_sas_port_stop(struct ata_port *ap)
+{
+ ata_pad_free(ap, ap->dev);
+}
+EXPORT_SYMBOL_GPL(ata_sas_port_stop);
+
+/**
+ * ata_sas_port_init - Initialize a SATA device
+ * @ap: SATA port to initialize
+ *
+ * LOCKING:
+ * PCI/etc. bus probe sem.
+ *
+ * RETURNS:
+ * Zero on success, non-zero on error.
+ */
+
+int ata_sas_port_init(struct ata_port *ap)
+{
+ int rc = ap->ops->port_start(ap);
+
+ if (!rc)
+ rc = ata_bus_probe(ap);
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(ata_sas_port_init);
+
+/**
+ * ata_sas_port_destroy - Destroy a SATA port allocated by ata_sas_port_alloc
+ * @ap: SATA port to destroy
+ *
+ */
+
+void ata_sas_port_destroy(struct ata_port *ap)
+{
+ ap->ops->port_stop(ap);
+ kfree(ap);
+}
+EXPORT_SYMBOL_GPL(ata_sas_port_destroy);
+
+/**
+ * ata_sas_slave_configure - Default slave_config routine for libata devices
+ * @sdev: SCSI device to configure
+ * @ap: ATA port to which SCSI device is attached
+ *
+ * RETURNS:
+ * Zero.
+ */
+
+int ata_sas_slave_configure(struct scsi_device *sdev, struct ata_port *ap)
+{
+ ata_scsi_sdev_config(sdev);
+ ata_scsi_dev_config(sdev, ap->device);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ata_sas_slave_configure);
+
+/**
+ * ata_sas_queuecmd - Issue SCSI cdb to libata-managed device
+ * @cmd: SCSI command to be sent
+ * @done: Completion function, called when command is complete
+ * @ap: ATA port to which the command is being sent
+ *
+ * RETURNS:
+ * Zero.
+ */
+
+int ata_sas_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *),
+ struct ata_port *ap)
+{
+ ata_scsi_dump_cdb(ap, cmd);
+
+ if (likely(ata_scsi_dev_enabled(ap->device)))
+ __ata_scsi_queuecmd(cmd, done, ap->device);
+ else {
+ cmd->result = (DID_BAD_TARGET << 16);
+ done(cmd);
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ata_sas_queuecmd);
diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c
new file mode 100644
index 00000000000..08b3a407473
--- /dev/null
+++ b/drivers/ata/libata-sff.c
@@ -0,0 +1,1121 @@
+/*
+ * libata-bmdma.c - helper library for PCI IDE BMDMA
+ *
+ * Maintained by: Jeff Garzik <jgarzik@pobox.com>
+ * Please ALWAYS copy linux-ide@vger.kernel.org
+ * on emails.
+ *
+ * Copyright 2003-2006 Red Hat, Inc. All rights reserved.
+ * Copyright 2003-2006 Jeff Garzik
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * libata documentation is available via 'make {ps|pdf}docs',
+ * as Documentation/DocBook/libata.*
+ *
+ * Hardware documentation available from http://www.t13.org/ and
+ * http://www.sata-io.org/
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/libata.h>
+
+#include "libata.h"
+
+/**
+ * ata_tf_load_pio - send taskfile registers to host controller
+ * @ap: Port to which output is sent
+ * @tf: ATA taskfile register set
+ *
+ * Outputs ATA taskfile to standard ATA host controller.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+
+static void ata_tf_load_pio(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) {
+ outb(tf->ctl, ioaddr->ctl_addr);
+ ap->last_ctl = tf->ctl;
+ ata_wait_idle(ap);
+ }
+
+ if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
+ outb(tf->hob_feature, ioaddr->feature_addr);
+ outb(tf->hob_nsect, ioaddr->nsect_addr);
+ outb(tf->hob_lbal, ioaddr->lbal_addr);
+ outb(tf->hob_lbam, ioaddr->lbam_addr);
+ outb(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) {
+ outb(tf->feature, ioaddr->feature_addr);
+ outb(tf->nsect, ioaddr->nsect_addr);
+ outb(tf->lbal, ioaddr->lbal_addr);
+ outb(tf->lbam, ioaddr->lbam_addr);
+ outb(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) {
+ outb(tf->device, ioaddr->device_addr);
+ VPRINTK("device 0x%X\n", tf->device);
+ }
+
+ ata_wait_idle(ap);
+}
+
+/**
+ * ata_tf_load_mmio - send taskfile registers to host controller
+ * @ap: Port to which output is sent
+ * @tf: ATA taskfile register set
+ *
+ * Outputs ATA taskfile to standard ATA host controller using MMIO.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+
+static void ata_tf_load_mmio(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) {
+ writeb(tf->ctl, (void __iomem *) ap->ioaddr.ctl_addr);
+ ap->last_ctl = tf->ctl;
+ ata_wait_idle(ap);
+ }
+
+ if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
+ writeb(tf->hob_feature, (void __iomem *) ioaddr->feature_addr);
+ writeb(tf->hob_nsect, (void __iomem *) ioaddr->nsect_addr);
+ writeb(tf->hob_lbal, (void __iomem *) ioaddr->lbal_addr);
+ writeb(tf->hob_lbam, (void __iomem *) ioaddr->lbam_addr);
+ writeb(tf->hob_lbah, (void __iomem *) 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) {
+ writeb(tf->feature, (void __iomem *) ioaddr->feature_addr);
+ writeb(tf->nsect, (void __iomem *) ioaddr->nsect_addr);
+ writeb(tf->lbal, (void __iomem *) ioaddr->lbal_addr);
+ writeb(tf->lbam, (void __iomem *) ioaddr->lbam_addr);
+ writeb(tf->lbah, (void __iomem *) 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) {
+ writeb(tf->device, (void __iomem *) ioaddr->device_addr);
+ VPRINTK("device 0x%X\n", tf->device);
+ }
+
+ ata_wait_idle(ap);
+}
+
+
+/**
+ * ata_tf_load - send taskfile registers to host controller
+ * @ap: Port to which output is sent
+ * @tf: ATA taskfile register set
+ *
+ * Outputs ATA taskfile to standard ATA host controller using MMIO
+ * or PIO as indicated by the ATA_FLAG_MMIO flag.
+ * Writes the control, feature, nsect, lbal, lbam, and lbah registers.
+ * Optionally (ATA_TFLAG_LBA48) writes hob_feature, hob_nsect,
+ * hob_lbal, hob_lbam, and hob_lbah.
+ *
+ * This function waits for idle (!BUSY and !DRQ) after writing
+ * registers. If the control register has a new value, this
+ * function also waits for idle after writing control and before
+ * writing the remaining registers.
+ *
+ * May be used as the tf_load() entry in ata_port_operations.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+void ata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf)
+{
+ if (ap->flags & ATA_FLAG_MMIO)
+ ata_tf_load_mmio(ap, tf);
+ else
+ ata_tf_load_pio(ap, tf);
+}
+
+/**
+ * ata_exec_command_pio - issue ATA command to host controller
+ * @ap: port to which command is being issued
+ * @tf: ATA taskfile register set
+ *
+ * Issues PIO write to ATA command register, with proper
+ * synchronization with interrupt handler / other threads.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ */
+
+static void ata_exec_command_pio(struct ata_port *ap, const struct ata_taskfile *tf)
+{
+ DPRINTK("ata%u: cmd 0x%X\n", ap->id, tf->command);
+
+ outb(tf->command, ap->ioaddr.command_addr);
+ ata_pause(ap);
+}
+
+
+/**
+ * ata_exec_command_mmio - issue ATA command to host controller
+ * @ap: port to which command is being issued
+ * @tf: ATA taskfile register set
+ *
+ * Issues MMIO write to ATA command register, with proper
+ * synchronization with interrupt handler / other threads.
+ *
+ * FIXME: missing write posting for 400nS delay enforcement
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ */
+
+static void ata_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf)
+{
+ DPRINTK("ata%u: cmd 0x%X\n", ap->id, tf->command);
+
+ writeb(tf->command, (void __iomem *) ap->ioaddr.command_addr);
+ ata_pause(ap);
+}
+
+
+/**
+ * ata_exec_command - issue ATA command to host controller
+ * @ap: port to which command is being issued
+ * @tf: ATA taskfile register set
+ *
+ * Issues PIO/MMIO write to ATA command register, with proper
+ * synchronization with interrupt handler / other threads.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ */
+void ata_exec_command(struct ata_port *ap, const struct ata_taskfile *tf)
+{
+ if (ap->flags & ATA_FLAG_MMIO)
+ ata_exec_command_mmio(ap, tf);
+ else
+ ata_exec_command_pio(ap, tf);
+}
+
+/**
+ * ata_tf_read_pio - input device's ATA taskfile shadow registers
+ * @ap: Port from which input is read
+ * @tf: ATA taskfile register set for storing input
+ *
+ * Reads ATA taskfile registers for currently-selected device
+ * into @tf.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+
+static void ata_tf_read_pio(struct ata_port *ap, struct ata_taskfile *tf)
+{
+ struct ata_ioports *ioaddr = &ap->ioaddr;
+
+ tf->command = ata_check_status(ap);
+ tf->feature = inb(ioaddr->error_addr);
+ tf->nsect = inb(ioaddr->nsect_addr);
+ tf->lbal = inb(ioaddr->lbal_addr);
+ tf->lbam = inb(ioaddr->lbam_addr);
+ tf->lbah = inb(ioaddr->lbah_addr);
+ tf->device = inb(ioaddr->device_addr);
+
+ if (tf->flags & ATA_TFLAG_LBA48) {
+ outb(tf->ctl | ATA_HOB, ioaddr->ctl_addr);
+ tf->hob_feature = inb(ioaddr->error_addr);
+ tf->hob_nsect = inb(ioaddr->nsect_addr);
+ tf->hob_lbal = inb(ioaddr->lbal_addr);
+ tf->hob_lbam = inb(ioaddr->lbam_addr);
+ tf->hob_lbah = inb(ioaddr->lbah_addr);
+ }
+}
+
+/**
+ * ata_tf_read_mmio - input device's ATA taskfile shadow registers
+ * @ap: Port from which input is read
+ * @tf: ATA taskfile register set for storing input
+ *
+ * Reads ATA taskfile registers for currently-selected device
+ * into @tf via MMIO.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+
+static void ata_tf_read_mmio(struct ata_port *ap, struct ata_taskfile *tf)
+{
+ struct ata_ioports *ioaddr = &ap->ioaddr;
+
+ tf->command = ata_check_status(ap);
+ tf->feature = readb((void __iomem *)ioaddr->error_addr);
+ tf->nsect = readb((void __iomem *)ioaddr->nsect_addr);
+ tf->lbal = readb((void __iomem *)ioaddr->lbal_addr);
+ tf->lbam = readb((void __iomem *)ioaddr->lbam_addr);
+ tf->lbah = readb((void __iomem *)ioaddr->lbah_addr);
+ tf->device = readb((void __iomem *)ioaddr->device_addr);
+
+ if (tf->flags & ATA_TFLAG_LBA48) {
+ writeb(tf->ctl | ATA_HOB, (void __iomem *) ap->ioaddr.ctl_addr);
+ tf->hob_feature = readb((void __iomem *)ioaddr->error_addr);
+ tf->hob_nsect = readb((void __iomem *)ioaddr->nsect_addr);
+ tf->hob_lbal = readb((void __iomem *)ioaddr->lbal_addr);
+ tf->hob_lbam = readb((void __iomem *)ioaddr->lbam_addr);
+ tf->hob_lbah = readb((void __iomem *)ioaddr->lbah_addr);
+ }
+}
+
+
+/**
+ * ata_tf_read - input device's ATA taskfile shadow registers
+ * @ap: Port from which input is read
+ * @tf: ATA taskfile register set for storing input
+ *
+ * Reads ATA taskfile registers for currently-selected device
+ * into @tf.
+ *
+ * Reads nsect, lbal, lbam, lbah, and device. If ATA_TFLAG_LBA48
+ * is set, also reads the hob registers.
+ *
+ * May be used as the tf_read() entry in ata_port_operations.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
+{
+ if (ap->flags & ATA_FLAG_MMIO)
+ ata_tf_read_mmio(ap, tf);
+ else
+ ata_tf_read_pio(ap, tf);
+}
+
+/**
+ * ata_check_status_pio - Read device status reg & clear interrupt
+ * @ap: port where the device is
+ *
+ * Reads ATA taskfile status register for currently-selected device
+ * and return its value. This also clears pending interrupts
+ * from this device
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+static u8 ata_check_status_pio(struct ata_port *ap)
+{
+ return inb(ap->ioaddr.status_addr);
+}
+
+/**
+ * ata_check_status_mmio - Read device status reg & clear interrupt
+ * @ap: port where the device is
+ *
+ * Reads ATA taskfile status register for currently-selected device
+ * via MMIO and return its value. This also clears pending interrupts
+ * from this device
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+static u8 ata_check_status_mmio(struct ata_port *ap)
+{
+ return readb((void __iomem *) ap->ioaddr.status_addr);
+}
+
+
+/**
+ * ata_check_status - Read device status reg & clear interrupt
+ * @ap: port where the device is
+ *
+ * Reads ATA taskfile status register for currently-selected device
+ * and return its value. This also clears pending interrupts
+ * from this device
+ *
+ * May be used as the check_status() entry in ata_port_operations.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+u8 ata_check_status(struct ata_port *ap)
+{
+ if (ap->flags & ATA_FLAG_MMIO)
+ return ata_check_status_mmio(ap);
+ return ata_check_status_pio(ap);
+}
+
+
+/**
+ * ata_altstatus - Read device alternate status reg
+ * @ap: port where the device is
+ *
+ * Reads ATA taskfile alternate status register for
+ * currently-selected device and return its value.
+ *
+ * Note: may NOT be used as the check_altstatus() entry in
+ * ata_port_operations.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+u8 ata_altstatus(struct ata_port *ap)
+{
+ if (ap->ops->check_altstatus)
+ return ap->ops->check_altstatus(ap);
+
+ if (ap->flags & ATA_FLAG_MMIO)
+ return readb((void __iomem *)ap->ioaddr.altstatus_addr);
+ return inb(ap->ioaddr.altstatus_addr);
+}
+
+/**
+ * ata_bmdma_setup_mmio - Set up PCI IDE BMDMA transaction
+ * @qc: Info associated with this ATA transaction.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ */
+
+static void ata_bmdma_setup_mmio (struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE);
+ u8 dmactl;
+ void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr;
+
+ /* load PRD table addr. */
+ mb(); /* make sure PRD table writes are visible to controller */
+ writel(ap->prd_dma, mmio + ATA_DMA_TABLE_OFS);
+
+ /* specify data direction, triple-check start bit is clear */
+ dmactl = readb(mmio + ATA_DMA_CMD);
+ dmactl &= ~(ATA_DMA_WR | ATA_DMA_START);
+ if (!rw)
+ dmactl |= ATA_DMA_WR;
+ writeb(dmactl, mmio + ATA_DMA_CMD);
+
+ /* issue r/w command */
+ ap->ops->exec_command(ap, &qc->tf);
+}
+
+/**
+ * ata_bmdma_start_mmio - Start a PCI IDE BMDMA transaction
+ * @qc: Info associated with this ATA transaction.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ */
+
+static void ata_bmdma_start_mmio (struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr;
+ u8 dmactl;
+
+ /* start host DMA transaction */
+ dmactl = readb(mmio + ATA_DMA_CMD);
+ writeb(dmactl | ATA_DMA_START, mmio + ATA_DMA_CMD);
+
+ /* Strictly, one may wish to issue a readb() here, to
+ * flush the mmio write. However, control also passes
+ * to the hardware at this point, and it will interrupt
+ * us when we are to resume control. So, in effect,
+ * we don't care when the mmio write flushes.
+ * Further, a read of the DMA status register _immediately_
+ * following the write may not be what certain flaky hardware
+ * is expected, so I think it is best to not add a readb()
+ * without first all the MMIO ATA cards/mobos.
+ * Or maybe I'm just being paranoid.
+ */
+}
+
+/**
+ * ata_bmdma_setup_pio - Set up PCI IDE BMDMA transaction (PIO)
+ * @qc: Info associated with this ATA transaction.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ */
+
+static void ata_bmdma_setup_pio (struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE);
+ u8 dmactl;
+
+ /* load PRD table addr. */
+ outl(ap->prd_dma, ap->ioaddr.bmdma_addr + ATA_DMA_TABLE_OFS);
+
+ /* specify data direction, triple-check start bit is clear */
+ dmactl = inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
+ dmactl &= ~(ATA_DMA_WR | ATA_DMA_START);
+ if (!rw)
+ dmactl |= ATA_DMA_WR;
+ outb(dmactl, ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
+
+ /* issue r/w command */
+ ap->ops->exec_command(ap, &qc->tf);
+}
+
+/**
+ * ata_bmdma_start_pio - Start a PCI IDE BMDMA transaction (PIO)
+ * @qc: Info associated with this ATA transaction.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ */
+
+static void ata_bmdma_start_pio (struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ u8 dmactl;
+
+ /* start host DMA transaction */
+ dmactl = inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
+ outb(dmactl | ATA_DMA_START,
+ ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
+}
+
+
+/**
+ * ata_bmdma_start - Start a PCI IDE BMDMA transaction
+ * @qc: Info associated with this ATA transaction.
+ *
+ * Writes the ATA_DMA_START flag to the DMA command register.
+ *
+ * May be used as the bmdma_start() entry in ata_port_operations.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ */
+void ata_bmdma_start(struct ata_queued_cmd *qc)
+{
+ if (qc->ap->flags & ATA_FLAG_MMIO)
+ ata_bmdma_start_mmio(qc);
+ else
+ ata_bmdma_start_pio(qc);
+}
+
+
+/**
+ * ata_bmdma_setup - Set up PCI IDE BMDMA transaction
+ * @qc: Info associated with this ATA transaction.
+ *
+ * Writes address of PRD table to device's PRD Table Address
+ * register, sets the DMA control register, and calls
+ * ops->exec_command() to start the transfer.
+ *
+ * May be used as the bmdma_setup() entry in ata_port_operations.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ */
+void ata_bmdma_setup(struct ata_queued_cmd *qc)
+{
+ if (qc->ap->flags & ATA_FLAG_MMIO)
+ ata_bmdma_setup_mmio(qc);
+ else
+ ata_bmdma_setup_pio(qc);
+}
+
+
+/**
+ * ata_bmdma_irq_clear - Clear PCI IDE BMDMA interrupt.
+ * @ap: Port associated with this ATA transaction.
+ *
+ * Clear interrupt and error flags in DMA status register.
+ *
+ * May be used as the irq_clear() entry in ata_port_operations.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ */
+
+void ata_bmdma_irq_clear(struct ata_port *ap)
+{
+ if (!ap->ioaddr.bmdma_addr)
+ return;
+
+ if (ap->flags & ATA_FLAG_MMIO) {
+ void __iomem *mmio =
+ ((void __iomem *) ap->ioaddr.bmdma_addr) + ATA_DMA_STATUS;
+ writeb(readb(mmio), mmio);
+ } else {
+ unsigned long addr = ap->ioaddr.bmdma_addr + ATA_DMA_STATUS;
+ outb(inb(addr), addr);
+ }
+}
+
+
+/**
+ * ata_bmdma_status - Read PCI IDE BMDMA status
+ * @ap: Port associated with this ATA transaction.
+ *
+ * Read and return BMDMA status register.
+ *
+ * May be used as the bmdma_status() entry in ata_port_operations.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ */
+
+u8 ata_bmdma_status(struct ata_port *ap)
+{
+ u8 host_stat;
+ if (ap->flags & ATA_FLAG_MMIO) {
+ void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr;
+ host_stat = readb(mmio + ATA_DMA_STATUS);
+ } else
+ host_stat = inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
+ return host_stat;
+}
+
+
+/**
+ * ata_bmdma_stop - Stop PCI IDE BMDMA transfer
+ * @qc: Command we are ending DMA for
+ *
+ * Clears the ATA_DMA_START flag in the dma control register
+ *
+ * May be used as the bmdma_stop() entry in ata_port_operations.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ */
+
+void ata_bmdma_stop(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ if (ap->flags & ATA_FLAG_MMIO) {
+ void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr;
+
+ /* clear start/stop bit */
+ writeb(readb(mmio + ATA_DMA_CMD) & ~ATA_DMA_START,
+ mmio + ATA_DMA_CMD);
+ } else {
+ /* clear start/stop bit */
+ outb(inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD) & ~ATA_DMA_START,
+ ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
+ }
+
+ /* one-PIO-cycle guaranteed wait, per spec, for HDMA1:0 transition */
+ ata_altstatus(ap); /* dummy read */
+}
+
+/**
+ * ata_bmdma_freeze - Freeze BMDMA controller port
+ * @ap: port to freeze
+ *
+ * Freeze BMDMA controller port.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+void ata_bmdma_freeze(struct ata_port *ap)
+{
+ struct ata_ioports *ioaddr = &ap->ioaddr;
+
+ ap->ctl |= ATA_NIEN;
+ ap->last_ctl = ap->ctl;
+
+ if (ap->flags & ATA_FLAG_MMIO)
+ writeb(ap->ctl, (void __iomem *)ioaddr->ctl_addr);
+ else
+ outb(ap->ctl, ioaddr->ctl_addr);
+}
+
+/**
+ * ata_bmdma_thaw - Thaw BMDMA controller port
+ * @ap: port to thaw
+ *
+ * Thaw BMDMA controller port.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+void ata_bmdma_thaw(struct ata_port *ap)
+{
+ /* clear & re-enable interrupts */
+ ata_chk_status(ap);
+ ap->ops->irq_clear(ap);
+ if (ap->ioaddr.ctl_addr) /* FIXME: hack. create a hook instead */
+ ata_irq_on(ap);
+}
+
+/**
+ * ata_bmdma_drive_eh - Perform EH with given methods for BMDMA controller
+ * @ap: port to handle error for
+ * @prereset: prereset method (can be NULL)
+ * @softreset: softreset method (can be NULL)
+ * @hardreset: hardreset method (can be NULL)
+ * @postreset: postreset method (can be NULL)
+ *
+ * Handle error for ATA BMDMA controller. It can handle both
+ * PATA and SATA controllers. Many controllers should be able to
+ * use this EH as-is or with some added handling before and
+ * after.
+ *
+ * This function is intended to be used for constructing
+ * ->error_handler callback by low level drivers.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep)
+ */
+void ata_bmdma_drive_eh(struct ata_port *ap, ata_prereset_fn_t prereset,
+ ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
+ ata_postreset_fn_t postreset)
+{
+ struct ata_eh_context *ehc = &ap->eh_context;
+ struct ata_queued_cmd *qc;
+ unsigned long flags;
+ int thaw = 0;
+
+ qc = __ata_qc_from_tag(ap, ap->active_tag);
+ if (qc && !(qc->flags & ATA_QCFLAG_FAILED))
+ qc = NULL;
+
+ /* reset PIO HSM and stop DMA engine */
+ spin_lock_irqsave(ap->lock, flags);
+
+ ap->hsm_task_state = HSM_ST_IDLE;
+
+ if (qc && (qc->tf.protocol == ATA_PROT_DMA ||
+ qc->tf.protocol == ATA_PROT_ATAPI_DMA)) {
+ u8 host_stat;
+
+ host_stat = ata_bmdma_status(ap);
+
+ ata_ehi_push_desc(&ehc->i, "BMDMA stat 0x%x", host_stat);
+
+ /* BMDMA controllers indicate host bus error by
+ * setting DMA_ERR bit and timing out. As it wasn't
+ * really a timeout event, adjust error mask and
+ * cancel frozen state.
+ */
+ if (qc->err_mask == AC_ERR_TIMEOUT && host_stat & ATA_DMA_ERR) {
+ qc->err_mask = AC_ERR_HOST_BUS;
+ thaw = 1;
+ }
+
+ ap->ops->bmdma_stop(qc);
+ }
+
+ ata_altstatus(ap);
+ ata_chk_status(ap);
+ ap->ops->irq_clear(ap);
+
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ if (thaw)
+ ata_eh_thaw_port(ap);
+
+ /* PIO and DMA engines have been stopped, perform recovery */
+ ata_do_eh(ap, prereset, softreset, hardreset, postreset);
+}
+
+/**
+ * ata_bmdma_error_handler - Stock error handler for BMDMA controller
+ * @ap: port to handle error for
+ *
+ * Stock error handler for BMDMA controller.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep)
+ */
+void ata_bmdma_error_handler(struct ata_port *ap)
+{
+ ata_reset_fn_t hardreset;
+
+ hardreset = NULL;
+ if (sata_scr_valid(ap))
+ hardreset = sata_std_hardreset;
+
+ ata_bmdma_drive_eh(ap, ata_std_prereset, ata_std_softreset, hardreset,
+ ata_std_postreset);
+}
+
+/**
+ * ata_bmdma_post_internal_cmd - Stock post_internal_cmd for
+ * BMDMA controller
+ * @qc: internal command to clean up
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep)
+ */
+void ata_bmdma_post_internal_cmd(struct ata_queued_cmd *qc)
+{
+ ata_bmdma_stop(qc);
+}
+
+#ifdef CONFIG_PCI
+/**
+ * ata_pci_init_native_mode - Initialize native-mode driver
+ * @pdev: pci device to be initialized
+ * @port: array[2] of pointers to port info structures.
+ * @ports: bitmap of ports present
+ *
+ * Utility function which allocates and initializes an
+ * ata_probe_ent structure for a standard dual-port
+ * PIO-based IDE controller. The returned ata_probe_ent
+ * structure can be passed to ata_device_add(). The returned
+ * ata_probe_ent structure should then be freed with kfree().
+ *
+ * The caller need only pass the address of the primary port, the
+ * secondary will be deduced automatically. If the device has non
+ * standard secondary port mappings this function can be called twice,
+ * once for each interface.
+ */
+
+struct ata_probe_ent *
+ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port, int ports)
+{
+ struct ata_probe_ent *probe_ent =
+ ata_probe_ent_alloc(pci_dev_to_dev(pdev), port[0]);
+ int p = 0;
+ unsigned long bmdma;
+
+ if (!probe_ent)
+ return NULL;
+
+ probe_ent->irq = pdev->irq;
+ probe_ent->irq_flags = IRQF_SHARED;
+ probe_ent->private_data = port[0]->private_data;
+
+ if (ports & ATA_PORT_PRIMARY) {
+ probe_ent->port[p].cmd_addr = pci_resource_start(pdev, 0);
+ probe_ent->port[p].altstatus_addr =
+ probe_ent->port[p].ctl_addr =
+ pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS;
+ bmdma = pci_resource_start(pdev, 4);
+ if (bmdma) {
+ if (inb(bmdma + 2) & 0x80)
+ probe_ent->_host_flags |= ATA_HOST_SIMPLEX;
+ probe_ent->port[p].bmdma_addr = bmdma;
+ }
+ ata_std_ports(&probe_ent->port[p]);
+ p++;
+ }
+
+ if (ports & ATA_PORT_SECONDARY) {
+ probe_ent->port[p].cmd_addr = pci_resource_start(pdev, 2);
+ probe_ent->port[p].altstatus_addr =
+ probe_ent->port[p].ctl_addr =
+ pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS;
+ bmdma = pci_resource_start(pdev, 4);
+ if (bmdma) {
+ bmdma += 8;
+ if(inb(bmdma + 2) & 0x80)
+ probe_ent->_host_flags |= ATA_HOST_SIMPLEX;
+ probe_ent->port[p].bmdma_addr = bmdma;
+ }
+ ata_std_ports(&probe_ent->port[p]);
+ probe_ent->pinfo2 = port[1];
+ p++;
+ }
+
+ probe_ent->n_ports = p;
+ return probe_ent;
+}
+
+
+static struct ata_probe_ent *ata_pci_init_legacy_port(struct pci_dev *pdev,
+ struct ata_port_info **port, int port_mask)
+{
+ struct ata_probe_ent *probe_ent;
+ unsigned long bmdma = pci_resource_start(pdev, 4);
+
+ probe_ent = ata_probe_ent_alloc(pci_dev_to_dev(pdev), port[0]);
+ if (!probe_ent)
+ return NULL;
+
+ probe_ent->n_ports = 2;
+ probe_ent->private_data = port[0]->private_data;
+
+ if (port_mask & ATA_PORT_PRIMARY) {
+ probe_ent->irq = ATA_PRIMARY_IRQ;
+ probe_ent->port[0].cmd_addr = ATA_PRIMARY_CMD;
+ probe_ent->port[0].altstatus_addr =
+ probe_ent->port[0].ctl_addr = ATA_PRIMARY_CTL;
+ if (bmdma) {
+ probe_ent->port[0].bmdma_addr = bmdma;
+ if (inb(bmdma + 2) & 0x80)
+ probe_ent->_host_flags |= ATA_HOST_SIMPLEX;
+ }
+ ata_std_ports(&probe_ent->port[0]);
+ } else
+ probe_ent->dummy_port_mask |= ATA_PORT_PRIMARY;
+
+ if (port_mask & ATA_PORT_SECONDARY) {
+ if (probe_ent->irq)
+ probe_ent->irq2 = ATA_SECONDARY_IRQ;
+ else
+ probe_ent->irq = ATA_SECONDARY_IRQ;
+ probe_ent->port[1].cmd_addr = ATA_SECONDARY_CMD;
+ probe_ent->port[1].altstatus_addr =
+ probe_ent->port[1].ctl_addr = ATA_SECONDARY_CTL;
+ if (bmdma) {
+ probe_ent->port[1].bmdma_addr = bmdma + 8;
+ if (inb(bmdma + 10) & 0x80)
+ probe_ent->_host_flags |= ATA_HOST_SIMPLEX;
+ }
+ ata_std_ports(&probe_ent->port[1]);
+ probe_ent->pinfo2 = port[1];
+ } else
+ probe_ent->dummy_port_mask |= ATA_PORT_SECONDARY;
+
+ return probe_ent;
+}
+
+
+/**
+ * ata_pci_init_one - Initialize/register PCI IDE host controller
+ * @pdev: Controller to be initialized
+ * @port_info: Information from low-level host driver
+ * @n_ports: Number of ports attached to host controller
+ *
+ * This is a helper function which can be called from a driver's
+ * xxx_init_one() probe function if the hardware uses traditional
+ * IDE taskfile registers.
+ *
+ * This function calls pci_enable_device(), reserves its register
+ * regions, sets the dma mask, enables bus master mode, and calls
+ * ata_device_add()
+ *
+ * ASSUMPTION:
+ * Nobody makes a single channel controller that appears solely as
+ * the secondary legacy port on PCI.
+ *
+ * LOCKING:
+ * Inherited from PCI layer (may sleep).
+ *
+ * RETURNS:
+ * Zero on success, negative on errno-based value on error.
+ */
+
+int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info,
+ unsigned int n_ports)
+{
+ struct ata_probe_ent *probe_ent = NULL;
+ struct ata_port_info *port[2];
+ u8 tmp8, mask;
+ unsigned int legacy_mode = 0;
+ int disable_dev_on_err = 1;
+ int rc;
+
+ DPRINTK("ENTER\n");
+
+ port[0] = port_info[0];
+ if (n_ports > 1)
+ port[1] = port_info[1];
+ else
+ port[1] = port[0];
+
+ if ((port[0]->flags & ATA_FLAG_NO_LEGACY) == 0
+ && (pdev->class >> 8) == PCI_CLASS_STORAGE_IDE) {
+ /* TODO: What if one channel is in native mode ... */
+ pci_read_config_byte(pdev, PCI_CLASS_PROG, &tmp8);
+ mask = (1 << 2) | (1 << 0);
+ if ((tmp8 & mask) != mask)
+ legacy_mode = (1 << 3);
+ }
+
+ /* FIXME... */
+ if ((!legacy_mode) && (n_ports > 2)) {
+ printk(KERN_ERR "ata: BUG: native mode, n_ports > 2\n");
+ n_ports = 2;
+ /* For now */
+ }
+
+ /* FIXME: Really for ATA it isn't safe because the device may be
+ multi-purpose and we want to leave it alone if it was already
+ enabled. Secondly for shared use as Arjan says we want refcounting
+
+ Checking dev->is_enabled is insufficient as this is not set at
+ boot for the primary video which is BIOS enabled
+ */
+
+ rc = pci_enable_device(pdev);
+ if (rc)
+ return rc;
+
+ rc = pci_request_regions(pdev, DRV_NAME);
+ if (rc) {
+ disable_dev_on_err = 0;
+ goto err_out;
+ }
+
+ if (legacy_mode) {
+ if (!request_region(ATA_PRIMARY_CMD, 8, "libata")) {
+ struct resource *conflict, res;
+ res.start = ATA_PRIMARY_CMD;
+ res.end = ATA_PRIMARY_CMD + 8 - 1;
+ conflict = ____request_resource(&ioport_resource, &res);
+ while (conflict->child)
+ conflict = ____request_resource(conflict, &res);
+ if (!strcmp(conflict->name, "libata"))
+ legacy_mode |= ATA_PORT_PRIMARY;
+ else {
+ disable_dev_on_err = 0;
+ printk(KERN_WARNING "ata: 0x%0X IDE port busy\n" \
+ "ata: conflict with %s\n",
+ ATA_PRIMARY_CMD,
+ conflict->name);
+ }
+ } else
+ legacy_mode |= ATA_PORT_PRIMARY;
+
+ if (!request_region(ATA_SECONDARY_CMD, 8, "libata")) {
+ struct resource *conflict, res;
+ res.start = ATA_SECONDARY_CMD;
+ res.end = ATA_SECONDARY_CMD + 8 - 1;
+ conflict = ____request_resource(&ioport_resource, &res);
+ while (conflict->child)
+ conflict = ____request_resource(conflict, &res);
+ if (!strcmp(conflict->name, "libata"))
+ legacy_mode |= ATA_PORT_SECONDARY;
+ else {
+ disable_dev_on_err = 0;
+ printk(KERN_WARNING "ata: 0x%X IDE port busy\n" \
+ "ata: conflict with %s\n",
+ ATA_SECONDARY_CMD,
+ conflict->name);
+ }
+ } else
+ legacy_mode |= ATA_PORT_SECONDARY;
+ }
+
+ /* we have legacy mode, but all ports are unavailable */
+ if (legacy_mode == (1 << 3)) {
+ rc = -EBUSY;
+ goto err_out_regions;
+ }
+
+ /* FIXME: If we get no DMA mask we should fall back to PIO */
+ rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
+ if (rc)
+ goto err_out_regions;
+ rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
+ if (rc)
+ goto err_out_regions;
+
+ if (legacy_mode) {
+ probe_ent = ata_pci_init_legacy_port(pdev, port, legacy_mode);
+ } else {
+ if (n_ports == 2)
+ probe_ent = ata_pci_init_native_mode(pdev, port, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY);
+ else
+ probe_ent = ata_pci_init_native_mode(pdev, port, ATA_PORT_PRIMARY);
+ }
+ if (!probe_ent) {
+ rc = -ENOMEM;
+ goto err_out_regions;
+ }
+
+ pci_set_master(pdev);
+
+ /* FIXME: check ata_device_add return */
+ ata_device_add(probe_ent);
+
+ kfree(probe_ent);
+
+ return 0;
+
+err_out_regions:
+ if (legacy_mode & ATA_PORT_PRIMARY)
+ release_region(ATA_PRIMARY_CMD, 8);
+ if (legacy_mode & ATA_PORT_SECONDARY)
+ release_region(ATA_SECONDARY_CMD, 8);
+ pci_release_regions(pdev);
+err_out:
+ if (disable_dev_on_err)
+ pci_disable_device(pdev);
+ return rc;
+}
+
+/**
+ * ata_pci_clear_simplex - attempt to kick device out of simplex
+ * @pdev: PCI device
+ *
+ * Some PCI ATA devices report simplex mode but in fact can be told to
+ * enter non simplex mode. This implements the neccessary logic to
+ * perform the task on such devices. Calling it on other devices will
+ * have -undefined- behaviour.
+ */
+
+int ata_pci_clear_simplex(struct pci_dev *pdev)
+{
+ unsigned long bmdma = pci_resource_start(pdev, 4);
+ u8 simplex;
+
+ if (bmdma == 0)
+ return -ENOENT;
+
+ simplex = inb(bmdma + 0x02);
+ outb(simplex & 0x60, bmdma + 0x02);
+ simplex = inb(bmdma + 0x02);
+ if (simplex & 0x80)
+ return -EOPNOTSUPP;
+ return 0;
+}
+
+unsigned long ata_pci_default_filter(const struct ata_port *ap, struct ata_device *adev, unsigned long xfer_mask)
+{
+ /* Filter out DMA modes if the device has been configured by
+ the BIOS as PIO only */
+
+ if (ap->ioaddr.bmdma_addr == 0)
+ xfer_mask &= ~(ATA_MASK_MWDMA | ATA_MASK_UDMA);
+ return xfer_mask;
+}
+
+#endif /* CONFIG_PCI */
+
diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h
new file mode 100644
index 00000000000..a5ecb71390a
--- /dev/null
+++ b/drivers/ata/libata.h
@@ -0,0 +1,122 @@
+/*
+ * libata.h - helper library for ATA
+ *
+ * Copyright 2003-2004 Red Hat, Inc. All rights reserved.
+ * Copyright 2003-2004 Jeff Garzik
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * libata documentation is available via 'make {ps|pdf}docs',
+ * as Documentation/DocBook/libata.*
+ *
+ */
+
+#ifndef __LIBATA_H__
+#define __LIBATA_H__
+
+#define DRV_NAME "libata"
+#define DRV_VERSION "2.00" /* must be exactly four chars */
+
+struct ata_scsi_args {
+ struct ata_device *dev;
+ u16 *id;
+ struct scsi_cmnd *cmd;
+ void (*done)(struct scsi_cmnd *);
+};
+
+/* libata-core.c */
+extern struct workqueue_struct *ata_aux_wq;
+extern int atapi_enabled;
+extern int atapi_dmadir;
+extern int libata_fua;
+extern struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev);
+extern int ata_rwcmd_protocol(struct ata_queued_cmd *qc);
+extern void ata_dev_disable(struct ata_device *dev);
+extern void ata_port_flush_task(struct ata_port *ap);
+extern unsigned ata_exec_internal(struct ata_device *dev,
+ struct ata_taskfile *tf, const u8 *cdb,
+ int dma_dir, void *buf, unsigned int buflen);
+extern unsigned int ata_do_simple_cmd(struct ata_device *dev, u8 cmd);
+extern int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
+ int post_reset, u16 *id);
+extern int ata_dev_configure(struct ata_device *dev, int print_info);
+extern int sata_down_spd_limit(struct ata_port *ap);
+extern int sata_set_spd_needed(struct ata_port *ap);
+extern int ata_down_xfermask_limit(struct ata_device *dev, int force_pio0);
+extern int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev);
+extern void ata_qc_free(struct ata_queued_cmd *qc);
+extern void ata_qc_issue(struct ata_queued_cmd *qc);
+extern void __ata_qc_complete(struct ata_queued_cmd *qc);
+extern int ata_check_atapi_dma(struct ata_queued_cmd *qc);
+extern void ata_dev_select(struct ata_port *ap, unsigned int device,
+ unsigned int wait, unsigned int can_sleep);
+extern void swap_buf_le16(u16 *buf, unsigned int buf_words);
+extern int ata_flush_cache(struct ata_device *dev);
+extern void ata_dev_init(struct ata_device *dev);
+extern int ata_task_ioctl(struct scsi_device *scsidev, void __user *arg);
+extern int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg);
+extern void ata_port_init(struct ata_port *ap, struct ata_host *host,
+ const struct ata_probe_ent *ent, unsigned int port_no);
+extern struct ata_probe_ent *ata_probe_ent_alloc(struct device *dev,
+ const struct ata_port_info *port);
+
+
+/* libata-scsi.c */
+extern struct scsi_transport_template ata_scsi_transport_template;
+
+extern void ata_scsi_scan_host(struct ata_port *ap);
+extern int ata_scsi_offline_dev(struct ata_device *dev);
+extern void ata_scsi_hotplug(void *data);
+extern unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf,
+ unsigned int buflen);
+
+extern unsigned int ata_scsiop_inq_00(struct ata_scsi_args *args, u8 *rbuf,
+ unsigned int buflen);
+
+extern unsigned int ata_scsiop_inq_80(struct ata_scsi_args *args, u8 *rbuf,
+ unsigned int buflen);
+extern unsigned int ata_scsiop_inq_83(struct ata_scsi_args *args, u8 *rbuf,
+ unsigned int buflen);
+extern unsigned int ata_scsiop_noop(struct ata_scsi_args *args, u8 *rbuf,
+ unsigned int buflen);
+extern unsigned int ata_scsiop_sync_cache(struct ata_scsi_args *args, u8 *rbuf,
+ unsigned int buflen);
+extern unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf,
+ unsigned int buflen);
+extern unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf,
+ unsigned int buflen);
+extern unsigned int ata_scsiop_report_luns(struct ata_scsi_args *args, u8 *rbuf,
+ unsigned int buflen);
+extern void ata_scsi_badcmd(struct scsi_cmnd *cmd,
+ void (*done)(struct scsi_cmnd *),
+ u8 asc, u8 ascq);
+extern void ata_scsi_set_sense(struct scsi_cmnd *cmd,
+ u8 sk, u8 asc, u8 ascq);
+extern void ata_scsi_rbuf_fill(struct ata_scsi_args *args,
+ unsigned int (*actor) (struct ata_scsi_args *args,
+ u8 *rbuf, unsigned int buflen));
+extern void ata_schedule_scsi_eh(struct Scsi_Host *shost);
+extern void ata_scsi_dev_rescan(void *data);
+extern int ata_bus_probe(struct ata_port *ap);
+
+/* libata-eh.c */
+extern enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd);
+extern void ata_scsi_error(struct Scsi_Host *host);
+extern void ata_port_wait_eh(struct ata_port *ap);
+extern void ata_qc_schedule_eh(struct ata_queued_cmd *qc);
+
+#endif /* __LIBATA_H__ */
diff --git a/drivers/ata/pata_ali.c b/drivers/ata/pata_ali.c
new file mode 100644
index 00000000000..87af3b5861a
--- /dev/null
+++ b/drivers/ata/pata_ali.c
@@ -0,0 +1,679 @@
+/*
+ * pata_ali.c - ALI 15x3 PATA for new ATA layer
+ * (C) 2005 Red Hat Inc
+ * Alan Cox <alan@redhat.com>
+ *
+ * based in part upon
+ * linux/drivers/ide/pci/alim15x3.c Version 0.17 2003/01/02
+ *
+ * Copyright (C) 1998-2000 Michel Aubry, Maintainer
+ * Copyright (C) 1998-2000 Andrzej Krzysztofowicz, Maintainer
+ * Copyright (C) 1999-2000 CJ, cjtsai@ali.com.tw, Maintainer
+ *
+ * Copyright (C) 1998-2000 Andre Hedrick (andre@linux-ide.org)
+ * May be copied or modified under the terms of the GNU General Public License
+ * Copyright (C) 2002 Alan Cox <alan@redhat.com>
+ * ALi (now ULi M5228) support by Clear Zhang <Clear.Zhang@ali.com.tw>
+ *
+ * Documentation
+ * Chipset documentation available under NDA only
+ *
+ * TODO/CHECK
+ * Cannot have ATAPI on both master & slave for rev < c2 (???) but
+ * otherwise should do atapi DMA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+#include <linux/dmi.h>
+
+#define DRV_NAME "pata_ali"
+#define DRV_VERSION "0.6.5"
+
+/*
+ * Cable special cases
+ */
+
+static struct dmi_system_id cable_dmi_table[] = {
+ {
+ .ident = "HP Pavilion N5430",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "Hewlett-Packard"),
+ DMI_MATCH(DMI_BOARD_NAME, "OmniBook N32N-736"),
+ },
+ },
+ { }
+};
+
+static int ali_cable_override(struct pci_dev *pdev)
+{
+ /* Fujitsu P2000 */
+ if (pdev->subsystem_vendor == 0x10CF && pdev->subsystem_device == 0x10AF)
+ return 1;
+ /* Systems by DMI */
+ if (dmi_check_system(cable_dmi_table))
+ return 1;
+ return 0;
+}
+
+/**
+ * ali_c2_cable_detect - cable detection
+ * @ap: ATA port
+ *
+ * Perform cable detection for C2 and later revisions
+ */
+
+static int ali_c2_cable_detect(struct ata_port *ap)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u8 ata66;
+
+ /* Certain laptops use short but suitable cables and don't
+ implement the detect logic */
+
+ if (ali_cable_override(pdev))
+ return ATA_CBL_PATA80;
+
+ /* Host view cable detect 0x4A bit 0 primary bit 1 secondary
+ Bit set for 40 pin */
+ pci_read_config_byte(pdev, 0x4A, &ata66);
+ if (ata66 & (1 << ap->port_no))
+ return ATA_CBL_PATA40;
+ else
+ return ATA_CBL_PATA80;
+}
+
+/**
+ * ali_early_error_handler - reset for eary chip
+ * @ap: ATA port
+ *
+ * Handle the reset callback for the later chips with cable detect
+ */
+
+static int ali_c2_pre_reset(struct ata_port *ap)
+{
+ ap->cbl = ali_c2_cable_detect(ap);
+ return ata_std_prereset(ap);
+}
+
+static void ali_c2_error_handler(struct ata_port *ap)
+{
+ ata_bmdma_drive_eh(ap, ali_c2_pre_reset,
+ ata_std_softreset, NULL,
+ ata_std_postreset);
+}
+
+/**
+ * ali_early_cable_detect - cable detection
+ * @ap: ATA port
+ *
+ * Perform cable detection for older chipsets. This turns out to be
+ * rather easy to implement
+ */
+
+static int ali_early_cable_detect(struct ata_port *ap)
+{
+ return ATA_CBL_PATA40;
+}
+
+/**
+ * ali_early_probe_init - reset for early chip
+ * @ap: ATA port
+ *
+ * Handle the reset callback for the early (pre cable detect) chips.
+ */
+
+static int ali_early_pre_reset(struct ata_port *ap)
+{
+ ap->cbl = ali_early_cable_detect(ap);
+ return ata_std_prereset(ap);
+}
+
+static void ali_early_error_handler(struct ata_port *ap)
+{
+ return ata_bmdma_drive_eh(ap, ali_early_pre_reset,
+ ata_std_softreset, NULL,
+ ata_std_postreset);
+}
+
+/**
+ * ali_20_filter - filter for earlier ALI DMA
+ * @ap: ALi ATA port
+ * @adev: attached device
+ *
+ * Ensure that we do not do DMA on CD devices. We may be able to
+ * fix that later on. Also ensure we do not do UDMA on WDC drives
+ */
+
+static unsigned long ali_20_filter(const struct ata_port *ap, struct ata_device *adev, unsigned long mask)
+{
+ char model_num[40];
+ /* No DMA on anything but a disk for now */
+ if (adev->class != ATA_DEV_ATA)
+ mask &= ~(ATA_MASK_MWDMA | ATA_MASK_UDMA);
+ ata_id_string(adev->id, model_num, ATA_ID_PROD_OFS, sizeof(model_num));
+ if (strstr(model_num, "WDC"))
+ return mask &= ~ATA_MASK_UDMA;
+ return ata_pci_default_filter(ap, adev, mask);
+}
+
+/**
+ * ali_fifo_control - FIFO manager
+ * @ap: ALi channel to control
+ * @adev: device for FIFO control
+ * @on: 0 for off 1 for on
+ *
+ * Enable or disable the FIFO on a given device. Because of the way the
+ * ALi FIFO works it provides a boost on ATA disk but can be confused by
+ * ATAPI and we must therefore manage it.
+ */
+
+static void ali_fifo_control(struct ata_port *ap, struct ata_device *adev, int on)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ int pio_fifo = 0x54 + ap->port_no;
+ u8 fifo;
+ int shift = 4 * adev->devno;
+
+ /* ATA - FIFO on set nibble to 0x05, ATAPI - FIFO off, set nibble to
+ 0x00. Not all the docs agree but the behaviour we now use is the
+ one stated in the BIOS Programming Guide */
+
+ pci_read_config_byte(pdev, pio_fifo, &fifo);
+ fifo &= ~(0x0F << shift);
+ if (on)
+ fifo |= (on << shift);
+ pci_write_config_byte(pdev, pio_fifo, fifo);
+}
+
+/**
+ * ali_program_modes - load mode registers
+ * @ap: ALi channel to load
+ * @adev: Device the timing is for
+ * @cmd: Command timing
+ * @data: Data timing
+ * @ultra: UDMA timing or zero for off
+ *
+ * Loads the timing registers for cmd/data and disable UDMA if
+ * ultra is zero. If ultra is set then load and enable the UDMA
+ * timing but do not touch the command/data timing.
+ */
+
+static void ali_program_modes(struct ata_port *ap, struct ata_device *adev, struct ata_timing *t, u8 ultra)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ int cas = 0x58 + 4 * ap->port_no; /* Command timing */
+ int cbt = 0x59 + 4 * ap->port_no; /* Command timing */
+ int drwt = 0x5A + 4 * ap->port_no + adev->devno; /* R/W timing */
+ int udmat = 0x56 + ap->port_no; /* UDMA timing */
+ int shift = 4 * adev->devno;
+ u8 udma;
+
+ if (t != NULL) {
+ t->setup = FIT(t->setup, 1, 8) & 7;
+ t->act8b = FIT(t->act8b, 1, 8) & 7;
+ t->rec8b = FIT(t->rec8b, 1, 16) & 15;
+ t->active = FIT(t->active, 1, 8) & 7;
+ t->recover = FIT(t->recover, 1, 16) & 15;
+
+ pci_write_config_byte(pdev, cas, t->setup);
+ pci_write_config_byte(pdev, cbt, (t->act8b << 4) | t->rec8b);
+ pci_write_config_byte(pdev, drwt, (t->active << 4) | t->recover);
+ }
+
+ /* Set up the UDMA enable */
+ pci_read_config_byte(pdev, udmat, &udma);
+ udma &= ~(0x0F << shift);
+ udma |= ultra << shift;
+ pci_write_config_byte(pdev, udmat, udma);
+}
+
+/**
+ * ali_set_piomode - set initial PIO mode data
+ * @ap: ATA interface
+ * @adev: ATA device
+ *
+ * Program the ALi registers for PIO mode. FIXME: add timings for
+ * PIO5.
+ */
+
+static void ali_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ struct ata_device *pair = ata_dev_pair(adev);
+ struct ata_timing t;
+ unsigned long T = 1000000000 / 33333; /* PCI clock based */
+
+ ata_timing_compute(adev, adev->pio_mode, &t, T, 1);
+ if (pair) {
+ struct ata_timing p;
+ ata_timing_compute(pair, pair->pio_mode, &p, T, 1);
+ ata_timing_merge(&p, &t, &t, ATA_TIMING_SETUP|ATA_TIMING_8BIT);
+ if (pair->dma_mode) {
+ ata_timing_compute(pair, pair->dma_mode, &p, T, 1);
+ ata_timing_merge(&p, &t, &t, ATA_TIMING_SETUP|ATA_TIMING_8BIT);
+ }
+ }
+
+ /* PIO FIFO is only permitted on ATA disk */
+ if (adev->class != ATA_DEV_ATA)
+ ali_fifo_control(ap, adev, 0x00);
+ ali_program_modes(ap, adev, &t, 0);
+ if (adev->class == ATA_DEV_ATA)
+ ali_fifo_control(ap, adev, 0x05);
+
+}
+
+/**
+ * ali_set_dmamode - set initial DMA mode data
+ * @ap: ATA interface
+ * @adev: ATA device
+ *
+ * FIXME: MWDMA timings
+ */
+
+static void ali_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+ static u8 udma_timing[7] = { 0xC, 0xB, 0xA, 0x9, 0x8, 0xF, 0xD };
+ struct ata_device *pair = ata_dev_pair(adev);
+ struct ata_timing t;
+ unsigned long T = 1000000000 / 33333; /* PCI clock based */
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+
+
+ if (adev->class == ATA_DEV_ATA)
+ ali_fifo_control(ap, adev, 0x08);
+
+ if (adev->dma_mode >= XFER_UDMA_0) {
+ ali_program_modes(ap, adev, NULL, udma_timing[adev->dma_mode - XFER_UDMA_0]);
+ if (adev->dma_mode >= XFER_UDMA_3) {
+ u8 reg4b;
+ pci_read_config_byte(pdev, 0x4B, &reg4b);
+ reg4b |= 1;
+ pci_write_config_byte(pdev, 0x4B, reg4b);
+ }
+ } else {
+ ata_timing_compute(adev, adev->dma_mode, &t, T, 1);
+ if (pair) {
+ struct ata_timing p;
+ ata_timing_compute(pair, pair->pio_mode, &p, T, 1);
+ ata_timing_merge(&p, &t, &t, ATA_TIMING_SETUP|ATA_TIMING_8BIT);
+ if (pair->dma_mode) {
+ ata_timing_compute(pair, pair->dma_mode, &p, T, 1);
+ ata_timing_merge(&p, &t, &t, ATA_TIMING_SETUP|ATA_TIMING_8BIT);
+ }
+ }
+ ali_program_modes(ap, adev, &t, 0);
+ }
+}
+
+/**
+ * ali_lock_sectors - Keep older devices to 255 sector mode
+ * @ap: ATA port
+ * @adev: Device
+ *
+ * Called during the bus probe for each device that is found. We use
+ * this call to lock the sector count of the device to 255 or less on
+ * older ALi controllers. If we didn't do this then large I/O's would
+ * require LBA48 commands which the older ALi requires are issued by
+ * slower PIO methods
+ */
+
+static void ali_lock_sectors(struct ata_port *ap, struct ata_device *adev)
+{
+ adev->max_sectors = 255;
+}
+
+static struct scsi_host_template ali_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ /* Keep LBA28 counts so large I/O's don't turn LBA48 and PIO
+ with older controllers. Not locked so will grow on C5 or later */
+ .max_sectors = 255,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .bios_param = ata_std_bios_param,
+};
+
+/*
+ * Port operations for PIO only ALi
+ */
+
+static struct ata_port_operations ali_early_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = ali_set_piomode,
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = ali_early_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+/*
+ * Port operations for DMA capable ALi without cable
+ * detect
+ */
+static struct ata_port_operations ali_20_port_ops = {
+ .port_disable = ata_port_disable,
+
+ .set_piomode = ali_set_piomode,
+ .set_dmamode = ali_set_dmamode,
+ .mode_filter = ali_20_filter,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+ .dev_config = ali_lock_sectors,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = ali_early_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+/*
+ * Port operations for DMA capable ALi with cable detect
+ */
+static struct ata_port_operations ali_c2_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = ali_set_piomode,
+ .set_dmamode = ali_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+ .dev_config = ali_lock_sectors,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = ali_c2_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+/*
+ * Port operations for DMA capable ALi with cable detect and LBA48
+ */
+static struct ata_port_operations ali_c5_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = ali_set_piomode,
+ .set_dmamode = ali_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = ali_c2_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+/**
+ * ali_init_one - discovery callback
+ * @pdev: PCI device ID
+ * @id: PCI table info
+ *
+ * An ALi IDE interface has been discovered. Figure out what revision
+ * and perform configuration work before handing it to the ATA layer
+ */
+
+static int ali_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ static struct ata_port_info info_early = {
+ .sht = &ali_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .port_ops = &ali_early_port_ops
+ };
+ /* Revision 0x20 added DMA */
+ static struct ata_port_info info_20 = {
+ .sht = &ali_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST | ATA_FLAG_PIO_LBA48,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .port_ops = &ali_20_port_ops
+ };
+ /* Revision 0x20 with support logic added UDMA */
+ static struct ata_port_info info_20_udma = {
+ .sht = &ali_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST | ATA_FLAG_PIO_LBA48,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x07, /* UDMA33 */
+ .port_ops = &ali_20_port_ops
+ };
+ /* Revision 0xC2 adds UDMA66 */
+ static struct ata_port_info info_c2 = {
+ .sht = &ali_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST | ATA_FLAG_PIO_LBA48,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x1f,
+ .port_ops = &ali_c2_port_ops
+ };
+ /* Revision 0xC3 is UDMA100 */
+ static struct ata_port_info info_c3 = {
+ .sht = &ali_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST | ATA_FLAG_PIO_LBA48,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x3f,
+ .port_ops = &ali_c2_port_ops
+ };
+ /* Revision 0xC4 is UDMA133 */
+ static struct ata_port_info info_c4 = {
+ .sht = &ali_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST | ATA_FLAG_PIO_LBA48,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x7f,
+ .port_ops = &ali_c2_port_ops
+ };
+ /* Revision 0xC5 is UDMA133 with LBA48 DMA */
+ static struct ata_port_info info_c5 = {
+ .sht = &ali_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x7f,
+ .port_ops = &ali_c5_port_ops
+ };
+
+ static struct ata_port_info *port_info[2];
+ u8 rev, tmp;
+ struct pci_dev *north, *isa_bridge;
+
+ pci_read_config_byte(pdev, PCI_REVISION_ID, &rev);
+
+ /*
+ * The chipset revision selects the driver operations and
+ * mode data.
+ */
+
+ if (rev < 0x20) {
+ port_info[0] = port_info[1] = &info_early;
+ } else if (rev < 0xC2) {
+ /* 1543-E/F, 1543C-C, 1543C-D, 1543C-E */
+ pci_read_config_byte(pdev, 0x4B, &tmp);
+ /* Clear CD-ROM DMA write bit */
+ tmp &= 0x7F;
+ pci_write_config_byte(pdev, 0x4B, tmp);
+ port_info[0] = port_info[1] = &info_20;
+ } else if (rev == 0xC2) {
+ port_info[0] = port_info[1] = &info_c2;
+ } else if (rev == 0xC3) {
+ port_info[0] = port_info[1] = &info_c3;
+ } else if (rev == 0xC4) {
+ port_info[0] = port_info[1] = &info_c4;
+ } else
+ port_info[0] = port_info[1] = &info_c5;
+
+ if (rev >= 0xC2) {
+ /* Enable cable detection logic */
+ pci_read_config_byte(pdev, 0x4B, &tmp);
+ pci_write_config_byte(pdev, 0x4B, tmp | 0x08);
+ }
+
+ north = pci_get_slot(pdev->bus, PCI_DEVFN(0,0));
+ isa_bridge = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL);
+
+ if (north && north->vendor == PCI_VENDOR_ID_AL) {
+ /* Configure the ALi bridge logic. For non ALi rely on BIOS.
+ Set the south bridge enable bit */
+ pci_read_config_byte(isa_bridge, 0x79, &tmp);
+ if (rev == 0xC2)
+ pci_write_config_byte(isa_bridge, 0x79, tmp | 0x04);
+ else if (rev > 0xC2)
+ pci_write_config_byte(isa_bridge, 0x79, tmp | 0x02);
+ }
+
+ if (rev >= 0x20) {
+ if (rev < 0xC2) {
+ /* Are we paired with a UDMA capable chip */
+ pci_read_config_byte(isa_bridge, 0x5E, &tmp);
+ if ((tmp & 0x1E) == 0x12)
+ port_info[0] = port_info[1] = &info_20_udma;
+ }
+ /*
+ * CD_ROM DMA on (0x53 bit 0). Enable this even if we want
+ * to use PIO. 0x53 bit 1 (rev 20 only) - enable FIFO control
+ * via 0x54/55.
+ */
+ pci_read_config_byte(pdev, 0x53, &tmp);
+ if (rev <= 0x20)
+ tmp &= ~0x02;
+ if (rev == 0xc7)
+ tmp |= 0x03;
+ else
+ tmp |= 0x01; /* CD_ROM enable for DMA */
+ pci_write_config_byte(pdev, 0x53, tmp);
+ }
+
+ pci_dev_put(isa_bridge);
+ pci_dev_put(north);
+
+ ata_pci_clear_simplex(pdev);
+ return ata_pci_init_one(pdev, port_info, 2);
+}
+
+static struct pci_device_id ali[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M5228), },
+ { PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M5229), },
+ { 0, },
+};
+
+static struct pci_driver ali_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = ali,
+ .probe = ali_init_one,
+ .remove = ata_pci_remove_one
+};
+
+static int __init ali_init(void)
+{
+ return pci_register_driver(&ali_pci_driver);
+}
+
+
+static void __exit ali_exit(void)
+{
+ pci_unregister_driver(&ali_pci_driver);
+}
+
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("low-level driver for ALi PATA");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, ali);
+MODULE_VERSION(DRV_VERSION);
+
+module_init(ali_init);
+module_exit(ali_exit);
diff --git a/drivers/ata/pata_amd.c b/drivers/ata/pata_amd.c
new file mode 100644
index 00000000000..599ee266722
--- /dev/null
+++ b/drivers/ata/pata_amd.c
@@ -0,0 +1,709 @@
+/*
+ * pata_amd.c - AMD PATA for new ATA layer
+ * (C) 2005-2006 Red Hat Inc
+ * Alan Cox <alan@redhat.com>
+ *
+ * Based on pata-sil680. Errata information is taken from data sheets
+ * and the amd74xx.c driver by Vojtech Pavlik. Nvidia SATA devices are
+ * claimed by sata-nv.c.
+ *
+ * TODO:
+ * Variable system clock when/if it makes sense
+ * Power management on ports
+ *
+ *
+ * Documentation publically available.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+
+#define DRV_NAME "pata_amd"
+#define DRV_VERSION "0.2.4"
+
+/**
+ * timing_setup - shared timing computation and load
+ * @ap: ATA port being set up
+ * @adev: drive being configured
+ * @offset: port offset
+ * @speed: target speed
+ * @clock: clock multiplier (number of times 33MHz for this part)
+ *
+ * Perform the actual timing set up for Nvidia or AMD PATA devices.
+ * The actual devices vary so they all call into this helper function
+ * providing the clock multipler and offset (because AMD and Nvidia put
+ * the ports at different locations).
+ */
+
+static void timing_setup(struct ata_port *ap, struct ata_device *adev, int offset, int speed, int clock)
+{
+ static const unsigned char amd_cyc2udma[] = {
+ 6, 6, 5, 4, 0, 1, 1, 2, 2, 3, 3, 3, 3, 3, 3, 7
+ };
+
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ struct ata_device *peer = ata_dev_pair(adev);
+ int dn = ap->port_no * 2 + adev->devno;
+ struct ata_timing at, apeer;
+ int T, UT;
+ const int amd_clock = 33333; /* KHz. */
+ u8 t;
+
+ T = 1000000000 / amd_clock;
+ UT = T / min_t(int, max_t(int, clock, 1), 2);
+
+ if (ata_timing_compute(adev, speed, &at, T, UT) < 0) {
+ dev_printk(KERN_ERR, &pdev->dev, "unknown mode %d.\n", speed);
+ return;
+ }
+
+ if (peer) {
+ /* This may be over conservative */
+ if (peer->dma_mode) {
+ ata_timing_compute(peer, peer->dma_mode, &apeer, T, UT);
+ ata_timing_merge(&apeer, &at, &at, ATA_TIMING_8BIT);
+ }
+ ata_timing_compute(peer, peer->pio_mode, &apeer, T, UT);
+ ata_timing_merge(&apeer, &at, &at, ATA_TIMING_8BIT);
+ }
+
+ if (speed == XFER_UDMA_5 && amd_clock <= 33333) at.udma = 1;
+ if (speed == XFER_UDMA_6 && amd_clock <= 33333) at.udma = 15;
+
+ /*
+ * Now do the setup work
+ */
+
+ /* Configure the address set up timing */
+ pci_read_config_byte(pdev, offset + 0x0C, &t);
+ t = (t & ~(3 << ((3 - dn) << 1))) | ((FIT(at.setup, 1, 4) - 1) << ((3 - dn) << 1));
+ pci_write_config_byte(pdev, offset + 0x0C , t);
+
+ /* Configure the 8bit I/O timing */
+ pci_write_config_byte(pdev, offset + 0x0E + (1 - (dn >> 1)),
+ ((FIT(at.act8b, 1, 16) - 1) << 4) | (FIT(at.rec8b, 1, 16) - 1));
+
+ /* Drive timing */
+ pci_write_config_byte(pdev, offset + 0x08 + (3 - dn),
+ ((FIT(at.active, 1, 16) - 1) << 4) | (FIT(at.recover, 1, 16) - 1));
+
+ switch (clock) {
+ case 1:
+ t = at.udma ? (0xc0 | (FIT(at.udma, 2, 5) - 2)) : 0x03;
+ break;
+
+ case 2:
+ t = at.udma ? (0xc0 | amd_cyc2udma[FIT(at.udma, 2, 10)]) : 0x03;
+ break;
+
+ case 3:
+ t = at.udma ? (0xc0 | amd_cyc2udma[FIT(at.udma, 1, 10)]) : 0x03;
+ break;
+
+ case 4:
+ t = at.udma ? (0xc0 | amd_cyc2udma[FIT(at.udma, 1, 15)]) : 0x03;
+ break;
+
+ default:
+ return;
+ }
+
+ /* UDMA timing */
+ pci_write_config_byte(pdev, offset + 0x10 + (3 - dn), t);
+}
+
+/**
+ * amd_probe_init - cable detection
+ * @ap: ATA port
+ *
+ * Perform cable detection. The BIOS stores this in PCI config
+ * space for us.
+ */
+
+static int amd_pre_reset(struct ata_port *ap)
+{
+ static const u32 bitmask[2] = {0x03, 0xC0};
+ static const struct pci_bits amd_enable_bits[] = {
+ { 0x40, 1, 0x02, 0x02 },
+ { 0x40, 1, 0x01, 0x01 }
+ };
+
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u8 ata66;
+
+ if (!pci_test_config_bits(pdev, &amd_enable_bits[ap->port_no]))
+ return -ENOENT;
+
+ pci_read_config_byte(pdev, 0x42, &ata66);
+ if (ata66 & bitmask[ap->port_no])
+ ap->cbl = ATA_CBL_PATA80;
+ else
+ ap->cbl = ATA_CBL_PATA40;
+ return ata_std_prereset(ap);
+
+}
+
+static void amd_error_handler(struct ata_port *ap)
+{
+ return ata_bmdma_drive_eh(ap, amd_pre_reset,
+ ata_std_softreset, NULL,
+ ata_std_postreset);
+}
+
+static int amd_early_pre_reset(struct ata_port *ap)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ static struct pci_bits amd_enable_bits[] = {
+ { 0x40, 1, 0x02, 0x02 },
+ { 0x40, 1, 0x01, 0x01 }
+ };
+
+ if (!pci_test_config_bits(pdev, &amd_enable_bits[ap->port_no]))
+ return -ENOENT;
+
+ /* No host side cable detection */
+ ap->cbl = ATA_CBL_PATA80;
+ return ata_std_prereset(ap);
+
+}
+
+static void amd_early_error_handler(struct ata_port *ap)
+{
+ ata_bmdma_drive_eh(ap, amd_early_pre_reset,
+ ata_std_softreset, NULL,
+ ata_std_postreset);
+}
+
+/**
+ * amd33_set_piomode - set initial PIO mode data
+ * @ap: ATA interface
+ * @adev: ATA device
+ *
+ * Program the AMD registers for PIO mode.
+ */
+
+static void amd33_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ timing_setup(ap, adev, 0x40, adev->pio_mode, 1);
+}
+
+static void amd66_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ timing_setup(ap, adev, 0x40, adev->pio_mode, 2);
+}
+
+static void amd100_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ timing_setup(ap, adev, 0x40, adev->pio_mode, 3);
+}
+
+static void amd133_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ timing_setup(ap, adev, 0x40, adev->pio_mode, 4);
+}
+
+/**
+ * amd33_set_dmamode - set initial DMA mode data
+ * @ap: ATA interface
+ * @adev: ATA device
+ *
+ * Program the MWDMA/UDMA modes for the AMD and Nvidia
+ * chipset.
+ */
+
+static void amd33_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+ timing_setup(ap, adev, 0x40, adev->dma_mode, 1);
+}
+
+static void amd66_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+ timing_setup(ap, adev, 0x40, adev->dma_mode, 2);
+}
+
+static void amd100_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+ timing_setup(ap, adev, 0x40, adev->dma_mode, 3);
+}
+
+static void amd133_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+ timing_setup(ap, adev, 0x40, adev->dma_mode, 4);
+}
+
+
+/**
+ * nv_probe_init - cable detection
+ * @ap: ATA port
+ *
+ * Perform cable detection. The BIOS stores this in PCI config
+ * space for us.
+ */
+
+static int nv_pre_reset(struct ata_port *ap) {
+ static const u8 bitmask[2] = {0x03, 0xC0};
+ static const struct pci_bits nv_enable_bits[] = {
+ { 0x50, 1, 0x02, 0x02 },
+ { 0x50, 1, 0x01, 0x01 }
+ };
+
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u8 ata66;
+ u16 udma;
+
+ if (!pci_test_config_bits(pdev, &nv_enable_bits[ap->port_no]))
+ return -ENOENT;
+
+ pci_read_config_byte(pdev, 0x52, &ata66);
+ if (ata66 & bitmask[ap->port_no])
+ ap->cbl = ATA_CBL_PATA80;
+ else
+ ap->cbl = ATA_CBL_PATA40;
+
+ /* We now have to double check because the Nvidia boxes BIOS
+ doesn't always set the cable bits but does set mode bits */
+
+ pci_read_config_word(pdev, 0x62 - 2 * ap->port_no, &udma);
+ if ((udma & 0xC4) == 0xC4 || (udma & 0xC400) == 0xC400)
+ ap->cbl = ATA_CBL_PATA80;
+ return ata_std_prereset(ap);
+}
+
+static void nv_error_handler(struct ata_port *ap)
+{
+ ata_bmdma_drive_eh(ap, nv_pre_reset,
+ ata_std_softreset, NULL,
+ ata_std_postreset);
+}
+/**
+ * nv100_set_piomode - set initial PIO mode data
+ * @ap: ATA interface
+ * @adev: ATA device
+ *
+ * Program the AMD registers for PIO mode.
+ */
+
+static void nv100_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ timing_setup(ap, adev, 0x50, adev->pio_mode, 3);
+}
+
+static void nv133_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ timing_setup(ap, adev, 0x50, adev->pio_mode, 4);
+}
+
+/**
+ * nv100_set_dmamode - set initial DMA mode data
+ * @ap: ATA interface
+ * @adev: ATA device
+ *
+ * Program the MWDMA/UDMA modes for the AMD and Nvidia
+ * chipset.
+ */
+
+static void nv100_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+ timing_setup(ap, adev, 0x50, adev->dma_mode, 3);
+}
+
+static void nv133_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+ timing_setup(ap, adev, 0x50, adev->dma_mode, 4);
+}
+
+static struct scsi_host_template amd_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .max_sectors = ATA_MAX_SECTORS,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .bios_param = ata_std_bios_param,
+};
+
+static struct ata_port_operations amd33_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = amd33_set_piomode,
+ .set_dmamode = amd33_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = amd_early_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+static struct ata_port_operations amd66_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = amd66_set_piomode,
+ .set_dmamode = amd66_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = amd_early_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+static struct ata_port_operations amd100_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = amd100_set_piomode,
+ .set_dmamode = amd100_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = amd_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+static struct ata_port_operations amd133_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = amd133_set_piomode,
+ .set_dmamode = amd133_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = amd_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+static struct ata_port_operations nv100_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = nv100_set_piomode,
+ .set_dmamode = nv100_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = nv_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+static struct ata_port_operations nv133_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = nv133_set_piomode,
+ .set_dmamode = nv133_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = nv_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ static struct ata_port_info info[10] = {
+ { /* 0: AMD 7401 */
+ .sht = &amd_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07, /* No SWDMA */
+ .udma_mask = 0x07, /* UDMA 33 */
+ .port_ops = &amd33_port_ops
+ },
+ { /* 1: Early AMD7409 - no swdma */
+ .sht = &amd_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x1f, /* UDMA 66 */
+ .port_ops = &amd66_port_ops
+ },
+ { /* 2: AMD 7409, no swdma errata */
+ .sht = &amd_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x1f, /* UDMA 66 */
+ .port_ops = &amd66_port_ops
+ },
+ { /* 3: AMD 7411 */
+ .sht = &amd_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x3f, /* UDMA 100 */
+ .port_ops = &amd100_port_ops
+ },
+ { /* 4: AMD 7441 */
+ .sht = &amd_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x3f, /* UDMA 100 */
+ .port_ops = &amd100_port_ops
+ },
+ { /* 5: AMD 8111*/
+ .sht = &amd_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x7f, /* UDMA 133, no swdma */
+ .port_ops = &amd133_port_ops
+ },
+ { /* 6: AMD 8111 UDMA 100 (Serenade) */
+ .sht = &amd_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x3f, /* UDMA 100, no swdma */
+ .port_ops = &amd133_port_ops
+ },
+ { /* 7: Nvidia Nforce */
+ .sht = &amd_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x3f, /* UDMA 100 */
+ .port_ops = &nv100_port_ops
+ },
+ { /* 8: Nvidia Nforce2 and later */
+ .sht = &amd_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x7f, /* UDMA 133, no swdma */
+ .port_ops = &nv133_port_ops
+ },
+ { /* 9: AMD CS5536 (Geode companion) */
+ .sht = &amd_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x3f, /* UDMA 100 */
+ .port_ops = &amd100_port_ops
+ }
+ };
+ static struct ata_port_info *port_info[2];
+ static int printed_version;
+ int type = id->driver_data;
+ u8 rev;
+ u8 fifo;
+
+ if (!printed_version++)
+ dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
+
+ pci_read_config_byte(pdev, PCI_REVISION_ID, &rev);
+ pci_read_config_byte(pdev, 0x41, &fifo);
+
+ /* Check for AMD7409 without swdma errata and if found adjust type */
+ if (type == 1 && rev > 0x7)
+ type = 2;
+
+ /* Check for AMD7411 */
+ if (type == 3)
+ /* FIFO is broken */
+ pci_write_config_byte(pdev, 0x41, fifo & 0x0F);
+ else
+ pci_write_config_byte(pdev, 0x41, fifo | 0xF0);
+
+ /* Serenade ? */
+ if (type == 5 && pdev->subsystem_vendor == PCI_VENDOR_ID_AMD &&
+ pdev->subsystem_device == PCI_DEVICE_ID_AMD_SERENADE)
+ type = 6; /* UDMA 100 only */
+
+ if (type < 3)
+ ata_pci_clear_simplex(pdev);
+
+ /* And fire it up */
+
+ port_info[0] = port_info[1] = &info[type];
+ return ata_pci_init_one(pdev, port_info, 2);
+}
+
+static const struct pci_device_id amd[] = {
+ { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_COBRA_7401, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7409, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 },
+ { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7411, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3 },
+ { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_OPUS_7441, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 },
+ { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5 },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 7 },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 },
+ { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 9 },
+ { 0, },
+};
+
+static struct pci_driver amd_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = amd,
+ .probe = amd_init_one,
+ .remove = ata_pci_remove_one
+};
+
+static int __init amd_init(void)
+{
+ return pci_register_driver(&amd_pci_driver);
+}
+
+static void __exit amd_exit(void)
+{
+ pci_unregister_driver(&amd_pci_driver);
+}
+
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("low-level driver for AMD PATA IDE");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, amd);
+MODULE_VERSION(DRV_VERSION);
+
+module_init(amd_init);
+module_exit(amd_exit);
diff --git a/drivers/ata/pata_artop.c b/drivers/ata/pata_artop.c
new file mode 100644
index 00000000000..c4ccb75a4f1
--- /dev/null
+++ b/drivers/ata/pata_artop.c
@@ -0,0 +1,512 @@
+/*
+ * pata_artop.c - ARTOP ATA controller driver
+ *
+ * (C) 2006 Red Hat <alan@redhat.com>
+ *
+ * Based in part on drivers/ide/pci/aec62xx.c
+ * Copyright (C) 1999-2002 Andre Hedrick <andre@linux-ide.org>
+ * 865/865R fixes for Macintosh card version from a patch to the old
+ * driver by Thibaut VARENE <varenet@parisc-linux.org>
+ * When setting the PCI latency we must set 0x80 or higher for burst
+ * performance Alessandro Zummo <alessandro.zummo@towertech.it>
+ *
+ * TODO
+ * 850 serialization once the core supports it
+ * Investigate no_dsc on 850R
+ * Clock detect
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+#include <linux/ata.h>
+
+#define DRV_NAME "pata_artop"
+#define DRV_VERSION "0.4.2"
+
+/*
+ * The ARTOP has 33 Mhz and "over clocked" timing tables. Until we
+ * get PCI bus speed functionality we leave this as 0. Its a variable
+ * for when we get the functionality and also for folks wanting to
+ * test stuff.
+ */
+
+static int clock = 0;
+
+static int artop6210_pre_reset(struct ata_port *ap)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ const struct pci_bits artop_enable_bits[] = {
+ { 0x4AU, 1U, 0x02UL, 0x02UL }, /* port 0 */
+ { 0x4AU, 1U, 0x04UL, 0x04UL }, /* port 1 */
+ };
+
+ if (!pci_test_config_bits(pdev, &artop_enable_bits[ap->port_no]))
+ return -ENOENT;
+
+ ap->cbl = ATA_CBL_PATA40;
+ return ata_std_prereset(ap);
+}
+
+/**
+ * artop6210_error_handler - Probe specified port on PATA host controller
+ * @ap: Port to probe
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void artop6210_error_handler(struct ata_port *ap)
+{
+ ata_bmdma_drive_eh(ap, artop6210_pre_reset,
+ ata_std_softreset, NULL,
+ ata_std_postreset);
+}
+
+/**
+ * artop6260_pre_reset - check for 40/80 pin
+ * @ap: Port
+ *
+ * The ARTOP hardware reports the cable detect bits in register 0x49.
+ * Nothing complicated needed here.
+ */
+
+static int artop6260_pre_reset(struct ata_port *ap)
+{
+ static const struct pci_bits artop_enable_bits[] = {
+ { 0x4AU, 1U, 0x02UL, 0x02UL }, /* port 0 */
+ { 0x4AU, 1U, 0x04UL, 0x04UL }, /* port 1 */
+ };
+
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u8 tmp;
+
+ /* Odd numbered device ids are the units with enable bits (the -R cards) */
+ if (pdev->device % 1 && !pci_test_config_bits(pdev, &artop_enable_bits[ap->port_no]))
+ return -ENOENT;
+
+ pci_read_config_byte(pdev, 0x49, &tmp);
+ if (tmp & (1 >> ap->port_no))
+ ap->cbl = ATA_CBL_PATA40;
+ else
+ ap->cbl = ATA_CBL_PATA80;
+ return ata_std_prereset(ap);
+}
+
+/**
+ * artop6260_error_handler - Probe specified port on PATA host controller
+ * @ap: Port to probe
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void artop6260_error_handler(struct ata_port *ap)
+{
+ ata_bmdma_drive_eh(ap, artop6260_pre_reset,
+ ata_std_softreset, NULL,
+ ata_std_postreset);
+}
+
+/**
+ * artop6210_load_piomode - Load a set of PATA PIO timings
+ * @ap: Port whose timings we are configuring
+ * @adev: Device
+ * @pio: PIO mode
+ *
+ * Set PIO mode for device, in host controller PCI config space. This
+ * is used both to set PIO timings in PIO mode and also to set the
+ * matching PIO clocking for UDMA, as well as the MWDMA timings.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void artop6210_load_piomode(struct ata_port *ap, struct ata_device *adev, unsigned int pio)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ int dn = adev->devno + 2 * ap->port_no;
+ const u16 timing[2][5] = {
+ { 0x0000, 0x000A, 0x0008, 0x0303, 0x0301 },
+ { 0x0700, 0x070A, 0x0708, 0x0403, 0x0401 }
+
+ };
+ /* Load the PIO timing active/recovery bits */
+ pci_write_config_word(pdev, 0x40 + 2 * dn, timing[clock][pio]);
+}
+
+/**
+ * artop6210_set_piomode - Initialize host controller PATA PIO timings
+ * @ap: Port whose timings we are configuring
+ * @adev: Device we are configuring
+ *
+ * Set PIO mode for device, in host controller PCI config space. For
+ * ARTOP we must also clear the UDMA bits if we are not doing UDMA. In
+ * the event UDMA is used the later call to set_dmamode will set the
+ * bits as required.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void artop6210_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ int dn = adev->devno + 2 * ap->port_no;
+ u8 ultra;
+
+ artop6210_load_piomode(ap, adev, adev->pio_mode - XFER_PIO_0);
+
+ /* Clear the UDMA mode bits (set_dmamode will redo this if needed) */
+ pci_read_config_byte(pdev, 0x54, &ultra);
+ ultra &= ~(3 << (2 * dn));
+ pci_write_config_byte(pdev, 0x54, ultra);
+}
+
+/**
+ * artop6260_load_piomode - Initialize host controller PATA PIO timings
+ * @ap: Port whose timings we are configuring
+ * @adev: Device we are configuring
+ * @pio: PIO mode
+ *
+ * Set PIO mode for device, in host controller PCI config space. The
+ * ARTOP6260 and relatives store the timing data differently.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void artop6260_load_piomode (struct ata_port *ap, struct ata_device *adev, unsigned int pio)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ int dn = adev->devno + 2 * ap->port_no;
+ const u8 timing[2][5] = {
+ { 0x00, 0x0A, 0x08, 0x33, 0x31 },
+ { 0x70, 0x7A, 0x78, 0x43, 0x41 }
+
+ };
+ /* Load the PIO timing active/recovery bits */
+ pci_write_config_byte(pdev, 0x40 + dn, timing[clock][pio]);
+}
+
+/**
+ * artop6260_set_piomode - Initialize host controller PATA PIO timings
+ * @ap: Port whose timings we are configuring
+ * @adev: Device we are configuring
+ *
+ * Set PIO mode for device, in host controller PCI config space. For
+ * ARTOP we must also clear the UDMA bits if we are not doing UDMA. In
+ * the event UDMA is used the later call to set_dmamode will set the
+ * bits as required.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void artop6260_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u8 ultra;
+
+ artop6260_load_piomode(ap, adev, adev->pio_mode - XFER_PIO_0);
+
+ /* Clear the UDMA mode bits (set_dmamode will redo this if needed) */
+ pci_read_config_byte(pdev, 0x44 + ap->port_no, &ultra);
+ ultra &= ~(7 << (4 * adev->devno)); /* One nibble per drive */
+ pci_write_config_byte(pdev, 0x44 + ap->port_no, ultra);
+}
+
+/**
+ * artop6210_set_dmamode - Initialize host controller PATA PIO timings
+ * @ap: Port whose timings we are configuring
+ * @adev: um
+ *
+ * Set DMA mode for device, in host controller PCI config space.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void artop6210_set_dmamode (struct ata_port *ap, struct ata_device *adev)
+{
+ unsigned int pio;
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ int dn = adev->devno + 2 * ap->port_no;
+ u8 ultra;
+
+ if (adev->dma_mode == XFER_MW_DMA_0)
+ pio = 1;
+ else
+ pio = 4;
+
+ /* Load the PIO timing active/recovery bits */
+ artop6210_load_piomode(ap, adev, pio);
+
+ pci_read_config_byte(pdev, 0x54, &ultra);
+ ultra &= ~(3 << (2 * dn));
+
+ /* Add ultra DMA bits if in UDMA mode */
+ if (adev->dma_mode >= XFER_UDMA_0) {
+ u8 mode = (adev->dma_mode - XFER_UDMA_0) + 1 - clock;
+ if (mode == 0)
+ mode = 1;
+ ultra |= (mode << (2 * dn));
+ }
+ pci_write_config_byte(pdev, 0x54, ultra);
+}
+
+/**
+ * artop6260_set_dmamode - Initialize host controller PATA PIO timings
+ * @ap: Port whose timings we are configuring
+ * @adev: Device we are configuring
+ *
+ * Set DMA mode for device, in host controller PCI config space. The
+ * ARTOP6260 and relatives store the timing data differently.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void artop6260_set_dmamode (struct ata_port *ap, struct ata_device *adev)
+{
+ unsigned int pio = adev->pio_mode - XFER_PIO_0;
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u8 ultra;
+
+ if (adev->dma_mode == XFER_MW_DMA_0)
+ pio = 1;
+ else
+ pio = 4;
+
+ /* Load the PIO timing active/recovery bits */
+ artop6260_load_piomode(ap, adev, pio);
+
+ /* Add ultra DMA bits if in UDMA mode */
+ pci_read_config_byte(pdev, 0x44 + ap->port_no, &ultra);
+ ultra &= ~(7 << (4 * adev->devno)); /* One nibble per drive */
+ if (adev->dma_mode >= XFER_UDMA_0) {
+ u8 mode = adev->dma_mode - XFER_UDMA_0 + 1 - clock;
+ if (mode == 0)
+ mode = 1;
+ ultra |= (mode << (4 * adev->devno));
+ }
+ pci_write_config_byte(pdev, 0x44 + ap->port_no, ultra);
+}
+
+static struct scsi_host_template artop_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .max_sectors = ATA_MAX_SECTORS,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .bios_param = ata_std_bios_param,
+};
+
+static const struct ata_port_operations artop6210_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = artop6210_set_piomode,
+ .set_dmamode = artop6210_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = artop6210_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop,
+};
+
+static const struct ata_port_operations artop6260_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = artop6260_set_piomode,
+ .set_dmamode = artop6260_set_dmamode,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = artop6260_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop,
+};
+
+
+/**
+ * artop_init_one - Register ARTOP ATA PCI device with kernel services
+ * @pdev: PCI device to register
+ * @ent: Entry in artop_pci_tbl matching with @pdev
+ *
+ * Called from kernel PCI layer.
+ *
+ * LOCKING:
+ * Inherited from PCI layer (may sleep).
+ *
+ * RETURNS:
+ * Zero on success, or -ERRNO value.
+ */
+
+static int artop_init_one (struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ static int printed_version;
+ static struct ata_port_info info_6210 = {
+ .sht = &artop_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .mwdma_mask = 0x07, /* mwdma0-2 */
+ .udma_mask = ATA_UDMA2,
+ .port_ops = &artop6210_ops,
+ };
+ static struct ata_port_info info_626x = {
+ .sht = &artop_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .mwdma_mask = 0x07, /* mwdma0-2 */
+ .udma_mask = ATA_UDMA4,
+ .port_ops = &artop6260_ops,
+ };
+ static struct ata_port_info info_626x_fast = {
+ .sht = &artop_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .mwdma_mask = 0x07, /* mwdma0-2 */
+ .udma_mask = ATA_UDMA5,
+ .port_ops = &artop6260_ops,
+ };
+ struct ata_port_info *port_info[2];
+ struct ata_port_info *info;
+ int ports = 2;
+
+ if (!printed_version++)
+ dev_printk(KERN_DEBUG, &pdev->dev,
+ "version " DRV_VERSION "\n");
+
+ if (id->driver_data == 0) { /* 6210 variant */
+ info = &info_6210;
+ /* BIOS may have left us in UDMA, clear it before libata probe */
+ pci_write_config_byte(pdev, 0x54, 0);
+ /* For the moment (also lacks dsc) */
+ printk(KERN_WARNING "ARTOP 6210 requires serialize functionality not yet supported by libata.\n");
+ printk(KERN_WARNING "Secondary ATA ports will not be activated.\n");
+ ports = 1;
+ }
+ else if (id->driver_data == 1) /* 6260 */
+ info = &info_626x;
+ else if (id->driver_data == 2) { /* 6260 or 6260 + fast */
+ unsigned long io = pci_resource_start(pdev, 4);
+ u8 reg;
+
+ info = &info_626x;
+ if (inb(io) & 0x10)
+ info = &info_626x_fast;
+ /* Mac systems come up with some registers not set as we
+ will need them */
+
+ /* Clear reset & test bits */
+ pci_read_config_byte(pdev, 0x49, &reg);
+ pci_write_config_byte(pdev, 0x49, reg & ~ 0x30);
+
+ /* PCI latency must be > 0x80 for burst mode, tweak it
+ * if required.
+ */
+ pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &reg);
+ if (reg <= 0x80)
+ pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x90);
+
+ /* Enable IRQ output and burst mode */
+ pci_read_config_byte(pdev, 0x4a, &reg);
+ pci_write_config_byte(pdev, 0x4a, (reg & ~0x01) | 0x80);
+
+ }
+ port_info[0] = port_info[1] = info;
+ return ata_pci_init_one(pdev, port_info, ports);
+}
+
+static const struct pci_device_id artop_pci_tbl[] = {
+ { 0x1191, 0x0005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { 0x1191, 0x0006, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+ { 0x1191, 0x0007, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+ { 0x1191, 0x0008, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
+ { 0x1191, 0x0009, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
+ { } /* terminate list */
+};
+
+static struct pci_driver artop_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = artop_pci_tbl,
+ .probe = artop_init_one,
+ .remove = ata_pci_remove_one,
+};
+
+static int __init artop_init(void)
+{
+ return pci_register_driver(&artop_pci_driver);
+}
+
+static void __exit artop_exit(void)
+{
+ pci_unregister_driver(&artop_pci_driver);
+}
+
+
+module_init(artop_init);
+module_exit(artop_exit);
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("SCSI low-level driver for ARTOP PATA");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, artop_pci_tbl);
+MODULE_VERSION(DRV_VERSION);
+
diff --git a/drivers/ata/pata_atiixp.c b/drivers/ata/pata_atiixp.c
new file mode 100644
index 00000000000..6c2269b6bd3
--- /dev/null
+++ b/drivers/ata/pata_atiixp.c
@@ -0,0 +1,304 @@
+/*
+ * pata_atiixp.c - ATI PATA for new ATA layer
+ * (C) 2005 Red Hat Inc
+ * Alan Cox <alan@redhat.com>
+ *
+ * Based on
+ *
+ * linux/drivers/ide/pci/atiixp.c Version 0.01-bart2 Feb. 26, 2004
+ *
+ * Copyright (C) 2003 ATI Inc. <hyu@ati.com>
+ * Copyright (C) 2004 Bartlomiej Zolnierkiewicz
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+
+#define DRV_NAME "pata_atiixp"
+#define DRV_VERSION "0.4.3"
+
+enum {
+ ATIIXP_IDE_PIO_TIMING = 0x40,
+ ATIIXP_IDE_MWDMA_TIMING = 0x44,
+ ATIIXP_IDE_PIO_CONTROL = 0x48,
+ ATIIXP_IDE_PIO_MODE = 0x4a,
+ ATIIXP_IDE_UDMA_CONTROL = 0x54,
+ ATIIXP_IDE_UDMA_MODE = 0x56
+};
+
+static int atiixp_pre_reset(struct ata_port *ap)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ static struct pci_bits atiixp_enable_bits[] = {
+ { 0x48, 1, 0x01, 0x00 },
+ { 0x48, 1, 0x08, 0x00 }
+ };
+
+ if (!pci_test_config_bits(pdev, &atiixp_enable_bits[ap->port_no]))
+ return -ENOENT;
+
+ ap->cbl = ATA_CBL_PATA80;
+ return ata_std_prereset(ap);
+}
+
+static void atiixp_error_handler(struct ata_port *ap)
+{
+ ata_bmdma_drive_eh(ap, atiixp_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
+}
+
+/**
+ * atiixp_set_pio_timing - set initial PIO mode data
+ * @ap: ATA interface
+ * @adev: ATA device
+ *
+ * Called by both the pio and dma setup functions to set the controller
+ * timings for PIO transfers. We must load both the mode number and
+ * timing values into the controller.
+ */
+
+static void atiixp_set_pio_timing(struct ata_port *ap, struct ata_device *adev, int pio)
+{
+ static u8 pio_timings[5] = { 0x5D, 0x47, 0x34, 0x22, 0x20 };
+
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ int dn = 2 * ap->port_no + adev->devno;
+
+ /* Check this is correct - the order is odd in both drivers */
+ int timing_shift = (16 * ap->port_no) + 8 * (adev->devno ^ 1);
+ u16 pio_mode_data, pio_timing_data;
+
+ pci_read_config_word(pdev, ATIIXP_IDE_PIO_MODE, &pio_mode_data);
+ pio_mode_data &= ~(0x7 << (4 * dn));
+ pio_mode_data |= pio << (4 * dn);
+ pci_write_config_word(pdev, ATIIXP_IDE_PIO_MODE, pio_mode_data);
+
+ pci_read_config_word(pdev, ATIIXP_IDE_PIO_TIMING, &pio_timing_data);
+ pio_mode_data &= ~(0xFF << timing_shift);
+ pio_mode_data |= (pio_timings[pio] << timing_shift);
+ pci_write_config_word(pdev, ATIIXP_IDE_PIO_TIMING, pio_timing_data);
+}
+
+/**
+ * atiixp_set_piomode - set initial PIO mode data
+ * @ap: ATA interface
+ * @adev: ATA device
+ *
+ * Called to do the PIO mode setup. We use a shared helper for this
+ * as the DMA setup must also adjust the PIO timing information.
+ */
+
+static void atiixp_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ atiixp_set_pio_timing(ap, adev, adev->pio_mode - XFER_PIO_0);
+}
+
+/**
+ * atiixp_set_dmamode - set initial DMA mode data
+ * @ap: ATA interface
+ * @adev: ATA device
+ *
+ * Called to do the DMA mode setup. We use timing tables for most
+ * modes but must tune an appropriate PIO mode to match.
+ */
+
+static void atiixp_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+ static u8 mwdma_timings[5] = { 0x77, 0x21, 0x20 };
+
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ int dma = adev->dma_mode;
+ int dn = 2 * ap->port_no + adev->devno;
+ int wanted_pio;
+
+ if (adev->dma_mode >= XFER_UDMA_0) {
+ u16 udma_mode_data;
+
+ dma -= XFER_UDMA_0;
+
+ pci_read_config_word(pdev, ATIIXP_IDE_UDMA_MODE, &udma_mode_data);
+ udma_mode_data &= ~(0x7 << (4 * dn));
+ udma_mode_data |= dma << (4 * dn);
+ pci_write_config_word(pdev, ATIIXP_IDE_UDMA_MODE, udma_mode_data);
+ } else {
+ u16 mwdma_timing_data;
+ /* Check this is correct - the order is odd in both drivers */
+ int timing_shift = (16 * ap->port_no) + 8 * (adev->devno ^ 1);
+
+ dma -= XFER_MW_DMA_0;
+
+ pci_read_config_word(pdev, ATIIXP_IDE_MWDMA_TIMING, &mwdma_timing_data);
+ mwdma_timing_data &= ~(0xFF << timing_shift);
+ mwdma_timing_data |= (mwdma_timings[dma] << timing_shift);
+ pci_write_config_word(pdev, ATIIXP_IDE_MWDMA_TIMING, mwdma_timing_data);
+ }
+ /*
+ * We must now look at the PIO mode situation. We may need to
+ * adjust the PIO mode to keep the timings acceptable
+ */
+ if (adev->dma_mode >= XFER_MW_DMA_2)
+ wanted_pio = 4;
+ else if (adev->dma_mode == XFER_MW_DMA_1)
+ wanted_pio = 3;
+ else if (adev->dma_mode == XFER_MW_DMA_0)
+ wanted_pio = 0;
+ else BUG();
+
+ if (adev->pio_mode != wanted_pio)
+ atiixp_set_pio_timing(ap, adev, wanted_pio);
+}
+
+/**
+ * atiixp_bmdma_start - DMA start callback
+ * @qc: Command in progress
+ *
+ * When DMA begins we need to ensure that the UDMA control
+ * register for the channel is correctly set.
+ */
+
+static void atiixp_bmdma_start(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct ata_device *adev = qc->dev;
+
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ int dn = (2 * ap->port_no) + adev->devno;
+ u16 tmp16;
+
+ pci_read_config_word(pdev, ATIIXP_IDE_UDMA_CONTROL, &tmp16);
+ if (adev->dma_mode >= XFER_UDMA_0)
+ tmp16 |= (1 << dn);
+ else
+ tmp16 &= ~(1 << dn);
+ pci_write_config_word(pdev, ATIIXP_IDE_UDMA_CONTROL, tmp16);
+ ata_bmdma_start(qc);
+}
+
+/**
+ * atiixp_dma_stop - DMA stop callback
+ * @qc: Command in progress
+ *
+ * DMA has completed. Clear the UDMA flag as the next operations will
+ * be PIO ones not UDMA data transfer.
+ */
+
+static void atiixp_bmdma_stop(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ int dn = (2 * ap->port_no) + qc->dev->devno;
+ u16 tmp16;
+
+ pci_read_config_word(pdev, ATIIXP_IDE_UDMA_CONTROL, &tmp16);
+ tmp16 &= ~(1 << dn);
+ pci_write_config_word(pdev, ATIIXP_IDE_UDMA_CONTROL, tmp16);
+ ata_bmdma_stop(qc);
+}
+
+static struct scsi_host_template atiixp_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .max_sectors = ATA_MAX_SECTORS,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .bios_param = ata_std_bios_param,
+};
+
+static struct ata_port_operations atiixp_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = atiixp_set_piomode,
+ .set_dmamode = atiixp_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = atiixp_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = atiixp_bmdma_start,
+ .bmdma_stop = atiixp_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+static int atiixp_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ static struct ata_port_info info = {
+ .sht = &atiixp_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x06, /* No MWDMA0 support */
+ .udma_mask = 0x3F,
+ .port_ops = &atiixp_port_ops
+ };
+ static struct ata_port_info *port_info[2] = { &info, &info };
+ return ata_pci_init_one(dev, port_info, 2);
+}
+
+static struct pci_device_id atiixp[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP200_IDE), },
+ { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP300_IDE), },
+ { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP400_IDE), },
+ { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP600_IDE), },
+ { 0, },
+};
+
+static struct pci_driver atiixp_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = atiixp,
+ .probe = atiixp_init_one,
+ .remove = ata_pci_remove_one
+};
+
+static int __init atiixp_init(void)
+{
+ return pci_register_driver(&atiixp_pci_driver);
+}
+
+
+static void __exit atiixp_exit(void)
+{
+ pci_unregister_driver(&atiixp_pci_driver);
+}
+
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("low-level driver for ATI IXP200/300/400");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, atiixp);
+MODULE_VERSION(DRV_VERSION);
+
+module_init(atiixp_init);
+module_exit(atiixp_exit);
diff --git a/drivers/ata/pata_cmd64x.c b/drivers/ata/pata_cmd64x.c
new file mode 100644
index 00000000000..e92b0ef43ec
--- /dev/null
+++ b/drivers/ata/pata_cmd64x.c
@@ -0,0 +1,505 @@
+/*
+ * pata_cmd64x.c - ATI PATA for new ATA layer
+ * (C) 2005 Red Hat Inc
+ * Alan Cox <alan@redhat.com>
+ *
+ * Based upon
+ * linux/drivers/ide/pci/cmd64x.c Version 1.30 Sept 10, 2002
+ *
+ * cmd64x.c: Enable interrupts at initialization time on Ultra/PCI machines.
+ * Note, this driver is not used at all on other systems because
+ * there the "BIOS" has done all of the following already.
+ * Due to massive hardware bugs, UltraDMA is only supported
+ * on the 646U2 and not on the 646U.
+ *
+ * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be)
+ * Copyright (C) 1998 David S. Miller (davem@redhat.com)
+ *
+ * Copyright (C) 1999-2002 Andre Hedrick <andre@linux-ide.org>
+ *
+ * TODO
+ * Testing work
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+
+#define DRV_NAME "pata_cmd64x"
+#define DRV_VERSION "0.2.1"
+
+/*
+ * CMD64x specific registers definition.
+ */
+
+enum {
+ CFR = 0x50,
+ CFR_INTR_CH0 = 0x02,
+ CNTRL = 0x51,
+ CNTRL_DIS_RA0 = 0x40,
+ CNTRL_DIS_RA1 = 0x80,
+ CNTRL_ENA_2ND = 0x08,
+ CMDTIM = 0x52,
+ ARTTIM0 = 0x53,
+ DRWTIM0 = 0x54,
+ ARTTIM1 = 0x55,
+ DRWTIM1 = 0x56,
+ ARTTIM23 = 0x57,
+ ARTTIM23_DIS_RA2 = 0x04,
+ ARTTIM23_DIS_RA3 = 0x08,
+ ARTTIM23_INTR_CH1 = 0x10,
+ ARTTIM2 = 0x57,
+ ARTTIM3 = 0x57,
+ DRWTIM23 = 0x58,
+ DRWTIM2 = 0x58,
+ BRST = 0x59,
+ DRWTIM3 = 0x5b,
+ BMIDECR0 = 0x70,
+ MRDMODE = 0x71,
+ MRDMODE_INTR_CH0 = 0x04,
+ MRDMODE_INTR_CH1 = 0x08,
+ MRDMODE_BLK_CH0 = 0x10,
+ MRDMODE_BLK_CH1 = 0x20,
+ BMIDESR0 = 0x72,
+ UDIDETCR0 = 0x73,
+ DTPR0 = 0x74,
+ BMIDECR1 = 0x78,
+ BMIDECSR = 0x79,
+ BMIDESR1 = 0x7A,
+ UDIDETCR1 = 0x7B,
+ DTPR1 = 0x7C
+};
+
+static int cmd64x_pre_reset(struct ata_port *ap)
+{
+ ap->cbl = ATA_CBL_PATA40;
+ return ata_std_prereset(ap);
+}
+
+static int cmd648_pre_reset(struct ata_port *ap)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u8 r;
+
+ /* Check cable detect bits */
+ pci_read_config_byte(pdev, BMIDECSR, &r);
+ if (r & (1 << ap->port_no))
+ ap->cbl = ATA_CBL_PATA80;
+ else
+ ap->cbl = ATA_CBL_PATA40;
+
+ return ata_std_prereset(ap);
+}
+
+static void cmd64x_error_handler(struct ata_port *ap)
+{
+ return ata_bmdma_drive_eh(ap, cmd64x_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
+}
+
+static void cmd648_error_handler(struct ata_port *ap)
+{
+ ata_bmdma_drive_eh(ap, cmd648_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
+}
+
+/**
+ * cmd64x_set_piomode - set initial PIO mode data
+ * @ap: ATA interface
+ * @adev: ATA device
+ *
+ * Called to do the PIO mode setup.
+ */
+
+static void cmd64x_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ struct ata_timing t;
+ const unsigned long T = 1000000 / 33;
+ const u8 setup_data[] = { 0x40, 0x40, 0x40, 0x80, 0x00 };
+
+ u8 reg;
+
+ /* Port layout is not logical so use a table */
+ const u8 arttim_port[2][2] = {
+ { ARTTIM0, ARTTIM1 },
+ { ARTTIM23, ARTTIM23 }
+ };
+ const u8 drwtim_port[2][2] = {
+ { DRWTIM0, DRWTIM1 },
+ { DRWTIM2, DRWTIM3 }
+ };
+
+ int arttim = arttim_port[ap->port_no][adev->devno];
+ int drwtim = drwtim_port[ap->port_no][adev->devno];
+
+
+ if (ata_timing_compute(adev, adev->pio_mode, &t, T, 0) < 0) {
+ printk(KERN_ERR DRV_NAME ": mode computation failed.\n");
+ return;
+ }
+ if (ap->port_no) {
+ /* Slave has shared address setup */
+ struct ata_device *pair = ata_dev_pair(adev);
+
+ if (pair) {
+ struct ata_timing tp;
+ ata_timing_compute(pair, pair->pio_mode, &tp, T, 0);
+ ata_timing_merge(&t, &tp, &t, ATA_TIMING_SETUP);
+ }
+ }
+
+ printk(KERN_DEBUG DRV_NAME ": active %d recovery %d setup %d.\n",
+ t.active, t.recover, t.setup);
+ if (t.recover > 16) {
+ t.active += t.recover - 16;
+ t.recover = 16;
+ }
+ if (t.active > 16)
+ t.active = 16;
+
+ /* Now convert the clocks into values we can actually stuff into
+ the chip */
+
+ if (t.recover > 1)
+ t.recover--;
+ else
+ t.recover = 15;
+
+ if (t.setup > 4)
+ t.setup = 0xC0;
+ else
+ t.setup = setup_data[t.setup];
+
+ t.active &= 0x0F; /* 0 = 16 */
+
+ /* Load setup timing */
+ pci_read_config_byte(pdev, arttim, &reg);
+ reg &= 0x3F;
+ reg |= t.setup;
+ pci_write_config_byte(pdev, arttim, reg);
+
+ /* Load active/recovery */
+ pci_write_config_byte(pdev, drwtim, (t.active << 4) | t.recover);
+}
+
+/**
+ * cmd64x_set_dmamode - set initial DMA mode data
+ * @ap: ATA interface
+ * @adev: ATA device
+ *
+ * Called to do the DMA mode setup.
+ */
+
+static void cmd64x_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+ static const u8 udma_data[] = {
+ 0x31, 0x21, 0x11, 0x25, 0x15, 0x05
+ };
+ static const u8 mwdma_data[] = {
+ 0x30, 0x20, 0x10
+ };
+
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u8 regU, regD;
+
+ int pciU = UDIDETCR0 + 8 * ap->port_no;
+ int pciD = BMIDESR0 + 8 * ap->port_no;
+ int shift = 2 * adev->devno;
+
+ pci_read_config_byte(pdev, pciD, &regD);
+ pci_read_config_byte(pdev, pciU, &regU);
+
+ regD &= ~(0x20 << shift);
+ regU &= ~(0x35 << shift);
+
+ if (adev->dma_mode >= XFER_UDMA_0)
+ regU |= udma_data[adev->dma_mode - XFER_UDMA_0] << shift;
+ else
+ regD |= mwdma_data[adev->dma_mode - XFER_MW_DMA_0] << shift;
+
+ regD |= 0x20 << adev->devno;
+
+ pci_write_config_byte(pdev, pciU, regU);
+ pci_write_config_byte(pdev, pciD, regD);
+}
+
+/**
+ * cmd648_dma_stop - DMA stop callback
+ * @qc: Command in progress
+ *
+ * DMA has completed.
+ */
+
+static void cmd648_bmdma_stop(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u8 dma_intr;
+ int dma_reg = ap->port_no ? ARTTIM23_INTR_CH1 : CFR_INTR_CH0;
+ int dma_mask = ap->port_no ? ARTTIM2 : CFR;
+
+ ata_bmdma_stop(qc);
+
+ pci_read_config_byte(pdev, dma_reg, &dma_intr);
+ pci_write_config_byte(pdev, dma_reg, dma_intr | dma_mask);
+}
+
+/**
+ * cmd646r1_dma_stop - DMA stop callback
+ * @qc: Command in progress
+ *
+ * Stub for now while investigating the r1 quirk in the old driver.
+ */
+
+static void cmd646r1_bmdma_stop(struct ata_queued_cmd *qc)
+{
+ ata_bmdma_stop(qc);
+}
+
+static struct scsi_host_template cmd64x_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .max_sectors = ATA_MAX_SECTORS,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .bios_param = ata_std_bios_param,
+};
+
+static struct ata_port_operations cmd64x_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = cmd64x_set_piomode,
+ .set_dmamode = cmd64x_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = cmd64x_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+static struct ata_port_operations cmd646r1_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = cmd64x_set_piomode,
+ .set_dmamode = cmd64x_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = cmd64x_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = cmd646r1_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+static struct ata_port_operations cmd648_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = cmd64x_set_piomode,
+ .set_dmamode = cmd64x_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = cmd648_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = cmd648_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+static int cmd64x_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ u32 class_rev;
+
+ static struct ata_port_info cmd_info[6] = {
+ { /* CMD 643 - no UDMA */
+ .sht = &cmd64x_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .port_ops = &cmd64x_port_ops
+ },
+ { /* CMD 646 with broken UDMA */
+ .sht = &cmd64x_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .port_ops = &cmd64x_port_ops
+ },
+ { /* CMD 646 with working UDMA */
+ .sht = &cmd64x_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = ATA_UDMA1,
+ .port_ops = &cmd64x_port_ops
+ },
+ { /* CMD 646 rev 1 */
+ .sht = &cmd64x_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .port_ops = &cmd646r1_port_ops
+ },
+ { /* CMD 648 */
+ .sht = &cmd64x_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = ATA_UDMA2,
+ .port_ops = &cmd648_port_ops
+ },
+ { /* CMD 649 */
+ .sht = &cmd64x_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = ATA_UDMA3,
+ .port_ops = &cmd648_port_ops
+ }
+ };
+ static struct ata_port_info *port_info[2], *info;
+ u8 mrdmode;
+
+ info = &cmd_info[id->driver_data];
+
+ pci_read_config_dword(pdev, PCI_CLASS_REVISION, &class_rev);
+ class_rev &= 0xFF;
+
+ if (id->driver_data == 0) /* 643 */
+ ata_pci_clear_simplex(pdev);
+
+ if (pdev->device == PCI_DEVICE_ID_CMD_646) {
+ /* Does UDMA work ? */
+ if (class_rev > 4)
+ info = &cmd_info[2];
+ /* Early rev with other problems ? */
+ else if (class_rev == 1)
+ info = &cmd_info[3];
+ }
+
+ pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 64);
+ pci_read_config_byte(pdev, MRDMODE, &mrdmode);
+ mrdmode &= ~ 0x30; /* IRQ set up */
+ mrdmode |= 0x02; /* Memory read line enable */
+ pci_write_config_byte(pdev, MRDMODE, mrdmode);
+
+ /* Force PIO 0 here.. */
+
+ /* PPC specific fixup copied from old driver */
+#ifdef CONFIG_PPC
+ pci_write_config_byte(pdev, UDIDETCR0, 0xF0);
+#endif
+
+ port_info[0] = port_info[1] = info;
+ return ata_pci_init_one(pdev, port_info, 2);
+}
+
+static struct pci_device_id cmd64x[] = {
+ { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_643, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_646, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+ { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_648, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4},
+ { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_649, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5},
+ { 0, },
+};
+
+static struct pci_driver cmd64x_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = cmd64x,
+ .probe = cmd64x_init_one,
+ .remove = ata_pci_remove_one
+};
+
+static int __init cmd64x_init(void)
+{
+ return pci_register_driver(&cmd64x_pci_driver);
+}
+
+
+static void __exit cmd64x_exit(void)
+{
+ pci_unregister_driver(&cmd64x_pci_driver);
+}
+
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("low-level driver for CMD64x series PATA controllers");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, cmd64x);
+MODULE_VERSION(DRV_VERSION);
+
+module_init(cmd64x_init);
+module_exit(cmd64x_exit);
diff --git a/drivers/ata/pata_cs5520.c b/drivers/ata/pata_cs5520.c
new file mode 100644
index 00000000000..a6c6cebd0da
--- /dev/null
+++ b/drivers/ata/pata_cs5520.c
@@ -0,0 +1,334 @@
+/*
+ * IDE tuning and bus mastering support for the CS5510/CS5520
+ * chipsets
+ *
+ * The CS5510/CS5520 are slightly unusual devices. Unlike the
+ * typical IDE controllers they do bus mastering with the drive in
+ * PIO mode and smarter silicon.
+ *
+ * The practical upshot of this is that we must always tune the
+ * drive for the right PIO mode. We must also ignore all the blacklists
+ * and the drive bus mastering DMA information. Also to confuse matters
+ * further we can do DMA on PIO only drives.
+ *
+ * DMA on the 5510 also requires we disable_hlt() during DMA on early
+ * revisions.
+ *
+ * *** This driver is strictly experimental ***
+ *
+ * (c) Copyright Red Hat Inc 2002
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * Documentation:
+ * Not publically available.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+
+#define DRV_NAME "pata_cs5520"
+#define DRV_VERSION "0.6.2"
+
+struct pio_clocks
+{
+ int address;
+ int assert;
+ int recovery;
+};
+
+static const struct pio_clocks cs5520_pio_clocks[]={
+ {3, 6, 11},
+ {2, 5, 6},
+ {1, 4, 3},
+ {1, 3, 2},
+ {1, 2, 1}
+};
+
+/**
+ * cs5520_set_timings - program PIO timings
+ * @ap: ATA port
+ * @adev: ATA device
+ *
+ * Program the PIO mode timings for the controller according to the pio
+ * clocking table.
+ */
+
+static void cs5520_set_timings(struct ata_port *ap, struct ata_device *adev, int pio)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ int slave = adev->devno;
+
+ pio -= XFER_PIO_0;
+
+ /* Channel command timing */
+ pci_write_config_byte(pdev, 0x62 + ap->port_no,
+ (cs5520_pio_clocks[pio].recovery << 4) |
+ (cs5520_pio_clocks[pio].assert));
+ /* FIXME: should these use address ? */
+ /* Read command timing */
+ pci_write_config_byte(pdev, 0x64 + 4*ap->port_no + slave,
+ (cs5520_pio_clocks[pio].recovery << 4) |
+ (cs5520_pio_clocks[pio].assert));
+ /* Write command timing */
+ pci_write_config_byte(pdev, 0x66 + 4*ap->port_no + slave,
+ (cs5520_pio_clocks[pio].recovery << 4) |
+ (cs5520_pio_clocks[pio].assert));
+}
+
+/**
+ * cs5520_enable_dma - turn on DMA bits
+ *
+ * Turn on the DMA bits for this disk. Needed because the BIOS probably
+ * has not done the work for us. Belongs in the core SATA code.
+ */
+
+static void cs5520_enable_dma(struct ata_port *ap, struct ata_device *adev)
+{
+ /* Set the DMA enable/disable flag */
+ u8 reg = inb(ap->ioaddr.bmdma_addr + 0x02);
+ reg |= 1<<(adev->devno + 5);
+ outb(reg, ap->ioaddr.bmdma_addr + 0x02);
+}
+
+/**
+ * cs5520_set_dmamode - program DMA timings
+ * @ap: ATA port
+ * @adev: ATA device
+ *
+ * Program the DMA mode timings for the controller according to the pio
+ * clocking table. Note that this device sets the DMA timings to PIO
+ * mode values. This may seem bizarre but the 5520 architecture talks
+ * PIO mode to the disk and DMA mode to the controller so the underlying
+ * transfers are PIO timed.
+ */
+
+static void cs5520_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+ static const int dma_xlate[3] = { XFER_PIO_0, XFER_PIO_3, XFER_PIO_4 };
+ cs5520_set_timings(ap, adev, dma_xlate[adev->dma_mode]);
+ cs5520_enable_dma(ap, adev);
+}
+
+/**
+ * cs5520_set_piomode - program PIO timings
+ * @ap: ATA port
+ * @adev: ATA device
+ *
+ * Program the PIO mode timings for the controller according to the pio
+ * clocking table. We know pio_mode will equal dma_mode because of the
+ * CS5520 architecture. At least once we turned DMA on and wrote a
+ * mode setter.
+ */
+
+static void cs5520_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ cs5520_set_timings(ap, adev, adev->pio_mode);
+}
+
+
+static int cs5520_pre_reset(struct ata_port *ap)
+{
+ ap->cbl = ATA_CBL_PATA40;
+ return ata_std_prereset(ap);
+}
+
+static void cs5520_error_handler(struct ata_port *ap)
+{
+ return ata_bmdma_drive_eh(ap, cs5520_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
+}
+
+static struct scsi_host_template cs5520_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .max_sectors = ATA_MAX_SECTORS,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .bios_param = ata_std_bios_param,
+};
+
+static struct ata_port_operations cs5520_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = cs5520_set_piomode,
+ .set_dmamode = cs5520_set_dmamode,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = cs5520_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop,
+};
+
+static int __devinit cs5520_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ u8 pcicfg;
+ static struct ata_probe_ent probe[2];
+ int ports = 0;
+
+ /* IDE port enable bits */
+ pci_read_config_byte(dev, 0x60, &pcicfg);
+
+ /* Check if the ATA ports are enabled */
+ if ((pcicfg & 3) == 0)
+ return -ENODEV;
+
+ if ((pcicfg & 0x40) == 0) {
+ printk(KERN_WARNING DRV_NAME ": DMA mode disabled. Enabling.\n");
+ pci_write_config_byte(dev, 0x60, pcicfg | 0x40);
+ }
+
+ /* Perform set up for DMA */
+ if (pci_enable_device_bars(dev, 1<<2)) {
+ printk(KERN_ERR DRV_NAME ": unable to configure BAR2.\n");
+ return -ENODEV;
+ }
+ pci_set_master(dev);
+ if (pci_set_dma_mask(dev, DMA_32BIT_MASK)) {
+ printk(KERN_ERR DRV_NAME ": unable to configure DMA mask.\n");
+ return -ENODEV;
+ }
+ if (pci_set_consistent_dma_mask(dev, DMA_32BIT_MASK)) {
+ printk(KERN_ERR DRV_NAME ": unable to configure consistent DMA mask.\n");
+ return -ENODEV;
+ }
+
+ /* We have to do our own plumbing as the PCI setup for this
+ chipset is non-standard so we can't punt to the libata code */
+
+ INIT_LIST_HEAD(&probe[0].node);
+ probe[0].dev = pci_dev_to_dev(dev);
+ probe[0].port_ops = &cs5520_port_ops;
+ probe[0].sht = &cs5520_sht;
+ probe[0].pio_mask = 0x1F;
+ probe[0].mwdma_mask = id->driver_data;
+ probe[0].irq = 14;
+ probe[0].irq_flags = 0;
+ probe[0].port_flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST;
+ probe[0].n_ports = 1;
+ probe[0].port[0].cmd_addr = 0x1F0;
+ probe[0].port[0].ctl_addr = 0x3F6;
+ probe[0].port[0].altstatus_addr = 0x3F6;
+ probe[0].port[0].bmdma_addr = pci_resource_start(dev, 2);
+
+ /* The secondary lurks at different addresses but is otherwise
+ the same beastie */
+
+ probe[1] = probe[0];
+ INIT_LIST_HEAD(&probe[1].node);
+ probe[1].irq = 15;
+ probe[1].port[0].cmd_addr = 0x170;
+ probe[1].port[0].ctl_addr = 0x376;
+ probe[1].port[0].altstatus_addr = 0x376;
+ probe[1].port[0].bmdma_addr = pci_resource_start(dev, 2) + 8;
+
+ /* Let libata fill in the port details */
+ ata_std_ports(&probe[0].port[0]);
+ ata_std_ports(&probe[1].port[0]);
+
+ /* Now add the ports that are active */
+ if (pcicfg & 1)
+ ports += ata_device_add(&probe[0]);
+ if (pcicfg & 2)
+ ports += ata_device_add(&probe[1]);
+ if (ports)
+ return 0;
+ return -ENODEV;
+}
+
+/**
+ * cs5520_remove_one - device unload
+ * @pdev: PCI device being removed
+ *
+ * Handle an unplug/unload event for a PCI device. Unload the
+ * PCI driver but do not use the default handler as we manage
+ * resources ourself and *MUST NOT* disable the device as it has
+ * other functions.
+ */
+
+static void __devexit cs5520_remove_one(struct pci_dev *pdev)
+{
+ struct device *dev = pci_dev_to_dev(pdev);
+ struct ata_host *host = dev_get_drvdata(dev);
+
+ ata_host_remove(host);
+ dev_set_drvdata(dev, NULL);
+}
+
+/* For now keep DMA off. We can set it for all but A rev CS5510 once the
+ core ATA code can handle it */
+
+static struct pci_device_id pata_cs5520[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5510), },
+ { PCI_DEVICE(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5520), },
+ { 0, },
+};
+
+static struct pci_driver cs5520_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = pata_cs5520,
+ .probe = cs5520_init_one,
+ .remove = cs5520_remove_one
+};
+
+
+static int __init cs5520_init(void)
+{
+ return pci_register_driver(&cs5520_pci_driver);
+}
+
+static void __exit cs5520_exit(void)
+{
+ pci_unregister_driver(&cs5520_pci_driver);
+}
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("low-level driver for Cyrix CS5510/5520");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, pata_cs5520);
+MODULE_VERSION(DRV_VERSION);
+
+module_init(cs5520_init);
+module_exit(cs5520_exit);
+
diff --git a/drivers/ata/pata_cs5530.c b/drivers/ata/pata_cs5530.c
new file mode 100644
index 00000000000..7bba4d954e9
--- /dev/null
+++ b/drivers/ata/pata_cs5530.c
@@ -0,0 +1,387 @@
+/*
+ * pata-cs5530.c - CS5530 PATA for new ATA layer
+ * (C) 2005 Red Hat Inc
+ * Alan Cox <alan@redhat.com>
+ *
+ * based upon cs5530.c by Mark Lord.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Loosely based on the piix & svwks drivers.
+ *
+ * Documentation:
+ * Available from AMD web site.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+#include <linux/dmi.h>
+
+#define DRV_NAME "pata_cs5530"
+#define DRV_VERSION "0.6"
+
+/**
+ * cs5530_set_piomode - PIO setup
+ * @ap: ATA interface
+ * @adev: device on the interface
+ *
+ * Set our PIO requirements. This is fairly simple on the CS5530
+ * chips.
+ */
+
+static void cs5530_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ static const unsigned int cs5530_pio_timings[2][5] = {
+ {0x00009172, 0x00012171, 0x00020080, 0x00032010, 0x00040010},
+ {0xd1329172, 0x71212171, 0x30200080, 0x20102010, 0x00100010}
+ };
+ unsigned long base = ( ap->ioaddr.bmdma_addr & ~0x0F) + 0x20 + 0x10 * ap->port_no;
+ u32 tuning;
+ int format;
+
+ /* Find out which table to use */
+ tuning = inl(base + 0x04);
+ format = (tuning & 0x80000000UL) ? 1 : 0;
+
+ /* Now load the right timing register */
+ if (adev->devno)
+ base += 0x08;
+
+ outl(cs5530_pio_timings[format][adev->pio_mode - XFER_PIO_0], base);
+}
+
+/**
+ * cs5530_set_dmamode - DMA timing setup
+ * @ap: ATA interface
+ * @adev: Device being configured
+ *
+ * We cannot mix MWDMA and UDMA without reloading timings each switch
+ * master to slave. We track the last DMA setup in order to minimise
+ * reloads.
+ */
+
+static void cs5530_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+ unsigned long base = ( ap->ioaddr.bmdma_addr & ~0x0F) + 0x20 + 0x10 * ap->port_no;
+ u32 tuning, timing = 0;
+ u8 reg;
+
+ /* Find out which table to use */
+ tuning = inl(base + 0x04);
+
+ switch(adev->dma_mode) {
+ case XFER_UDMA_0:
+ timing = 0x00921250;break;
+ case XFER_UDMA_1:
+ timing = 0x00911140;break;
+ case XFER_UDMA_2:
+ timing = 0x00911030;break;
+ case XFER_MW_DMA_0:
+ timing = 0x00077771;break;
+ case XFER_MW_DMA_1:
+ timing = 0x00012121;break;
+ case XFER_MW_DMA_2:
+ timing = 0x00002020;break;
+ default:
+ BUG();
+ }
+ /* Merge in the PIO format bit */
+ timing |= (tuning & 0x80000000UL);
+ if (adev->devno == 0) /* Master */
+ outl(timing, base + 0x04);
+ else {
+ if (timing & 0x00100000)
+ tuning |= 0x00100000; /* UDMA for both */
+ else
+ tuning &= ~0x00100000; /* MWDMA for both */
+ outl(tuning, base + 0x04);
+ outl(timing, base + 0x0C);
+ }
+
+ /* Set the DMA capable bit in the BMDMA area */
+ reg = inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
+ reg |= (1 << (5 + adev->devno));
+ outb(reg, ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
+
+ /* Remember the last DMA setup we did */
+
+ ap->private_data = adev;
+}
+
+/**
+ * cs5530_qc_issue_prot - command issue
+ * @qc: command pending
+ *
+ * Called when the libata layer is about to issue a command. We wrap
+ * this interface so that we can load the correct ATA timings if
+ * neccessary. Specifically we have a problem that there is only
+ * one MWDMA/UDMA bit.
+ */
+
+static unsigned int cs5530_qc_issue_prot(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct ata_device *adev = qc->dev;
+ struct ata_device *prev = ap->private_data;
+
+ /* See if the DMA settings could be wrong */
+ if (adev->dma_mode != 0 && adev != prev && prev != NULL) {
+ /* Maybe, but do the channels match MWDMA/UDMA ? */
+ if ((adev->dma_mode >= XFER_UDMA_0 && prev->dma_mode < XFER_UDMA_0) ||
+ (adev->dma_mode < XFER_UDMA_0 && prev->dma_mode >= XFER_UDMA_0))
+ /* Switch the mode bits */
+ cs5530_set_dmamode(ap, adev);
+ }
+
+ return ata_qc_issue_prot(qc);
+}
+
+static int cs5530_pre_reset(struct ata_port *ap)
+{
+ ap->cbl = ATA_CBL_PATA40;
+ return ata_std_prereset(ap);
+}
+
+static void cs5530_error_handler(struct ata_port *ap)
+{
+ return ata_bmdma_drive_eh(ap, cs5530_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
+}
+
+
+static struct scsi_host_template cs5530_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .max_sectors = ATA_MAX_SECTORS,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .bios_param = ata_std_bios_param,
+};
+
+static struct ata_port_operations cs5530_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = cs5530_set_piomode,
+ .set_dmamode = cs5530_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = cs5530_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = cs5530_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+static struct dmi_system_id palmax_dmi_table[] = {
+ {
+ .ident = "Palmax PD1100",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Cyrix"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Caddis"),
+ },
+ },
+ { }
+};
+
+static int cs5530_is_palmax(void)
+{
+ if (dmi_check_system(palmax_dmi_table)) {
+ printk(KERN_INFO "Palmax PD1100: Disabling DMA on docking port.\n");
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * cs5530_init_one - Initialise a CS5530
+ * @dev: PCI device
+ * @id: Entry in match table
+ *
+ * Install a driver for the newly found CS5530 companion chip. Most of
+ * this is just housekeeping. We have to set the chip up correctly and
+ * turn off various bits of emulation magic.
+ */
+
+static int cs5530_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ int compiler_warning_pointless_fix;
+ struct pci_dev *master_0 = NULL, *cs5530_0 = NULL;
+ static struct ata_port_info info = {
+ .sht = &cs5530_sht,
+ .flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x07,
+ .port_ops = &cs5530_port_ops
+ };
+ /* The docking connector doesn't do UDMA, and it seems not MWDMA */
+ static struct ata_port_info info_palmax_secondary = {
+ .sht = &cs5530_sht,
+ .flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .port_ops = &cs5530_port_ops
+ };
+ static struct ata_port_info *port_info[2] = { &info, &info };
+
+ dev = NULL;
+ while ((dev = pci_get_device(PCI_VENDOR_ID_CYRIX, PCI_ANY_ID, dev)) != NULL) {
+ switch (dev->device) {
+ case PCI_DEVICE_ID_CYRIX_PCI_MASTER:
+ master_0 = pci_dev_get(dev);
+ break;
+ case PCI_DEVICE_ID_CYRIX_5530_LEGACY:
+ cs5530_0 = pci_dev_get(dev);
+ break;
+ }
+ }
+ if (!master_0) {
+ printk(KERN_ERR DRV_NAME ": unable to locate PCI MASTER function\n");
+ goto fail_put;
+ }
+ if (!cs5530_0) {
+ printk(KERN_ERR DRV_NAME ": unable to locate CS5530 LEGACY function\n");
+ goto fail_put;
+ }
+
+ pci_set_master(cs5530_0);
+ compiler_warning_pointless_fix = pci_set_mwi(cs5530_0);
+
+ /*
+ * Set PCI CacheLineSize to 16-bytes:
+ * --> Write 0x04 into 8-bit PCI CACHELINESIZE reg of function 0 of the cs5530
+ *
+ * Note: This value is constant because the 5530 is only a Geode companion
+ */
+
+ pci_write_config_byte(cs5530_0, PCI_CACHE_LINE_SIZE, 0x04);
+
+ /*
+ * Disable trapping of UDMA register accesses (Win98 hack):
+ * --> Write 0x5006 into 16-bit reg at offset 0xd0 of function 0 of the cs5530
+ */
+
+ pci_write_config_word(cs5530_0, 0xd0, 0x5006);
+
+ /*
+ * Bit-1 at 0x40 enables MemoryWriteAndInvalidate on internal X-bus:
+ * The other settings are what is necessary to get the register
+ * into a sane state for IDE DMA operation.
+ */
+
+ pci_write_config_byte(master_0, 0x40, 0x1e);
+
+ /*
+ * Set max PCI burst size (16-bytes seems to work best):
+ * 16bytes: set bit-1 at 0x41 (reg value of 0x16)
+ * all others: clear bit-1 at 0x41, and do:
+ * 128bytes: OR 0x00 at 0x41
+ * 256bytes: OR 0x04 at 0x41
+ * 512bytes: OR 0x08 at 0x41
+ * 1024bytes: OR 0x0c at 0x41
+ */
+
+ pci_write_config_byte(master_0, 0x41, 0x14);
+
+ /*
+ * These settings are necessary to get the chip
+ * into a sane state for IDE DMA operation.
+ */
+
+ pci_write_config_byte(master_0, 0x42, 0x00);
+ pci_write_config_byte(master_0, 0x43, 0xc1);
+
+ pci_dev_put(master_0);
+ pci_dev_put(cs5530_0);
+
+ if (cs5530_is_palmax())
+ port_info[1] = &info_palmax_secondary;
+
+ /* Now kick off ATA set up */
+ return ata_pci_init_one(dev, port_info, 2);
+
+fail_put:
+ if (master_0)
+ pci_dev_put(master_0);
+ if (cs5530_0)
+ pci_dev_put(cs5530_0);
+ return -ENODEV;
+}
+
+static struct pci_device_id cs5530[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_IDE), },
+ { 0, },
+};
+
+static struct pci_driver cs5530_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = cs5530,
+ .probe = cs5530_init_one,
+ .remove = ata_pci_remove_one
+};
+
+static int __init cs5530_init(void)
+{
+ return pci_register_driver(&cs5530_pci_driver);
+}
+
+
+static void __exit cs5530_exit(void)
+{
+ pci_unregister_driver(&cs5530_pci_driver);
+}
+
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("low-level driver for the Cyrix/NS/AMD 5530");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, cs5530);
+MODULE_VERSION(DRV_VERSION);
+
+module_init(cs5530_init);
+module_exit(cs5530_exit);
diff --git a/drivers/ata/pata_cs5535.c b/drivers/ata/pata_cs5535.c
new file mode 100644
index 00000000000..d64fcdceaf0
--- /dev/null
+++ b/drivers/ata/pata_cs5535.c
@@ -0,0 +1,291 @@
+/*
+ * pata-cs5535.c - CS5535 PATA for new ATA layer
+ * (C) 2005-2006 Red Hat Inc
+ * Alan Cox <alan@redhat.com>
+ *
+ * based upon cs5535.c from AMD <Jens.Altmann@amd.com> as cleaned up and
+ * made readable and Linux style by Wolfgang Zuleger <wolfgang.zuleger@gmx.de
+ * and Alexander Kiausch <alex.kiausch@t-online.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Loosely based on the piix & svwks drivers.
+ *
+ * Documentation:
+ * Available from AMD web site.
+ * TODO
+ * Review errata to see if serializing is neccessary
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+#include <asm/msr.h>
+
+#define DRV_NAME "cs5535"
+#define DRV_VERSION "0.2.10"
+
+/*
+ * The Geode (Aka Athlon GX now) uses an internal MSR based
+ * bus system for control. Demented but there you go.
+ */
+
+#define MSR_ATAC_BASE 0x51300000
+#define ATAC_GLD_MSR_CAP (MSR_ATAC_BASE+0)
+#define ATAC_GLD_MSR_CONFIG (MSR_ATAC_BASE+0x01)
+#define ATAC_GLD_MSR_SMI (MSR_ATAC_BASE+0x02)
+#define ATAC_GLD_MSR_ERROR (MSR_ATAC_BASE+0x03)
+#define ATAC_GLD_MSR_PM (MSR_ATAC_BASE+0x04)
+#define ATAC_GLD_MSR_DIAG (MSR_ATAC_BASE+0x05)
+#define ATAC_IO_BAR (MSR_ATAC_BASE+0x08)
+#define ATAC_RESET (MSR_ATAC_BASE+0x10)
+#define ATAC_CH0D0_PIO (MSR_ATAC_BASE+0x20)
+#define ATAC_CH0D0_DMA (MSR_ATAC_BASE+0x21)
+#define ATAC_CH0D1_PIO (MSR_ATAC_BASE+0x22)
+#define ATAC_CH0D1_DMA (MSR_ATAC_BASE+0x23)
+#define ATAC_PCI_ABRTERR (MSR_ATAC_BASE+0x24)
+
+#define ATAC_BM0_CMD_PRIM 0x00
+#define ATAC_BM0_STS_PRIM 0x02
+#define ATAC_BM0_PRD 0x04
+
+#define CS5535_CABLE_DETECT 0x48
+
+#define CS5535_BAD_PIO(timings) ( (timings&~0x80000000UL)==0x00009172 )
+
+/**
+ * cs5535_pre_reset - detect cable type
+ * @ap: Port to detect on
+ *
+ * Perform cable detection for ATA66 capable cable. Return a libata
+ * cable type.
+ */
+
+static int cs5535_pre_reset(struct ata_port *ap)
+{
+ u8 cable;
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+
+ pci_read_config_byte(pdev, CS5535_CABLE_DETECT, &cable);
+ if (cable & 1)
+ ap->cbl = ATA_CBL_PATA80;
+ else
+ ap->cbl = ATA_CBL_PATA40;
+ return ata_std_prereset(ap);
+}
+
+/**
+ * cs5535_error_handler - reset/probe
+ * @ap: Port to reset
+ *
+ * Reset and configure a port
+ */
+
+static void cs5535_error_handler(struct ata_port *ap)
+{
+ ata_bmdma_drive_eh(ap, cs5535_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
+}
+
+/**
+ * cs5535_set_piomode - PIO setup
+ * @ap: ATA interface
+ * @adev: device on the interface
+ *
+ * Set our PIO requirements. The CS5535 is pretty clean about all this
+ */
+
+static void cs5535_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ static const u16 pio_timings[5] = {
+ 0xF7F4, 0x53F3, 0x13F1, 0x5131, 0x1131
+ };
+ static const u16 pio_cmd_timings[5] = {
+ 0xF7F4, 0x53F3, 0x13F1, 0x5131, 0x1131
+ };
+ u32 reg, dummy;
+ struct ata_device *pair = ata_dev_pair(adev);
+
+ int mode = adev->pio_mode - XFER_PIO_0;
+ int cmdmode = mode;
+
+ /* Command timing has to be for the lowest of the pair of devices */
+ if (pair) {
+ int pairmode = pair->pio_mode - XFER_PIO_0;
+ cmdmode = min(mode, pairmode);
+ /* Write the other drive timing register if it changed */
+ if (cmdmode < pairmode)
+ wrmsr(ATAC_CH0D0_PIO + 2 * pair->devno,
+ pio_cmd_timings[cmdmode] << 16 | pio_timings[pairmode], 0);
+ }
+ /* Write the drive timing register */
+ wrmsr(ATAC_CH0D0_PIO + 2 * adev->devno,
+ pio_cmd_timings[cmdmode] << 16 | pio_timings[mode], 0);
+
+ /* Set the PIO "format 1" bit in the DMA timing register */
+ rdmsr(ATAC_CH0D0_DMA + 2 * adev->devno, reg, dummy);
+ wrmsr(ATAC_CH0D0_DMA + 2 * adev->devno, reg | 0x80000000UL, 0);
+}
+
+/**
+ * cs5535_set_dmamode - DMA timing setup
+ * @ap: ATA interface
+ * @adev: Device being configured
+ *
+ */
+
+static void cs5535_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+ static const u32 udma_timings[5] = {
+ 0x7F7436A1, 0x7F733481, 0x7F723261, 0x7F713161, 0x7F703061
+ };
+ static const u32 mwdma_timings[3] = {
+ 0x7F0FFFF3, 0x7F035352, 0x7F024241
+ };
+ u32 reg, dummy;
+ int mode = adev->dma_mode;
+
+ rdmsr(ATAC_CH0D0_DMA + 2 * adev->devno, reg, dummy);
+ reg &= 0x80000000UL;
+ if (mode >= XFER_UDMA_0)
+ reg |= udma_timings[mode - XFER_UDMA_0];
+ else
+ reg |= mwdma_timings[mode - XFER_MW_DMA_0];
+ wrmsr(ATAC_CH0D0_DMA + 2 * adev->devno, reg, 0);
+}
+
+static struct scsi_host_template cs5535_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .max_sectors = ATA_MAX_SECTORS,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .bios_param = ata_std_bios_param,
+};
+
+static struct ata_port_operations cs5535_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = cs5535_set_piomode,
+ .set_dmamode = cs5535_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = cs5535_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+/**
+ * cs5535_init_one - Initialise a CS5530
+ * @dev: PCI device
+ * @id: Entry in match table
+ *
+ * Install a driver for the newly found CS5530 companion chip. Most of
+ * this is just housekeeping. We have to set the chip up correctly and
+ * turn off various bits of emulation magic.
+ */
+
+static int cs5535_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ static struct ata_port_info info = {
+ .sht = &cs5535_sht,
+ .flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x1f,
+ .port_ops = &cs5535_port_ops
+ };
+ struct ata_port_info *ports[1] = { &info };
+
+ u32 timings, dummy;
+
+ /* Check the BIOS set the initial timing clock. If not set the
+ timings for PIO0 */
+ rdmsr(ATAC_CH0D0_PIO, timings, dummy);
+ if (CS5535_BAD_PIO(timings))
+ wrmsr(ATAC_CH0D0_PIO, 0xF7F4F7F4UL, 0);
+ rdmsr(ATAC_CH0D1_PIO, timings, dummy);
+ if (CS5535_BAD_PIO(timings))
+ wrmsr(ATAC_CH0D1_PIO, 0xF7F4F7F4UL, 0);
+ return ata_pci_init_one(dev, ports, 1);
+}
+
+static struct pci_device_id cs5535[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_NS, 0x002D), },
+ { 0, },
+};
+
+static struct pci_driver cs5535_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = cs5535,
+ .probe = cs5535_init_one,
+ .remove = ata_pci_remove_one
+};
+
+static int __init cs5535_init(void)
+{
+ return pci_register_driver(&cs5535_pci_driver);
+}
+
+
+static void __exit cs5535_exit(void)
+{
+ pci_unregister_driver(&cs5535_pci_driver);
+}
+
+
+MODULE_AUTHOR("Alan Cox, Jens Altmann, Wolfgan Zuleger, Alexander Kiausch");
+MODULE_DESCRIPTION("low-level driver for the NS/AMD 5530");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, cs5535);
+MODULE_VERSION(DRV_VERSION);
+
+module_init(cs5535_init);
+module_exit(cs5535_exit);
diff --git a/drivers/ata/pata_cypress.c b/drivers/ata/pata_cypress.c
new file mode 100644
index 00000000000..dfa5ac53904
--- /dev/null
+++ b/drivers/ata/pata_cypress.c
@@ -0,0 +1,227 @@
+/*
+ * pata_cypress.c - Cypress PATA for new ATA layer
+ * (C) 2006 Red Hat Inc
+ * Alan Cox <alan@redhat.com>
+ *
+ * Based heavily on
+ * linux/drivers/ide/pci/cy82c693.c Version 0.40 Sep. 10, 2002
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+
+#define DRV_NAME "pata_cypress"
+#define DRV_VERSION "0.1.2"
+
+/* here are the offset definitions for the registers */
+
+enum {
+ CY82_IDE_CMDREG = 0x04,
+ CY82_IDE_ADDRSETUP = 0x48,
+ CY82_IDE_MASTER_IOR = 0x4C,
+ CY82_IDE_MASTER_IOW = 0x4D,
+ CY82_IDE_SLAVE_IOR = 0x4E,
+ CY82_IDE_SLAVE_IOW = 0x4F,
+ CY82_IDE_MASTER_8BIT = 0x50,
+ CY82_IDE_SLAVE_8BIT = 0x51,
+
+ CY82_INDEX_PORT = 0x22,
+ CY82_DATA_PORT = 0x23,
+
+ CY82_INDEX_CTRLREG1 = 0x01,
+ CY82_INDEX_CHANNEL0 = 0x30,
+ CY82_INDEX_CHANNEL1 = 0x31,
+ CY82_INDEX_TIMEOUT = 0x32
+};
+
+static int cy82c693_pre_reset(struct ata_port *ap)
+{
+ ap->cbl = ATA_CBL_PATA40;
+ return ata_std_prereset(ap);
+}
+
+static void cy82c693_error_handler(struct ata_port *ap)
+{
+ ata_bmdma_drive_eh(ap, cy82c693_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
+}
+
+/**
+ * cy82c693_set_piomode - set initial PIO mode data
+ * @ap: ATA interface
+ * @adev: ATA device
+ *
+ * Called to do the PIO mode setup.
+ */
+
+static void cy82c693_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ struct ata_timing t;
+ const unsigned long T = 1000000 / 33;
+ short time_16, time_8;
+ u32 addr;
+
+ if (ata_timing_compute(adev, adev->pio_mode, &t, T, 1) < 0) {
+ printk(KERN_ERR DRV_NAME ": mome computation failed.\n");
+ return;
+ }
+
+ time_16 = FIT(t.recover, 0, 15) | (FIT(t.active, 0, 15) << 4);
+ time_8 = FIT(t.act8b, 0, 15) | (FIT(t.rec8b, 0, 15) << 4);
+
+ if (adev->devno == 0) {
+ pci_read_config_dword(pdev, CY82_IDE_ADDRSETUP, &addr);
+
+ addr &= ~0x0F; /* Mask bits */
+ addr |= FIT(t.setup, 0, 15);
+
+ pci_write_config_dword(pdev, CY82_IDE_ADDRSETUP, addr);
+ pci_write_config_byte(pdev, CY82_IDE_MASTER_IOR, time_16);
+ pci_write_config_byte(pdev, CY82_IDE_MASTER_IOW, time_16);
+ pci_write_config_byte(pdev, CY82_IDE_MASTER_8BIT, time_8);
+ } else {
+ pci_read_config_dword(pdev, CY82_IDE_ADDRSETUP, &addr);
+
+ addr &= ~0xF0; /* Mask bits */
+ addr |= (FIT(t.setup, 0, 15) << 4);
+
+ pci_write_config_dword(pdev, CY82_IDE_ADDRSETUP, addr);
+ pci_write_config_byte(pdev, CY82_IDE_SLAVE_IOR, time_16);
+ pci_write_config_byte(pdev, CY82_IDE_SLAVE_IOW, time_16);
+ pci_write_config_byte(pdev, CY82_IDE_SLAVE_8BIT, time_8);
+ }
+}
+
+/**
+ * cy82c693_set_dmamode - set initial DMA mode data
+ * @ap: ATA interface
+ * @adev: ATA device
+ *
+ * Called to do the DMA mode setup.
+ */
+
+static void cy82c693_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+ int reg = CY82_INDEX_CHANNEL0 + ap->port_no;
+
+ /* Be afraid, be very afraid. Magic registers in low I/O space */
+ outb(reg, 0x22);
+ outb(adev->dma_mode - XFER_MW_DMA_0, 0x23);
+
+ /* 0x50 gives the best behaviour on the Alpha's using this chip */
+ outb(CY82_INDEX_TIMEOUT, 0x22);
+ outb(0x50, 0x23);
+}
+
+static struct scsi_host_template cy82c693_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .max_sectors = ATA_MAX_SECTORS,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .bios_param = ata_std_bios_param,
+};
+
+static struct ata_port_operations cy82c693_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = cy82c693_set_piomode,
+ .set_dmamode = cy82c693_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = cy82c693_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+static int cy82c693_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ static struct ata_port_info info = {
+ .sht = &cy82c693_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .port_ops = &cy82c693_port_ops
+ };
+ static struct ata_port_info *port_info[1] = { &info };
+
+ /* Devfn 1 is the ATA primary. The secondary is magic and on devfn2. For the
+ moment we don't handle the secondary. FIXME */
+
+ if (PCI_FUNC(pdev->devfn) != 1)
+ return -ENODEV;
+
+ return ata_pci_init_one(pdev, port_info, 1);
+}
+
+static struct pci_device_id cy82c693[] = {
+ { PCI_VENDOR_ID_CONTAQ, PCI_DEVICE_ID_CONTAQ_82C693, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { 0, },
+};
+
+static struct pci_driver cy82c693_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = cy82c693,
+ .probe = cy82c693_init_one,
+ .remove = ata_pci_remove_one
+};
+
+static int __init cy82c693_init(void)
+{
+ return pci_register_driver(&cy82c693_pci_driver);
+}
+
+
+static void __exit cy82c693_exit(void)
+{
+ pci_unregister_driver(&cy82c693_pci_driver);
+}
+
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("low-level driver for the CY82C693 PATA controller");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, cy82c693);
+MODULE_VERSION(DRV_VERSION);
+
+module_init(cy82c693_init);
+module_exit(cy82c693_exit);
diff --git a/drivers/ata/pata_efar.c b/drivers/ata/pata_efar.c
new file mode 100644
index 00000000000..95cd1ca181f
--- /dev/null
+++ b/drivers/ata/pata_efar.c
@@ -0,0 +1,338 @@
+/*
+ * pata_efar.c - EFAR PIIX clone controller driver
+ *
+ * (C) 2005 Red Hat <alan@redhat.com>
+ *
+ * Some parts based on ata_piix.c by Jeff Garzik and others.
+ *
+ * The EFAR is a PIIX4 clone with UDMA66 support. Unlike the later
+ * Intel ICH controllers the EFAR widened the UDMA mode register bits
+ * and doesn't require the funky clock selection.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+#include <linux/ata.h>
+
+#define DRV_NAME "pata_efar"
+#define DRV_VERSION "0.4.2"
+
+/**
+ * efar_pre_reset - check for 40/80 pin
+ * @ap: Port
+ *
+ * Perform cable detection for the EFAR ATA interface. This is
+ * different to the PIIX arrangement
+ */
+
+static int efar_pre_reset(struct ata_port *ap)
+{
+ static const struct pci_bits efar_enable_bits[] = {
+ { 0x41U, 1U, 0x80UL, 0x80UL }, /* port 0 */
+ { 0x43U, 1U, 0x80UL, 0x80UL }, /* port 1 */
+ };
+
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u8 tmp;
+
+ if (!pci_test_config_bits(pdev, &efar_enable_bits[ap->port_no]))
+ return -ENOENT;
+
+ pci_read_config_byte(pdev, 0x47, &tmp);
+ if (tmp & (2 >> ap->port_no))
+ ap->cbl = ATA_CBL_PATA40;
+ else
+ ap->cbl = ATA_CBL_PATA80;
+ return ata_std_prereset(ap);
+}
+
+/**
+ * efar_probe_reset - Probe specified port on PATA host controller
+ * @ap: Port to probe
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void efar_error_handler(struct ata_port *ap)
+{
+ ata_bmdma_drive_eh(ap, efar_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
+}
+
+/**
+ * efar_set_piomode - Initialize host controller PATA PIO timings
+ * @ap: Port whose timings we are configuring
+ * @adev: um
+ *
+ * Set PIO mode for device, in host controller PCI config space.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void efar_set_piomode (struct ata_port *ap, struct ata_device *adev)
+{
+ unsigned int pio = adev->pio_mode - XFER_PIO_0;
+ struct pci_dev *dev = to_pci_dev(ap->host->dev);
+ unsigned int idetm_port= ap->port_no ? 0x42 : 0x40;
+ u16 idetm_data;
+ int control = 0;
+
+ /*
+ * See Intel Document 298600-004 for the timing programing rules
+ * for PIIX/ICH. The EFAR is a clone so very similar
+ */
+
+ static const /* ISP RTC */
+ u8 timings[][2] = { { 0, 0 },
+ { 0, 0 },
+ { 1, 0 },
+ { 2, 1 },
+ { 2, 3 }, };
+
+ if (pio > 2)
+ control |= 1; /* TIME1 enable */
+ if (ata_pio_need_iordy(adev)) /* PIO 3/4 require IORDY */
+ control |= 2; /* IE enable */
+ /* Intel specifies that the PPE functionality is for disk only */
+ if (adev->class == ATA_DEV_ATA)
+ control |= 4; /* PPE enable */
+
+ pci_read_config_word(dev, idetm_port, &idetm_data);
+
+ /* Enable PPE, IE and TIME as appropriate */
+
+ if (adev->devno == 0) {
+ idetm_data &= 0xCCF0;
+ idetm_data |= control;
+ idetm_data |= (timings[pio][0] << 12) |
+ (timings[pio][1] << 8);
+ } else {
+ int shift = 4 * ap->port_no;
+ u8 slave_data;
+
+ idetm_data &= 0xCC0F;
+ idetm_data |= (control << 4);
+
+ /* Slave timing in seperate register */
+ pci_read_config_byte(dev, 0x44, &slave_data);
+ slave_data &= 0x0F << shift;
+ slave_data |= ((timings[pio][0] << 2) | timings[pio][1]) << shift;
+ pci_write_config_byte(dev, 0x44, slave_data);
+ }
+
+ idetm_data |= 0x4000; /* Ensure SITRE is enabled */
+ pci_write_config_word(dev, idetm_port, idetm_data);
+}
+
+/**
+ * efar_set_dmamode - Initialize host controller PATA DMA timings
+ * @ap: Port whose timings we are configuring
+ * @adev: Device to program
+ *
+ * Set UDMA/MWDMA mode for device, in host controller PCI config space.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void efar_set_dmamode (struct ata_port *ap, struct ata_device *adev)
+{
+ struct pci_dev *dev = to_pci_dev(ap->host->dev);
+ u8 master_port = ap->port_no ? 0x42 : 0x40;
+ u16 master_data;
+ u8 speed = adev->dma_mode;
+ int devid = adev->devno + 2 * ap->port_no;
+ u8 udma_enable;
+
+ static const /* ISP RTC */
+ u8 timings[][2] = { { 0, 0 },
+ { 0, 0 },
+ { 1, 0 },
+ { 2, 1 },
+ { 2, 3 }, };
+
+ pci_read_config_word(dev, master_port, &master_data);
+ pci_read_config_byte(dev, 0x48, &udma_enable);
+
+ if (speed >= XFER_UDMA_0) {
+ unsigned int udma = adev->dma_mode - XFER_UDMA_0;
+ u16 udma_timing;
+
+ udma_enable |= (1 << devid);
+
+ /* Load the UDMA mode number */
+ pci_read_config_word(dev, 0x4A, &udma_timing);
+ udma_timing &= ~(7 << (4 * devid));
+ udma_timing |= udma << (4 * devid);
+ pci_write_config_word(dev, 0x4A, udma_timing);
+ } else {
+ /*
+ * MWDMA is driven by the PIO timings. We must also enable
+ * IORDY unconditionally along with TIME1. PPE has already
+ * been set when the PIO timing was set.
+ */
+ unsigned int mwdma = adev->dma_mode - XFER_MW_DMA_0;
+ unsigned int control;
+ u8 slave_data;
+ const unsigned int needed_pio[3] = {
+ XFER_PIO_0, XFER_PIO_3, XFER_PIO_4
+ };
+ int pio = needed_pio[mwdma] - XFER_PIO_0;
+
+ control = 3; /* IORDY|TIME1 */
+
+ /* If the drive MWDMA is faster than it can do PIO then
+ we must force PIO into PIO0 */
+
+ if (adev->pio_mode < needed_pio[mwdma])
+ /* Enable DMA timing only */
+ control |= 8; /* PIO cycles in PIO0 */
+
+ if (adev->devno) { /* Slave */
+ master_data &= 0xFF4F; /* Mask out IORDY|TIME1|DMAONLY */
+ master_data |= control << 4;
+ pci_read_config_byte(dev, 0x44, &slave_data);
+ slave_data &= (0x0F + 0xE1 * ap->port_no);
+ /* Load the matching timing */
+ slave_data |= ((timings[pio][0] << 2) | timings[pio][1]) << (ap->port_no ? 4 : 0);
+ pci_write_config_byte(dev, 0x44, slave_data);
+ } else { /* Master */
+ master_data &= 0xCCF4; /* Mask out IORDY|TIME1|DMAONLY
+ and master timing bits */
+ master_data |= control;
+ master_data |=
+ (timings[pio][0] << 12) |
+ (timings[pio][1] << 8);
+ }
+ udma_enable &= ~(1 << devid);
+ pci_write_config_word(dev, master_port, master_data);
+ }
+ pci_write_config_byte(dev, 0x48, udma_enable);
+}
+
+static struct scsi_host_template efar_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .max_sectors = ATA_MAX_SECTORS,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .bios_param = ata_std_bios_param,
+};
+
+static const struct ata_port_operations efar_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = efar_set_piomode,
+ .set_dmamode = efar_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = efar_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop,
+};
+
+
+/**
+ * efar_init_one - Register EFAR ATA PCI device with kernel services
+ * @pdev: PCI device to register
+ * @ent: Entry in efar_pci_tbl matching with @pdev
+ *
+ * Called from kernel PCI layer.
+ *
+ * LOCKING:
+ * Inherited from PCI layer (may sleep).
+ *
+ * RETURNS:
+ * Zero on success, or -ERRNO value.
+ */
+
+static int efar_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ static int printed_version;
+ static struct ata_port_info info = {
+ .sht = &efar_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .mwdma_mask = 0x07, /* mwdma1-2 */
+ .udma_mask = 0x0f, /* UDMA 66 */
+ .port_ops = &efar_ops,
+ };
+ static struct ata_port_info *port_info[2] = { &info, &info };
+
+ if (!printed_version++)
+ dev_printk(KERN_DEBUG, &pdev->dev,
+ "version " DRV_VERSION "\n");
+
+ return ata_pci_init_one(pdev, port_info, 2);
+}
+
+static const struct pci_device_id efar_pci_tbl[] = {
+ { 0x1055, 0x9130, PCI_ANY_ID, PCI_ANY_ID, },
+ { } /* terminate list */
+};
+
+static struct pci_driver efar_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = efar_pci_tbl,
+ .probe = efar_init_one,
+ .remove = ata_pci_remove_one,
+};
+
+static int __init efar_init(void)
+{
+ return pci_register_driver(&efar_pci_driver);
+}
+
+static void __exit efar_exit(void)
+{
+ pci_unregister_driver(&efar_pci_driver);
+}
+
+
+module_init(efar_init);
+module_exit(efar_exit);
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("SCSI low-level driver for EFAR PIIX clones");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, efar_pci_tbl);
+MODULE_VERSION(DRV_VERSION);
+
diff --git a/drivers/ata/pata_hpt366.c b/drivers/ata/pata_hpt366.c
new file mode 100644
index 00000000000..cf656ecbe50
--- /dev/null
+++ b/drivers/ata/pata_hpt366.c
@@ -0,0 +1,478 @@
+/*
+ * Libata driver for the highpoint 366 and 368 UDMA66 ATA controllers.
+ *
+ * This driver is heavily based upon:
+ *
+ * linux/drivers/ide/pci/hpt366.c Version 0.36 April 25, 2003
+ *
+ * Copyright (C) 1999-2003 Andre Hedrick <andre@linux-ide.org>
+ * Portions Copyright (C) 2001 Sun Microsystems, Inc.
+ * Portions Copyright (C) 2003 Red Hat Inc
+ *
+ *
+ * TODO
+ * Maybe PLL mode
+ * Look into engine reset on timeout errors. Should not be
+ * required.
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+
+#define DRV_NAME "pata_hpt366"
+#define DRV_VERSION "0.5"
+
+struct hpt_clock {
+ u8 xfer_speed;
+ u32 timing;
+};
+
+/* key for bus clock timings
+ * bit
+ * 0:3 data_high_time. inactive time of DIOW_/DIOR_ for PIO and MW
+ * DMA. cycles = value + 1
+ * 4:8 data_low_time. active time of DIOW_/DIOR_ for PIO and MW
+ * DMA. cycles = value + 1
+ * 9:12 cmd_high_time. inactive time of DIOW_/DIOR_ during task file
+ * register access.
+ * 13:17 cmd_low_time. active time of DIOW_/DIOR_ during task file
+ * register access.
+ * 18:21 udma_cycle_time. clock freq and clock cycles for UDMA xfer.
+ * during task file register access.
+ * 22:24 pre_high_time. time to initialize 1st cycle for PIO and MW DMA
+ * xfer.
+ * 25:27 cmd_pre_high_time. time to initialize 1st PIO cycle for task
+ * register access.
+ * 28 UDMA enable
+ * 29 DMA enable
+ * 30 PIO_MST enable. if set, the chip is in bus master mode during
+ * PIO.
+ * 31 FIFO enable.
+ */
+
+static const struct hpt_clock hpt366_40[] = {
+ { XFER_UDMA_4, 0x900fd943 },
+ { XFER_UDMA_3, 0x900ad943 },
+ { XFER_UDMA_2, 0x900bd943 },
+ { XFER_UDMA_1, 0x9008d943 },
+ { XFER_UDMA_0, 0x9008d943 },
+
+ { XFER_MW_DMA_2, 0xa008d943 },
+ { XFER_MW_DMA_1, 0xa010d955 },
+ { XFER_MW_DMA_0, 0xa010d9fc },
+
+ { XFER_PIO_4, 0xc008d963 },
+ { XFER_PIO_3, 0xc010d974 },
+ { XFER_PIO_2, 0xc010d997 },
+ { XFER_PIO_1, 0xc010d9c7 },
+ { XFER_PIO_0, 0xc018d9d9 },
+ { 0, 0x0120d9d9 }
+};
+
+static const struct hpt_clock hpt366_33[] = {
+ { XFER_UDMA_4, 0x90c9a731 },
+ { XFER_UDMA_3, 0x90cfa731 },
+ { XFER_UDMA_2, 0x90caa731 },
+ { XFER_UDMA_1, 0x90cba731 },
+ { XFER_UDMA_0, 0x90c8a731 },
+
+ { XFER_MW_DMA_2, 0xa0c8a731 },
+ { XFER_MW_DMA_1, 0xa0c8a732 }, /* 0xa0c8a733 */
+ { XFER_MW_DMA_0, 0xa0c8a797 },
+
+ { XFER_PIO_4, 0xc0c8a731 },
+ { XFER_PIO_3, 0xc0c8a742 },
+ { XFER_PIO_2, 0xc0d0a753 },
+ { XFER_PIO_1, 0xc0d0a7a3 }, /* 0xc0d0a793 */
+ { XFER_PIO_0, 0xc0d0a7aa }, /* 0xc0d0a7a7 */
+ { 0, 0x0120a7a7 }
+};
+
+static const struct hpt_clock hpt366_25[] = {
+ { XFER_UDMA_4, 0x90c98521 },
+ { XFER_UDMA_3, 0x90cf8521 },
+ { XFER_UDMA_2, 0x90cf8521 },
+ { XFER_UDMA_1, 0x90cb8521 },
+ { XFER_UDMA_0, 0x90cb8521 },
+
+ { XFER_MW_DMA_2, 0xa0ca8521 },
+ { XFER_MW_DMA_1, 0xa0ca8532 },
+ { XFER_MW_DMA_0, 0xa0ca8575 },
+
+ { XFER_PIO_4, 0xc0ca8521 },
+ { XFER_PIO_3, 0xc0ca8532 },
+ { XFER_PIO_2, 0xc0ca8542 },
+ { XFER_PIO_1, 0xc0d08572 },
+ { XFER_PIO_0, 0xc0d08585 },
+ { 0, 0x01208585 }
+};
+
+static const char *bad_ata33[] = {
+ "Maxtor 92720U8", "Maxtor 92040U6", "Maxtor 91360U4", "Maxtor 91020U3", "Maxtor 90845U3", "Maxtor 90650U2",
+ "Maxtor 91360D8", "Maxtor 91190D7", "Maxtor 91020D6", "Maxtor 90845D5", "Maxtor 90680D4", "Maxtor 90510D3", "Maxtor 90340D2",
+ "Maxtor 91152D8", "Maxtor 91008D7", "Maxtor 90845D6", "Maxtor 90840D6", "Maxtor 90720D5", "Maxtor 90648D5", "Maxtor 90576D4",
+ "Maxtor 90510D4",
+ "Maxtor 90432D3", "Maxtor 90288D2", "Maxtor 90256D2",
+ "Maxtor 91000D8", "Maxtor 90910D8", "Maxtor 90875D7", "Maxtor 90840D7", "Maxtor 90750D6", "Maxtor 90625D5", "Maxtor 90500D4",
+ "Maxtor 91728D8", "Maxtor 91512D7", "Maxtor 91303D6", "Maxtor 91080D5", "Maxtor 90845D4", "Maxtor 90680D4", "Maxtor 90648D3", "Maxtor 90432D2",
+ NULL
+};
+
+static const char *bad_ata66_4[] = {
+ "IBM-DTLA-307075",
+ "IBM-DTLA-307060",
+ "IBM-DTLA-307045",
+ "IBM-DTLA-307030",
+ "IBM-DTLA-307020",
+ "IBM-DTLA-307015",
+ "IBM-DTLA-305040",
+ "IBM-DTLA-305030",
+ "IBM-DTLA-305020",
+ "IC35L010AVER07-0",
+ "IC35L020AVER07-0",
+ "IC35L030AVER07-0",
+ "IC35L040AVER07-0",
+ "IC35L060AVER07-0",
+ "WDC AC310200R",
+ NULL
+};
+
+static const char *bad_ata66_3[] = {
+ "WDC AC310200R",
+ NULL
+};
+
+static int hpt_dma_blacklisted(const struct ata_device *dev, char *modestr, const char *list[])
+{
+ unsigned char model_num[40];
+ char *s;
+ unsigned int len;
+ int i = 0;
+
+ ata_id_string(dev->id, model_num, ATA_ID_PROD_OFS, sizeof(model_num));
+ s = &model_num[0];
+ len = strnlen(s, sizeof(model_num));
+
+ /* ATAPI specifies that empty space is blank-filled; remove blanks */
+ while ((len > 0) && (s[len - 1] == ' ')) {
+ len--;
+ s[len] = 0;
+ }
+
+ while(list[i] != NULL) {
+ if (!strncmp(list[i], s, len)) {
+ printk(KERN_WARNING DRV_NAME ": %s is not supported for %s.\n",
+ modestr, list[i]);
+ return 1;
+ }
+ i++;
+ }
+ return 0;
+}
+
+/**
+ * hpt366_filter - mode selection filter
+ * @ap: ATA interface
+ * @adev: ATA device
+ *
+ * Block UDMA on devices that cause trouble with this controller.
+ */
+
+static unsigned long hpt366_filter(const struct ata_port *ap, struct ata_device *adev, unsigned long mask)
+{
+ if (adev->class == ATA_DEV_ATA) {
+ if (hpt_dma_blacklisted(adev, "UDMA", bad_ata33))
+ mask &= ~ATA_MASK_UDMA;
+ if (hpt_dma_blacklisted(adev, "UDMA3", bad_ata66_3))
+ mask &= ~(0x07 << ATA_SHIFT_UDMA);
+ if (hpt_dma_blacklisted(adev, "UDMA4", bad_ata66_4))
+ mask &= ~(0x0F << ATA_SHIFT_UDMA);
+ }
+ return ata_pci_default_filter(ap, adev, mask);
+}
+
+/**
+ * hpt36x_find_mode - reset the hpt36x bus
+ * @ap: ATA port
+ * @speed: transfer mode
+ *
+ * Return the 32bit register programming information for this channel
+ * that matches the speed provided.
+ */
+
+static u32 hpt36x_find_mode(struct ata_port *ap, int speed)
+{
+ struct hpt_clock *clocks = ap->host->private_data;
+
+ while(clocks->xfer_speed) {
+ if (clocks->xfer_speed == speed)
+ return clocks->timing;
+ clocks++;
+ }
+ BUG();
+ return 0xffffffffU; /* silence compiler warning */
+}
+
+static int hpt36x_pre_reset(struct ata_port *ap)
+{
+ u8 ata66;
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+
+ pci_read_config_byte(pdev, 0x5A, &ata66);
+ if (ata66 & (1 << ap->port_no))
+ ap->cbl = ATA_CBL_PATA40;
+ else
+ ap->cbl = ATA_CBL_PATA80;
+ return ata_std_prereset(ap);
+}
+
+/**
+ * hpt36x_error_handler - reset the hpt36x bus
+ * @ap: ATA port to reset
+ *
+ * Perform the reset handling for the 366/368
+ */
+
+static void hpt36x_error_handler(struct ata_port *ap)
+{
+ ata_bmdma_drive_eh(ap, hpt36x_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
+}
+
+/**
+ * hpt366_set_piomode - PIO setup
+ * @ap: ATA interface
+ * @adev: device on the interface
+ *
+ * Perform PIO mode setup.
+ */
+
+static void hpt366_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u32 addr1, addr2;
+ u32 reg;
+ u32 mode;
+ u8 fast;
+
+ addr1 = 0x40 + 4 * (adev->devno + 2 * ap->port_no);
+ addr2 = 0x51 + 4 * ap->port_no;
+
+ /* Fast interrupt prediction disable, hold off interrupt disable */
+ pci_read_config_byte(pdev, addr2, &fast);
+ if (fast & 0x80) {
+ fast &= ~0x80;
+ pci_write_config_byte(pdev, addr2, fast);
+ }
+
+ pci_read_config_dword(pdev, addr1, &reg);
+ mode = hpt36x_find_mode(ap, adev->pio_mode);
+ mode &= ~0x8000000; /* No FIFO in PIO */
+ mode &= ~0x30070000; /* Leave config bits alone */
+ reg &= 0x30070000; /* Strip timing bits */
+ pci_write_config_dword(pdev, addr1, reg | mode);
+}
+
+/**
+ * hpt366_set_dmamode - DMA timing setup
+ * @ap: ATA interface
+ * @adev: Device being configured
+ *
+ * Set up the channel for MWDMA or UDMA modes. Much the same as with
+ * PIO, load the mode number and then set MWDMA or UDMA flag.
+ */
+
+static void hpt366_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u32 addr1, addr2;
+ u32 reg;
+ u32 mode;
+ u8 fast;
+
+ addr1 = 0x40 + 4 * (adev->devno + 2 * ap->port_no);
+ addr2 = 0x51 + 4 * ap->port_no;
+
+ /* Fast interrupt prediction disable, hold off interrupt disable */
+ pci_read_config_byte(pdev, addr2, &fast);
+ if (fast & 0x80) {
+ fast &= ~0x80;
+ pci_write_config_byte(pdev, addr2, fast);
+ }
+
+ pci_read_config_dword(pdev, addr1, &reg);
+ mode = hpt36x_find_mode(ap, adev->dma_mode);
+ mode |= 0x8000000; /* FIFO in MWDMA or UDMA */
+ mode &= ~0xC0000000; /* Leave config bits alone */
+ reg &= 0xC0000000; /* Strip timing bits */
+ pci_write_config_dword(pdev, addr1, reg | mode);
+}
+
+static struct scsi_host_template hpt36x_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .max_sectors = ATA_MAX_SECTORS,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .bios_param = ata_std_bios_param,
+};
+
+/*
+ * Configuration for HPT366/68
+ */
+
+static struct ata_port_operations hpt366_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = hpt366_set_piomode,
+ .set_dmamode = hpt366_set_dmamode,
+ .mode_filter = hpt366_filter,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = hpt36x_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+/**
+ * hpt36x_init_one - Initialise an HPT366/368
+ * @dev: PCI device
+ * @id: Entry in match table
+ *
+ * Initialise an HPT36x device. There are some interesting complications
+ * here. Firstly the chip may report 366 and be one of several variants.
+ * Secondly all the timings depend on the clock for the chip which we must
+ * detect and look up
+ *
+ * This is the known chip mappings. It may be missing a couple of later
+ * releases.
+ *
+ * Chip version PCI Rev Notes
+ * HPT366 4 (HPT366) 0 UDMA66
+ * HPT366 4 (HPT366) 1 UDMA66
+ * HPT368 4 (HPT366) 2 UDMA66
+ * HPT37x/30x 4 (HPT366) 3+ Other driver
+ *
+ */
+
+static int hpt36x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ static struct ata_port_info info_hpt366 = {
+ .sht = &hpt36x_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x1f,
+ .port_ops = &hpt366_port_ops
+ };
+ struct ata_port_info *port_info[2] = {&info_hpt366, &info_hpt366};
+
+ u32 class_rev;
+ u32 reg1;
+ u8 drive_fast;
+
+ pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
+ class_rev &= 0xFF;
+
+ /* May be a later chip in disguise. Check */
+ /* Newer chips are not in the HPT36x driver. Ignore them */
+ if (class_rev > 2)
+ return -ENODEV;
+
+ pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, (L1_CACHE_BYTES / 4));
+ pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x78);
+ pci_write_config_byte(dev, PCI_MIN_GNT, 0x08);
+ pci_write_config_byte(dev, PCI_MAX_LAT, 0x08);
+
+ pci_read_config_byte(dev, 0x51, &drive_fast);
+ if (drive_fast & 0x80)
+ pci_write_config_byte(dev, 0x51, drive_fast & ~0x80);
+
+ pci_read_config_dword(dev, 0x40, &reg1);
+
+ /* PCI clocking determines the ATA timing values to use */
+ /* info_hpt366 is safe against re-entry so we can scribble on it */
+ switch(reg1 & 0x700) {
+ case 5:
+ info_hpt366.private_data = &hpt366_40;
+ break;
+ case 9:
+ info_hpt366.private_data = &hpt366_25;
+ break;
+ default:
+ info_hpt366.private_data = &hpt366_33;
+ break;
+ }
+ /* Now kick off ATA set up */
+ return ata_pci_init_one(dev, port_info, 2);
+}
+
+static struct pci_device_id hpt36x[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT366), },
+ { 0, },
+};
+
+static struct pci_driver hpt36x_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = hpt36x,
+ .probe = hpt36x_init_one,
+ .remove = ata_pci_remove_one
+};
+
+static int __init hpt36x_init(void)
+{
+ return pci_register_driver(&hpt36x_pci_driver);
+}
+
+
+static void __exit hpt36x_exit(void)
+{
+ pci_unregister_driver(&hpt36x_pci_driver);
+}
+
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("low-level driver for the Highpoint HPT366/368");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, hpt36x);
+MODULE_VERSION(DRV_VERSION);
+
+module_init(hpt36x_init);
+module_exit(hpt36x_exit);
diff --git a/drivers/ata/pata_hpt37x.c b/drivers/ata/pata_hpt37x.c
new file mode 100644
index 00000000000..10318c0012e
--- /dev/null
+++ b/drivers/ata/pata_hpt37x.c
@@ -0,0 +1,1257 @@
+/*
+ * Libata driver for the highpoint 37x and 30x UDMA66 ATA controllers.
+ *
+ * This driver is heavily based upon:
+ *
+ * linux/drivers/ide/pci/hpt366.c Version 0.36 April 25, 2003
+ *
+ * Copyright (C) 1999-2003 Andre Hedrick <andre@linux-ide.org>
+ * Portions Copyright (C) 2001 Sun Microsystems, Inc.
+ * Portions Copyright (C) 2003 Red Hat Inc
+ *
+ * TODO
+ * PLL mode
+ * Look into engine reset on timeout errors. Should not be
+ * required.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+
+#define DRV_NAME "pata_hpt37x"
+#define DRV_VERSION "0.5"
+
+struct hpt_clock {
+ u8 xfer_speed;
+ u32 timing;
+};
+
+struct hpt_chip {
+ const char *name;
+ unsigned int base;
+ struct hpt_clock const *clocks[4];
+};
+
+/* key for bus clock timings
+ * bit
+ * 0:3 data_high_time. inactive time of DIOW_/DIOR_ for PIO and MW
+ * DMA. cycles = value + 1
+ * 4:8 data_low_time. active time of DIOW_/DIOR_ for PIO and MW
+ * DMA. cycles = value + 1
+ * 9:12 cmd_high_time. inactive time of DIOW_/DIOR_ during task file
+ * register access.
+ * 13:17 cmd_low_time. active time of DIOW_/DIOR_ during task file
+ * register access.
+ * 18:21 udma_cycle_time. clock freq and clock cycles for UDMA xfer.
+ * during task file register access.
+ * 22:24 pre_high_time. time to initialize 1st cycle for PIO and MW DMA
+ * xfer.
+ * 25:27 cmd_pre_high_time. time to initialize 1st PIO cycle for task
+ * register access.
+ * 28 UDMA enable
+ * 29 DMA enable
+ * 30 PIO_MST enable. if set, the chip is in bus master mode during
+ * PIO.
+ * 31 FIFO enable.
+ */
+
+/* from highpoint documentation. these are old values */
+static const struct hpt_clock hpt370_timings_33[] = {
+/* { XFER_UDMA_5, 0x1A85F442, 0x16454e31 }, */
+ { XFER_UDMA_5, 0x16454e31 },
+ { XFER_UDMA_4, 0x16454e31 },
+ { XFER_UDMA_3, 0x166d4e31 },
+ { XFER_UDMA_2, 0x16494e31 },
+ { XFER_UDMA_1, 0x164d4e31 },
+ { XFER_UDMA_0, 0x16514e31 },
+
+ { XFER_MW_DMA_2, 0x26514e21 },
+ { XFER_MW_DMA_1, 0x26514e33 },
+ { XFER_MW_DMA_0, 0x26514e97 },
+
+ { XFER_PIO_4, 0x06514e21 },
+ { XFER_PIO_3, 0x06514e22 },
+ { XFER_PIO_2, 0x06514e33 },
+ { XFER_PIO_1, 0x06914e43 },
+ { XFER_PIO_0, 0x06914e57 },
+ { 0, 0x06514e57 }
+};
+
+static const struct hpt_clock hpt370_timings_66[] = {
+ { XFER_UDMA_5, 0x14846231 },
+ { XFER_UDMA_4, 0x14886231 },
+ { XFER_UDMA_3, 0x148c6231 },
+ { XFER_UDMA_2, 0x148c6231 },
+ { XFER_UDMA_1, 0x14906231 },
+ { XFER_UDMA_0, 0x14986231 },
+
+ { XFER_MW_DMA_2, 0x26514e21 },
+ { XFER_MW_DMA_1, 0x26514e33 },
+ { XFER_MW_DMA_0, 0x26514e97 },
+
+ { XFER_PIO_4, 0x06514e21 },
+ { XFER_PIO_3, 0x06514e22 },
+ { XFER_PIO_2, 0x06514e33 },
+ { XFER_PIO_1, 0x06914e43 },
+ { XFER_PIO_0, 0x06914e57 },
+ { 0, 0x06514e57 }
+};
+
+/* these are the current (4 sep 2001) timings from highpoint */
+static const struct hpt_clock hpt370a_timings_33[] = {
+ { XFER_UDMA_5, 0x12446231 },
+ { XFER_UDMA_4, 0x12446231 },
+ { XFER_UDMA_3, 0x126c6231 },
+ { XFER_UDMA_2, 0x12486231 },
+ { XFER_UDMA_1, 0x124c6233 },
+ { XFER_UDMA_0, 0x12506297 },
+
+ { XFER_MW_DMA_2, 0x22406c31 },
+ { XFER_MW_DMA_1, 0x22406c33 },
+ { XFER_MW_DMA_0, 0x22406c97 },
+
+ { XFER_PIO_4, 0x06414e31 },
+ { XFER_PIO_3, 0x06414e42 },
+ { XFER_PIO_2, 0x06414e53 },
+ { XFER_PIO_1, 0x06814e93 },
+ { XFER_PIO_0, 0x06814ea7 },
+ { 0, 0x06814ea7 }
+};
+
+/* 2x 33MHz timings */
+static const struct hpt_clock hpt370a_timings_66[] = {
+ { XFER_UDMA_5, 0x1488e673 },
+ { XFER_UDMA_4, 0x1488e673 },
+ { XFER_UDMA_3, 0x1498e673 },
+ { XFER_UDMA_2, 0x1490e673 },
+ { XFER_UDMA_1, 0x1498e677 },
+ { XFER_UDMA_0, 0x14a0e73f },
+
+ { XFER_MW_DMA_2, 0x2480fa73 },
+ { XFER_MW_DMA_1, 0x2480fa77 },
+ { XFER_MW_DMA_0, 0x2480fb3f },
+
+ { XFER_PIO_4, 0x0c82be73 },
+ { XFER_PIO_3, 0x0c82be95 },
+ { XFER_PIO_2, 0x0c82beb7 },
+ { XFER_PIO_1, 0x0d02bf37 },
+ { XFER_PIO_0, 0x0d02bf5f },
+ { 0, 0x0d02bf5f }
+};
+
+static const struct hpt_clock hpt370a_timings_50[] = {
+ { XFER_UDMA_5, 0x12848242 },
+ { XFER_UDMA_4, 0x12ac8242 },
+ { XFER_UDMA_3, 0x128c8242 },
+ { XFER_UDMA_2, 0x120c8242 },
+ { XFER_UDMA_1, 0x12148254 },
+ { XFER_UDMA_0, 0x121882ea },
+
+ { XFER_MW_DMA_2, 0x22808242 },
+ { XFER_MW_DMA_1, 0x22808254 },
+ { XFER_MW_DMA_0, 0x228082ea },
+
+ { XFER_PIO_4, 0x0a81f442 },
+ { XFER_PIO_3, 0x0a81f443 },
+ { XFER_PIO_2, 0x0a81f454 },
+ { XFER_PIO_1, 0x0ac1f465 },
+ { XFER_PIO_0, 0x0ac1f48a },
+ { 0, 0x0ac1f48a }
+};
+
+static const struct hpt_clock hpt372_timings_33[] = {
+ { XFER_UDMA_6, 0x1c81dc62 },
+ { XFER_UDMA_5, 0x1c6ddc62 },
+ { XFER_UDMA_4, 0x1c8ddc62 },
+ { XFER_UDMA_3, 0x1c8edc62 }, /* checkme */
+ { XFER_UDMA_2, 0x1c91dc62 },
+ { XFER_UDMA_1, 0x1c9adc62 }, /* checkme */
+ { XFER_UDMA_0, 0x1c82dc62 }, /* checkme */
+
+ { XFER_MW_DMA_2, 0x2c829262 },
+ { XFER_MW_DMA_1, 0x2c829266 }, /* checkme */
+ { XFER_MW_DMA_0, 0x2c82922e }, /* checkme */
+
+ { XFER_PIO_4, 0x0c829c62 },
+ { XFER_PIO_3, 0x0c829c84 },
+ { XFER_PIO_2, 0x0c829ca6 },
+ { XFER_PIO_1, 0x0d029d26 },
+ { XFER_PIO_0, 0x0d029d5e },
+ { 0, 0x0d029d5e }
+};
+
+static const struct hpt_clock hpt372_timings_50[] = {
+ { XFER_UDMA_5, 0x12848242 },
+ { XFER_UDMA_4, 0x12ac8242 },
+ { XFER_UDMA_3, 0x128c8242 },
+ { XFER_UDMA_2, 0x120c8242 },
+ { XFER_UDMA_1, 0x12148254 },
+ { XFER_UDMA_0, 0x121882ea },
+
+ { XFER_MW_DMA_2, 0x22808242 },
+ { XFER_MW_DMA_1, 0x22808254 },
+ { XFER_MW_DMA_0, 0x228082ea },
+
+ { XFER_PIO_4, 0x0a81f442 },
+ { XFER_PIO_3, 0x0a81f443 },
+ { XFER_PIO_2, 0x0a81f454 },
+ { XFER_PIO_1, 0x0ac1f465 },
+ { XFER_PIO_0, 0x0ac1f48a },
+ { 0, 0x0a81f443 }
+};
+
+static const struct hpt_clock hpt372_timings_66[] = {
+ { XFER_UDMA_6, 0x1c869c62 },
+ { XFER_UDMA_5, 0x1cae9c62 },
+ { XFER_UDMA_4, 0x1c8a9c62 },
+ { XFER_UDMA_3, 0x1c8e9c62 },
+ { XFER_UDMA_2, 0x1c929c62 },
+ { XFER_UDMA_1, 0x1c9a9c62 },
+ { XFER_UDMA_0, 0x1c829c62 },
+
+ { XFER_MW_DMA_2, 0x2c829c62 },
+ { XFER_MW_DMA_1, 0x2c829c66 },
+ { XFER_MW_DMA_0, 0x2c829d2e },
+
+ { XFER_PIO_4, 0x0c829c62 },
+ { XFER_PIO_3, 0x0c829c84 },
+ { XFER_PIO_2, 0x0c829ca6 },
+ { XFER_PIO_1, 0x0d029d26 },
+ { XFER_PIO_0, 0x0d029d5e },
+ { 0, 0x0d029d26 }
+};
+
+static const struct hpt_clock hpt374_timings_33[] = {
+ { XFER_UDMA_6, 0x12808242 },
+ { XFER_UDMA_5, 0x12848242 },
+ { XFER_UDMA_4, 0x12ac8242 },
+ { XFER_UDMA_3, 0x128c8242 },
+ { XFER_UDMA_2, 0x120c8242 },
+ { XFER_UDMA_1, 0x12148254 },
+ { XFER_UDMA_0, 0x121882ea },
+
+ { XFER_MW_DMA_2, 0x22808242 },
+ { XFER_MW_DMA_1, 0x22808254 },
+ { XFER_MW_DMA_0, 0x228082ea },
+
+ { XFER_PIO_4, 0x0a81f442 },
+ { XFER_PIO_3, 0x0a81f443 },
+ { XFER_PIO_2, 0x0a81f454 },
+ { XFER_PIO_1, 0x0ac1f465 },
+ { XFER_PIO_0, 0x0ac1f48a },
+ { 0, 0x06814e93 }
+};
+
+static const struct hpt_chip hpt370 = {
+ "HPT370",
+ 48,
+ {
+ hpt370_timings_33,
+ NULL,
+ NULL,
+ hpt370_timings_66
+ }
+};
+
+static const struct hpt_chip hpt370a = {
+ "HPT370A",
+ 48,
+ {
+ hpt370a_timings_33,
+ NULL,
+ hpt370a_timings_50,
+ hpt370a_timings_66
+ }
+};
+
+static const struct hpt_chip hpt372 = {
+ "HPT372",
+ 55,
+ {
+ hpt372_timings_33,
+ NULL,
+ hpt372_timings_50,
+ hpt372_timings_66
+ }
+};
+
+static const struct hpt_chip hpt302 = {
+ "HPT302",
+ 66,
+ {
+ hpt372_timings_33,
+ NULL,
+ hpt372_timings_50,
+ hpt372_timings_66
+ }
+};
+
+static const struct hpt_chip hpt371 = {
+ "HPT371",
+ 66,
+ {
+ hpt372_timings_33,
+ NULL,
+ hpt372_timings_50,
+ hpt372_timings_66
+ }
+};
+
+static const struct hpt_chip hpt372a = {
+ "HPT372A",
+ 66,
+ {
+ hpt372_timings_33,
+ NULL,
+ hpt372_timings_50,
+ hpt372_timings_66
+ }
+};
+
+static const struct hpt_chip hpt374 = {
+ "HPT374",
+ 48,
+ {
+ hpt374_timings_33,
+ NULL,
+ NULL,
+ NULL
+ }
+};
+
+/**
+ * hpt37x_find_mode - reset the hpt37x bus
+ * @ap: ATA port
+ * @speed: transfer mode
+ *
+ * Return the 32bit register programming information for this channel
+ * that matches the speed provided.
+ */
+
+static u32 hpt37x_find_mode(struct ata_port *ap, int speed)
+{
+ struct hpt_clock *clocks = ap->host->private_data;
+
+ while(clocks->xfer_speed) {
+ if (clocks->xfer_speed == speed)
+ return clocks->timing;
+ clocks++;
+ }
+ BUG();
+ return 0xffffffffU; /* silence compiler warning */
+}
+
+static int hpt_dma_blacklisted(const struct ata_device *dev, char *modestr, const char *list[])
+{
+ unsigned char model_num[40];
+ char *s;
+ unsigned int len;
+ int i = 0;
+
+ ata_id_string(dev->id, model_num, ATA_ID_PROD_OFS,
+ sizeof(model_num));
+ s = &model_num[0];
+ len = strnlen(s, sizeof(model_num));
+
+ /* ATAPI specifies that empty space is blank-filled; remove blanks */
+ while ((len > 0) && (s[len - 1] == ' ')) {
+ len--;
+ s[len] = 0;
+ }
+
+ while(list[i] != NULL) {
+ if (!strncmp(list[i], s, len)) {
+ printk(KERN_WARNING DRV_NAME ": %s is not supported for %s.\n",
+ modestr, list[i]);
+ return 1;
+ }
+ i++;
+ }
+ return 0;
+}
+
+static const char *bad_ata33[] = {
+ "Maxtor 92720U8", "Maxtor 92040U6", "Maxtor 91360U4", "Maxtor 91020U3", "Maxtor 90845U3", "Maxtor 90650U2",
+ "Maxtor 91360D8", "Maxtor 91190D7", "Maxtor 91020D6", "Maxtor 90845D5", "Maxtor 90680D4", "Maxtor 90510D3", "Maxtor 90340D2",
+ "Maxtor 91152D8", "Maxtor 91008D7", "Maxtor 90845D6", "Maxtor 90840D6", "Maxtor 90720D5", "Maxtor 90648D5", "Maxtor 90576D4",
+ "Maxtor 90510D4",
+ "Maxtor 90432D3", "Maxtor 90288D2", "Maxtor 90256D2",
+ "Maxtor 91000D8", "Maxtor 90910D8", "Maxtor 90875D7", "Maxtor 90840D7", "Maxtor 90750D6", "Maxtor 90625D5", "Maxtor 90500D4",
+ "Maxtor 91728D8", "Maxtor 91512D7", "Maxtor 91303D6", "Maxtor 91080D5", "Maxtor 90845D4", "Maxtor 90680D4", "Maxtor 90648D3", "Maxtor 90432D2",
+ NULL
+};
+
+static const char *bad_ata100_5[] = {
+ "IBM-DTLA-307075",
+ "IBM-DTLA-307060",
+ "IBM-DTLA-307045",
+ "IBM-DTLA-307030",
+ "IBM-DTLA-307020",
+ "IBM-DTLA-307015",
+ "IBM-DTLA-305040",
+ "IBM-DTLA-305030",
+ "IBM-DTLA-305020",
+ "IC35L010AVER07-0",
+ "IC35L020AVER07-0",
+ "IC35L030AVER07-0",
+ "IC35L040AVER07-0",
+ "IC35L060AVER07-0",
+ "WDC AC310200R",
+ NULL
+};
+
+/**
+ * hpt370_filter - mode selection filter
+ * @ap: ATA interface
+ * @adev: ATA device
+ *
+ * Block UDMA on devices that cause trouble with this controller.
+ */
+
+static unsigned long hpt370_filter(const struct ata_port *ap, struct ata_device *adev, unsigned long mask)
+{
+ if (adev->class != ATA_DEV_ATA) {
+ if (hpt_dma_blacklisted(adev, "UDMA", bad_ata33))
+ mask &= ~ATA_MASK_UDMA;
+ if (hpt_dma_blacklisted(adev, "UDMA100", bad_ata100_5))
+ mask &= ~(0x1F << ATA_SHIFT_UDMA);
+ }
+ return ata_pci_default_filter(ap, adev, mask);
+}
+
+/**
+ * hpt370a_filter - mode selection filter
+ * @ap: ATA interface
+ * @adev: ATA device
+ *
+ * Block UDMA on devices that cause trouble with this controller.
+ */
+
+static unsigned long hpt370a_filter(const struct ata_port *ap, struct ata_device *adev, unsigned long mask)
+{
+ if (adev->class != ATA_DEV_ATA) {
+ if (hpt_dma_blacklisted(adev, "UDMA100", bad_ata100_5))
+ mask &= ~ (0x1F << ATA_SHIFT_UDMA);
+ }
+ return ata_pci_default_filter(ap, adev, mask);
+}
+
+/**
+ * hpt37x_pre_reset - reset the hpt37x bus
+ * @ap: ATA port to reset
+ *
+ * Perform the initial reset handling for the 370/372 and 374 func 0
+ */
+
+static int hpt37x_pre_reset(struct ata_port *ap)
+{
+ u8 scr2, ata66;
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+
+ pci_read_config_byte(pdev, 0x5B, &scr2);
+ pci_write_config_byte(pdev, 0x5B, scr2 & ~0x01);
+ /* Cable register now active */
+ pci_read_config_byte(pdev, 0x5A, &ata66);
+ /* Restore state */
+ pci_write_config_byte(pdev, 0x5B, scr2);
+
+ if (ata66 & (1 << ap->port_no))
+ ap->cbl = ATA_CBL_PATA40;
+ else
+ ap->cbl = ATA_CBL_PATA80;
+
+ /* Reset the state machine */
+ pci_write_config_byte(pdev, 0x50, 0x37);
+ pci_write_config_byte(pdev, 0x54, 0x37);
+ udelay(100);
+
+ return ata_std_prereset(ap);
+}
+
+/**
+ * hpt37x_error_handler - reset the hpt374
+ * @ap: ATA port to reset
+ *
+ * Perform probe for HPT37x, except for HPT374 channel 2
+ */
+
+static void hpt37x_error_handler(struct ata_port *ap)
+{
+ ata_bmdma_drive_eh(ap, hpt37x_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
+}
+
+static int hpt374_pre_reset(struct ata_port *ap)
+{
+ u16 mcr3, mcr6;
+ u8 ata66;
+
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ /* Do the extra channel work */
+ pci_read_config_word(pdev, 0x52, &mcr3);
+ pci_read_config_word(pdev, 0x56, &mcr6);
+ /* Set bit 15 of 0x52 to enable TCBLID as input
+ Set bit 15 of 0x56 to enable FCBLID as input
+ */
+ pci_write_config_word(pdev, 0x52, mcr3 | 0x8000);
+ pci_write_config_word(pdev, 0x56, mcr6 | 0x8000);
+ pci_read_config_byte(pdev, 0x5A, &ata66);
+ /* Reset TCBLID/FCBLID to output */
+ pci_write_config_word(pdev, 0x52, mcr3);
+ pci_write_config_word(pdev, 0x56, mcr6);
+
+ if (ata66 & (1 << ap->port_no))
+ ap->cbl = ATA_CBL_PATA40;
+ else
+ ap->cbl = ATA_CBL_PATA80;
+
+ /* Reset the state machine */
+ pci_write_config_byte(pdev, 0x50, 0x37);
+ pci_write_config_byte(pdev, 0x54, 0x37);
+ udelay(100);
+
+ return ata_std_prereset(ap);
+}
+
+/**
+ * hpt374_error_handler - reset the hpt374
+ * @classes:
+ *
+ * The 374 cable detect is a little different due to the extra
+ * channels. The function 0 channels work like usual but function 1
+ * is special
+ */
+
+static void hpt374_error_handler(struct ata_port *ap)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+
+ if (!(PCI_FUNC(pdev->devfn) & 1))
+ hpt37x_error_handler(ap);
+ else
+ ata_bmdma_drive_eh(ap, hpt374_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
+}
+
+/**
+ * hpt370_set_piomode - PIO setup
+ * @ap: ATA interface
+ * @adev: device on the interface
+ *
+ * Perform PIO mode setup.
+ */
+
+static void hpt370_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u32 addr1, addr2;
+ u32 reg;
+ u32 mode;
+ u8 fast;
+
+ addr1 = 0x40 + 4 * (adev->devno + 2 * ap->port_no);
+ addr2 = 0x51 + 4 * ap->port_no;
+
+ /* Fast interrupt prediction disable, hold off interrupt disable */
+ pci_read_config_byte(pdev, addr2, &fast);
+ fast &= ~0x02;
+ fast |= 0x01;
+ pci_write_config_byte(pdev, addr2, fast);
+
+ pci_read_config_dword(pdev, addr1, &reg);
+ mode = hpt37x_find_mode(ap, adev->pio_mode);
+ mode &= ~0x8000000; /* No FIFO in PIO */
+ mode &= ~0x30070000; /* Leave config bits alone */
+ reg &= 0x30070000; /* Strip timing bits */
+ pci_write_config_dword(pdev, addr1, reg | mode);
+}
+
+/**
+ * hpt370_set_dmamode - DMA timing setup
+ * @ap: ATA interface
+ * @adev: Device being configured
+ *
+ * Set up the channel for MWDMA or UDMA modes. Much the same as with
+ * PIO, load the mode number and then set MWDMA or UDMA flag.
+ */
+
+static void hpt370_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u32 addr1, addr2;
+ u32 reg;
+ u32 mode;
+ u8 fast;
+
+ addr1 = 0x40 + 4 * (adev->devno + 2 * ap->port_no);
+ addr2 = 0x51 + 4 * ap->port_no;
+
+ /* Fast interrupt prediction disable, hold off interrupt disable */
+ pci_read_config_byte(pdev, addr2, &fast);
+ fast &= ~0x02;
+ fast |= 0x01;
+ pci_write_config_byte(pdev, addr2, fast);
+
+ pci_read_config_dword(pdev, addr1, &reg);
+ mode = hpt37x_find_mode(ap, adev->dma_mode);
+ mode |= 0x8000000; /* FIFO in MWDMA or UDMA */
+ mode &= ~0xC0000000; /* Leave config bits alone */
+ reg &= 0xC0000000; /* Strip timing bits */
+ pci_write_config_dword(pdev, addr1, reg | mode);
+}
+
+/**
+ * hpt370_bmdma_start - DMA engine begin
+ * @qc: ATA command
+ *
+ * The 370 and 370A want us to reset the DMA engine each time we
+ * use it. The 372 and later are fine.
+ */
+
+static void hpt370_bmdma_start(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ pci_write_config_byte(pdev, 0x50 + 4 * ap->port_no, 0x37);
+ udelay(10);
+ ata_bmdma_start(qc);
+}
+
+/**
+ * hpt370_bmdma_end - DMA engine stop
+ * @qc: ATA command
+ *
+ * Work around the HPT370 DMA engine.
+ */
+
+static void hpt370_bmdma_stop(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u8 dma_stat = inb(ap->ioaddr.bmdma_addr + 2);
+ u8 dma_cmd;
+ unsigned long bmdma = ap->ioaddr.bmdma_addr;
+
+ if (dma_stat & 0x01) {
+ udelay(20);
+ dma_stat = inb(bmdma + 2);
+ }
+ if (dma_stat & 0x01) {
+ /* Clear the engine */
+ pci_write_config_byte(pdev, 0x50 + 4 * ap->port_no, 0x37);
+ udelay(10);
+ /* Stop DMA */
+ dma_cmd = inb(bmdma );
+ outb(dma_cmd & 0xFE, bmdma);
+ /* Clear Error */
+ dma_stat = inb(bmdma + 2);
+ outb(dma_stat | 0x06 , bmdma + 2);
+ /* Clear the engine */
+ pci_write_config_byte(pdev, 0x50 + 4 * ap->port_no, 0x37);
+ udelay(10);
+ }
+ ata_bmdma_stop(qc);
+}
+
+/**
+ * hpt372_set_piomode - PIO setup
+ * @ap: ATA interface
+ * @adev: device on the interface
+ *
+ * Perform PIO mode setup.
+ */
+
+static void hpt372_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u32 addr1, addr2;
+ u32 reg;
+ u32 mode;
+ u8 fast;
+
+ addr1 = 0x40 + 4 * (adev->devno + 2 * ap->port_no);
+ addr2 = 0x51 + 4 * ap->port_no;
+
+ /* Fast interrupt prediction disable, hold off interrupt disable */
+ pci_read_config_byte(pdev, addr2, &fast);
+ fast &= ~0x07;
+ pci_write_config_byte(pdev, addr2, fast);
+
+ pci_read_config_dword(pdev, addr1, &reg);
+ mode = hpt37x_find_mode(ap, adev->pio_mode);
+
+ printk("Find mode for %d reports %X\n", adev->pio_mode, mode);
+ mode &= ~0x80000000; /* No FIFO in PIO */
+ mode &= ~0x30070000; /* Leave config bits alone */
+ reg &= 0x30070000; /* Strip timing bits */
+ pci_write_config_dword(pdev, addr1, reg | mode);
+}
+
+/**
+ * hpt372_set_dmamode - DMA timing setup
+ * @ap: ATA interface
+ * @adev: Device being configured
+ *
+ * Set up the channel for MWDMA or UDMA modes. Much the same as with
+ * PIO, load the mode number and then set MWDMA or UDMA flag.
+ */
+
+static void hpt372_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u32 addr1, addr2;
+ u32 reg;
+ u32 mode;
+ u8 fast;
+
+ addr1 = 0x40 + 4 * (adev->devno + 2 * ap->port_no);
+ addr2 = 0x51 + 4 * ap->port_no;
+
+ /* Fast interrupt prediction disable, hold off interrupt disable */
+ pci_read_config_byte(pdev, addr2, &fast);
+ fast &= ~0x07;
+ pci_write_config_byte(pdev, addr2, fast);
+
+ pci_read_config_dword(pdev, addr1, &reg);
+ mode = hpt37x_find_mode(ap, adev->dma_mode);
+ printk("Find mode for DMA %d reports %X\n", adev->dma_mode, mode);
+ mode &= ~0xC0000000; /* Leave config bits alone */
+ mode |= 0x80000000; /* FIFO in MWDMA or UDMA */
+ reg &= 0xC0000000; /* Strip timing bits */
+ pci_write_config_dword(pdev, addr1, reg | mode);
+}
+
+/**
+ * hpt37x_bmdma_end - DMA engine stop
+ * @qc: ATA command
+ *
+ * Clean up after the HPT372 and later DMA engine
+ */
+
+static void hpt37x_bmdma_stop(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ int mscreg = 0x50 + 2 * ap->port_no;
+ u8 bwsr_stat, msc_stat;
+
+ pci_read_config_byte(pdev, 0x6A, &bwsr_stat);
+ pci_read_config_byte(pdev, mscreg, &msc_stat);
+ if (bwsr_stat & (1 << ap->port_no))
+ pci_write_config_byte(pdev, mscreg, msc_stat | 0x30);
+ ata_bmdma_stop(qc);
+}
+
+
+static struct scsi_host_template hpt37x_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .max_sectors = ATA_MAX_SECTORS,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .bios_param = ata_std_bios_param,
+};
+
+/*
+ * Configuration for HPT370
+ */
+
+static struct ata_port_operations hpt370_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = hpt370_set_piomode,
+ .set_dmamode = hpt370_set_dmamode,
+ .mode_filter = hpt370_filter,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = hpt37x_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = hpt370_bmdma_start,
+ .bmdma_stop = hpt370_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+/*
+ * Configuration for HPT370A. Close to 370 but less filters
+ */
+
+static struct ata_port_operations hpt370a_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = hpt370_set_piomode,
+ .set_dmamode = hpt370_set_dmamode,
+ .mode_filter = hpt370a_filter,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = hpt37x_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = hpt370_bmdma_start,
+ .bmdma_stop = hpt370_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+/*
+ * Configuration for HPT372, HPT371, HPT302. Slightly different PIO
+ * and DMA mode setting functionality.
+ */
+
+static struct ata_port_operations hpt372_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = hpt372_set_piomode,
+ .set_dmamode = hpt372_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = hpt37x_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = hpt37x_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+/*
+ * Configuration for HPT374. Mode setting works like 372 and friends
+ * but we have a different cable detection procedure.
+ */
+
+static struct ata_port_operations hpt374_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = hpt372_set_piomode,
+ .set_dmamode = hpt372_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = hpt374_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = hpt37x_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+/**
+ * htp37x_clock_slot - Turn timing to PC clock entry
+ * @freq: Reported frequency timing
+ * @base: Base timing
+ *
+ * Turn the timing data intoa clock slot (0 for 33, 1 for 40, 2 for 50
+ * and 3 for 66Mhz)
+ */
+
+static int hpt37x_clock_slot(unsigned int freq, unsigned int base)
+{
+ unsigned int f = (base * freq) / 192; /* Mhz */
+ if (f < 40)
+ return 0; /* 33Mhz slot */
+ if (f < 45)
+ return 1; /* 40Mhz slot */
+ if (f < 55)
+ return 2; /* 50Mhz slot */
+ return 3; /* 60Mhz slot */
+}
+
+/**
+ * hpt37x_calibrate_dpll - Calibrate the DPLL loop
+ * @dev: PCI device
+ *
+ * Perform a calibration cycle on the HPT37x DPLL. Returns 1 if this
+ * succeeds
+ */
+
+static int hpt37x_calibrate_dpll(struct pci_dev *dev)
+{
+ u8 reg5b;
+ u32 reg5c;
+ int tries;
+
+ for(tries = 0; tries < 0x5000; tries++) {
+ udelay(50);
+ pci_read_config_byte(dev, 0x5b, &reg5b);
+ if (reg5b & 0x80) {
+ /* See if it stays set */
+ for(tries = 0; tries < 0x1000; tries ++) {
+ pci_read_config_byte(dev, 0x5b, &reg5b);
+ /* Failed ? */
+ if ((reg5b & 0x80) == 0)
+ return 0;
+ }
+ /* Turn off tuning, we have the DPLL set */
+ pci_read_config_dword(dev, 0x5c, &reg5c);
+ pci_write_config_dword(dev, 0x5c, reg5c & ~ 0x100);
+ return 1;
+ }
+ }
+ /* Never went stable */
+ return 0;
+}
+/**
+ * hpt37x_init_one - Initialise an HPT37X/302
+ * @dev: PCI device
+ * @id: Entry in match table
+ *
+ * Initialise an HPT37x device. There are some interesting complications
+ * here. Firstly the chip may report 366 and be one of several variants.
+ * Secondly all the timings depend on the clock for the chip which we must
+ * detect and look up
+ *
+ * This is the known chip mappings. It may be missing a couple of later
+ * releases.
+ *
+ * Chip version PCI Rev Notes
+ * HPT366 4 (HPT366) 0 Other driver
+ * HPT366 4 (HPT366) 1 Other driver
+ * HPT368 4 (HPT366) 2 Other driver
+ * HPT370 4 (HPT366) 3 UDMA100
+ * HPT370A 4 (HPT366) 4 UDMA100
+ * HPT372 4 (HPT366) 5 UDMA133 (1)
+ * HPT372N 4 (HPT366) 6 Other driver
+ * HPT372A 5 (HPT372) 1 UDMA133 (1)
+ * HPT372N 5 (HPT372) 2 Other driver
+ * HPT302 6 (HPT302) 1 UDMA133
+ * HPT302N 6 (HPT302) 2 Other driver
+ * HPT371 7 (HPT371) * UDMA133
+ * HPT374 8 (HPT374) * UDMA133 4 channel
+ * HPT372N 9 (HPT372N) * Other driver
+ *
+ * (1) UDMA133 support depends on the bus clock
+ */
+
+static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ /* HPT370 - UDMA100 */
+ static struct ata_port_info info_hpt370 = {
+ .sht = &hpt37x_sht,
+ .flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x3f,
+ .port_ops = &hpt370_port_ops
+ };
+ /* HPT370A - UDMA100 */
+ static struct ata_port_info info_hpt370a = {
+ .sht = &hpt37x_sht,
+ .flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x3f,
+ .port_ops = &hpt370a_port_ops
+ };
+ /* HPT371, 372 and friends - UDMA133 */
+ static struct ata_port_info info_hpt372 = {
+ .sht = &hpt37x_sht,
+ .flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x7f,
+ .port_ops = &hpt372_port_ops
+ };
+ /* HPT371, 372 and friends - UDMA100 at 50MHz clock */
+ static struct ata_port_info info_hpt372_50 = {
+ .sht = &hpt37x_sht,
+ .flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x3f,
+ .port_ops = &hpt372_port_ops
+ };
+ /* HPT374 - UDMA133 */
+ static struct ata_port_info info_hpt374 = {
+ .sht = &hpt37x_sht,
+ .flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x7f,
+ .port_ops = &hpt374_port_ops
+ };
+
+ static const int MHz[4] = { 33, 40, 50, 66 };
+
+ struct ata_port_info *port_info[2];
+ struct ata_port_info *port;
+
+ u8 irqmask;
+ u32 class_rev;
+ u32 freq;
+
+ const struct hpt_chip *chip_table;
+ int clock_slot;
+
+ pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
+ class_rev &= 0xFF;
+
+ if (dev->device == PCI_DEVICE_ID_TTI_HPT366) {
+ /* May be a later chip in disguise. Check */
+ /* Older chips are in the HPT366 driver. Ignore them */
+ if (class_rev < 3)
+ return -ENODEV;
+ /* N series chips have their own driver. Ignore */
+ if (class_rev == 6)
+ return -ENODEV;
+
+ switch(class_rev) {
+ case 3:
+ port = &info_hpt370;
+ chip_table = &hpt370;
+ break;
+ case 4:
+ port = &info_hpt370a;
+ chip_table = &hpt370a;
+ break;
+ case 5:
+ port = &info_hpt372;
+ chip_table = &hpt372;
+ break;
+ default:
+ printk(KERN_ERR "pata_hpt37x: Unknown HPT366 subtype please report (%d).\n", class_rev);
+ return -ENODEV;
+ }
+ } else {
+ switch(dev->device) {
+ case PCI_DEVICE_ID_TTI_HPT372:
+ /* 372N if rev >= 2*/
+ if (class_rev >= 2)
+ return -ENODEV;
+ port = &info_hpt372;
+ chip_table = &hpt372a;
+ break;
+ case PCI_DEVICE_ID_TTI_HPT302:
+ /* 302N if rev > 1 */
+ if (class_rev > 1)
+ return -ENODEV;
+ port = &info_hpt372;
+ /* Check this */
+ chip_table = &hpt302;
+ break;
+ case PCI_DEVICE_ID_TTI_HPT371:
+ port = &info_hpt372;
+ chip_table = &hpt371;
+ break;
+ case PCI_DEVICE_ID_TTI_HPT374:
+ chip_table = &hpt374;
+ port = &info_hpt374;
+ break;
+ default:
+ printk(KERN_ERR "pata_hpt37x: PCI table is bogus please report (%d).\n", dev->device);
+ return -ENODEV;
+ }
+ }
+ /* Ok so this is a chip we support */
+
+ pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, (L1_CACHE_BYTES / 4));
+ pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x78);
+ pci_write_config_byte(dev, PCI_MIN_GNT, 0x08);
+ pci_write_config_byte(dev, PCI_MAX_LAT, 0x08);
+
+ pci_read_config_byte(dev, 0x5A, &irqmask);
+ irqmask &= ~0x10;
+ pci_write_config_byte(dev, 0x5a, irqmask);
+
+ /*
+ * default to pci clock. make sure MA15/16 are set to output
+ * to prevent drives having problems with 40-pin cables. Needed
+ * for some drives such as IBM-DTLA which will not enter ready
+ * state on reset when PDIAG is a input.
+ */
+
+ pci_write_config_byte(dev, 0x5b, 0x23);
+
+ pci_read_config_dword(dev, 0x70, &freq);
+ if ((freq >> 12) != 0xABCDE) {
+ int i;
+ u8 sr;
+ u32 total = 0;
+
+ printk(KERN_WARNING "pata_hpt37x: BIOS has not set timing clocks.\n");
+
+ /* This is the process the HPT371 BIOS is reported to use */
+ for(i = 0; i < 128; i++) {
+ pci_read_config_byte(dev, 0x78, &sr);
+ total += sr;
+ udelay(15);
+ }
+ freq = total / 128;
+ }
+ freq &= 0x1FF;
+
+ /*
+ * Turn the frequency check into a band and then find a timing
+ * table to match it.
+ */
+
+ clock_slot = hpt37x_clock_slot(freq, chip_table->base);
+ if (chip_table->clocks[clock_slot] == NULL) {
+ /*
+ * We need to try PLL mode instead
+ */
+ unsigned int f_low = (MHz[clock_slot] * chip_table->base) / 192;
+ unsigned int f_high = f_low + 2;
+ int adjust;
+
+ for(adjust = 0; adjust < 8; adjust++) {
+ if (hpt37x_calibrate_dpll(dev))
+ break;
+ /* See if it'll settle at a fractionally different clock */
+ if ((adjust & 3) == 3) {
+ f_low --;
+ f_high ++;
+ }
+ pci_write_config_dword(dev, 0x5C, (f_high << 16) | f_low);
+ }
+ if (adjust == 8) {
+ printk(KERN_WARNING "hpt37x: DPLL did not stabilize.\n");
+ return -ENODEV;
+ }
+ /* Check if this works for all cases */
+ port->private_data = (void *)hpt370_timings_66;
+
+ printk(KERN_INFO "hpt37x: Bus clock %dMHz, using DPLL.\n", MHz[clock_slot]);
+ } else {
+ port->private_data = (void *)chip_table->clocks[clock_slot];
+ /*
+ * Perform a final fixup. The 371 and 372 clock determines
+ * if UDMA133 is available.
+ */
+
+ if (clock_slot == 2 && chip_table == &hpt372) { /* 50Mhz */
+ printk(KERN_WARNING "pata_hpt37x: No UDMA133 support available with 50MHz bus clock.\n");
+ if (port == &info_hpt372)
+ port = &info_hpt372_50;
+ else BUG();
+ }
+ printk(KERN_INFO "hpt37x: %s: Bus clock %dMHz.\n", chip_table->name, MHz[clock_slot]);
+ }
+ port_info[0] = port_info[1] = port;
+ /* Now kick off ATA set up */
+ return ata_pci_init_one(dev, port_info, 2);
+}
+
+static struct pci_device_id hpt37x[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT366), },
+ { PCI_DEVICE(PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT371), },
+ { PCI_DEVICE(PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT372), },
+ { PCI_DEVICE(PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT374), },
+ { PCI_DEVICE(PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT302), },
+ { 0, },
+};
+
+static struct pci_driver hpt37x_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = hpt37x,
+ .probe = hpt37x_init_one,
+ .remove = ata_pci_remove_one
+};
+
+static int __init hpt37x_init(void)
+{
+ return pci_register_driver(&hpt37x_pci_driver);
+}
+
+
+static void __exit hpt37x_exit(void)
+{
+ pci_unregister_driver(&hpt37x_pci_driver);
+}
+
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("low-level driver for the Highpoint HPT37x/30x");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, hpt37x);
+MODULE_VERSION(DRV_VERSION);
+
+module_init(hpt37x_init);
+module_exit(hpt37x_exit);
diff --git a/drivers/ata/pata_hpt3x2n.c b/drivers/ata/pata_hpt3x2n.c
new file mode 100644
index 00000000000..5c5d4f6ab90
--- /dev/null
+++ b/drivers/ata/pata_hpt3x2n.c
@@ -0,0 +1,597 @@
+/*
+ * Libata driver for the highpoint 372N and 302N UDMA66 ATA controllers.
+ *
+ * This driver is heavily based upon:
+ *
+ * linux/drivers/ide/pci/hpt366.c Version 0.36 April 25, 2003
+ *
+ * Copyright (C) 1999-2003 Andre Hedrick <andre@linux-ide.org>
+ * Portions Copyright (C) 2001 Sun Microsystems, Inc.
+ * Portions Copyright (C) 2003 Red Hat Inc
+ *
+ *
+ * TODO
+ * 371N
+ * Work out best PLL policy
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+
+#define DRV_NAME "pata_hpt3x2n"
+#define DRV_VERSION "0.3"
+
+enum {
+ HPT_PCI_FAST = (1 << 31),
+ PCI66 = (1 << 1),
+ USE_DPLL = (1 << 0)
+};
+
+struct hpt_clock {
+ u8 xfer_speed;
+ u32 timing;
+};
+
+struct hpt_chip {
+ const char *name;
+ struct hpt_clock *clocks[3];
+};
+
+/* key for bus clock timings
+ * bit
+ * 0:3 data_high_time. inactive time of DIOW_/DIOR_ for PIO and MW
+ * DMA. cycles = value + 1
+ * 4:8 data_low_time. active time of DIOW_/DIOR_ for PIO and MW
+ * DMA. cycles = value + 1
+ * 9:12 cmd_high_time. inactive time of DIOW_/DIOR_ during task file
+ * register access.
+ * 13:17 cmd_low_time. active time of DIOW_/DIOR_ during task file
+ * register access.
+ * 18:21 udma_cycle_time. clock freq and clock cycles for UDMA xfer.
+ * during task file register access.
+ * 22:24 pre_high_time. time to initialize 1st cycle for PIO and MW DMA
+ * xfer.
+ * 25:27 cmd_pre_high_time. time to initialize 1st PIO cycle for task
+ * register access.
+ * 28 UDMA enable
+ * 29 DMA enable
+ * 30 PIO_MST enable. if set, the chip is in bus master mode during
+ * PIO.
+ * 31 FIFO enable.
+ */
+
+/* 66MHz DPLL clocks */
+
+static struct hpt_clock hpt3x2n_clocks[] = {
+ { XFER_UDMA_7, 0x1c869c62 },
+ { XFER_UDMA_6, 0x1c869c62 },
+ { XFER_UDMA_5, 0x1c8a9c62 },
+ { XFER_UDMA_4, 0x1c8a9c62 },
+ { XFER_UDMA_3, 0x1c8e9c62 },
+ { XFER_UDMA_2, 0x1c929c62 },
+ { XFER_UDMA_1, 0x1c9a9c62 },
+ { XFER_UDMA_0, 0x1c829c62 },
+
+ { XFER_MW_DMA_2, 0x2c829c62 },
+ { XFER_MW_DMA_1, 0x2c829c66 },
+ { XFER_MW_DMA_0, 0x2c829d2c },
+
+ { XFER_PIO_4, 0x0c829c62 },
+ { XFER_PIO_3, 0x0c829c84 },
+ { XFER_PIO_2, 0x0c829ca6 },
+ { XFER_PIO_1, 0x0d029d26 },
+ { XFER_PIO_0, 0x0d029d5e },
+ { 0, 0x0d029d5e }
+};
+
+/**
+ * hpt3x2n_find_mode - reset the hpt3x2n bus
+ * @ap: ATA port
+ * @speed: transfer mode
+ *
+ * Return the 32bit register programming information for this channel
+ * that matches the speed provided. For the moment the clocks table
+ * is hard coded but easy to change. This will be needed if we use
+ * different DPLLs
+ */
+
+static u32 hpt3x2n_find_mode(struct ata_port *ap, int speed)
+{
+ struct hpt_clock *clocks = hpt3x2n_clocks;
+
+ while(clocks->xfer_speed) {
+ if (clocks->xfer_speed == speed)
+ return clocks->timing;
+ clocks++;
+ }
+ BUG();
+ return 0xffffffffU; /* silence compiler warning */
+}
+
+/**
+ * hpt3x2n_pre_reset - reset the hpt3x2n bus
+ * @ap: ATA port to reset
+ *
+ * Perform the initial reset handling for the 3x2n series controllers.
+ * Reset the hardware and state machine, obtain the cable type.
+ */
+
+static int hpt3xn_pre_reset(struct ata_port *ap)
+{
+ u8 scr2, ata66;
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+
+ pci_read_config_byte(pdev, 0x5B, &scr2);
+ pci_write_config_byte(pdev, 0x5B, scr2 & ~0x01);
+ /* Cable register now active */
+ pci_read_config_byte(pdev, 0x5A, &ata66);
+ /* Restore state */
+ pci_write_config_byte(pdev, 0x5B, scr2);
+
+ if (ata66 & (1 << ap->port_no))
+ ap->cbl = ATA_CBL_PATA40;
+ else
+ ap->cbl = ATA_CBL_PATA80;
+
+ /* Reset the state machine */
+ pci_write_config_byte(pdev, 0x50, 0x37);
+ pci_write_config_byte(pdev, 0x54, 0x37);
+ udelay(100);
+
+ return ata_std_prereset(ap);
+}
+
+/**
+ * hpt3x2n_error_handler - probe the hpt3x2n bus
+ * @ap: ATA port to reset
+ *
+ * Perform the probe reset handling for the 3x2N
+ */
+
+static void hpt3x2n_error_handler(struct ata_port *ap)
+{
+ ata_bmdma_drive_eh(ap, hpt3xn_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
+}
+
+/**
+ * hpt3x2n_set_piomode - PIO setup
+ * @ap: ATA interface
+ * @adev: device on the interface
+ *
+ * Perform PIO mode setup.
+ */
+
+static void hpt3x2n_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u32 addr1, addr2;
+ u32 reg;
+ u32 mode;
+ u8 fast;
+
+ addr1 = 0x40 + 4 * (adev->devno + 2 * ap->port_no);
+ addr2 = 0x51 + 4 * ap->port_no;
+
+ /* Fast interrupt prediction disable, hold off interrupt disable */
+ pci_read_config_byte(pdev, addr2, &fast);
+ fast &= ~0x07;
+ pci_write_config_byte(pdev, addr2, fast);
+
+ pci_read_config_dword(pdev, addr1, &reg);
+ mode = hpt3x2n_find_mode(ap, adev->pio_mode);
+ mode &= ~0x8000000; /* No FIFO in PIO */
+ mode &= ~0x30070000; /* Leave config bits alone */
+ reg &= 0x30070000; /* Strip timing bits */
+ pci_write_config_dword(pdev, addr1, reg | mode);
+}
+
+/**
+ * hpt3x2n_set_dmamode - DMA timing setup
+ * @ap: ATA interface
+ * @adev: Device being configured
+ *
+ * Set up the channel for MWDMA or UDMA modes. Much the same as with
+ * PIO, load the mode number and then set MWDMA or UDMA flag.
+ */
+
+static void hpt3x2n_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u32 addr1, addr2;
+ u32 reg;
+ u32 mode;
+ u8 fast;
+
+ addr1 = 0x40 + 4 * (adev->devno + 2 * ap->port_no);
+ addr2 = 0x51 + 4 * ap->port_no;
+
+ /* Fast interrupt prediction disable, hold off interrupt disable */
+ pci_read_config_byte(pdev, addr2, &fast);
+ fast &= ~0x07;
+ pci_write_config_byte(pdev, addr2, fast);
+
+ pci_read_config_dword(pdev, addr1, &reg);
+ mode = hpt3x2n_find_mode(ap, adev->dma_mode);
+ mode |= 0x8000000; /* FIFO in MWDMA or UDMA */
+ mode &= ~0xC0000000; /* Leave config bits alone */
+ reg &= 0xC0000000; /* Strip timing bits */
+ pci_write_config_dword(pdev, addr1, reg | mode);
+}
+
+/**
+ * hpt3x2n_bmdma_end - DMA engine stop
+ * @qc: ATA command
+ *
+ * Clean up after the HPT3x2n and later DMA engine
+ */
+
+static void hpt3x2n_bmdma_stop(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ int mscreg = 0x50 + 2 * ap->port_no;
+ u8 bwsr_stat, msc_stat;
+
+ pci_read_config_byte(pdev, 0x6A, &bwsr_stat);
+ pci_read_config_byte(pdev, mscreg, &msc_stat);
+ if (bwsr_stat & (1 << ap->port_no))
+ pci_write_config_byte(pdev, mscreg, msc_stat | 0x30);
+ ata_bmdma_stop(qc);
+}
+
+/**
+ * hpt3x2n_set_clock - clock control
+ * @ap: ATA port
+ * @source: 0x21 or 0x23 for PLL or PCI sourced clock
+ *
+ * Switch the ATA bus clock between the PLL and PCI clock sources
+ * while correctly isolating the bus and resetting internal logic
+ *
+ * We must use the DPLL for
+ * - writing
+ * - second channel UDMA7 (SATA ports) or higher
+ * - 66MHz PCI
+ *
+ * or we will underclock the device and get reduced performance.
+ */
+
+static void hpt3x2n_set_clock(struct ata_port *ap, int source)
+{
+ unsigned long bmdma = ap->ioaddr.bmdma_addr;
+
+ /* Tristate the bus */
+ outb(0x80, bmdma+0x73);
+ outb(0x80, bmdma+0x77);
+
+ /* Switch clock and reset channels */
+ outb(source, bmdma+0x7B);
+ outb(0xC0, bmdma+0x79);
+
+ /* Reset state machines */
+ outb(0x37, bmdma+0x70);
+ outb(0x37, bmdma+0x74);
+
+ /* Complete reset */
+ outb(0x00, bmdma+0x79);
+
+ /* Reconnect channels to bus */
+ outb(0x00, bmdma+0x73);
+ outb(0x00, bmdma+0x77);
+}
+
+/* Check if our partner interface is busy */
+
+static int hpt3x2n_pair_idle(struct ata_port *ap)
+{
+ struct ata_host *host = ap->host;
+ struct ata_port *pair = host->ports[ap->port_no ^ 1];
+
+ if (pair->hsm_task_state == HSM_ST_IDLE)
+ return 1;
+ return 0;
+}
+
+static int hpt3x2n_use_dpll(struct ata_port *ap, int reading)
+{
+ long flags = (long)ap->host->private_data;
+ /* See if we should use the DPLL */
+ if (reading == 0)
+ return USE_DPLL; /* Needed for write */
+ if (flags & PCI66)
+ return USE_DPLL; /* Needed at 66Mhz */
+ return 0;
+}
+
+static unsigned int hpt3x2n_qc_issue_prot(struct ata_queued_cmd *qc)
+{
+ struct ata_taskfile *tf = &qc->tf;
+ struct ata_port *ap = qc->ap;
+ int flags = (long)ap->host->private_data;
+
+ if (hpt3x2n_pair_idle(ap)) {
+ int dpll = hpt3x2n_use_dpll(ap, (tf->flags & ATA_TFLAG_WRITE));
+ if ((flags & USE_DPLL) != dpll) {
+ if (dpll == 1)
+ hpt3x2n_set_clock(ap, 0x21);
+ else
+ hpt3x2n_set_clock(ap, 0x23);
+ }
+ }
+ return ata_qc_issue_prot(qc);
+}
+
+static struct scsi_host_template hpt3x2n_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .max_sectors = ATA_MAX_SECTORS,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .bios_param = ata_std_bios_param,
+};
+
+/*
+ * Configuration for HPT3x2n.
+ */
+
+static struct ata_port_operations hpt3x2n_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = hpt3x2n_set_piomode,
+ .set_dmamode = hpt3x2n_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = hpt3x2n_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = hpt3x2n_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = hpt3x2n_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+/**
+ * hpt3xn_calibrate_dpll - Calibrate the DPLL loop
+ * @dev: PCI device
+ *
+ * Perform a calibration cycle on the HPT3xN DPLL. Returns 1 if this
+ * succeeds
+ */
+
+static int hpt3xn_calibrate_dpll(struct pci_dev *dev)
+{
+ u8 reg5b;
+ u32 reg5c;
+ int tries;
+
+ for(tries = 0; tries < 0x5000; tries++) {
+ udelay(50);
+ pci_read_config_byte(dev, 0x5b, &reg5b);
+ if (reg5b & 0x80) {
+ /* See if it stays set */
+ for(tries = 0; tries < 0x1000; tries ++) {
+ pci_read_config_byte(dev, 0x5b, &reg5b);
+ /* Failed ? */
+ if ((reg5b & 0x80) == 0)
+ return 0;
+ }
+ /* Turn off tuning, we have the DPLL set */
+ pci_read_config_dword(dev, 0x5c, &reg5c);
+ pci_write_config_dword(dev, 0x5c, reg5c & ~ 0x100);
+ return 1;
+ }
+ }
+ /* Never went stable */
+ return 0;
+}
+
+static int hpt3x2n_pci_clock(struct pci_dev *pdev)
+{
+ unsigned long freq;
+ u32 fcnt;
+
+ pci_read_config_dword(pdev, 0x70/*CHECKME*/, &fcnt);
+ if ((fcnt >> 12) != 0xABCDE) {
+ printk(KERN_WARNING "hpt3xn: BIOS clock data not set.\n");
+ return 33; /* Not BIOS set */
+ }
+ fcnt &= 0x1FF;
+
+ freq = (fcnt * 77) / 192;
+
+ /* Clamp to bands */
+ if (freq < 40)
+ return 33;
+ if (freq < 45)
+ return 40;
+ if (freq < 55)
+ return 50;
+ return 66;
+}
+
+/**
+ * hpt3x2n_init_one - Initialise an HPT37X/302
+ * @dev: PCI device
+ * @id: Entry in match table
+ *
+ * Initialise an HPT3x2n device. There are some interesting complications
+ * here. Firstly the chip may report 366 and be one of several variants.
+ * Secondly all the timings depend on the clock for the chip which we must
+ * detect and look up
+ *
+ * This is the known chip mappings. It may be missing a couple of later
+ * releases.
+ *
+ * Chip version PCI Rev Notes
+ * HPT372 4 (HPT366) 5 Other driver
+ * HPT372N 4 (HPT366) 6 UDMA133
+ * HPT372 5 (HPT372) 1 Other driver
+ * HPT372N 5 (HPT372) 2 UDMA133
+ * HPT302 6 (HPT302) * Other driver
+ * HPT302N 6 (HPT302) > 1 UDMA133
+ * HPT371 7 (HPT371) * Other driver
+ * HPT371N 7 (HPT371) > 1 UDMA133
+ * HPT374 8 (HPT374) * Other driver
+ * HPT372N 9 (HPT372N) * UDMA133
+ *
+ * (1) UDMA133 support depends on the bus clock
+ *
+ * To pin down HPT371N
+ */
+
+static int hpt3x2n_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ /* HPT372N and friends - UDMA133 */
+ static struct ata_port_info info = {
+ .sht = &hpt3x2n_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x7f,
+ .port_ops = &hpt3x2n_port_ops
+ };
+ struct ata_port_info *port_info[2];
+ struct ata_port_info *port = &info;
+
+ u8 irqmask;
+ u32 class_rev;
+
+ unsigned int pci_mhz;
+ unsigned int f_low, f_high;
+ int adjust;
+
+ pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
+ class_rev &= 0xFF;
+
+ switch(dev->device) {
+ case PCI_DEVICE_ID_TTI_HPT366:
+ if (class_rev < 6)
+ return -ENODEV;
+ break;
+ case PCI_DEVICE_ID_TTI_HPT372:
+ /* 372N if rev >= 1*/
+ if (class_rev == 0)
+ return -ENODEV;
+ break;
+ case PCI_DEVICE_ID_TTI_HPT302:
+ if (class_rev < 2)
+ return -ENODEV;
+ break;
+ case PCI_DEVICE_ID_TTI_HPT372N:
+ break;
+ default:
+ printk(KERN_ERR "pata_hpt3x2n: PCI table is bogus please report (%d).\n", dev->device);
+ return -ENODEV;
+ }
+
+ /* Ok so this is a chip we support */
+
+ pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, (L1_CACHE_BYTES / 4));
+ pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x78);
+ pci_write_config_byte(dev, PCI_MIN_GNT, 0x08);
+ pci_write_config_byte(dev, PCI_MAX_LAT, 0x08);
+
+ pci_read_config_byte(dev, 0x5A, &irqmask);
+ irqmask &= ~0x10;
+ pci_write_config_byte(dev, 0x5a, irqmask);
+
+ /* Tune the PLL. HPT recommend using 75 for SATA, 66 for UDMA133 or
+ 50 for UDMA100. Right now we always use 66 */
+
+ pci_mhz = hpt3x2n_pci_clock(dev);
+
+ f_low = (pci_mhz * 48) / 66; /* PCI Mhz for 66Mhz DPLL */
+ f_high = f_low + 2; /* Tolerance */
+
+ pci_write_config_dword(dev, 0x5C, (f_high << 16) | f_low | 0x100);
+ /* PLL clock */
+ pci_write_config_byte(dev, 0x5B, 0x21);
+
+ /* Unlike the 37x we don't try jiggling the frequency */
+ for(adjust = 0; adjust < 8; adjust++) {
+ if (hpt3xn_calibrate_dpll(dev))
+ break;
+ pci_write_config_dword(dev, 0x5C, (f_high << 16) | f_low);
+ }
+ if (adjust == 8)
+ printk(KERN_WARNING "hpt3xn: DPLL did not stabilize.\n");
+
+ /* Set our private data up. We only need a few flags so we use
+ it directly */
+ port->private_data = NULL;
+ if (pci_mhz > 60)
+ port->private_data = (void *)PCI66;
+
+ /* Now kick off ATA set up */
+ port_info[0] = port_info[1] = port;
+ return ata_pci_init_one(dev, port_info, 2);
+}
+
+static struct pci_device_id hpt3x2n[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT366), },
+ { PCI_DEVICE(PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT372), },
+ { PCI_DEVICE(PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT302), },
+ { PCI_DEVICE(PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT372N), },
+ { 0, },
+};
+
+static struct pci_driver hpt3x2n_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = hpt3x2n,
+ .probe = hpt3x2n_init_one,
+ .remove = ata_pci_remove_one
+};
+
+static int __init hpt3x2n_init(void)
+{
+ return pci_register_driver(&hpt3x2n_pci_driver);
+}
+
+
+static void __exit hpt3x2n_exit(void)
+{
+ pci_unregister_driver(&hpt3x2n_pci_driver);
+}
+
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("low-level driver for the Highpoint HPT3x2n/30x");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, hpt3x2n);
+MODULE_VERSION(DRV_VERSION);
+
+module_init(hpt3x2n_init);
+module_exit(hpt3x2n_exit);
diff --git a/drivers/ata/pata_hpt3x3.c b/drivers/ata/pata_hpt3x3.c
new file mode 100644
index 00000000000..1f084ab1ccc
--- /dev/null
+++ b/drivers/ata/pata_hpt3x3.c
@@ -0,0 +1,226 @@
+/*
+ * pata_hpt3x3 - HPT3x3 driver
+ * (c) Copyright 2005-2006 Red Hat
+ *
+ * Was pata_hpt34x but the naming was confusing as it supported the
+ * 343 and 363 so it has been renamed.
+ *
+ * Based on:
+ * linux/drivers/ide/pci/hpt34x.c Version 0.40 Sept 10, 2002
+ * Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org>
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+
+#define DRV_NAME "pata_hpt3x3"
+#define DRV_VERSION "0.4.1"
+
+static int hpt3x3_probe_init(struct ata_port *ap)
+{
+ ap->cbl = ATA_CBL_PATA40;
+ return ata_std_prereset(ap);
+}
+
+/**
+ * hpt3x3_probe_reset - reset the hpt3x3 bus
+ * @ap: ATA port to reset
+ *
+ * Perform the housekeeping when doing an ATA bus reeset. We just
+ * need to force the cable type.
+ */
+
+static void hpt3x3_error_handler(struct ata_port *ap)
+{
+ return ata_bmdma_drive_eh(ap, hpt3x3_probe_init, ata_std_softreset, NULL, ata_std_postreset);
+}
+
+/**
+ * hpt3x3_set_piomode - PIO setup
+ * @ap: ATA interface
+ * @adev: device on the interface
+ *
+ * Set our PIO requirements. This is fairly simple on the HPT3x3 as
+ * all we have to do is clear the MWDMA and UDMA bits then load the
+ * mode number.
+ */
+
+static void hpt3x3_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u32 r1, r2;
+ int dn = 2 * ap->port_no + adev->devno;
+
+ pci_read_config_dword(pdev, 0x44, &r1);
+ pci_read_config_dword(pdev, 0x48, &r2);
+ /* Load the PIO timing number */
+ r1 &= ~(7 << (3 * dn));
+ r1 |= (adev->pio_mode - XFER_PIO_0) << (3 * dn);
+ r2 &= ~(0x11 << dn); /* Clear MWDMA and UDMA bits */
+
+ pci_write_config_dword(pdev, 0x44, r1);
+ pci_write_config_dword(pdev, 0x48, r2);
+}
+
+/**
+ * hpt3x3_set_dmamode - DMA timing setup
+ * @ap: ATA interface
+ * @adev: Device being configured
+ *
+ * Set up the channel for MWDMA or UDMA modes. Much the same as with
+ * PIO, load the mode number and then set MWDMA or UDMA flag.
+ */
+
+static void hpt3x3_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u32 r1, r2;
+ int dn = 2 * ap->port_no + adev->devno;
+ int mode_num = adev->dma_mode & 0x0F;
+
+ pci_read_config_dword(pdev, 0x44, &r1);
+ pci_read_config_dword(pdev, 0x48, &r2);
+ /* Load the timing number */
+ r1 &= ~(7 << (3 * dn));
+ r1 |= (mode_num << (3 * dn));
+ r2 &= ~(0x11 << dn); /* Clear MWDMA and UDMA bits */
+
+ if (adev->dma_mode >= XFER_UDMA_0)
+ r2 |= 0x01 << dn; /* Ultra mode */
+ else
+ r2 |= 0x10 << dn; /* MWDMA */
+
+ pci_write_config_dword(pdev, 0x44, r1);
+ pci_write_config_dword(pdev, 0x48, r2);
+}
+
+static struct scsi_host_template hpt3x3_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .max_sectors = ATA_MAX_SECTORS,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .bios_param = ata_std_bios_param,
+};
+
+static struct ata_port_operations hpt3x3_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = hpt3x3_set_piomode,
+ .set_dmamode = hpt3x3_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = hpt3x3_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+/**
+ * hpt3x3_init_one - Initialise an HPT343/363
+ * @dev: PCI device
+ * @id: Entry in match table
+ *
+ * Perform basic initialisation. The chip has a quirk that it won't
+ * function unless it is at XX00. The old ATA driver touched this up
+ * but we leave it for pci quirks to do properly.
+ */
+
+static int hpt3x3_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ static struct ata_port_info info = {
+ .sht = &hpt3x3_sht,
+ .flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x07,
+ .port_ops = &hpt3x3_port_ops
+ };
+ static struct ata_port_info *port_info[2] = { &info, &info };
+ u16 cmd;
+
+ /* Initialize the board */
+ pci_write_config_word(dev, 0x80, 0x00);
+ /* Check if it is a 343 or a 363. 363 has COMMAND_MEMORY set */
+ pci_read_config_word(dev, PCI_COMMAND, &cmd);
+ if (cmd & PCI_COMMAND_MEMORY)
+ pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xF0);
+ else
+ pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x20);
+
+ /* Now kick off ATA set up */
+ return ata_pci_init_one(dev, port_info, 2);
+}
+
+static struct pci_device_id hpt3x3[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT343), },
+ { 0, },
+};
+
+static struct pci_driver hpt3x3_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = hpt3x3,
+ .probe = hpt3x3_init_one,
+ .remove = ata_pci_remove_one
+};
+
+static int __init hpt3x3_init(void)
+{
+ return pci_register_driver(&hpt3x3_pci_driver);
+}
+
+
+static void __exit hpt3x3_exit(void)
+{
+ pci_unregister_driver(&hpt3x3_pci_driver);
+}
+
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("low-level driver for the Highpoint HPT343/363");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, hpt3x3);
+MODULE_VERSION(DRV_VERSION);
+
+module_init(hpt3x3_init);
+module_exit(hpt3x3_exit);
diff --git a/drivers/ata/pata_isapnp.c b/drivers/ata/pata_isapnp.c
new file mode 100644
index 00000000000..640b8b0954f
--- /dev/null
+++ b/drivers/ata/pata_isapnp.c
@@ -0,0 +1,156 @@
+
+/*
+ * pata-isapnp.c - ISA PnP PATA controller driver.
+ * Copyright 2005/2006 Red Hat Inc <alan@redhat.com>, all rights reserved.
+ *
+ * Based in part on ide-pnp.c by Andrey Panin <pazke@donpac.ru>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/isapnp.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <scsi/scsi_host.h>
+#include <linux/ata.h>
+#include <linux/libata.h>
+
+#define DRV_NAME "pata_isapnp"
+#define DRV_VERSION "0.1.5"
+
+static struct scsi_host_template isapnp_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .max_sectors = ATA_MAX_SECTORS,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .bios_param = ata_std_bios_param,
+};
+
+static struct ata_port_operations isapnp_port_ops = {
+ .port_disable = ata_port_disable,
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = ata_bmdma_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+/**
+ * isapnp_init_one - attach an isapnp interface
+ * @idev: PnP device
+ * @dev_id: matching detect line
+ *
+ * Register an ISA bus IDE interface. Such interfaces are PIO 0 and
+ * non shared IRQ.
+ */
+
+static int isapnp_init_one(struct pnp_dev *idev, const struct pnp_device_id *dev_id)
+{
+ struct ata_probe_ent ae;
+
+ if (pnp_port_valid(idev, 0) == 0)
+ return -ENODEV;
+
+ /* FIXME: Should selected polled PIO here not fail */
+ if (pnp_irq_valid(idev, 0) == 0)
+ return -ENODEV;
+
+ memset(&ae, 0, sizeof(struct ata_probe_ent));
+ INIT_LIST_HEAD(&ae.node);
+ ae.dev = &idev->dev;
+ ae.port_ops = &isapnp_port_ops;
+ ae.sht = &isapnp_sht;
+ ae.n_ports = 1;
+ ae.pio_mask = 1; /* ISA so PIO 0 cycles */
+ ae.irq = pnp_irq(idev, 0);
+ ae.irq_flags = 0;
+ ae.port_flags = ATA_FLAG_SLAVE_POSS;
+ ae.port[0].cmd_addr = pnp_port_start(idev, 0);
+
+ if (pnp_port_valid(idev, 1) == 0) {
+ ae.port[0].altstatus_addr = pnp_port_start(idev, 1);
+ ae.port[0].ctl_addr = pnp_port_start(idev, 1);
+ ae.port_flags |= ATA_FLAG_SRST;
+ }
+ ata_std_ports(&ae.port[0]);
+
+ if (ata_device_add(&ae) == 0)
+ return -ENODEV;
+ return 0;
+}
+
+/**
+ * isapnp_remove_one - unplug an isapnp interface
+ * @idev: PnP device
+ *
+ * Remove a previously configured PnP ATA port. Called only on module
+ * unload events as the core does not currently deal with ISAPnP docking.
+ */
+
+static void isapnp_remove_one(struct pnp_dev *idev)
+{
+ struct device *dev = &idev->dev;
+ struct ata_host *host = dev_get_drvdata(dev);
+
+ ata_host_remove(host);
+ dev_set_drvdata(dev, NULL);
+}
+
+static struct pnp_device_id isapnp_devices[] = {
+ /* Generic ESDI/IDE/ATA compatible hard disk controller */
+ {.id = "PNP0600", .driver_data = 0},
+ {.id = ""}
+};
+
+static struct pnp_driver isapnp_driver = {
+ .name = DRV_NAME,
+ .id_table = isapnp_devices,
+ .probe = isapnp_init_one,
+ .remove = isapnp_remove_one,
+};
+
+static int __init isapnp_init(void)
+{
+ return pnp_register_driver(&isapnp_driver);
+}
+
+static void __exit isapnp_exit(void)
+{
+ pnp_unregister_driver(&isapnp_driver);
+}
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("low-level driver for ISA PnP ATA");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
+module_init(isapnp_init);
+module_exit(isapnp_exit);
diff --git a/drivers/ata/pata_it821x.c b/drivers/ata/pata_it821x.c
new file mode 100644
index 00000000000..82a46ff4000
--- /dev/null
+++ b/drivers/ata/pata_it821x.c
@@ -0,0 +1,847 @@
+/*
+ * ata-it821x.c - IT821x PATA for new ATA layer
+ * (C) 2005 Red Hat Inc
+ * Alan Cox <alan@redhat.com>
+ *
+ * based upon
+ *
+ * it821x.c
+ *
+ * linux/drivers/ide/pci/it821x.c Version 0.09 December 2004
+ *
+ * Copyright (C) 2004 Red Hat <alan@redhat.com>
+ *
+ * May be copied or modified under the terms of the GNU General Public License
+ * Based in part on the ITE vendor provided SCSI driver.
+ *
+ * Documentation available from
+ * http://www.ite.com.tw/pc/IT8212F_V04.pdf
+ * Some other documents are NDA.
+ *
+ * The ITE8212 isn't exactly a standard IDE controller. It has two
+ * modes. In pass through mode then it is an IDE controller. In its smart
+ * mode its actually quite a capable hardware raid controller disguised
+ * as an IDE controller. Smart mode only understands DMA read/write and
+ * identify, none of the fancier commands apply. The IT8211 is identical
+ * in other respects but lacks the raid mode.
+ *
+ * Errata:
+ * o Rev 0x10 also requires master/slave hold the same DMA timings and
+ * cannot do ATAPI MWDMA.
+ * o The identify data for raid volumes lacks CHS info (technically ok)
+ * but also fails to set the LBA28 and other bits. We fix these in
+ * the IDE probe quirk code.
+ * o If you write LBA48 sized I/O's (ie > 256 sector) in smart mode
+ * raid then the controller firmware dies
+ * o Smart mode without RAID doesn't clear all the necessary identify
+ * bits to reduce the command set to the one used
+ *
+ * This has a few impacts on the driver
+ * - In pass through mode we do all the work you would expect
+ * - In smart mode the clocking set up is done by the controller generally
+ * but we must watch the other limits and filter.
+ * - There are a few extra vendor commands that actually talk to the
+ * controller but only work PIO with no IRQ.
+ *
+ * Vendor areas of the identify block in smart mode are used for the
+ * timing and policy set up. Each HDD in raid mode also has a serial
+ * block on the disk. The hardware extra commands are get/set chip status,
+ * rebuild, get rebuild status.
+ *
+ * In Linux the driver supports pass through mode as if the device was
+ * just another IDE controller. If the smart mode is running then
+ * volumes are managed by the controller firmware and each IDE "disk"
+ * is a raid volume. Even more cute - the controller can do automated
+ * hotplug and rebuild.
+ *
+ * The pass through controller itself is a little demented. It has a
+ * flaw that it has a single set of PIO/MWDMA timings per channel so
+ * non UDMA devices restrict each others performance. It also has a
+ * single clock source per channel so mixed UDMA100/133 performance
+ * isn't perfect and we have to pick a clock. Thankfully none of this
+ * matters in smart mode. ATAPI DMA is not currently supported.
+ *
+ * It seems the smart mode is a win for RAID1/RAID10 but otherwise not.
+ *
+ * TODO
+ * - ATAPI and other speed filtering
+ * - Command filter in smart mode
+ * - RAID configuration ioctls
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+
+
+#define DRV_NAME "pata_it821x"
+#define DRV_VERSION "0.3.2"
+
+struct it821x_dev
+{
+ unsigned int smart:1, /* Are we in smart raid mode */
+ timing10:1; /* Rev 0x10 */
+ u8 clock_mode; /* 0, ATA_50 or ATA_66 */
+ u8 want[2][2]; /* Mode/Pri log for master slave */
+ /* We need these for switching the clock when DMA goes on/off
+ The high byte is the 66Mhz timing */
+ u16 pio[2]; /* Cached PIO values */
+ u16 mwdma[2]; /* Cached MWDMA values */
+ u16 udma[2]; /* Cached UDMA values (per drive) */
+ u16 last_device; /* Master or slave loaded ? */
+};
+
+#define ATA_66 0
+#define ATA_50 1
+#define ATA_ANY 2
+
+#define UDMA_OFF 0
+#define MWDMA_OFF 0
+
+/*
+ * We allow users to force the card into non raid mode without
+ * flashing the alternative BIOS. This is also neccessary right now
+ * for embedded platforms that cannot run a PC BIOS but are using this
+ * device.
+ */
+
+static int it8212_noraid;
+
+/**
+ * it821x_pre_reset - probe
+ * @ap: ATA port
+ *
+ * Set the cable type
+ */
+
+static int it821x_pre_reset(struct ata_port *ap)
+{
+ ap->cbl = ATA_CBL_PATA80;
+ return ata_std_prereset(ap);
+}
+
+/**
+ * it821x_error_handler - probe/reset
+ * @ap: ATA port
+ *
+ * Set the cable type and trigger a probe
+ */
+
+static void it821x_error_handler(struct ata_port *ap)
+{
+ return ata_bmdma_drive_eh(ap, it821x_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
+}
+
+/**
+ * it821x_program - program the PIO/MWDMA registers
+ * @ap: ATA port
+ * @adev: Device to program
+ * @timing: Timing value (66Mhz in top 8bits, 50 in the low 8)
+ *
+ * Program the PIO/MWDMA timing for this channel according to the
+ * current clock. These share the same register so are managed by
+ * the DMA start/stop sequence as with the old driver.
+ */
+
+static void it821x_program(struct ata_port *ap, struct ata_device *adev, u16 timing)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ struct it821x_dev *itdev = ap->private_data;
+ int channel = ap->port_no;
+ u8 conf;
+
+ /* Program PIO/MWDMA timing bits */
+ if (itdev->clock_mode == ATA_66)
+ conf = timing >> 8;
+ else
+ conf = timing & 0xFF;
+ pci_write_config_byte(pdev, 0x54 + 4 * channel, conf);
+}
+
+
+/**
+ * it821x_program_udma - program the UDMA registers
+ * @ap: ATA port
+ * @adev: ATA device to update
+ * @timing: Timing bits. Top 8 are for 66Mhz bottom for 50Mhz
+ *
+ * Program the UDMA timing for this drive according to the
+ * current clock. Handles the dual clocks and also knows about
+ * the errata on the 0x10 revision. The UDMA errata is partly handled
+ * here and partly in start_dma.
+ */
+
+static void it821x_program_udma(struct ata_port *ap, struct ata_device *adev, u16 timing)
+{
+ struct it821x_dev *itdev = ap->private_data;
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ int channel = ap->port_no;
+ int unit = adev->devno;
+ u8 conf;
+
+ /* Program UDMA timing bits */
+ if (itdev->clock_mode == ATA_66)
+ conf = timing >> 8;
+ else
+ conf = timing & 0xFF;
+ if (itdev->timing10 == 0)
+ pci_write_config_byte(pdev, 0x56 + 4 * channel + unit, conf);
+ else {
+ /* Early revision must be programmed for both together */
+ pci_write_config_byte(pdev, 0x56 + 4 * channel, conf);
+ pci_write_config_byte(pdev, 0x56 + 4 * channel + 1, conf);
+ }
+}
+
+/**
+ * it821x_clock_strategy
+ * @ap: ATA interface
+ * @adev: ATA device being updated
+ *
+ * Select between the 50 and 66Mhz base clocks to get the best
+ * results for this interface.
+ */
+
+static void it821x_clock_strategy(struct ata_port *ap, struct ata_device *adev)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ struct it821x_dev *itdev = ap->private_data;
+ u8 unit = adev->devno;
+ struct ata_device *pair = ata_dev_pair(adev);
+
+ int clock, altclock;
+ u8 v;
+ int sel = 0;
+
+ /* Look for the most wanted clocking */
+ if (itdev->want[0][0] > itdev->want[1][0]) {
+ clock = itdev->want[0][1];
+ altclock = itdev->want[1][1];
+ } else {
+ clock = itdev->want[1][1];
+ altclock = itdev->want[0][1];
+ }
+
+ /* Master doesn't care does the slave ? */
+ if (clock == ATA_ANY)
+ clock = altclock;
+
+ /* Nobody cares - keep the same clock */
+ if (clock == ATA_ANY)
+ return;
+ /* No change */
+ if (clock == itdev->clock_mode)
+ return;
+
+ /* Load this into the controller */
+ if (clock == ATA_66)
+ itdev->clock_mode = ATA_66;
+ else {
+ itdev->clock_mode = ATA_50;
+ sel = 1;
+ }
+ pci_read_config_byte(pdev, 0x50, &v);
+ v &= ~(1 << (1 + ap->port_no));
+ v |= sel << (1 + ap->port_no);
+ pci_write_config_byte(pdev, 0x50, v);
+
+ /*
+ * Reprogram the UDMA/PIO of the pair drive for the switch
+ * MWDMA will be dealt with by the dma switcher
+ */
+ if (pair && itdev->udma[1-unit] != UDMA_OFF) {
+ it821x_program_udma(ap, pair, itdev->udma[1-unit]);
+ it821x_program(ap, pair, itdev->pio[1-unit]);
+ }
+ /*
+ * Reprogram the UDMA/PIO of our drive for the switch.
+ * MWDMA will be dealt with by the dma switcher
+ */
+ if (itdev->udma[unit] != UDMA_OFF) {
+ it821x_program_udma(ap, adev, itdev->udma[unit]);
+ it821x_program(ap, adev, itdev->pio[unit]);
+ }
+}
+
+/**
+ * it821x_passthru_set_piomode - set PIO mode data
+ * @ap: ATA interface
+ * @adev: ATA device
+ *
+ * Configure for PIO mode. This is complicated as the register is
+ * shared by PIO and MWDMA and for both channels.
+ */
+
+static void it821x_passthru_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ /* Spec says 89 ref driver uses 88 */
+ static const u16 pio[] = { 0xAA88, 0xA382, 0xA181, 0x3332, 0x3121 };
+ static const u8 pio_want[] = { ATA_66, ATA_66, ATA_66, ATA_66, ATA_ANY };
+
+ struct it821x_dev *itdev = ap->private_data;
+ int unit = adev->devno;
+ int mode_wanted = adev->pio_mode - XFER_PIO_0;
+
+ /* We prefer 66Mhz clock for PIO 0-3, don't care for PIO4 */
+ itdev->want[unit][1] = pio_want[mode_wanted];
+ itdev->want[unit][0] = 1; /* PIO is lowest priority */
+ itdev->pio[unit] = pio[mode_wanted];
+ it821x_clock_strategy(ap, adev);
+ it821x_program(ap, adev, itdev->pio[unit]);
+}
+
+/**
+ * it821x_passthru_set_dmamode - set initial DMA mode data
+ * @ap: ATA interface
+ * @adev: ATA device
+ *
+ * Set up the DMA modes. The actions taken depend heavily on the mode
+ * to use. If UDMA is used as is hopefully the usual case then the
+ * timing register is private and we need only consider the clock. If
+ * we are using MWDMA then we have to manage the setting ourself as
+ * we switch devices and mode.
+ */
+
+static void it821x_passthru_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+ static const u16 dma[] = { 0x8866, 0x3222, 0x3121 };
+ static const u8 mwdma_want[] = { ATA_ANY, ATA_66, ATA_ANY };
+ static const u16 udma[] = { 0x4433, 0x4231, 0x3121, 0x2121, 0x1111, 0x2211, 0x1111 };
+ static const u8 udma_want[] = { ATA_ANY, ATA_50, ATA_ANY, ATA_66, ATA_66, ATA_50, ATA_66 };
+
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ struct it821x_dev *itdev = ap->private_data;
+ int channel = ap->port_no;
+ int unit = adev->devno;
+ u8 conf;
+
+ if (adev->dma_mode >= XFER_UDMA_0) {
+ int mode_wanted = adev->dma_mode - XFER_UDMA_0;
+
+ itdev->want[unit][1] = udma_want[mode_wanted];
+ itdev->want[unit][0] = 3; /* UDMA is high priority */
+ itdev->mwdma[unit] = MWDMA_OFF;
+ itdev->udma[unit] = udma[mode_wanted];
+ if (mode_wanted >= 5)
+ itdev->udma[unit] |= 0x8080; /* UDMA 5/6 select on */
+
+ /* UDMA on. Again revision 0x10 must do the pair */
+ pci_read_config_byte(pdev, 0x50, &conf);
+ if (itdev->timing10)
+ conf &= channel ? 0x9F: 0xE7;
+ else
+ conf &= ~ (1 << (3 + 2 * channel + unit));
+ pci_write_config_byte(pdev, 0x50, conf);
+ it821x_clock_strategy(ap, adev);
+ it821x_program_udma(ap, adev, itdev->udma[unit]);
+ } else {
+ int mode_wanted = adev->dma_mode - XFER_MW_DMA_0;
+
+ itdev->want[unit][1] = mwdma_want[mode_wanted];
+ itdev->want[unit][0] = 2; /* MWDMA is low priority */
+ itdev->mwdma[unit] = dma[mode_wanted];
+ itdev->udma[unit] = UDMA_OFF;
+
+ /* UDMA bits off - Revision 0x10 do them in pairs */
+ pci_read_config_byte(pdev, 0x50, &conf);
+ if (itdev->timing10)
+ conf |= channel ? 0x60: 0x18;
+ else
+ conf |= 1 << (3 + 2 * channel + unit);
+ pci_write_config_byte(pdev, 0x50, conf);
+ it821x_clock_strategy(ap, adev);
+ }
+}
+
+/**
+ * it821x_passthru_dma_start - DMA start callback
+ * @qc: Command in progress
+ *
+ * Usually drivers set the DMA timing at the point the set_dmamode call
+ * is made. IT821x however requires we load new timings on the
+ * transitions in some cases.
+ */
+
+static void it821x_passthru_bmdma_start(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct ata_device *adev = qc->dev;
+ struct it821x_dev *itdev = ap->private_data;
+ int unit = adev->devno;
+
+ if (itdev->mwdma[unit] != MWDMA_OFF)
+ it821x_program(ap, adev, itdev->mwdma[unit]);
+ else if (itdev->udma[unit] != UDMA_OFF && itdev->timing10)
+ it821x_program_udma(ap, adev, itdev->udma[unit]);
+ ata_bmdma_start(qc);
+}
+
+/**
+ * it821x_passthru_dma_stop - DMA stop callback
+ * @qc: ATA command
+ *
+ * We loaded new timings in dma_start, as a result we need to restore
+ * the PIO timings in dma_stop so that the next command issue gets the
+ * right clock values.
+ */
+
+static void it821x_passthru_bmdma_stop(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct ata_device *adev = qc->dev;
+ struct it821x_dev *itdev = ap->private_data;
+ int unit = adev->devno;
+
+ ata_bmdma_stop(qc);
+ if (itdev->mwdma[unit] != MWDMA_OFF)
+ it821x_program(ap, adev, itdev->pio[unit]);
+}
+
+
+/**
+ * it821x_passthru_dev_select - Select master/slave
+ * @ap: ATA port
+ * @device: Device number (not pointer)
+ *
+ * Device selection hook. If neccessary perform clock switching
+ */
+
+static void it821x_passthru_dev_select(struct ata_port *ap,
+ unsigned int device)
+{
+ struct it821x_dev *itdev = ap->private_data;
+ if (itdev && device != itdev->last_device) {
+ struct ata_device *adev = &ap->device[device];
+ it821x_program(ap, adev, itdev->pio[adev->devno]);
+ itdev->last_device = device;
+ }
+ ata_std_dev_select(ap, device);
+}
+
+/**
+ * it821x_smart_qc_issue_prot - wrap qc issue prot
+ * @qc: command
+ *
+ * Wrap the command issue sequence for the IT821x. We need to
+ * perform out own device selection timing loads before the
+ * usual happenings kick off
+ */
+
+static unsigned int it821x_smart_qc_issue_prot(struct ata_queued_cmd *qc)
+{
+ switch(qc->tf.command)
+ {
+ /* Commands the firmware supports */
+ case ATA_CMD_READ:
+ case ATA_CMD_READ_EXT:
+ case ATA_CMD_WRITE:
+ case ATA_CMD_WRITE_EXT:
+ case ATA_CMD_PIO_READ:
+ case ATA_CMD_PIO_READ_EXT:
+ case ATA_CMD_PIO_WRITE:
+ case ATA_CMD_PIO_WRITE_EXT:
+ case ATA_CMD_READ_MULTI:
+ case ATA_CMD_READ_MULTI_EXT:
+ case ATA_CMD_WRITE_MULTI:
+ case ATA_CMD_WRITE_MULTI_EXT:
+ case ATA_CMD_ID_ATA:
+ /* Arguably should just no-op this one */
+ case ATA_CMD_SET_FEATURES:
+ return ata_qc_issue_prot(qc);
+ }
+ printk(KERN_DEBUG "it821x: can't process command 0x%02X\n", qc->tf.command);
+ return AC_ERR_INVALID;
+}
+
+/**
+ * it821x_passthru_qc_issue_prot - wrap qc issue prot
+ * @qc: command
+ *
+ * Wrap the command issue sequence for the IT821x. We need to
+ * perform out own device selection timing loads before the
+ * usual happenings kick off
+ */
+
+static unsigned int it821x_passthru_qc_issue_prot(struct ata_queued_cmd *qc)
+{
+ it821x_passthru_dev_select(qc->ap, qc->dev->devno);
+ return ata_qc_issue_prot(qc);
+}
+
+/**
+ * it821x_smart_set_mode - mode setting
+ * @ap: interface to set up
+ *
+ * Use a non standard set_mode function. We don't want to be tuned.
+ * The BIOS configured everything. Our job is not to fiddle. We
+ * read the dma enabled bits from the PCI configuration of the device
+ * and respect them.
+ */
+
+static void it821x_smart_set_mode(struct ata_port *ap)
+{
+ int dma_enabled = 0;
+ int i;
+
+ /* Bits 5 and 6 indicate if DMA is active on master/slave */
+ /* It is possible that BMDMA isn't allocated */
+ if (ap->ioaddr.bmdma_addr)
+ dma_enabled = inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
+
+ for (i = 0; i < ATA_MAX_DEVICES; i++) {
+ struct ata_device *dev = &ap->device[i];
+ if (ata_dev_enabled(dev)) {
+ /* We don't really care */
+ dev->pio_mode = XFER_PIO_0;
+ dev->dma_mode = XFER_MW_DMA_0;
+ /* We do need the right mode information for DMA or PIO
+ and this comes from the current configuration flags */
+ if (dma_enabled & (1 << (5 + i))) {
+ dev->xfer_mode = XFER_MW_DMA_0;
+ dev->xfer_shift = ATA_SHIFT_MWDMA;
+ dev->flags &= ~ATA_DFLAG_PIO;
+ } else {
+ dev->xfer_mode = XFER_PIO_0;
+ dev->xfer_shift = ATA_SHIFT_PIO;
+ dev->flags |= ATA_DFLAG_PIO;
+ }
+ }
+ }
+}
+
+/**
+ * it821x_dev_config - Called each device identify
+ * @ap: ATA port
+ * @adev: Device that has just been identified
+ *
+ * Perform the initial setup needed for each device that is chip
+ * special. In our case we need to lock the sector count to avoid
+ * blowing the brains out of the firmware with large LBA48 requests
+ *
+ * FIXME: When FUA appears we need to block FUA too. And SMART and
+ * basically we need to filter commands for this chip.
+ */
+
+static void it821x_dev_config(struct ata_port *ap, struct ata_device *adev)
+{
+ unsigned char model_num[40];
+ char *s;
+ unsigned int len;
+
+ /* This block ought to be a library routine as it is in several
+ drivers now */
+
+ ata_id_string(adev->id, model_num, ATA_ID_PROD_OFS,
+ sizeof(model_num));
+ s = &model_num[0];
+ len = strnlen(s, sizeof(model_num));
+
+ /* ATAPI specifies that empty space is blank-filled; remove blanks */
+ while ((len > 0) && (s[len - 1] == ' ')) {
+ len--;
+ s[len] = 0;
+ }
+
+ if (adev->max_sectors > 255)
+ adev->max_sectors = 255;
+
+ if (strstr(model_num, "Integrated Technology Express")) {
+ /* RAID mode */
+ printk(KERN_INFO "IT821x %sRAID%d volume",
+ adev->id[147]?"Bootable ":"",
+ adev->id[129]);
+ if (adev->id[129] != 1)
+ printk("(%dK stripe)", adev->id[146]);
+ printk(".\n");
+ }
+}
+
+
+/**
+ * it821x_check_atapi_dma - ATAPI DMA handler
+ * @qc: Command we are about to issue
+ *
+ * Decide if this ATAPI command can be issued by DMA on this
+ * controller. Return 0 if it can be.
+ */
+
+static int it821x_check_atapi_dma(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct it821x_dev *itdev = ap->private_data;
+
+ /* No ATAPI DMA in smart mode */
+ if (itdev->smart)
+ return -EOPNOTSUPP;
+ /* No ATAPI DMA on rev 10 */
+ if (itdev->timing10)
+ return -EOPNOTSUPP;
+ /* Cool */
+ return 0;
+}
+
+
+/**
+ * it821x_port_start - port setup
+ * @ap: ATA port being set up
+ *
+ * The it821x needs to maintain private data structures and also to
+ * use the standard PCI interface which lacks support for this
+ * functionality. We instead set up the private data on the port
+ * start hook, and tear it down on port stop
+ */
+
+static int it821x_port_start(struct ata_port *ap)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ struct it821x_dev *itdev;
+ u8 conf;
+
+ int ret = ata_port_start(ap);
+ if (ret < 0)
+ return ret;
+
+ ap->private_data = kmalloc(sizeof(struct it821x_dev), GFP_KERNEL);
+ if (ap->private_data == NULL) {
+ ata_port_stop(ap);
+ return -ENOMEM;
+ }
+
+ itdev = ap->private_data;
+ memset(itdev, 0, sizeof(struct it821x_dev));
+
+ pci_read_config_byte(pdev, 0x50, &conf);
+
+ if (conf & 1) {
+ itdev->smart = 1;
+ /* Long I/O's although allowed in LBA48 space cause the
+ onboard firmware to enter the twighlight zone */
+ /* No ATAPI DMA in this mode either */
+ }
+ /* Pull the current clocks from 0x50 */
+ if (conf & (1 << (1 + ap->port_no)))
+ itdev->clock_mode = ATA_50;
+ else
+ itdev->clock_mode = ATA_66;
+
+ itdev->want[0][1] = ATA_ANY;
+ itdev->want[1][1] = ATA_ANY;
+ itdev->last_device = -1;
+
+ pci_read_config_byte(pdev, PCI_REVISION_ID, &conf);
+ if (conf == 0x10) {
+ itdev->timing10 = 1;
+ /* Need to disable ATAPI DMA for this case */
+ if (!itdev->smart)
+ printk(KERN_WARNING DRV_NAME": Revision 0x10, workarounds activated.\n");
+ }
+
+ return 0;
+}
+
+/**
+ * it821x_port_stop - port shutdown
+ * @ap: ATA port being removed
+ *
+ * Release the private objects we added in it821x_port_start
+ */
+
+static void it821x_port_stop(struct ata_port *ap) {
+ kfree(ap->private_data);
+ ap->private_data = NULL; /* We want an OOPS if we reuse this
+ too late! */
+ ata_port_stop(ap);
+}
+
+static struct scsi_host_template it821x_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ /* 255 sectors to begin with. This is locked in smart mode but not
+ in pass through */
+ .max_sectors = 255,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .bios_param = ata_std_bios_param,
+};
+
+static struct ata_port_operations it821x_smart_port_ops = {
+ .set_mode = it821x_smart_set_mode,
+ .port_disable = ata_port_disable,
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .mode_filter = ata_pci_default_filter,
+
+ .check_status = ata_check_status,
+ .check_atapi_dma= it821x_check_atapi_dma,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+ .dev_config = it821x_dev_config,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = it821x_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = it821x_smart_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = it821x_port_start,
+ .port_stop = it821x_port_stop,
+ .host_stop = ata_host_stop
+};
+
+static struct ata_port_operations it821x_passthru_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = it821x_passthru_set_piomode,
+ .set_dmamode = it821x_passthru_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .check_atapi_dma= it821x_check_atapi_dma,
+ .dev_select = it821x_passthru_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = it821x_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = it821x_passthru_bmdma_start,
+ .bmdma_stop = it821x_passthru_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = it821x_passthru_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_clear = ata_bmdma_irq_clear,
+ .irq_handler = ata_interrupt,
+
+ .port_start = it821x_port_start,
+ .port_stop = it821x_port_stop,
+ .host_stop = ata_host_stop
+};
+
+static void __devinit it821x_disable_raid(struct pci_dev *pdev)
+{
+ /* Reset local CPU, and set BIOS not ready */
+ pci_write_config_byte(pdev, 0x5E, 0x01);
+
+ /* Set to bypass mode, and reset PCI bus */
+ pci_write_config_byte(pdev, 0x50, 0x00);
+ pci_write_config_word(pdev, PCI_COMMAND,
+ PCI_COMMAND_PARITY | PCI_COMMAND_IO |
+ PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
+ pci_write_config_word(pdev, 0x40, 0xA0F3);
+
+ pci_write_config_dword(pdev,0x4C, 0x02040204);
+ pci_write_config_byte(pdev, 0x42, 0x36);
+ pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x20);
+}
+
+
+static int it821x_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ u8 conf;
+
+ static struct ata_port_info info_smart = {
+ .sht = &it821x_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .port_ops = &it821x_smart_port_ops
+ };
+ static struct ata_port_info info_passthru = {
+ .sht = &it821x_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x7f,
+ .port_ops = &it821x_passthru_port_ops
+ };
+ static struct ata_port_info *port_info[2];
+
+ static char *mode[2] = { "pass through", "smart" };
+
+ /* Force the card into bypass mode if so requested */
+ if (it8212_noraid) {
+ printk(KERN_INFO DRV_NAME ": forcing bypass mode.\n");
+ it821x_disable_raid(pdev);
+ }
+ pci_read_config_byte(pdev, 0x50, &conf);
+ conf &= 1;
+
+ printk(KERN_INFO DRV_NAME ": controller in %s mode.\n", mode[conf]);
+ if (conf == 0)
+ port_info[0] = port_info[1] = &info_passthru;
+ else
+ port_info[0] = port_info[1] = &info_smart;
+
+ return ata_pci_init_one(pdev, port_info, 2);
+}
+
+static struct pci_device_id it821x[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_8211), },
+ { PCI_DEVICE(PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_8212), },
+ { 0, },
+};
+
+static struct pci_driver it821x_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = it821x,
+ .probe = it821x_init_one,
+ .remove = ata_pci_remove_one
+};
+
+static int __init it821x_init(void)
+{
+ return pci_register_driver(&it821x_pci_driver);
+}
+
+
+static void __exit it821x_exit(void)
+{
+ pci_unregister_driver(&it821x_pci_driver);
+}
+
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("low-level driver for the IT8211/IT8212 IDE RAID controller");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, it821x);
+MODULE_VERSION(DRV_VERSION);
+
+
+module_param_named(noraid, it8212_noraid, int, S_IRUGO);
+MODULE_PARM_DESC(it8212_noraid, "Force card into bypass mode");
+
+module_init(it821x_init);
+module_exit(it821x_exit);
diff --git a/drivers/ata/pata_jmicron.c b/drivers/ata/pata_jmicron.c
new file mode 100644
index 00000000000..be3a866b111
--- /dev/null
+++ b/drivers/ata/pata_jmicron.c
@@ -0,0 +1,265 @@
+/*
+ * pata_jmicron.c - JMicron ATA driver for non AHCI mode. This drives the
+ * PATA port of the controller. The SATA ports are
+ * driven by AHCI in the usual configuration although
+ * this driver can handle other setups if we need it.
+ *
+ * (c) 2006 Red Hat <alan@redhat.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+#include <linux/ata.h>
+
+#define DRV_NAME "pata_jmicron"
+#define DRV_VERSION "0.1.2"
+
+typedef enum {
+ PORT_PATA0 = 0,
+ PORT_PATA1 = 1,
+ PORT_SATA = 2,
+} port_type;
+
+/**
+ * jmicron_pre_reset - check for 40/80 pin
+ * @ap: Port
+ *
+ * Perform the PATA port setup we need.
+
+ * On the Jmicron 361/363 there is a single PATA port that can be mapped
+ * either as primary or secondary (or neither). We don't do any policy
+ * and setup here. We assume that has been done by init_one and the
+ * BIOS.
+ */
+
+static int jmicron_pre_reset(struct ata_port *ap)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u32 control;
+ u32 control5;
+ int port_mask = 1<< (4 * ap->port_no);
+ int port = ap->port_no;
+ port_type port_map[2];
+
+ /* Check if our port is enabled */
+ pci_read_config_dword(pdev, 0x40, &control);
+ if ((control & port_mask) == 0)
+ return -ENOENT;
+
+ /* There are two basic mappings. One has the two SATA ports merged
+ as master/slave and the secondary as PATA, the other has only the
+ SATA port mapped */
+ if (control & (1 << 23)) {
+ port_map[0] = PORT_SATA;
+ port_map[1] = PORT_PATA0;
+ } else {
+ port_map[0] = PORT_SATA;
+ port_map[1] = PORT_SATA;
+ }
+
+ /* The 365/366 may have this bit set to map the second PATA port
+ as the internal primary channel */
+ pci_read_config_dword(pdev, 0x80, &control5);
+ if (control5 & (1<<24))
+ port_map[0] = PORT_PATA1;
+
+ /* The two ports may then be logically swapped by the firmware */
+ if (control & (1 << 22))
+ port = port ^ 1;
+
+ /*
+ * Now we know which physical port we are talking about we can
+ * actually do our cable checking etc. Thankfully we don't need
+ * to do the plumbing for other cases.
+ */
+ switch (port_map[port])
+ {
+ case PORT_PATA0:
+ if (control & (1 << 5))
+ return 0;
+ if (control & (1 << 3)) /* 40/80 pin primary */
+ ap->cbl = ATA_CBL_PATA40;
+ else
+ ap->cbl = ATA_CBL_PATA80;
+ break;
+ case PORT_PATA1:
+ /* Bit 21 is set if the port is enabled */
+ if ((control5 & (1 << 21)) == 0)
+ return 0;
+ if (control5 & (1 << 19)) /* 40/80 pin secondary */
+ ap->cbl = ATA_CBL_PATA40;
+ else
+ ap->cbl = ATA_CBL_PATA80;
+ break;
+ case PORT_SATA:
+ ap->cbl = ATA_CBL_SATA;
+ break;
+ }
+ return ata_std_prereset(ap);
+}
+
+/**
+ * jmicron_error_handler - Setup and error handler
+ * @ap: Port to handle
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void jmicron_error_handler(struct ata_port *ap)
+{
+ return ata_bmdma_drive_eh(ap, jmicron_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
+}
+
+/* No PIO or DMA methods needed for this device */
+
+static struct scsi_host_template jmicron_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ /* Special handling needed if you have sector or LBA48 limits */
+ .max_sectors = ATA_MAX_SECTORS,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ /* Use standard CHS mapping rules */
+ .bios_param = ata_std_bios_param,
+};
+
+static const struct ata_port_operations jmicron_ops = {
+ .port_disable = ata_port_disable,
+
+ /* Task file is PCI ATA format, use helpers */
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = jmicron_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ /* BMDMA handling is PCI ATA format, use helpers */
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+ .data_xfer = ata_pio_data_xfer,
+
+ /* IRQ-related hooks */
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ /* Generic PATA PCI ATA helpers */
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop,
+};
+
+
+/**
+ * jmicron_init_one - Register Jmicron ATA PCI device with kernel services
+ * @pdev: PCI device to register
+ * @ent: Entry in jmicron_pci_tbl matching with @pdev
+ *
+ * Called from kernel PCI layer.
+ *
+ * LOCKING:
+ * Inherited from PCI layer (may sleep).
+ *
+ * RETURNS:
+ * Zero on success, or -ERRNO value.
+ */
+
+static int jmicron_init_one (struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ static struct ata_port_info info = {
+ .sht = &jmicron_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x3f,
+
+ .port_ops = &jmicron_ops,
+ };
+ struct ata_port_info *port_info[2] = { &info, &info };
+
+ u32 reg;
+
+ if (id->driver_data != 368) {
+ /* Put the controller into AHCI mode in case the AHCI driver
+ has not yet been loaded. This can be done with either
+ function present */
+
+ /* FIXME: We may want a way to override this in future */
+ pci_write_config_byte(pdev, 0x41, 0xa1);
+ }
+
+ /* PATA controller is fn 1, AHCI is fn 0 */
+ if (PCI_FUNC(pdev->devfn) != 1)
+ return -ENODEV;
+
+ if ( id->driver_data == 365 || id->driver_data == 366) {
+ /* The 365/66 have two PATA channels, redirect the second */
+ pci_read_config_dword(pdev, 0x80, &reg);
+ reg |= (1 << 24); /* IDE1 to PATA IDE secondary */
+ pci_write_config_dword(pdev, 0x80, reg);
+ }
+
+ return ata_pci_init_one(pdev, port_info, 2);
+}
+
+static const struct pci_device_id jmicron_pci_tbl[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB361), 361},
+ { PCI_DEVICE(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB363), 363},
+ { PCI_DEVICE(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB365), 365},
+ { PCI_DEVICE(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB366), 366},
+ { PCI_DEVICE(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB368), 368},
+ { } /* terminate list */
+};
+
+static struct pci_driver jmicron_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = jmicron_pci_tbl,
+ .probe = jmicron_init_one,
+ .remove = ata_pci_remove_one,
+};
+
+static int __init jmicron_init(void)
+{
+ return pci_register_driver(&jmicron_pci_driver);
+}
+
+static void __exit jmicron_exit(void)
+{
+ pci_unregister_driver(&jmicron_pci_driver);
+}
+
+module_init(jmicron_init);
+module_exit(jmicron_exit);
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("SCSI low-level driver for Jmicron PATA ports");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, jmicron_pci_tbl);
+MODULE_VERSION(DRV_VERSION);
+
diff --git a/drivers/ata/pata_legacy.c b/drivers/ata/pata_legacy.c
new file mode 100644
index 00000000000..10231ef731d
--- /dev/null
+++ b/drivers/ata/pata_legacy.c
@@ -0,0 +1,949 @@
+/*
+ * pata-legacy.c - Legacy port PATA/SATA controller driver.
+ * Copyright 2005/2006 Red Hat <alan@redhat.com>, all rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * An ATA driver for the legacy ATA ports.
+ *
+ * Data Sources:
+ * Opti 82C465/82C611 support: Data sheets at opti-inc.com
+ * HT6560 series:
+ * Promise 20230/20620:
+ * http://www.ryston.cz/petr/vlb/pdc20230b.html
+ * http://www.ryston.cz/petr/vlb/pdc20230c.html
+ * http://www.ryston.cz/petr/vlb/pdc20630.html
+ *
+ * Unsupported but docs exist:
+ * Appian/Adaptec AIC25VL01/Cirrus Logic PD7220
+ * Winbond W83759A
+ *
+ * This driver handles legacy (that is "ISA/VLB side") IDE ports found
+ * on PC class systems. There are three hybrid devices that are exceptions
+ * The Cyrix 5510/5520 where a pre SFF ATA device is on the bridge and
+ * the MPIIX where the tuning is PCI side but the IDE is "ISA side".
+ *
+ * Specific support is included for the ht6560a/ht6560b/opti82c611a/
+ * opti82c465mv/promise 20230c/20630
+ *
+ * Use the autospeed and pio_mask options with:
+ * Appian ADI/2 aka CLPD7220 or AIC25VL01.
+ * Use the jumpers, autospeed and set pio_mask to the mode on the jumpers with
+ * Goldstar GM82C711, PIC-1288A-125, UMC 82C871F, Winbond W83759,
+ * Winbond W83759A, Promise PDC20230-B
+ *
+ * For now use autospeed and pio_mask as above with the W83759A. This may
+ * change.
+ *
+ * TODO
+ * Merge existing pata_qdi driver
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <scsi/scsi_host.h>
+#include <linux/ata.h>
+#include <linux/libata.h>
+#include <linux/platform_device.h>
+
+#define DRV_NAME "pata_legacy"
+#define DRV_VERSION "0.5.3"
+
+#define NR_HOST 6
+
+static int legacy_port[NR_HOST] = { 0x1f0, 0x170, 0x1e8, 0x168, 0x1e0, 0x160 };
+static int legacy_irq[NR_HOST] = { 15, 14, 11, 10, 8, 12 };
+
+struct legacy_data {
+ unsigned long timing;
+ u8 clock[2];
+ u8 last;
+ int fast;
+ struct platform_device *platform_dev;
+
+};
+
+static struct legacy_data legacy_data[NR_HOST];
+static struct ata_host *legacy_host[NR_HOST];
+static int nr_legacy_host;
+
+
+static int probe_all; /* Set to check all ISA port ranges */
+static int ht6560a; /* HT 6560A on primary 1, secondary 2, both 3 */
+static int ht6560b; /* HT 6560A on primary 1, secondary 2, both 3 */
+static int opti82c611a; /* Opti82c611A on primary 1, secondary 2, both 3 */
+static int opti82c46x; /* Opti 82c465MV present (pri/sec autodetect) */
+static int autospeed; /* Chip present which snoops speed changes */
+static int pio_mask = 0x1F; /* PIO range for autospeed devices */
+
+/**
+ * legacy_set_mode - mode setting
+ * @ap: IDE interface
+ *
+ * Use a non standard set_mode function. We don't want to be tuned.
+ *
+ * The BIOS configured everything. Our job is not to fiddle. Just use
+ * whatever PIO the hardware is using and leave it at that. When we
+ * get some kind of nice user driven API for control then we can
+ * expand on this as per hdparm in the base kernel.
+ */
+
+static void legacy_set_mode(struct ata_port *ap)
+{
+ int i;
+
+ for (i = 0; i < ATA_MAX_DEVICES; i++) {
+ struct ata_device *dev = &ap->device[i];
+ if (ata_dev_enabled(dev)) {
+ dev->pio_mode = XFER_PIO_0;
+ dev->xfer_mode = XFER_PIO_0;
+ dev->xfer_shift = ATA_SHIFT_PIO;
+ dev->flags |= ATA_DFLAG_PIO;
+ }
+ }
+}
+
+static struct scsi_host_template legacy_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .max_sectors = ATA_MAX_SECTORS,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .bios_param = ata_std_bios_param,
+};
+
+/*
+ * These ops are used if the user indicates the hardware
+ * snoops the commands to decide on the mode and handles the
+ * mode selection "magically" itself. Several legacy controllers
+ * do this. The mode range can be set if it is not 0x1F by setting
+ * pio_mask as well.
+ */
+
+static struct ata_port_operations simple_port_ops = {
+ .port_disable = ata_port_disable,
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = ata_bmdma_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer_noirq,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+static struct ata_port_operations legacy_port_ops = {
+ .set_mode = legacy_set_mode,
+
+ .port_disable = ata_port_disable,
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .error_handler = ata_bmdma_error_handler,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer_noirq,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+/*
+ * Promise 20230C and 20620 support
+ *
+ * This controller supports PIO0 to PIO2. We set PIO timings conservatively to
+ * allow for 50MHz Vesa Local Bus. The 20620 DMA support is weird being DMA to
+ * controller and PIO'd to the host and not supported.
+ */
+
+static void pdc20230_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ int tries = 5;
+ int pio = adev->pio_mode - XFER_PIO_0;
+ u8 rt;
+ unsigned long flags;
+
+ /* Safe as UP only. Force I/Os to occur together */
+
+ local_irq_save(flags);
+
+ /* Unlock the control interface */
+ do
+ {
+ inb(0x1F5);
+ outb(inb(0x1F2) | 0x80, 0x1F2);
+ inb(0x1F2);
+ inb(0x3F6);
+ inb(0x3F6);
+ inb(0x1F2);
+ inb(0x1F2);
+ }
+ while((inb(0x1F2) & 0x80) && --tries);
+
+ local_irq_restore(flags);
+
+ outb(inb(0x1F4) & 0x07, 0x1F4);
+
+ rt = inb(0x1F3);
+ rt &= 0x07 << (3 * adev->devno);
+ if (pio)
+ rt |= (1 + 3 * pio) << (3 * adev->devno);
+
+ udelay(100);
+ outb(inb(0x1F2) | 0x01, 0x1F2);
+ udelay(100);
+ inb(0x1F5);
+
+}
+
+static void pdc_data_xfer_vlb(struct ata_device *adev, unsigned char *buf, unsigned int buflen, int write_data)
+{
+ struct ata_port *ap = adev->ap;
+ int slop = buflen & 3;
+ unsigned long flags;
+
+ if (ata_id_has_dword_io(adev->id)) {
+ local_irq_save(flags);
+
+ /* Perform the 32bit I/O synchronization sequence */
+ inb(ap->ioaddr.nsect_addr);
+ inb(ap->ioaddr.nsect_addr);
+ inb(ap->ioaddr.nsect_addr);
+
+ /* Now the data */
+
+ if (write_data)
+ outsl(ap->ioaddr.data_addr, buf, buflen >> 2);
+ else
+ insl(ap->ioaddr.data_addr, buf, buflen >> 2);
+
+ if (unlikely(slop)) {
+ u32 pad;
+ if (write_data) {
+ memcpy(&pad, buf + buflen - slop, slop);
+ outl(le32_to_cpu(pad), ap->ioaddr.data_addr);
+ } else {
+ pad = cpu_to_le16(inl(ap->ioaddr.data_addr));
+ memcpy(buf + buflen - slop, &pad, slop);
+ }
+ }
+ local_irq_restore(flags);
+ }
+ else
+ ata_pio_data_xfer_noirq(adev, buf, buflen, write_data);
+}
+
+static struct ata_port_operations pdc20230_port_ops = {
+ .set_piomode = pdc20230_set_piomode,
+
+ .port_disable = ata_port_disable,
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .error_handler = ata_bmdma_error_handler,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = pdc_data_xfer_vlb,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+/*
+ * Holtek 6560A support
+ *
+ * This controller supports PIO0 to PIO2 (no IORDY even though higher timings
+ * can be loaded).
+ */
+
+static void ht6560a_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ u8 active, recover;
+ struct ata_timing t;
+
+ /* Get the timing data in cycles. For now play safe at 50Mhz */
+ ata_timing_compute(adev, adev->pio_mode, &t, 20000, 1000);
+
+ active = FIT(t.active, 2, 15);
+ recover = FIT(t.recover, 4, 15);
+
+ inb(0x3E6);
+ inb(0x3E6);
+ inb(0x3E6);
+ inb(0x3E6);
+
+ outb(recover << 4 | active, ap->ioaddr.device_addr);
+ inb(ap->ioaddr.status_addr);
+}
+
+static struct ata_port_operations ht6560a_port_ops = {
+ .set_piomode = ht6560a_set_piomode,
+
+ .port_disable = ata_port_disable,
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .error_handler = ata_bmdma_error_handler,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer, /* Check vlb/noirq */
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+/*
+ * Holtek 6560B support
+ *
+ * This controller supports PIO0 to PIO4. We honour the BIOS/jumper FIFO setting
+ * unless we see an ATAPI device in which case we force it off.
+ *
+ * FIXME: need to implement 2nd channel support.
+ */
+
+static void ht6560b_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ u8 active, recover;
+ struct ata_timing t;
+
+ /* Get the timing data in cycles. For now play safe at 50Mhz */
+ ata_timing_compute(adev, adev->pio_mode, &t, 20000, 1000);
+
+ active = FIT(t.active, 2, 15);
+ recover = FIT(t.recover, 2, 16);
+ recover &= 0x15;
+
+ inb(0x3E6);
+ inb(0x3E6);
+ inb(0x3E6);
+ inb(0x3E6);
+
+ outb(recover << 4 | active, ap->ioaddr.device_addr);
+
+ if (adev->class != ATA_DEV_ATA) {
+ u8 rconf = inb(0x3E6);
+ if (rconf & 0x24) {
+ rconf &= ~ 0x24;
+ outb(rconf, 0x3E6);
+ }
+ }
+ inb(ap->ioaddr.status_addr);
+}
+
+static struct ata_port_operations ht6560b_port_ops = {
+ .set_piomode = ht6560b_set_piomode,
+
+ .port_disable = ata_port_disable,
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .error_handler = ata_bmdma_error_handler,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer, /* FIXME: Check 32bit and noirq */
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+/*
+ * Opti core chipset helpers
+ */
+
+/**
+ * opti_syscfg - read OPTI chipset configuration
+ * @reg: Configuration register to read
+ *
+ * Returns the value of an OPTI system board configuration register.
+ */
+
+static u8 opti_syscfg(u8 reg)
+{
+ unsigned long flags;
+ u8 r;
+
+ /* Uniprocessor chipset and must force cycles adjancent */
+ local_irq_save(flags);
+ outb(reg, 0x22);
+ r = inb(0x24);
+ local_irq_restore(flags);
+ return r;
+}
+
+/*
+ * Opti 82C611A
+ *
+ * This controller supports PIO0 to PIO3.
+ */
+
+static void opti82c611a_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ u8 active, recover, setup;
+ struct ata_timing t;
+ struct ata_device *pair = ata_dev_pair(adev);
+ int clock;
+ int khz[4] = { 50000, 40000, 33000, 25000 };
+ u8 rc;
+
+ /* Enter configuration mode */
+ inw(ap->ioaddr.error_addr);
+ inw(ap->ioaddr.error_addr);
+ outb(3, ap->ioaddr.nsect_addr);
+
+ /* Read VLB clock strapping */
+ clock = 1000000000 / khz[inb(ap->ioaddr.lbah_addr) & 0x03];
+
+ /* Get the timing data in cycles */
+ ata_timing_compute(adev, adev->pio_mode, &t, clock, 1000);
+
+ /* Setup timing is shared */
+ if (pair) {
+ struct ata_timing tp;
+ ata_timing_compute(pair, pair->pio_mode, &tp, clock, 1000);
+
+ ata_timing_merge(&t, &tp, &t, ATA_TIMING_SETUP);
+ }
+
+ active = FIT(t.active, 2, 17) - 2;
+ recover = FIT(t.recover, 1, 16) - 1;
+ setup = FIT(t.setup, 1, 4) - 1;
+
+ /* Select the right timing bank for write timing */
+ rc = inb(ap->ioaddr.lbal_addr);
+ rc &= 0x7F;
+ rc |= (adev->devno << 7);
+ outb(rc, ap->ioaddr.lbal_addr);
+
+ /* Write the timings */
+ outb(active << 4 | recover, ap->ioaddr.error_addr);
+
+ /* Select the right bank for read timings, also
+ load the shared timings for address */
+ rc = inb(ap->ioaddr.device_addr);
+ rc &= 0xC0;
+ rc |= adev->devno; /* Index select */
+ rc |= (setup << 4) | 0x04;
+ outb(rc, ap->ioaddr.device_addr);
+
+ /* Load the read timings */
+ outb(active << 4 | recover, ap->ioaddr.data_addr);
+
+ /* Ensure the timing register mode is right */
+ rc = inb (ap->ioaddr.lbal_addr);
+ rc &= 0x73;
+ rc |= 0x84;
+ outb(rc, ap->ioaddr.lbal_addr);
+
+ /* Exit command mode */
+ outb(0x83, ap->ioaddr.nsect_addr);
+}
+
+
+static struct ata_port_operations opti82c611a_port_ops = {
+ .set_piomode = opti82c611a_set_piomode,
+
+ .port_disable = ata_port_disable,
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .error_handler = ata_bmdma_error_handler,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+/*
+ * Opti 82C465MV
+ *
+ * This controller supports PIO0 to PIO3. Unlike the 611A the MVB
+ * version is dual channel but doesn't have a lot of unique registers.
+ */
+
+static void opti82c46x_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ u8 active, recover, setup;
+ struct ata_timing t;
+ struct ata_device *pair = ata_dev_pair(adev);
+ int clock;
+ int khz[4] = { 50000, 40000, 33000, 25000 };
+ u8 rc;
+ u8 sysclk;
+
+ /* Get the clock */
+ sysclk = opti_syscfg(0xAC) & 0xC0; /* BIOS set */
+
+ /* Enter configuration mode */
+ inw(ap->ioaddr.error_addr);
+ inw(ap->ioaddr.error_addr);
+ outb(3, ap->ioaddr.nsect_addr);
+
+ /* Read VLB clock strapping */
+ clock = 1000000000 / khz[sysclk];
+
+ /* Get the timing data in cycles */
+ ata_timing_compute(adev, adev->pio_mode, &t, clock, 1000);
+
+ /* Setup timing is shared */
+ if (pair) {
+ struct ata_timing tp;
+ ata_timing_compute(pair, pair->pio_mode, &tp, clock, 1000);
+
+ ata_timing_merge(&t, &tp, &t, ATA_TIMING_SETUP);
+ }
+
+ active = FIT(t.active, 2, 17) - 2;
+ recover = FIT(t.recover, 1, 16) - 1;
+ setup = FIT(t.setup, 1, 4) - 1;
+
+ /* Select the right timing bank for write timing */
+ rc = inb(ap->ioaddr.lbal_addr);
+ rc &= 0x7F;
+ rc |= (adev->devno << 7);
+ outb(rc, ap->ioaddr.lbal_addr);
+
+ /* Write the timings */
+ outb(active << 4 | recover, ap->ioaddr.error_addr);
+
+ /* Select the right bank for read timings, also
+ load the shared timings for address */
+ rc = inb(ap->ioaddr.device_addr);
+ rc &= 0xC0;
+ rc |= adev->devno; /* Index select */
+ rc |= (setup << 4) | 0x04;
+ outb(rc, ap->ioaddr.device_addr);
+
+ /* Load the read timings */
+ outb(active << 4 | recover, ap->ioaddr.data_addr);
+
+ /* Ensure the timing register mode is right */
+ rc = inb (ap->ioaddr.lbal_addr);
+ rc &= 0x73;
+ rc |= 0x84;
+ outb(rc, ap->ioaddr.lbal_addr);
+
+ /* Exit command mode */
+ outb(0x83, ap->ioaddr.nsect_addr);
+
+ /* We need to know this for quad device on the MVB */
+ ap->host->private_data = ap;
+}
+
+/**
+ * opt82c465mv_qc_issue_prot - command issue
+ * @qc: command pending
+ *
+ * Called when the libata layer is about to issue a command. We wrap
+ * this interface so that we can load the correct ATA timings. The
+ * MVB has a single set of timing registers and these are shared
+ * across channels. As there are two registers we really ought to
+ * track the last two used values as a sort of register window. For
+ * now we just reload on a channel switch. On the single channel
+ * setup this condition never fires so we do nothing extra.
+ *
+ * FIXME: dual channel needs ->serialize support
+ */
+
+static unsigned int opti82c46x_qc_issue_prot(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct ata_device *adev = qc->dev;
+
+ /* If timings are set and for the wrong channel (2nd test is
+ due to a libata shortcoming and will eventually go I hope) */
+ if (ap->host->private_data != ap->host
+ && ap->host->private_data != NULL)
+ opti82c46x_set_piomode(ap, adev);
+
+ return ata_qc_issue_prot(qc);
+}
+
+static struct ata_port_operations opti82c46x_port_ops = {
+ .set_piomode = opti82c46x_set_piomode,
+
+ .port_disable = ata_port_disable,
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .error_handler = ata_bmdma_error_handler,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = opti82c46x_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+
+/**
+ * legacy_init_one - attach a legacy interface
+ * @port: port number
+ * @io: I/O port start
+ * @ctrl: control port
+ * @irq: interrupt line
+ *
+ * Register an ISA bus IDE interface. Such interfaces are PIO and we
+ * assume do not support IRQ sharing.
+ */
+
+static __init int legacy_init_one(int port, unsigned long io, unsigned long ctrl, int irq)
+{
+ struct legacy_data *ld = &legacy_data[nr_legacy_host];
+ struct ata_probe_ent ae;
+ struct platform_device *pdev;
+ int ret = -EBUSY;
+ struct ata_port_operations *ops = &legacy_port_ops;
+ int pio_modes = pio_mask;
+ u32 mask = (1 << port);
+
+ if (request_region(io, 8, "pata_legacy") == NULL)
+ return -EBUSY;
+ if (request_region(ctrl, 1, "pata_legacy") == NULL)
+ goto fail_io;
+
+ pdev = platform_device_register_simple(DRV_NAME, nr_legacy_host, NULL, 0);
+ if (pdev == NULL)
+ goto fail_dev;
+
+ if (ht6560a & mask) {
+ ops = &ht6560a_port_ops;
+ pio_modes = 0x07;
+ }
+ if (ht6560b & mask) {
+ ops = &ht6560b_port_ops;
+ pio_modes = 0x1F;
+ }
+ if (opti82c611a & mask) {
+ ops = &opti82c611a_port_ops;
+ pio_modes = 0x0F;
+ }
+ if (opti82c46x & mask) {
+ ops = &opti82c46x_port_ops;
+ pio_modes = 0x0F;
+ }
+
+ /* Probe for automatically detectable controllers */
+
+ if (io == 0x1F0 && ops == &legacy_port_ops) {
+ unsigned long flags;
+
+ local_irq_save(flags);
+
+ /* Probes */
+ inb(0x1F5);
+ outb(inb(0x1F2) | 0x80, 0x1F2);
+ inb(0x1F2);
+ inb(0x3F6);
+ inb(0x3F6);
+ inb(0x1F2);
+ inb(0x1F2);
+
+ if ((inb(0x1F2) & 0x80) == 0) {
+ /* PDC20230c or 20630 ? */
+ printk(KERN_INFO "PDC20230-C/20630 VLB ATA controller detected.\n");
+ pio_modes = 0x07;
+ ops = &pdc20230_port_ops;
+ udelay(100);
+ inb(0x1F5);
+ } else {
+ outb(0x55, 0x1F2);
+ inb(0x1F2);
+ inb(0x1F2);
+ if (inb(0x1F2) == 0x00) {
+ printk(KERN_INFO "PDC20230-B VLB ATA controller detected.\n");
+ }
+ }
+ local_irq_restore(flags);
+ }
+
+
+ /* Chip does mode setting by command snooping */
+ if (ops == &legacy_port_ops && (autospeed & mask))
+ ops = &simple_port_ops;
+ memset(&ae, 0, sizeof(struct ata_probe_ent));
+ INIT_LIST_HEAD(&ae.node);
+ ae.dev = &pdev->dev;
+ ae.port_ops = ops;
+ ae.sht = &legacy_sht;
+ ae.n_ports = 1;
+ ae.pio_mask = pio_modes;
+ ae.irq = irq;
+ ae.irq_flags = 0;
+ ae.port_flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST;
+ ae.port[0].cmd_addr = io;
+ ae.port[0].altstatus_addr = ctrl;
+ ae.port[0].ctl_addr = ctrl;
+ ata_std_ports(&ae.port[0]);
+ ae.private_data = ld;
+
+ ret = ata_device_add(&ae);
+ if (ret == 0) {
+ ret = -ENODEV;
+ goto fail;
+ }
+ legacy_host[nr_legacy_host++] = dev_get_drvdata(&pdev->dev);
+ ld->platform_dev = pdev;
+ return 0;
+
+fail:
+ platform_device_unregister(pdev);
+fail_dev:
+ release_region(ctrl, 1);
+fail_io:
+ release_region(io, 8);
+ return ret;
+}
+
+/**
+ * legacy_check_special_cases - ATA special cases
+ * @p: PCI device to check
+ * @master: set this if we find an ATA master
+ * @master: set this if we find an ATA secondary
+ *
+ * A small number of vendors implemented early PCI ATA interfaces on bridge logic
+ * without the ATA interface being PCI visible. Where we have a matching PCI driver
+ * we must skip the relevant device here. If we don't know about it then the legacy
+ * driver is the right driver anyway.
+ */
+
+static void legacy_check_special_cases(struct pci_dev *p, int *primary, int *secondary)
+{
+ /* Cyrix CS5510 pre SFF MWDMA ATA on the bridge */
+ if (p->vendor == 0x1078 && p->device == 0x0000) {
+ *primary = *secondary = 1;
+ return;
+ }
+ /* Cyrix CS5520 pre SFF MWDMA ATA on the bridge */
+ if (p->vendor == 0x1078 && p->device == 0x0002) {
+ *primary = *secondary = 1;
+ return;
+ }
+ /* Intel MPIIX - PIO ATA on non PCI side of bridge */
+ if (p->vendor == 0x8086 && p->device == 0x1234) {
+ u16 r;
+ pci_read_config_word(p, 0x6C, &r);
+ if (r & 0x8000) { /* ATA port enabled */
+ if (r & 0x4000)
+ *secondary = 1;
+ else
+ *primary = 1;
+ }
+ return;
+ }
+}
+
+
+/**
+ * legacy_init - attach legacy interfaces
+ *
+ * Attach legacy IDE interfaces by scanning the usual IRQ/port suspects.
+ * Right now we do not scan the ide0 and ide1 address but should do so
+ * for non PCI systems or systems with no PCI IDE legacy mode devices.
+ * If you fix that note there are special cases to consider like VLB
+ * drivers and CS5510/20.
+ */
+
+static __init int legacy_init(void)
+{
+ int i;
+ int ct = 0;
+ int primary = 0;
+ int secondary = 0;
+ int last_port = NR_HOST;
+
+ struct pci_dev *p = NULL;
+
+ for_each_pci_dev(p) {
+ int r;
+ /* Check for any overlap of the system ATA mappings. Native mode controllers
+ stuck on these addresses or some devices in 'raid' mode won't be found by
+ the storage class test */
+ for (r = 0; r < 6; r++) {
+ if (pci_resource_start(p, r) == 0x1f0)
+ primary = 1;
+ if (pci_resource_start(p, r) == 0x170)
+ secondary = 1;
+ }
+ /* Check for special cases */
+ legacy_check_special_cases(p, &primary, &secondary);
+
+ /* If PCI bus is present then don't probe for tertiary legacy ports */
+ if (probe_all == 0)
+ last_port = 2;
+ }
+
+ /* If an OPTI 82C46X is present find out where the channels are */
+ if (opti82c46x) {
+ static const char *optis[4] = {
+ "3/463MV", "5MV",
+ "5MVA", "5MVB"
+ };
+ u8 chans = 1;
+ u8 ctrl = (opti_syscfg(0x30) & 0xC0) >> 6;
+
+ opti82c46x = 3; /* Assume master and slave first */
+ printk(KERN_INFO DRV_NAME ": Opti 82C46%s chipset support.\n", optis[ctrl]);
+ if (ctrl == 3)
+ chans = (opti_syscfg(0x3F) & 0x20) ? 2 : 1;
+ ctrl = opti_syscfg(0xAC);
+ /* Check enabled and this port is the 465MV port. On the
+ MVB we may have two channels */
+ if (ctrl & 8) {
+ if (ctrl & 4)
+ opti82c46x = 2; /* Slave */
+ else
+ opti82c46x = 1; /* Master */
+ if (chans == 2)
+ opti82c46x = 3; /* Master and Slave */
+ } /* Slave only */
+ else if (chans == 1)
+ opti82c46x = 1;
+ }
+
+ for (i = 0; i < last_port; i++) {
+ /* Skip primary if we have seen a PCI one */
+ if (i == 0 && primary == 1)
+ continue;
+ /* Skip secondary if we have seen a PCI one */
+ if (i == 1 && secondary == 1)
+ continue;
+ if (legacy_init_one(i, legacy_port[i],
+ legacy_port[i] + 0x0206,
+ legacy_irq[i]) == 0)
+ ct++;
+ }
+ if (ct != 0)
+ return 0;
+ return -ENODEV;
+}
+
+static __exit void legacy_exit(void)
+{
+ int i;
+
+ for (i = 0; i < nr_legacy_host; i++) {
+ struct legacy_data *ld = &legacy_data[i];
+ struct ata_port *ap =legacy_host[i]->ports[0];
+ unsigned long io = ap->ioaddr.cmd_addr;
+ unsigned long ctrl = ap->ioaddr.ctl_addr;
+ ata_host_remove(legacy_host[i]);
+ platform_device_unregister(ld->platform_dev);
+ if (ld->timing)
+ release_region(ld->timing, 2);
+ release_region(io, 8);
+ release_region(ctrl, 1);
+ }
+}
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("low-level driver for legacy ATA");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
+module_param(probe_all, int, 0);
+module_param(autospeed, int, 0);
+module_param(ht6560a, int, 0);
+module_param(ht6560b, int, 0);
+module_param(opti82c611a, int, 0);
+module_param(opti82c46x, int, 0);
+module_param(pio_mask, int, 0);
+
+module_init(legacy_init);
+module_exit(legacy_exit);
+
diff --git a/drivers/ata/pata_mpiix.c b/drivers/ata/pata_mpiix.c
new file mode 100644
index 00000000000..3c65393c1f0
--- /dev/null
+++ b/drivers/ata/pata_mpiix.c
@@ -0,0 +1,310 @@
+/*
+ * pata_mpiix.c - Intel MPIIX PATA for new ATA layer
+ * (C) 2005-2006 Red Hat Inc
+ * Alan Cox <alan@redhat.com>
+ *
+ * The MPIIX is different enough to the PIIX4 and friends that we give it
+ * a separate driver. The old ide/pci code handles this by just not tuning
+ * MPIIX at all.
+ *
+ * The MPIIX also differs in another important way from the majority of PIIX
+ * devices. The chip is a bridge (pardon the pun) between the old world of
+ * ISA IDE and PCI IDE. Although the ATA timings are PCI configured the actual
+ * IDE controller is not decoded in PCI space and the chip does not claim to
+ * be IDE class PCI. This requires slightly non-standard probe logic compared
+ * with PCI IDE and also that we do not disable the device when our driver is
+ * unloaded (as it has many other functions).
+ *
+ * The driver conciously keeps this logic internally to avoid pushing quirky
+ * PATA history into the clean libata layer.
+ *
+ * Thinkpad specific note: If you boot an MPIIX using a thinkpad with a PCMCIA
+ * hard disk present this driver will not detect it. This is not a bug. In this
+ * configuration the secondary port of the MPIIX is disabled and the addresses
+ * are decoded by the PCMCIA bridge and therefore are for a generic IDE driver
+ * to operate.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+
+#define DRV_NAME "pata_mpiix"
+#define DRV_VERSION "0.7.2"
+
+enum {
+ IDETIM = 0x6C, /* IDE control register */
+ IORDY = (1 << 1),
+ PPE = (1 << 2),
+ FTIM = (1 << 0),
+ ENABLED = (1 << 15),
+ SECONDARY = (1 << 14)
+};
+
+static int mpiix_pre_reset(struct ata_port *ap)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ static const struct pci_bits mpiix_enable_bits[] = {
+ { 0x6D, 1, 0x80, 0x80 },
+ { 0x6F, 1, 0x80, 0x80 }
+ };
+
+ if (!pci_test_config_bits(pdev, &mpiix_enable_bits[ap->port_no]))
+ return -ENOENT;
+ ap->cbl = ATA_CBL_PATA40;
+ return ata_std_prereset(ap);
+}
+
+/**
+ * mpiix_error_handler - probe reset
+ * @ap: ATA port
+ *
+ * Perform the ATA probe and bus reset sequence plus specific handling
+ * for this hardware. The MPIIX has the enable bits in a different place
+ * to PIIX4 and friends. As a pure PIO device it has no cable detect
+ */
+
+static void mpiix_error_handler(struct ata_port *ap)
+{
+ ata_bmdma_drive_eh(ap, mpiix_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
+}
+
+/**
+ * mpiix_set_piomode - set initial PIO mode data
+ * @ap: ATA interface
+ * @adev: ATA device
+ *
+ * Called to do the PIO mode setup. The MPIIX allows us to program the
+ * IORDY sample point (2-5 clocks), recovery 1-4 clocks and whether
+ * prefetching or iordy are used.
+ *
+ * This would get very ugly because we can only program timing for one
+ * device at a time, the other gets PIO0. Fortunately libata calls
+ * our qc_issue_prot command before a command is issued so we can
+ * flip the timings back and forth to reduce the pain.
+ */
+
+static void mpiix_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ int control = 0;
+ int pio = adev->pio_mode - XFER_PIO_0;
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u16 idetim;
+ static const /* ISP RTC */
+ u8 timings[][2] = { { 0, 0 },
+ { 0, 0 },
+ { 1, 0 },
+ { 2, 1 },
+ { 2, 3 }, };
+
+ pci_read_config_word(pdev, IDETIM, &idetim);
+ /* Mask the IORDY/TIME/PPE0 bank for this device */
+ if (adev->class == ATA_DEV_ATA)
+ control |= PPE; /* PPE enable for disk */
+ if (ata_pio_need_iordy(adev))
+ control |= IORDY; /* IORDY */
+ if (pio > 0)
+ control |= FTIM; /* This drive is on the fast timing bank */
+
+ /* Mask out timing and clear both TIME bank selects */
+ idetim &= 0xCCEE;
+ idetim &= ~(0x07 << (2 * adev->devno));
+ idetim |= (control << (2 * adev->devno));
+
+ idetim |= (timings[pio][0] << 12) | (timings[pio][1] << 8);
+ pci_write_config_word(pdev, IDETIM, idetim);
+
+ /* We use ap->private_data as a pointer to the device currently
+ loaded for timing */
+ ap->private_data = adev;
+}
+
+/**
+ * mpiix_qc_issue_prot - command issue
+ * @qc: command pending
+ *
+ * Called when the libata layer is about to issue a command. We wrap
+ * this interface so that we can load the correct ATA timings if
+ * neccessary. Our logic also clears TIME0/TIME1 for the other device so
+ * that, even if we get this wrong, cycles to the other device will
+ * be made PIO0.
+ */
+
+static unsigned int mpiix_qc_issue_prot(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct ata_device *adev = qc->dev;
+
+ /* If modes have been configured and the channel data is not loaded
+ then load it. We have to check if pio_mode is set as the core code
+ does not set adev->pio_mode to XFER_PIO_0 while probing as would be
+ logical */
+
+ if (adev->pio_mode && adev != ap->private_data)
+ mpiix_set_piomode(ap, adev);
+
+ return ata_qc_issue_prot(qc);
+}
+
+static struct scsi_host_template mpiix_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .max_sectors = ATA_MAX_SECTORS,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .bios_param = ata_std_bios_param,
+};
+
+static struct ata_port_operations mpiix_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = mpiix_set_piomode,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = mpiix_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = mpiix_qc_issue_prot,
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+static int mpiix_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ /* Single threaded by the PCI probe logic */
+ static struct ata_probe_ent probe[2];
+ static int printed_version;
+ u16 idetim;
+ int enabled;
+
+ if (!printed_version++)
+ dev_printk(KERN_DEBUG, &dev->dev, "version " DRV_VERSION "\n");
+
+ /* MPIIX has many functions which can be turned on or off according
+ to other devices present. Make sure IDE is enabled before we try
+ and use it */
+
+ pci_read_config_word(dev, IDETIM, &idetim);
+ if (!(idetim & ENABLED))
+ return -ENODEV;
+
+ /* We do our own plumbing to avoid leaking special cases for whacko
+ ancient hardware into the core code. There are two issues to
+ worry about. #1 The chip is a bridge so if in legacy mode and
+ without BARs set fools the setup. #2 If you pci_disable_device
+ the MPIIX your box goes castors up */
+
+ INIT_LIST_HEAD(&probe[0].node);
+ probe[0].dev = pci_dev_to_dev(dev);
+ probe[0].port_ops = &mpiix_port_ops;
+ probe[0].sht = &mpiix_sht;
+ probe[0].pio_mask = 0x1F;
+ probe[0].irq = 14;
+ probe[0].irq_flags = SA_SHIRQ;
+ probe[0].port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST;
+ probe[0].n_ports = 1;
+ probe[0].port[0].cmd_addr = 0x1F0;
+ probe[0].port[0].ctl_addr = 0x3F6;
+ probe[0].port[0].altstatus_addr = 0x3F6;
+
+ /* The secondary lurks at different addresses but is otherwise
+ the same beastie */
+
+ INIT_LIST_HEAD(&probe[1].node);
+ probe[1] = probe[0];
+ probe[1].irq = 15;
+ probe[1].port[0].cmd_addr = 0x170;
+ probe[1].port[0].ctl_addr = 0x376;
+ probe[1].port[0].altstatus_addr = 0x376;
+
+ /* Let libata fill in the port details */
+ ata_std_ports(&probe[0].port[0]);
+ ata_std_ports(&probe[1].port[0]);
+
+ /* Now add the port that is active */
+ enabled = (idetim & SECONDARY) ? 1 : 0;
+
+ if (ata_device_add(&probe[enabled]))
+ return 0;
+ return -ENODEV;
+}
+
+/**
+ * mpiix_remove_one - device unload
+ * @pdev: PCI device being removed
+ *
+ * Handle an unplug/unload event for a PCI device. Unload the
+ * PCI driver but do not use the default handler as we *MUST NOT*
+ * disable the device as it has other functions.
+ */
+
+static void __devexit mpiix_remove_one(struct pci_dev *pdev)
+{
+ struct device *dev = pci_dev_to_dev(pdev);
+ struct ata_host *host = dev_get_drvdata(dev);
+
+ ata_host_remove(host);
+ dev_set_drvdata(dev, NULL);
+}
+
+
+
+static const struct pci_device_id mpiix[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371MX), },
+ { 0, },
+};
+
+static struct pci_driver mpiix_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = mpiix,
+ .probe = mpiix_init_one,
+ .remove = mpiix_remove_one
+};
+
+static int __init mpiix_init(void)
+{
+ return pci_register_driver(&mpiix_pci_driver);
+}
+
+
+static void __exit mpiix_exit(void)
+{
+ pci_unregister_driver(&mpiix_pci_driver);
+}
+
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("low-level driver for Intel MPIIX");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, mpiix);
+MODULE_VERSION(DRV_VERSION);
+
+module_init(mpiix_init);
+module_exit(mpiix_exit);
diff --git a/drivers/ata/pata_netcell.c b/drivers/ata/pata_netcell.c
new file mode 100644
index 00000000000..76eb9c90bee
--- /dev/null
+++ b/drivers/ata/pata_netcell.c
@@ -0,0 +1,174 @@
+/*
+ * pata_netcell.c - Netcell PATA driver
+ *
+ * (c) 2006 Red Hat <alan@redhat.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+#include <linux/ata.h>
+
+#define DRV_NAME "pata_netcell"
+#define DRV_VERSION "0.1.5"
+
+/**
+ * netcell_probe_init - check for 40/80 pin
+ * @ap: Port
+ *
+ * Cables are handled by the RAID controller. Report 80 pin.
+ */
+
+static int netcell_pre_reset(struct ata_port *ap)
+{
+ ap->cbl = ATA_CBL_PATA80;
+ return ata_std_prereset(ap);
+}
+
+/**
+ * netcell_probe_reset - Probe specified port on PATA host controller
+ * @ap: Port to probe
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void netcell_error_handler(struct ata_port *ap)
+{
+ return ata_bmdma_drive_eh(ap, netcell_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
+}
+
+/* No PIO or DMA methods needed for this device */
+
+static struct scsi_host_template netcell_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ /* Special handling needed if you have sector or LBA48 limits */
+ .max_sectors = ATA_MAX_SECTORS,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ /* Use standard CHS mapping rules */
+ .bios_param = ata_std_bios_param,
+};
+
+static const struct ata_port_operations netcell_ops = {
+ .port_disable = ata_port_disable,
+
+ /* Task file is PCI ATA format, use helpers */
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = netcell_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ /* BMDMA handling is PCI ATA format, use helpers */
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+ .data_xfer = ata_pio_data_xfer,
+
+ /* IRQ-related hooks */
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ /* Generic PATA PCI ATA helpers */
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop,
+};
+
+
+/**
+ * netcell_init_one - Register Netcell ATA PCI device with kernel services
+ * @pdev: PCI device to register
+ * @ent: Entry in netcell_pci_tbl matching with @pdev
+ *
+ * Called from kernel PCI layer.
+ *
+ * LOCKING:
+ * Inherited from PCI layer (may sleep).
+ *
+ * RETURNS:
+ * Zero on success, or -ERRNO value.
+ */
+
+static int netcell_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ static int printed_version;
+ static struct ata_port_info info = {
+ .sht = &netcell_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ /* Actually we don't really care about these as the
+ firmware deals with it */
+ .pio_mask = 0x1f, /* pio0-4 */
+ .mwdma_mask = 0x07, /* mwdma0-2 */
+ .udma_mask = 0x3f, /* UDMA 133 */
+ .port_ops = &netcell_ops,
+ };
+ static struct ata_port_info *port_info[2] = { &info, &info };
+
+ if (!printed_version++)
+ dev_printk(KERN_DEBUG, &pdev->dev,
+ "version " DRV_VERSION "\n");
+
+ /* Any chip specific setup/optimisation/messages here */
+ ata_pci_clear_simplex(pdev);
+
+ /* And let the library code do the work */
+ return ata_pci_init_one(pdev, port_info, 2);
+}
+
+static const struct pci_device_id netcell_pci_tbl[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_NETCELL, PCI_DEVICE_ID_REVOLUTION), },
+ { } /* terminate list */
+};
+
+static struct pci_driver netcell_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = netcell_pci_tbl,
+ .probe = netcell_init_one,
+ .remove = ata_pci_remove_one,
+};
+
+static int __init netcell_init(void)
+{
+ return pci_register_driver(&netcell_pci_driver);
+}
+
+static void __exit netcell_exit(void)
+{
+ pci_unregister_driver(&netcell_pci_driver);
+}
+
+module_init(netcell_init);
+module_exit(netcell_exit);
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("SCSI low-level driver for Netcell PATA RAID");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, netcell_pci_tbl);
+MODULE_VERSION(DRV_VERSION);
+
diff --git a/drivers/ata/pata_ns87410.c b/drivers/ata/pata_ns87410.c
new file mode 100644
index 00000000000..2005a95f48f
--- /dev/null
+++ b/drivers/ata/pata_ns87410.c
@@ -0,0 +1,233 @@
+/*
+ * pata_ns87410.c - National Semiconductor 87410 PATA for new ATA layer
+ * (C) 2006 Red Hat Inc
+ * Alan Cox <alan@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+
+#define DRV_NAME "pata_ns87410"
+#define DRV_VERSION "0.4.2"
+
+/**
+ * ns87410_pre_reset - probe begin
+ * @ap: ATA port
+ *
+ * Set up cable type and use generic probe init
+ */
+
+static int ns87410_pre_reset(struct ata_port *ap)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ static const struct pci_bits ns87410_enable_bits[] = {
+ { 0x43, 1, 0x08, 0x08 },
+ { 0x47, 1, 0x08, 0x08 }
+ };
+
+ if (!pci_test_config_bits(pdev, &ns87410_enable_bits[ap->port_no]))
+ return -ENOENT;
+ ap->cbl = ATA_CBL_PATA40;
+ return ata_std_prereset(ap);
+}
+
+/**
+ * ns87410_error_handler - probe reset
+ * @ap: ATA port
+ *
+ * Perform the ATA probe and bus reset sequence plus specific handling
+ * for this hardware. The MPIIX has the enable bits in a different place
+ * to PIIX4 and friends. As a pure PIO device it has no cable detect
+ */
+
+static void ns87410_error_handler(struct ata_port *ap)
+{
+ ata_bmdma_drive_eh(ap, ns87410_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
+}
+
+/**
+ * ns87410_set_piomode - set initial PIO mode data
+ * @ap: ATA interface
+ * @adev: ATA device
+ *
+ * Program timing data. This is kept per channel not per device,
+ * and only affects the data port.
+ */
+
+static void ns87410_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ int port = 0x40 + 4 * ap->port_no;
+ u8 idetcr, idefr;
+ struct ata_timing at;
+
+ static const u8 activebits[15] = {
+ 0, 1, 2, 3, 4,
+ 5, 5, 6, 6, 6,
+ 6, 7, 7, 7, 7
+ };
+
+ static const u8 recoverbits[12] = {
+ 0, 1, 2, 3, 4, 5, 6, 6, 7, 7, 7, 7
+ };
+
+ pci_read_config_byte(pdev, port + 3, &idefr);
+
+ if (ata_pio_need_iordy(adev))
+ idefr |= 0x04; /* IORDY enable */
+ else
+ idefr &= ~0x04;
+
+ if (ata_timing_compute(adev, adev->pio_mode, &at, 30303, 1) < 0) {
+ dev_printk(KERN_ERR, &pdev->dev, "unknown mode %d.\n", adev->pio_mode);
+ return;
+ }
+
+ at.active = FIT(at.active, 2, 16) - 2;
+ at.setup = FIT(at.setup, 1, 4) - 1;
+ at.recover = FIT(at.recover, 1, 12) - 1;
+
+ idetcr = (at.setup << 6) | (recoverbits[at.recover] << 3) | activebits[at.active];
+
+ pci_write_config_byte(pdev, port, idetcr);
+ pci_write_config_byte(pdev, port + 3, idefr);
+ /* We use ap->private_data as a pointer to the device currently
+ loaded for timing */
+ ap->private_data = adev;
+}
+
+/**
+ * ns87410_qc_issue_prot - command issue
+ * @qc: command pending
+ *
+ * Called when the libata layer is about to issue a command. We wrap
+ * this interface so that we can load the correct ATA timings if
+ * neccessary.
+ */
+
+static unsigned int ns87410_qc_issue_prot(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct ata_device *adev = qc->dev;
+
+ /* If modes have been configured and the channel data is not loaded
+ then load it. We have to check if pio_mode is set as the core code
+ does not set adev->pio_mode to XFER_PIO_0 while probing as would be
+ logical */
+
+ if (adev->pio_mode && adev != ap->private_data)
+ ns87410_set_piomode(ap, adev);
+
+ return ata_qc_issue_prot(qc);
+}
+
+static struct scsi_host_template ns87410_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .max_sectors = ATA_MAX_SECTORS,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .bios_param = ata_std_bios_param,
+};
+
+static struct ata_port_operations ns87410_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = ns87410_set_piomode,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = ns87410_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ns87410_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+static int ns87410_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ static struct ata_port_info info = {
+ .sht = &ns87410_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x0F,
+ .port_ops = &ns87410_port_ops
+ };
+ static struct ata_port_info *port_info[2] = {&info, &info};
+ return ata_pci_init_one(dev, port_info, 2);
+}
+
+static const struct pci_device_id ns87410[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87410), },
+ { 0, },
+};
+
+static struct pci_driver ns87410_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = ns87410,
+ .probe = ns87410_init_one,
+ .remove = ata_pci_remove_one
+};
+
+static int __init ns87410_init(void)
+{
+ return pci_register_driver(&ns87410_pci_driver);
+}
+
+
+static void __exit ns87410_exit(void)
+{
+ pci_unregister_driver(&ns87410_pci_driver);
+}
+
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("low-level driver for Nat Semi 87410");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, ns87410);
+MODULE_VERSION(DRV_VERSION);
+
+module_init(ns87410_init);
+module_exit(ns87410_exit);
diff --git a/drivers/ata/pata_oldpiix.c b/drivers/ata/pata_oldpiix.c
new file mode 100644
index 00000000000..31a285ca88d
--- /dev/null
+++ b/drivers/ata/pata_oldpiix.c
@@ -0,0 +1,336 @@
+/*
+ * pata_oldpiix.c - Intel PATA/SATA controllers
+ *
+ * (C) 2005 Red Hat <alan@redhat.com>
+ *
+ * Some parts based on ata_piix.c by Jeff Garzik and others.
+ *
+ * Early PIIX differs significantly from the later PIIX as it lacks
+ * SITRE and the slave timing registers. This means that you have to
+ * set timing per channel, or be clever. Libata tells us whenever it
+ * does drive selection and we use this to reload the timings.
+ *
+ * Because of these behaviour differences PIIX gets its own driver module.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+#include <linux/ata.h>
+
+#define DRV_NAME "pata_oldpiix"
+#define DRV_VERSION "0.5.2"
+
+/**
+ * oldpiix_pre_reset - probe begin
+ * @ap: ATA port
+ *
+ * Set up cable type and use generic probe init
+ */
+
+static int oldpiix_pre_reset(struct ata_port *ap)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ static const struct pci_bits oldpiix_enable_bits[] = {
+ { 0x41U, 1U, 0x80UL, 0x80UL }, /* port 0 */
+ { 0x43U, 1U, 0x80UL, 0x80UL }, /* port 1 */
+ };
+
+ if (!pci_test_config_bits(pdev, &oldpiix_enable_bits[ap->port_no]))
+ return -ENOENT;
+ ap->cbl = ATA_CBL_PATA40;
+ return ata_std_prereset(ap);
+}
+
+/**
+ * oldpiix_pata_error_handler - Probe specified port on PATA host controller
+ * @ap: Port to probe
+ * @classes:
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void oldpiix_pata_error_handler(struct ata_port *ap)
+{
+ ata_bmdma_drive_eh(ap, oldpiix_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
+}
+
+/**
+ * oldpiix_set_piomode - Initialize host controller PATA PIO timings
+ * @ap: Port whose timings we are configuring
+ * @adev: um
+ *
+ * Set PIO mode for device, in host controller PCI config space.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void oldpiix_set_piomode (struct ata_port *ap, struct ata_device *adev)
+{
+ unsigned int pio = adev->pio_mode - XFER_PIO_0;
+ struct pci_dev *dev = to_pci_dev(ap->host->dev);
+ unsigned int idetm_port= ap->port_no ? 0x42 : 0x40;
+ u16 idetm_data;
+ int control = 0;
+
+ /*
+ * See Intel Document 298600-004 for the timing programing rules
+ * for PIIX/ICH. Note that the early PIIX does not have the slave
+ * timing port at 0x44.
+ */
+
+ static const /* ISP RTC */
+ u8 timings[][2] = { { 0, 0 },
+ { 0, 0 },
+ { 1, 0 },
+ { 2, 1 },
+ { 2, 3 }, };
+
+ if (pio > 2)
+ control |= 1; /* TIME1 enable */
+ if (ata_pio_need_iordy(adev))
+ control |= 2; /* IE IORDY */
+
+ /* Intel specifies that the PPE functionality is for disk only */
+ if (adev->class == ATA_DEV_ATA)
+ control |= 4; /* PPE enable */
+
+ pci_read_config_word(dev, idetm_port, &idetm_data);
+
+ /* Enable PPE, IE and TIME as appropriate. Clear the other
+ drive timing bits */
+ if (adev->devno == 0) {
+ idetm_data &= 0xCCE0;
+ idetm_data |= control;
+ } else {
+ idetm_data &= 0xCC0E;
+ idetm_data |= (control << 4);
+ }
+ idetm_data |= (timings[pio][0] << 12) |
+ (timings[pio][1] << 8);
+ pci_write_config_word(dev, idetm_port, idetm_data);
+
+ /* Track which port is configured */
+ ap->private_data = adev;
+}
+
+/**
+ * oldpiix_set_dmamode - Initialize host controller PATA DMA timings
+ * @ap: Port whose timings we are configuring
+ * @adev: Device to program
+ * @isich: True if the device is an ICH and has IOCFG registers
+ *
+ * Set MWDMA mode for device, in host controller PCI config space.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void oldpiix_set_dmamode (struct ata_port *ap, struct ata_device *adev)
+{
+ struct pci_dev *dev = to_pci_dev(ap->host->dev);
+ u8 idetm_port = ap->port_no ? 0x42 : 0x40;
+ u16 idetm_data;
+
+ static const /* ISP RTC */
+ u8 timings[][2] = { { 0, 0 },
+ { 0, 0 },
+ { 1, 0 },
+ { 2, 1 },
+ { 2, 3 }, };
+
+ /*
+ * MWDMA is driven by the PIO timings. We must also enable
+ * IORDY unconditionally along with TIME1. PPE has already
+ * been set when the PIO timing was set.
+ */
+
+ unsigned int mwdma = adev->dma_mode - XFER_MW_DMA_0;
+ unsigned int control;
+ const unsigned int needed_pio[3] = {
+ XFER_PIO_0, XFER_PIO_3, XFER_PIO_4
+ };
+ int pio = needed_pio[mwdma] - XFER_PIO_0;
+
+ pci_read_config_word(dev, idetm_port, &idetm_data);
+
+ control = 3; /* IORDY|TIME0 */
+ /* Intel specifies that the PPE functionality is for disk only */
+ if (adev->class == ATA_DEV_ATA)
+ control |= 4; /* PPE enable */
+
+ /* If the drive MWDMA is faster than it can do PIO then
+ we must force PIO into PIO0 */
+
+ if (adev->pio_mode < needed_pio[mwdma])
+ /* Enable DMA timing only */
+ control |= 8; /* PIO cycles in PIO0 */
+
+ /* Mask out the relevant control and timing bits we will load. Also
+ clear the other drive TIME register as a precaution */
+ if (adev->devno == 0) {
+ idetm_data &= 0xCCE0;
+ idetm_data |= control;
+ } else {
+ idetm_data &= 0xCC0E;
+ idetm_data |= (control << 4);
+ }
+ idetm_data |= (timings[pio][0] << 12) | (timings[pio][1] << 8);
+ pci_write_config_word(dev, idetm_port, idetm_data);
+
+ /* Track which port is configured */
+ ap->private_data = adev;
+}
+
+/**
+ * oldpiix_qc_issue_prot - command issue
+ * @qc: command pending
+ *
+ * Called when the libata layer is about to issue a command. We wrap
+ * this interface so that we can load the correct ATA timings if
+ * neccessary. Our logic also clears TIME0/TIME1 for the other device so
+ * that, even if we get this wrong, cycles to the other device will
+ * be made PIO0.
+ */
+
+static unsigned int oldpiix_qc_issue_prot(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct ata_device *adev = qc->dev;
+
+ if (adev != ap->private_data) {
+ if (adev->dma_mode)
+ oldpiix_set_dmamode(ap, adev);
+ else if (adev->pio_mode)
+ oldpiix_set_piomode(ap, adev);
+ }
+ return ata_qc_issue_prot(qc);
+}
+
+
+static struct scsi_host_template oldpiix_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .max_sectors = ATA_MAX_SECTORS,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .bios_param = ata_std_bios_param,
+};
+
+static const struct ata_port_operations oldpiix_pata_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = oldpiix_set_piomode,
+ .set_dmamode = oldpiix_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = oldpiix_pata_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+ .qc_prep = ata_qc_prep,
+ .qc_issue = oldpiix_qc_issue_prot,
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop,
+};
+
+
+/**
+ * oldpiix_init_one - Register PIIX ATA PCI device with kernel services
+ * @pdev: PCI device to register
+ * @ent: Entry in oldpiix_pci_tbl matching with @pdev
+ *
+ * Called from kernel PCI layer. We probe for combined mode (sigh),
+ * and then hand over control to libata, for it to do the rest.
+ *
+ * LOCKING:
+ * Inherited from PCI layer (may sleep).
+ *
+ * RETURNS:
+ * Zero on success, or -ERRNO value.
+ */
+
+static int oldpiix_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ static int printed_version;
+ static struct ata_port_info info = {
+ .sht = &oldpiix_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .mwdma_mask = 0x07, /* mwdma1-2 */
+ .port_ops = &oldpiix_pata_ops,
+ };
+ static struct ata_port_info *port_info[2] = { &info, &info };
+
+ if (!printed_version++)
+ dev_printk(KERN_DEBUG, &pdev->dev,
+ "version " DRV_VERSION "\n");
+
+ return ata_pci_init_one(pdev, port_info, 2);
+}
+
+static const struct pci_device_id oldpiix_pci_tbl[] = {
+ { PCI_DEVICE(0x8086, 0x1230), },
+ { } /* terminate list */
+};
+
+static struct pci_driver oldpiix_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = oldpiix_pci_tbl,
+ .probe = oldpiix_init_one,
+ .remove = ata_pci_remove_one,
+};
+
+static int __init oldpiix_init(void)
+{
+ return pci_register_driver(&oldpiix_pci_driver);
+}
+
+static void __exit oldpiix_exit(void)
+{
+ pci_unregister_driver(&oldpiix_pci_driver);
+}
+
+
+module_init(oldpiix_init);
+module_exit(oldpiix_exit);
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("SCSI low-level driver for early PIIX series controllers");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, oldpiix_pci_tbl);
+MODULE_VERSION(DRV_VERSION);
+
diff --git a/drivers/ata/pata_opti.c b/drivers/ata/pata_opti.c
new file mode 100644
index 00000000000..57fe21f3a97
--- /dev/null
+++ b/drivers/ata/pata_opti.c
@@ -0,0 +1,290 @@
+/*
+ * pata_opti.c - ATI PATA for new ATA layer
+ * (C) 2005 Red Hat Inc
+ * Alan Cox <alan@redhat.com>
+ *
+ * Based on
+ * linux/drivers/ide/pci/opti621.c Version 0.7 Sept 10, 2002
+ *
+ * Copyright (C) 1996-1998 Linus Torvalds & authors (see below)
+ *
+ * Authors:
+ * Jaromir Koutek <miri@punknet.cz>,
+ * Jan Harkes <jaharkes@cwi.nl>,
+ * Mark Lord <mlord@pobox.com>
+ * Some parts of code are from ali14xx.c and from rz1000.c.
+ *
+ * Also consulted the FreeBSD prototype driver by Kevin Day to try
+ * and resolve some confusions. Further documentation can be found in
+ * Ralf Brown's interrupt list
+ *
+ * If you have other variants of the Opti range (Viper/Vendetta) please
+ * try this driver with those PCI idents and report back. For the later
+ * chips see the pata_optidma driver
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+
+#define DRV_NAME "pata_opti"
+#define DRV_VERSION "0.2.5"
+
+enum {
+ READ_REG = 0, /* index of Read cycle timing register */
+ WRITE_REG = 1, /* index of Write cycle timing register */
+ CNTRL_REG = 3, /* index of Control register */
+ STRAP_REG = 5, /* index of Strap register */
+ MISC_REG = 6 /* index of Miscellaneous register */
+};
+
+/**
+ * opti_pre_reset - probe begin
+ * @ap: ATA port
+ *
+ * Set up cable type and use generic probe init
+ */
+
+static int opti_pre_reset(struct ata_port *ap)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ static const struct pci_bits opti_enable_bits[] = {
+ { 0x45, 1, 0x80, 0x00 },
+ { 0x40, 1, 0x08, 0x00 }
+ };
+
+ if (!pci_test_config_bits(pdev, &opti_enable_bits[ap->port_no]))
+ return -ENOENT;
+
+ ap->cbl = ATA_CBL_PATA40;
+ return ata_std_prereset(ap);
+}
+
+/**
+ * opti_probe_reset - probe reset
+ * @ap: ATA port
+ *
+ * Perform the ATA probe and bus reset sequence plus specific handling
+ * for this hardware. The Opti needs little handling - we have no UDMA66
+ * capability that needs cable detection. All we must do is check the port
+ * is enabled.
+ */
+
+static void opti_error_handler(struct ata_port *ap)
+{
+ ata_bmdma_drive_eh(ap, opti_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
+}
+
+/**
+ * opti_write_reg - control register setup
+ * @ap: ATA port
+ * @value: value
+ * @reg: control register number
+ *
+ * The Opti uses magic 'trapdoor' register accesses to do configuration
+ * rather than using PCI space as other controllers do. The double inw
+ * on the error register activates configuration mode. We can then write
+ * the control register
+ */
+
+static void opti_write_reg(struct ata_port *ap, u8 val, int reg)
+{
+ unsigned long regio = ap->ioaddr.cmd_addr;
+
+ /* These 3 unlock the control register access */
+ inw(regio + 1);
+ inw(regio + 1);
+ outb(3, regio + 2);
+
+ /* Do the I/O */
+ outb(val, regio + reg);
+
+ /* Relock */
+ outb(0x83, regio + 2);
+}
+
+#if 0
+/**
+ * opti_read_reg - control register read
+ * @ap: ATA port
+ * @reg: control register number
+ *
+ * The Opti uses magic 'trapdoor' register accesses to do configuration
+ * rather than using PCI space as other controllers do. The double inw
+ * on the error register activates configuration mode. We can then read
+ * the control register
+ */
+
+static u8 opti_read_reg(struct ata_port *ap, int reg)
+{
+ unsigned long regio = ap->ioaddr.cmd_addr;
+ u8 ret;
+ inw(regio + 1);
+ inw(regio + 1);
+ outb(3, regio + 2);
+ ret = inb(regio + reg);
+ outb(0x83, regio + 2);
+}
+#endif
+
+/**
+ * opti_set_piomode - set initial PIO mode data
+ * @ap: ATA interface
+ * @adev: ATA device
+ *
+ * Called to do the PIO mode setup. Timing numbers are taken from
+ * the FreeBSD driver then pre computed to keep the code clean. There
+ * are two tables depending on the hardware clock speed.
+ */
+
+static void opti_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ struct ata_device *pair = ata_dev_pair(adev);
+ int clock;
+ int pio = adev->pio_mode - XFER_PIO_0;
+ unsigned long regio = ap->ioaddr.cmd_addr;
+ u8 addr;
+
+ /* Address table precomputed with prefetch off and a DCLK of 2 */
+ static const u8 addr_timing[2][5] = {
+ { 0x30, 0x20, 0x20, 0x10, 0x10 },
+ { 0x20, 0x20, 0x10, 0x10, 0x10 }
+ };
+ static const u8 data_rec_timing[2][5] = {
+ { 0x6B, 0x56, 0x42, 0x32, 0x31 },
+ { 0x58, 0x44, 0x32, 0x22, 0x21 }
+ };
+
+ outb(0xff, regio + 5);
+ clock = inw(regio + 5) & 1;
+
+ /*
+ * As with many controllers the address setup time is shared
+ * and must suit both devices if present.
+ */
+
+ addr = addr_timing[clock][pio];
+ if (pair) {
+ /* Hardware constraint */
+ u8 pair_addr = addr_timing[clock][pair->pio_mode - XFER_PIO_0];
+ if (pair_addr > addr)
+ addr = pair_addr;
+ }
+
+ /* Commence primary programming sequence */
+ opti_write_reg(ap, adev->devno, MISC_REG);
+ opti_write_reg(ap, data_rec_timing[clock][pio], READ_REG);
+ opti_write_reg(ap, data_rec_timing[clock][pio], WRITE_REG);
+ opti_write_reg(ap, addr, MISC_REG);
+
+ /* Programming sequence complete, override strapping */
+ opti_write_reg(ap, 0x85, CNTRL_REG);
+}
+
+static struct scsi_host_template opti_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .max_sectors = ATA_MAX_SECTORS,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .bios_param = ata_std_bios_param,
+};
+
+static struct ata_port_operations opti_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = opti_set_piomode,
+/* .set_dmamode = opti_set_dmamode, */
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = opti_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+static int opti_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ static struct ata_port_info info = {
+ .sht = &opti_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .port_ops = &opti_port_ops
+ };
+ static struct ata_port_info *port_info[2] = { &info, &info };
+ static int printed_version;
+
+ if (!printed_version++)
+ dev_printk(KERN_DEBUG, &dev->dev, "version " DRV_VERSION "\n");
+
+ return ata_pci_init_one(dev, port_info, 2);
+}
+
+static const struct pci_device_id opti[] = {
+ { PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C621, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C825, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+ { 0, },
+};
+
+static struct pci_driver opti_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = opti,
+ .probe = opti_init_one,
+ .remove = ata_pci_remove_one
+};
+
+static int __init opti_init(void)
+{
+ return pci_register_driver(&opti_pci_driver);
+}
+
+
+static void __exit opti_exit(void)
+{
+ pci_unregister_driver(&opti_pci_driver);
+}
+
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("low-level driver for Opti 621/621X");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, opti);
+MODULE_VERSION(DRV_VERSION);
+
+module_init(opti_init);
+module_exit(opti_exit);
diff --git a/drivers/ata/pata_optidma.c b/drivers/ata/pata_optidma.c
new file mode 100644
index 00000000000..7296a20cd10
--- /dev/null
+++ b/drivers/ata/pata_optidma.c
@@ -0,0 +1,545 @@
+/*
+ * pata_optidma.c - Opti DMA PATA for new ATA layer
+ * (C) 2006 Red Hat Inc
+ * Alan Cox <alan@redhat.com>
+ *
+ * The Opti DMA controllers are related to the older PIO PCI controllers
+ * and indeed the VLB ones. The main differences are that the timing
+ * numbers are now based off PCI clocks not VLB and differ, and that
+ * MWDMA is supported.
+ *
+ * This driver should support Viper-N+, FireStar, FireStar Plus.
+ *
+ * These devices support virtual DMA for read (aka the CS5520). Later
+ * chips support UDMA33, but only if the rest of the board logic does,
+ * so you have to get this right. We don't support the virtual DMA
+ * but we do handle UDMA.
+ *
+ * Bits that are worth knowing
+ * Most control registers are shadowed into I/O registers
+ * 0x1F5 bit 0 tells you if the PCI/VLB clock is 33 or 25Mhz
+ * Virtual DMA registers *move* between rev 0x02 and rev 0x10
+ * UDMA requires a 66MHz FSB
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+
+#define DRV_NAME "pata_optidma"
+#define DRV_VERSION "0.2.2"
+
+enum {
+ READ_REG = 0, /* index of Read cycle timing register */
+ WRITE_REG = 1, /* index of Write cycle timing register */
+ CNTRL_REG = 3, /* index of Control register */
+ STRAP_REG = 5, /* index of Strap register */
+ MISC_REG = 6 /* index of Miscellaneous register */
+};
+
+static int pci_clock; /* 0 = 33 1 = 25 */
+
+/**
+ * optidma_pre_reset - probe begin
+ * @ap: ATA port
+ *
+ * Set up cable type and use generic probe init
+ */
+
+static int optidma_pre_reset(struct ata_port *ap)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ static const struct pci_bits optidma_enable_bits = {
+ 0x40, 1, 0x08, 0x00
+ };
+
+ if (ap->port_no && !pci_test_config_bits(pdev, &optidma_enable_bits))
+ return -ENOENT;
+
+ ap->cbl = ATA_CBL_PATA40;
+ return ata_std_prereset(ap);
+}
+
+/**
+ * optidma_probe_reset - probe reset
+ * @ap: ATA port
+ *
+ * Perform the ATA probe and bus reset sequence plus specific handling
+ * for this hardware. The Opti needs little handling - we have no UDMA66
+ * capability that needs cable detection. All we must do is check the port
+ * is enabled.
+ */
+
+static void optidma_error_handler(struct ata_port *ap)
+{
+ ata_bmdma_drive_eh(ap, optidma_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
+}
+
+/**
+ * optidma_unlock - unlock control registers
+ * @ap: ATA port
+ *
+ * Unlock the control register block for this adapter. Registers must not
+ * be unlocked in a situation where libata might look at them.
+ */
+
+static void optidma_unlock(struct ata_port *ap)
+{
+ unsigned long regio = ap->ioaddr.cmd_addr;
+
+ /* These 3 unlock the control register access */
+ inw(regio + 1);
+ inw(regio + 1);
+ outb(3, regio + 2);
+}
+
+/**
+ * optidma_lock - issue temporary relock
+ * @ap: ATA port
+ *
+ * Re-lock the configuration register settings.
+ */
+
+static void optidma_lock(struct ata_port *ap)
+{
+ unsigned long regio = ap->ioaddr.cmd_addr;
+
+ /* Relock */
+ outb(0x83, regio + 2);
+}
+
+/**
+ * optidma_set_mode - set mode data
+ * @ap: ATA interface
+ * @adev: ATA device
+ * @mode: Mode to set
+ *
+ * Called to do the DMA or PIO mode setup. Timing numbers are all
+ * pre computed to keep the code clean. There are two tables depending
+ * on the hardware clock speed.
+ *
+ * WARNING: While we do this the IDE registers vanish. If we take an
+ * IRQ here we depend on the host set locking to avoid catastrophe.
+ */
+
+static void optidma_set_mode(struct ata_port *ap, struct ata_device *adev, u8 mode)
+{
+ struct ata_device *pair = ata_dev_pair(adev);
+ int pio = adev->pio_mode - XFER_PIO_0;
+ int dma = adev->dma_mode - XFER_MW_DMA_0;
+ unsigned long regio = ap->ioaddr.cmd_addr;
+ u8 addr;
+
+ /* Address table precomputed with a DCLK of 2 */
+ static const u8 addr_timing[2][5] = {
+ { 0x30, 0x20, 0x20, 0x10, 0x10 },
+ { 0x20, 0x20, 0x10, 0x10, 0x10 }
+ };
+ static const u8 data_rec_timing[2][5] = {
+ { 0x59, 0x46, 0x30, 0x20, 0x20 },
+ { 0x46, 0x32, 0x20, 0x20, 0x10 }
+ };
+ static const u8 dma_data_rec_timing[2][3] = {
+ { 0x76, 0x20, 0x20 },
+ { 0x54, 0x20, 0x10 }
+ };
+
+ /* Switch from IDE to control mode */
+ optidma_unlock(ap);
+
+
+ /*
+ * As with many controllers the address setup time is shared
+ * and must suit both devices if present. FIXME: Check if we
+ * need to look at slowest of PIO/DMA mode of either device
+ */
+
+ if (mode >= XFER_MW_DMA_0)
+ addr = 0;
+ else
+ addr = addr_timing[pci_clock][pio];
+
+ if (pair) {
+ u8 pair_addr;
+ /* Hardware constraint */
+ if (pair->dma_mode)
+ pair_addr = 0;
+ else
+ pair_addr = addr_timing[pci_clock][pair->pio_mode - XFER_PIO_0];
+ if (pair_addr > addr)
+ addr = pair_addr;
+ }
+
+ /* Commence primary programming sequence */
+ /* First we load the device number into the timing select */
+ outb(adev->devno, regio + MISC_REG);
+ /* Now we load the data timings into read data/write data */
+ if (mode < XFER_MW_DMA_0) {
+ outb(data_rec_timing[pci_clock][pio], regio + READ_REG);
+ outb(data_rec_timing[pci_clock][pio], regio + WRITE_REG);
+ } else if (mode < XFER_UDMA_0) {
+ outb(dma_data_rec_timing[pci_clock][dma], regio + READ_REG);
+ outb(dma_data_rec_timing[pci_clock][dma], regio + WRITE_REG);
+ }
+ /* Finally we load the address setup into the misc register */
+ outb(addr | adev->devno, regio + MISC_REG);
+
+ /* Programming sequence complete, timing 0 dev 0, timing 1 dev 1 */
+ outb(0x85, regio + CNTRL_REG);
+
+ /* Switch back to IDE mode */
+ optidma_lock(ap);
+
+ /* Note: at this point our programming is incomplete. We are
+ not supposed to program PCI 0x43 "things we hacked onto the chip"
+ until we've done both sets of PIO/DMA timings */
+}
+
+/**
+ * optiplus_set_mode - DMA setup for Firestar Plus
+ * @ap: ATA port
+ * @adev: device
+ * @mode: desired mode
+ *
+ * The Firestar plus has additional UDMA functionality for UDMA0-2 and
+ * requires we do some additional work. Because the base work we must do
+ * is mostly shared we wrap the Firestar setup functionality in this
+ * one
+ */
+
+static void optiplus_set_mode(struct ata_port *ap, struct ata_device *adev, u8 mode)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u8 udcfg;
+ u8 udslave;
+ int dev2 = 2 * adev->devno;
+ int unit = 2 * ap->port_no + adev->devno;
+ int udma = mode - XFER_UDMA_0;
+
+ pci_read_config_byte(pdev, 0x44, &udcfg);
+ if (mode <= XFER_UDMA_0) {
+ udcfg &= ~(1 << unit);
+ optidma_set_mode(ap, adev, adev->dma_mode);
+ } else {
+ udcfg |= (1 << unit);
+ if (ap->port_no) {
+ pci_read_config_byte(pdev, 0x45, &udslave);
+ udslave &= ~(0x03 << dev2);
+ udslave |= (udma << dev2);
+ pci_write_config_byte(pdev, 0x45, udslave);
+ } else {
+ udcfg &= ~(0x30 << dev2);
+ udcfg |= (udma << dev2);
+ }
+ }
+ pci_write_config_byte(pdev, 0x44, udcfg);
+}
+
+/**
+ * optidma_set_pio_mode - PIO setup callback
+ * @ap: ATA port
+ * @adev: Device
+ *
+ * The libata core provides separate functions for handling PIO and
+ * DMA programming. The architecture of the Firestar makes it easier
+ * for us to have a common function so we provide wrappers
+ */
+
+static void optidma_set_pio_mode(struct ata_port *ap, struct ata_device *adev)
+{
+ optidma_set_mode(ap, adev, adev->pio_mode);
+}
+
+/**
+ * optidma_set_dma_mode - DMA setup callback
+ * @ap: ATA port
+ * @adev: Device
+ *
+ * The libata core provides separate functions for handling PIO and
+ * DMA programming. The architecture of the Firestar makes it easier
+ * for us to have a common function so we provide wrappers
+ */
+
+static void optidma_set_dma_mode(struct ata_port *ap, struct ata_device *adev)
+{
+ optidma_set_mode(ap, adev, adev->dma_mode);
+}
+
+/**
+ * optiplus_set_pio_mode - PIO setup callback
+ * @ap: ATA port
+ * @adev: Device
+ *
+ * The libata core provides separate functions for handling PIO and
+ * DMA programming. The architecture of the Firestar makes it easier
+ * for us to have a common function so we provide wrappers
+ */
+
+static void optiplus_set_pio_mode(struct ata_port *ap, struct ata_device *adev)
+{
+ optiplus_set_mode(ap, adev, adev->pio_mode);
+}
+
+/**
+ * optiplus_set_dma_mode - DMA setup callback
+ * @ap: ATA port
+ * @adev: Device
+ *
+ * The libata core provides separate functions for handling PIO and
+ * DMA programming. The architecture of the Firestar makes it easier
+ * for us to have a common function so we provide wrappers
+ */
+
+static void optiplus_set_dma_mode(struct ata_port *ap, struct ata_device *adev)
+{
+ optiplus_set_mode(ap, adev, adev->dma_mode);
+}
+
+/**
+ * optidma_make_bits - PCI setup helper
+ * @adev: ATA device
+ *
+ * Turn the ATA device setup into PCI configuration bits
+ * for register 0x43 and return the two bits needed.
+ */
+
+static u8 optidma_make_bits43(struct ata_device *adev)
+{
+ static const u8 bits43[5] = {
+ 0, 0, 0, 1, 2
+ };
+ if (!ata_dev_enabled(adev))
+ return 0;
+ if (adev->dma_mode)
+ return adev->dma_mode - XFER_MW_DMA_0;
+ return bits43[adev->pio_mode - XFER_PIO_0];
+}
+
+/**
+ * optidma_post_set_mode - finalize PCI setup
+ * @ap: port to set up
+ *
+ * Finalise the configuration by writing the nibble of extra bits
+ * of data into the chip.
+ */
+
+static void optidma_post_set_mode(struct ata_port *ap)
+{
+ u8 r;
+ int nybble = 4 * ap->port_no;
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+
+ pci_read_config_byte(pdev, 0x43, &r);
+
+ r &= (0x0F << nybble);
+ r |= (optidma_make_bits43(&ap->device[0]) +
+ (optidma_make_bits43(&ap->device[0]) << 2)) << nybble;
+
+ pci_write_config_byte(pdev, 0x43, r);
+}
+
+static struct scsi_host_template optidma_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .max_sectors = ATA_MAX_SECTORS,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .bios_param = ata_std_bios_param,
+};
+
+static struct ata_port_operations optidma_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = optidma_set_pio_mode,
+ .set_dmamode = optidma_set_dma_mode,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .error_handler = optidma_error_handler,
+ .post_set_mode = optidma_post_set_mode,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+static struct ata_port_operations optiplus_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = optiplus_set_pio_mode,
+ .set_dmamode = optiplus_set_dma_mode,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .error_handler = optidma_error_handler,
+ .post_set_mode = optidma_post_set_mode,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+/**
+ * optiplus_with_udma - Look for UDMA capable setup
+ * @pdev; ATA controller
+ */
+
+static int optiplus_with_udma(struct pci_dev *pdev)
+{
+ u8 r;
+ int ret = 0;
+ int ioport = 0x22;
+ struct pci_dev *dev1;
+
+ /* Find function 1 */
+ dev1 = pci_get_device(0x1045, 0xC701, NULL);
+ if(dev1 == NULL)
+ return 0;
+
+ /* Rev must be >= 0x10 */
+ pci_read_config_byte(dev1, 0x08, &r);
+ if (r < 0x10)
+ goto done_nomsg;
+ /* Read the chipset system configuration to check our mode */
+ pci_read_config_byte(dev1, 0x5F, &r);
+ ioport |= (r << 8);
+ outb(0x10, ioport);
+ /* Must be 66Mhz sync */
+ if ((inb(ioport + 2) & 1) == 0)
+ goto done;
+
+ /* Check the ATA arbitration/timing is suitable */
+ pci_read_config_byte(pdev, 0x42, &r);
+ if ((r & 0x36) != 0x36)
+ goto done;
+ pci_read_config_byte(dev1, 0x52, &r);
+ if (r & 0x80) /* IDEDIR disabled */
+ ret = 1;
+done:
+ printk(KERN_WARNING "UDMA not supported in this configuration.\n");
+done_nomsg: /* Wrong chip revision */
+ pci_dev_put(dev1);
+ return ret;
+}
+
+static int optidma_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ static struct ata_port_info info_82c700 = {
+ .sht = &optidma_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .port_ops = &optidma_port_ops
+ };
+ static struct ata_port_info info_82c700_udma = {
+ .sht = &optidma_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x07,
+ .port_ops = &optiplus_port_ops
+ };
+ static struct ata_port_info *port_info[2];
+ struct ata_port_info *info = &info_82c700;
+ static int printed_version;
+
+ if (!printed_version++)
+ dev_printk(KERN_DEBUG, &dev->dev, "version " DRV_VERSION "\n");
+
+ /* Fixed location chipset magic */
+ inw(0x1F1);
+ inw(0x1F1);
+ pci_clock = inb(0x1F5) & 1; /* 0 = 33Mhz, 1 = 25Mhz */
+
+ if (optiplus_with_udma(dev))
+ info = &info_82c700_udma;
+
+ port_info[0] = port_info[1] = info;
+ return ata_pci_init_one(dev, port_info, 2);
+}
+
+static const struct pci_device_id optidma[] = {
+ { PCI_DEVICE(0x1045, 0xD568), }, /* Opti 82C700 */
+ { 0, },
+};
+
+static struct pci_driver optidma_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = optidma,
+ .probe = optidma_init_one,
+ .remove = ata_pci_remove_one
+};
+
+static int __init optidma_init(void)
+{
+ return pci_register_driver(&optidma_pci_driver);
+}
+
+
+static void __exit optidma_exit(void)
+{
+ pci_unregister_driver(&optidma_pci_driver);
+}
+
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("low-level driver for Opti Firestar/Firestar Plus");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, optidma);
+MODULE_VERSION(DRV_VERSION);
+
+module_init(optidma_init);
+module_exit(optidma_exit);
diff --git a/drivers/ata/pata_pcmcia.c b/drivers/ata/pata_pcmcia.c
new file mode 100644
index 00000000000..cb501e145a4
--- /dev/null
+++ b/drivers/ata/pata_pcmcia.c
@@ -0,0 +1,393 @@
+/*
+ * pata_pcmcia.c - PCMCIA PATA controller driver.
+ * Copyright 2005-2006 Red Hat Inc <alan@redhat.com>, all rights reserved.
+ * PCMCIA ident update Copyright 2006 Marcin Juszkiewicz
+ * <openembedded@hrw.one.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Heavily based upon ide-cs.c
+ * The initial developer of the original code is David A. Hinds
+ * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <scsi/scsi_host.h>
+#include <linux/ata.h>
+#include <linux/libata.h>
+
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ds.h>
+#include <pcmcia/cisreg.h>
+#include <pcmcia/ciscode.h>
+
+
+#define DRV_NAME "pata_pcmcia"
+#define DRV_VERSION "0.2.9"
+
+/*
+ * Private data structure to glue stuff together
+ */
+
+struct ata_pcmcia_info {
+ struct pcmcia_device *pdev;
+ int ndev;
+ dev_node_t node;
+};
+
+static struct scsi_host_template pcmcia_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .max_sectors = ATA_MAX_SECTORS,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .bios_param = ata_std_bios_param,
+};
+
+static struct ata_port_operations pcmcia_port_ops = {
+ .port_disable = ata_port_disable,
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = ata_bmdma_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer_noirq,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+#define CS_CHECK(fn, ret) \
+do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
+
+/**
+ * pcmcia_init_one - attach a PCMCIA interface
+ * @pdev: pcmcia device
+ *
+ * Register a PCMCIA IDE interface. Such interfaces are PIO 0 and
+ * shared IRQ.
+ */
+
+static int pcmcia_init_one(struct pcmcia_device *pdev)
+{
+ struct ata_probe_ent ae;
+ struct ata_pcmcia_info *info;
+ tuple_t tuple;
+ struct {
+ unsigned short buf[128];
+ cisparse_t parse;
+ config_info_t conf;
+ cistpl_cftable_entry_t dflt;
+ } *stk = NULL;
+ cistpl_cftable_entry_t *cfg;
+ int pass, last_ret = 0, last_fn = 0, is_kme = 0, ret = -ENOMEM;
+ unsigned long io_base, ctl_base;
+
+ info = kzalloc(sizeof(*info), GFP_KERNEL);
+ if (info == NULL)
+ return -ENOMEM;
+
+ /* Glue stuff together. FIXME: We may be able to get rid of info with care */
+ info->pdev = pdev;
+ pdev->priv = info;
+
+ /* Set up attributes in order to probe card and get resources */
+ pdev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+ pdev->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
+ pdev->io.IOAddrLines = 3;
+ pdev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING;
+ pdev->irq.IRQInfo1 = IRQ_LEVEL_ID;
+ pdev->conf.Attributes = CONF_ENABLE_IRQ;
+ pdev->conf.IntType = INT_MEMORY_AND_IO;
+
+ /* Allocate resoure probing structures */
+
+ stk = kzalloc(sizeof(*stk), GFP_KERNEL);
+ if (!stk)
+ goto out1;
+
+ cfg = &stk->parse.cftable_entry;
+
+ /* Tuples we are walking */
+ tuple.TupleData = (cisdata_t *)&stk->buf;
+ tuple.TupleOffset = 0;
+ tuple.TupleDataMax = 255;
+ tuple.Attributes = 0;
+ tuple.DesiredTuple = CISTPL_CONFIG;
+
+ CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(pdev, &tuple));
+ CS_CHECK(GetTupleData, pcmcia_get_tuple_data(pdev, &tuple));
+ CS_CHECK(ParseTuple, pcmcia_parse_tuple(pdev, &tuple, &stk->parse));
+ pdev->conf.ConfigBase = stk->parse.config.base;
+ pdev->conf.Present = stk->parse.config.rmask[0];
+
+ /* See if we have a manufacturer identifier. Use it to set is_kme for
+ vendor quirks */
+ tuple.DesiredTuple = CISTPL_MANFID;
+ if (!pcmcia_get_first_tuple(pdev, &tuple) && !pcmcia_get_tuple_data(pdev, &tuple) && !pcmcia_parse_tuple(pdev, &tuple, &stk->parse))
+ is_kme = ((stk->parse.manfid.manf == MANFID_KME) && ((stk->parse.manfid.card == PRODID_KME_KXLC005_A) || (stk->parse.manfid.card == PRODID_KME_KXLC005_B)));
+
+ /* Not sure if this is right... look up the current Vcc */
+ CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(pdev, &stk->conf));
+/* link->conf.Vcc = stk->conf.Vcc; */
+
+ pass = io_base = ctl_base = 0;
+ tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+ tuple.Attributes = 0;
+ CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(pdev, &tuple));
+
+ /* Now munch the resources looking for a suitable set */
+ while (1) {
+ if (pcmcia_get_tuple_data(pdev, &tuple) != 0)
+ goto next_entry;
+ if (pcmcia_parse_tuple(pdev, &tuple, &stk->parse) != 0)
+ goto next_entry;
+ /* Check for matching Vcc, unless we're desperate */
+ if (!pass) {
+ if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) {
+ if (stk->conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000)
+ goto next_entry;
+ } else if (stk->dflt.vcc.present & (1 << CISTPL_POWER_VNOM)) {
+ if (stk->conf.Vcc != stk->dflt.vcc.param[CISTPL_POWER_VNOM] / 10000)
+ goto next_entry;
+ }
+ }
+
+ if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM))
+ pdev->conf.Vpp = cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
+ else if (stk->dflt.vpp1.present & (1 << CISTPL_POWER_VNOM))
+ pdev->conf.Vpp = stk->dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000;
+
+ if ((cfg->io.nwin > 0) || (stk->dflt.io.nwin > 0)) {
+ cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &stk->dflt.io;
+ pdev->conf.ConfigIndex = cfg->index;
+ pdev->io.BasePort1 = io->win[0].base;
+ pdev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
+ if (!(io->flags & CISTPL_IO_16BIT))
+ pdev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+ if (io->nwin == 2) {
+ pdev->io.NumPorts1 = 8;
+ pdev->io.BasePort2 = io->win[1].base;
+ pdev->io.NumPorts2 = (is_kme) ? 2 : 1;
+ if (pcmcia_request_io(pdev, &pdev->io) != 0)
+ goto next_entry;
+ io_base = pdev->io.BasePort1;
+ ctl_base = pdev->io.BasePort2;
+ } else if ((io->nwin == 1) && (io->win[0].len >= 16)) {
+ pdev->io.NumPorts1 = io->win[0].len;
+ pdev->io.NumPorts2 = 0;
+ if (pcmcia_request_io(pdev, &pdev->io) != 0)
+ goto next_entry;
+ io_base = pdev->io.BasePort1;
+ ctl_base = pdev->io.BasePort1 + 0x0e;
+ } else goto next_entry;
+ /* If we've got this far, we're done */
+ break;
+ }
+next_entry:
+ if (cfg->flags & CISTPL_CFTABLE_DEFAULT)
+ memcpy(&stk->dflt, cfg, sizeof(stk->dflt));
+ if (pass) {
+ CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(pdev, &tuple));
+ } else if (pcmcia_get_next_tuple(pdev, &tuple) != 0) {
+ CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(pdev, &tuple));
+ memset(&stk->dflt, 0, sizeof(stk->dflt));
+ pass++;
+ }
+ }
+
+ CS_CHECK(RequestIRQ, pcmcia_request_irq(pdev, &pdev->irq));
+ CS_CHECK(RequestConfiguration, pcmcia_request_configuration(pdev, &pdev->conf));
+
+ /* Success. Disable the IRQ nIEN line, do quirks */
+ outb(0x02, ctl_base);
+ if (is_kme)
+ outb(0x81, ctl_base + 0x01);
+
+ /* FIXME: Could be more ports at base + 0x10 but we only deal with
+ one right now */
+ if (pdev->io.NumPorts1 >= 0x20)
+ printk(KERN_WARNING DRV_NAME ": second channel not yet supported.\n");
+
+ /*
+ * Having done the PCMCIA plumbing the ATA side is relatively
+ * sane.
+ */
+
+ memset(&ae, 0, sizeof(struct ata_probe_ent));
+ INIT_LIST_HEAD(&ae.node);
+ ae.dev = &pdev->dev;
+ ae.port_ops = &pcmcia_port_ops;
+ ae.sht = &pcmcia_sht;
+ ae.n_ports = 1;
+ ae.pio_mask = 1; /* ISA so PIO 0 cycles */
+ ae.irq = pdev->irq.AssignedIRQ;
+ ae.irq_flags = SA_SHIRQ;
+ ae.port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST;
+ ae.port[0].cmd_addr = io_base;
+ ae.port[0].altstatus_addr = ctl_base;
+ ae.port[0].ctl_addr = ctl_base;
+ ata_std_ports(&ae.port[0]);
+
+ if (ata_device_add(&ae) == 0)
+ goto failed;
+
+ info->ndev = 1;
+ kfree(stk);
+ return 0;
+
+cs_failed:
+ cs_error(pdev, last_fn, last_ret);
+failed:
+ kfree(stk);
+ info->ndev = 0;
+ pcmcia_disable_device(pdev);
+out1:
+ kfree(info);
+ return ret;
+}
+
+/**
+ * pcmcia_remove_one - unplug an pcmcia interface
+ * @pdev: pcmcia device
+ *
+ * A PCMCIA ATA device has been unplugged. Perform the needed
+ * cleanup. Also called on module unload for any active devices.
+ */
+
+static void pcmcia_remove_one(struct pcmcia_device *pdev)
+{
+ struct ata_pcmcia_info *info = pdev->priv;
+ struct device *dev = &pdev->dev;
+
+ if (info != NULL) {
+ /* If we have attached the device to the ATA layer, detach it */
+ if (info->ndev) {
+ struct ata_host *host = dev_get_drvdata(dev);
+ ata_host_remove(host);
+ dev_set_drvdata(dev, NULL);
+ }
+ info->ndev = 0;
+ pdev->priv = NULL;
+ }
+ pcmcia_disable_device(pdev);
+ kfree(info);
+}
+
+static struct pcmcia_device_id pcmcia_devices[] = {
+ PCMCIA_DEVICE_FUNC_ID(4),
+ PCMCIA_DEVICE_MANF_CARD(0x0007, 0x0000), /* Hitachi */
+ PCMCIA_DEVICE_MANF_CARD(0x0032, 0x0704),
+ PCMCIA_DEVICE_MANF_CARD(0x0045, 0x0401),
+ PCMCIA_DEVICE_MANF_CARD(0x0098, 0x0000), /* Toshiba */
+ PCMCIA_DEVICE_MANF_CARD(0x00a4, 0x002d),
+ PCMCIA_DEVICE_MANF_CARD(0x00ce, 0x0000), /* Samsung */
+ PCMCIA_DEVICE_MANF_CARD(0x0319, 0x0000), /* Hitachi */
+ PCMCIA_DEVICE_MANF_CARD(0x2080, 0x0001),
+ PCMCIA_DEVICE_MANF_CARD(0x4e01, 0x0200), /* Lexar */
+ PCMCIA_DEVICE_PROD_ID123("Caravelle", "PSC-IDE ", "PSC000", 0x8c36137c, 0xd0693ab8, 0x2768a9f0),
+ PCMCIA_DEVICE_PROD_ID123("CDROM", "IDE", "MCD-601p", 0x1b9179ca, 0xede88951, 0x0d902f74),
+ PCMCIA_DEVICE_PROD_ID123("PCMCIA", "IDE CARD", "F1", 0x281f1c5d, 0x1907960c, 0xf7fde8b9),
+ PCMCIA_DEVICE_PROD_ID12("ARGOSY", "CD-ROM", 0x78f308dc, 0x66536591),
+ PCMCIA_DEVICE_PROD_ID12("ARGOSY", "PnPIDE", 0x78f308dc, 0x0c694728),
+ PCMCIA_DEVICE_PROD_ID12("CNF CD-M", "CD-ROM", 0x7d93b852, 0x66536591),
+ PCMCIA_DEVICE_PROD_ID12("Creative Technology Ltd.", "PCMCIA CD-ROM Interface Card", 0xff8c8a45, 0xfe8020c4),
+ PCMCIA_DEVICE_PROD_ID12("Digital Equipment Corporation.", "Digital Mobile Media CD-ROM", 0x17692a66, 0xef1dcbde),
+ PCMCIA_DEVICE_PROD_ID12("EXP", "CD+GAME", 0x6f58c983, 0x63c13aaf),
+ PCMCIA_DEVICE_PROD_ID12("EXP ", "CD-ROM", 0x0a5c52fd, 0x66536591),
+ PCMCIA_DEVICE_PROD_ID12("EXP ", "PnPIDE", 0x0a5c52fd, 0x0c694728),
+ PCMCIA_DEVICE_PROD_ID12("FREECOM", "PCCARD-IDE", 0x5714cbf7, 0x48e0ab8e),
+ PCMCIA_DEVICE_PROD_ID12("HITACHI", "FLASH", 0xf4f43949, 0x9eb86aae),
+ PCMCIA_DEVICE_PROD_ID12("HITACHI", "microdrive", 0xf4f43949, 0xa6d76178),
+ PCMCIA_DEVICE_PROD_ID12("IBM", "microdrive", 0xb569a6e5, 0xa6d76178),
+ PCMCIA_DEVICE_PROD_ID12("IBM", "IBM17JSSFP20", 0xb569a6e5, 0xf2508753),
+ PCMCIA_DEVICE_PROD_ID12("IO DATA", "CBIDE2 ", 0x547e66dc, 0x8671043b),
+ PCMCIA_DEVICE_PROD_ID12("IO DATA", "PCIDE", 0x547e66dc, 0x5c5ab149),
+ PCMCIA_DEVICE_PROD_ID12("IO DATA", "PCIDEII", 0x547e66dc, 0xb3662674),
+ PCMCIA_DEVICE_PROD_ID12("LOOKMEET", "CBIDE2 ", 0xe37be2b5, 0x8671043b),
+ PCMCIA_DEVICE_PROD_ID12("M-Systems", "CF500", 0x7ed2ad87, 0x7a13045c),
+ PCMCIA_DEVICE_PROD_ID2("NinjaATA-", 0xebe0bd79),
+ PCMCIA_DEVICE_PROD_ID12("PCMCIA", "CD-ROM", 0x281f1c5d, 0x66536591),
+ PCMCIA_DEVICE_PROD_ID12("PCMCIA", "PnPIDE", 0x281f1c5d, 0x0c694728),
+ PCMCIA_DEVICE_PROD_ID12("SHUTTLE TECHNOLOGY LTD.", "PCCARD-IDE/ATAPI Adapter", 0x4a3f0ba0, 0x322560e1),
+ PCMCIA_DEVICE_PROD_ID12("SEAGATE", "ST1", 0x87c1b330, 0xe1f30883),
+ PCMCIA_DEVICE_PROD_ID12("SAMSUNG", "04/05/06", 0x43d74cb4, 0x6a22777d),
+ PCMCIA_DEVICE_PROD_ID12("SMI VENDOR", "SMI PRODUCT", 0x30896c92, 0x703cc5f6),
+ PCMCIA_DEVICE_PROD_ID12("TOSHIBA", "MK2001MPL", 0xb4585a1a, 0x3489e003),
+ PCMCIA_DEVICE_PROD_ID12("WIT", "IDE16", 0x244e5994, 0x3e232852),
+ PCMCIA_DEVICE_PROD_ID1("STI Flash", 0xe4a13209),
+ PCMCIA_DEVICE_PROD_ID12("STI", "Flash 5.0", 0xbf2df18d, 0x8cb57a0e),
+ PCMCIA_MFC_DEVICE_PROD_ID12(1, "SanDisk", "ConnectPlus", 0x7a954bd9, 0x74be00c6),
+ PCMCIA_DEVICE_NULL,
+};
+
+MODULE_DEVICE_TABLE(pcmcia, pcmcia_devices);
+
+static struct pcmcia_driver pcmcia_driver = {
+ .owner = THIS_MODULE,
+ .drv = {
+ .name = DRV_NAME,
+ },
+ .id_table = pcmcia_devices,
+ .probe = pcmcia_init_one,
+ .remove = pcmcia_remove_one,
+};
+
+static int __init pcmcia_init(void)
+{
+ return pcmcia_register_driver(&pcmcia_driver);
+}
+
+static void __exit pcmcia_exit(void)
+{
+ pcmcia_unregister_driver(&pcmcia_driver);
+}
+
+MODULE_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
new file mode 100644
index 00000000000..bd4ed6734ed
--- /dev/null
+++ b/drivers/ata/pata_pdc2027x.c
@@ -0,0 +1,867 @@
+/*
+ * Promise PATA TX2/TX4/TX2000/133 IDE driver for pdc20268 to pdc20277.
+ *
+ * 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.
+ *
+ * Ported to libata by:
+ * Albert Lee <albertcc@tw.ibm.com> IBM Corporation
+ *
+ * Copyright (C) 1998-2002 Andre Hedrick <andre@linux-ide.org>
+ * Portions Copyright (C) 1999 Promise Technology, Inc.
+ *
+ * Author: Frank Tiernan (frankt@promise.com)
+ * Released under terms of General Public License
+ *
+ *
+ * libata documentation is available via 'make {ps|pdf}docs',
+ * as Documentation/DocBook/libata.*
+ *
+ * Hardware information only available under NDA.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_cmnd.h>
+#include <linux/libata.h>
+#include <asm/io.h>
+
+#define DRV_NAME "pata_pdc2027x"
+#define DRV_VERSION "0.74-ac5"
+#undef PDC_DEBUG
+
+#ifdef PDC_DEBUG
+#define PDPRINTK(fmt, args...) printk(KERN_ERR "%s: " fmt, __FUNCTION__, ## args)
+#else
+#define PDPRINTK(fmt, args...)
+#endif
+
+enum {
+ PDC_UDMA_100 = 0,
+ PDC_UDMA_133 = 1,
+
+ PDC_100_MHZ = 100000000,
+ PDC_133_MHZ = 133333333,
+
+ PDC_SYS_CTL = 0x1100,
+ PDC_ATA_CTL = 0x1104,
+ PDC_GLOBAL_CTL = 0x1108,
+ PDC_CTCR0 = 0x110C,
+ PDC_CTCR1 = 0x1110,
+ PDC_BYTE_COUNT = 0x1120,
+ PDC_PLL_CTL = 0x1202,
+};
+
+static int pdc2027x_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
+static void pdc2027x_remove_one(struct pci_dev *pdev);
+static void pdc2027x_error_handler(struct ata_port *ap);
+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);
+static void pdc2027x_post_set_mode(struct ata_port *ap);
+static int pdc2027x_check_atapi_dma(struct ata_queued_cmd *qc);
+
+/*
+ * ATA Timing Tables based on 133MHz controller clock.
+ * These tables are only used when the controller is in 133MHz clock.
+ * If the controller is in 100MHz clock, the ASIC hardware will
+ * set the timing registers automatically when "set feature" command
+ * is issued to the device. However, if the controller clock is 133MHz,
+ * the following tables must be used.
+ */
+static struct pdc2027x_pio_timing {
+ u8 value0, value1, value2;
+} pdc2027x_pio_timing_tbl [] = {
+ { 0xfb, 0x2b, 0xac }, /* PIO mode 0 */
+ { 0x46, 0x29, 0xa4 }, /* PIO mode 1 */
+ { 0x23, 0x26, 0x64 }, /* PIO mode 2 */
+ { 0x27, 0x0d, 0x35 }, /* PIO mode 3, IORDY on, Prefetch off */
+ { 0x23, 0x09, 0x25 }, /* PIO mode 4, IORDY on, Prefetch off */
+};
+
+static struct pdc2027x_mdma_timing {
+ u8 value0, value1;
+} pdc2027x_mdma_timing_tbl [] = {
+ { 0xdf, 0x5f }, /* MDMA mode 0 */
+ { 0x6b, 0x27 }, /* MDMA mode 1 */
+ { 0x69, 0x25 }, /* MDMA mode 2 */
+};
+
+static struct pdc2027x_udma_timing {
+ u8 value0, value1, value2;
+} pdc2027x_udma_timing_tbl [] = {
+ { 0x4a, 0x0f, 0xd5 }, /* UDMA mode 0 */
+ { 0x3a, 0x0a, 0xd0 }, /* UDMA mode 1 */
+ { 0x2a, 0x07, 0xcd }, /* UDMA mode 2 */
+ { 0x1a, 0x05, 0xcd }, /* UDMA mode 3 */
+ { 0x1a, 0x03, 0xcd }, /* UDMA mode 4 */
+ { 0x1a, 0x02, 0xcb }, /* UDMA mode 5 */
+ { 0x1a, 0x01, 0xcb }, /* UDMA mode 6 */
+};
+
+static const struct pci_device_id pdc2027x_pci_tbl[] = {
+ { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20268, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PDC_UDMA_100 },
+ { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20269, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PDC_UDMA_133 },
+ { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20270, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PDC_UDMA_100 },
+ { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20271, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PDC_UDMA_133 },
+ { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20275, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PDC_UDMA_133 },
+ { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20276, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PDC_UDMA_133 },
+ { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20277, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PDC_UDMA_133 },
+ { } /* terminate list */
+};
+
+static struct pci_driver pdc2027x_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = pdc2027x_pci_tbl,
+ .probe = pdc2027x_init_one,
+ .remove = __devexit_p(pdc2027x_remove_one),
+};
+
+static struct scsi_host_template pdc2027x_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .max_sectors = ATA_MAX_SECTORS,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .bios_param = ata_std_bios_param,
+};
+
+static struct ata_port_operations pdc2027x_pata100_ops = {
+ .port_disable = ata_port_disable,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .check_atapi_dma = pdc2027x_check_atapi_dma,
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+ .data_xfer = ata_mmio_data_xfer,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = pdc2027x_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_pci_host_stop,
+};
+
+static struct ata_port_operations pdc2027x_pata133_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = pdc2027x_set_piomode,
+ .set_dmamode = pdc2027x_set_dmamode,
+ .post_set_mode = pdc2027x_post_set_mode,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .check_atapi_dma = pdc2027x_check_atapi_dma,
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+ .data_xfer = ata_mmio_data_xfer,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = pdc2027x_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_pci_host_stop,
+};
+
+static struct ata_port_info pdc2027x_port_info[] = {
+ /* PDC_UDMA_100 */
+ {
+ .sht = &pdc2027x_sht,
+ .flags = ATA_FLAG_NO_LEGACY | ATA_FLAG_SLAVE_POSS |
+ ATA_FLAG_MMIO,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .mwdma_mask = 0x07, /* mwdma0-2 */
+ .udma_mask = ATA_UDMA5, /* udma0-5 */
+ .port_ops = &pdc2027x_pata100_ops,
+ },
+ /* PDC_UDMA_133 */
+ {
+ .sht = &pdc2027x_sht,
+ .flags = ATA_FLAG_NO_LEGACY | ATA_FLAG_SLAVE_POSS |
+ ATA_FLAG_MMIO,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .mwdma_mask = 0x07, /* mwdma0-2 */
+ .udma_mask = ATA_UDMA6, /* udma0-6 */
+ .port_ops = &pdc2027x_pata133_ops,
+ },
+};
+
+MODULE_AUTHOR("Andre Hedrick, Frank Tiernan, Albert Lee");
+MODULE_DESCRIPTION("libata driver module for Promise PDC20268 to PDC20277");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+MODULE_DEVICE_TABLE(pci, pdc2027x_pci_tbl);
+
+/**
+ * port_mmio - Get the MMIO address of PDC2027x extended registers
+ * @ap: Port
+ * @offset: offset from mmio base
+ */
+static inline void __iomem *port_mmio(struct ata_port *ap, unsigned int offset)
+{
+ return ap->host->mmio_base + ap->port_no * 0x100 + offset;
+}
+
+/**
+ * dev_mmio - Get the MMIO address of PDC2027x extended registers
+ * @ap: Port
+ * @adev: device
+ * @offset: offset from mmio base
+ */
+static inline void __iomem *dev_mmio(struct ata_port *ap, struct ata_device *adev, unsigned int offset)
+{
+ u8 adj = (adev->devno) ? 0x08 : 0x00;
+ return port_mmio(ap, offset) + adj;
+}
+
+/**
+ * pdc2027x_pata_cbl_detect - Probe host controller cable detect info
+ * @ap: Port for which cable detect info is desired
+ *
+ * Read 80c cable indicator from Promise extended register.
+ * This register is latched when the system is reset.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+static void pdc2027x_cbl_detect(struct ata_port *ap)
+{
+ u32 cgcr;
+
+ /* check cable detect results */
+ cgcr = readl(port_mmio(ap, PDC_GLOBAL_CTL));
+ if (cgcr & (1 << 26))
+ goto cbl40;
+
+ PDPRINTK("No cable or 80-conductor cable on port %d\n", ap->port_no);
+
+ ap->cbl = ATA_CBL_PATA80;
+ return;
+
+cbl40:
+ printk(KERN_INFO DRV_NAME ": 40-conductor cable detected on port %d\n", ap->port_no);
+ ap->cbl = ATA_CBL_PATA40;
+ ap->udma_mask &= ATA_UDMA_MASK_40C;
+}
+
+/**
+ * pdc2027x_port_enabled - Check PDC ATA control register to see whether the port is enabled.
+ * @ap: Port to check
+ */
+static inline int pdc2027x_port_enabled(struct ata_port *ap)
+{
+ return readb(port_mmio(ap, PDC_ATA_CTL)) & 0x02;
+}
+
+/**
+ * pdc2027x_prereset - prereset for PATA host controller
+ * @ap: Target port
+ *
+ * Probeinit including cable detection.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static int pdc2027x_prereset(struct ata_port *ap)
+{
+ /* Check whether port enabled */
+ if (!pdc2027x_port_enabled(ap))
+ return -ENOENT;
+ pdc2027x_cbl_detect(ap);
+ return ata_std_prereset(ap);
+}
+
+/**
+ * pdc2027x_error_handler - Perform reset on PATA port and classify
+ * @ap: Port to reset
+ *
+ * Reset PATA phy and classify attached devices.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void pdc2027x_error_handler(struct ata_port *ap)
+{
+ ata_bmdma_drive_eh(ap, pdc2027x_prereset, ata_std_softreset, NULL, ata_std_postreset);
+}
+
+/**
+ * pdc2027x_set_piomode - Initialize host controller PATA PIO timings
+ * @ap: Port to configure
+ * @adev: um
+ * @pio: PIO mode, 0 - 4
+ *
+ * Set PIO mode for device.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void pdc2027x_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ unsigned int pio = adev->pio_mode - XFER_PIO_0;
+ u32 ctcr0, ctcr1;
+
+ PDPRINTK("adev->pio_mode[%X]\n", adev->pio_mode);
+
+ /* Sanity check */
+ if (pio > 4) {
+ printk(KERN_ERR DRV_NAME ": Unknown pio mode [%d] ignored\n", pio);
+ return;
+
+ }
+
+ /* Set the PIO timing registers using value table for 133MHz */
+ PDPRINTK("Set pio regs... \n");
+
+ ctcr0 = readl(dev_mmio(ap, adev, PDC_CTCR0));
+ ctcr0 &= 0xffff0000;
+ ctcr0 |= pdc2027x_pio_timing_tbl[pio].value0 |
+ (pdc2027x_pio_timing_tbl[pio].value1 << 8);
+ writel(ctcr0, dev_mmio(ap, adev, PDC_CTCR0));
+
+ ctcr1 = readl(dev_mmio(ap, adev, PDC_CTCR1));
+ ctcr1 &= 0x00ffffff;
+ ctcr1 |= (pdc2027x_pio_timing_tbl[pio].value2 << 24);
+ writel(ctcr1, dev_mmio(ap, adev, PDC_CTCR1));
+
+ PDPRINTK("Set pio regs done\n");
+
+ PDPRINTK("Set to pio mode[%u] \n", pio);
+}
+
+/**
+ * pdc2027x_set_dmamode - Initialize host controller PATA UDMA timings
+ * @ap: Port to configure
+ * @adev: um
+ * @udma: udma mode, XFER_UDMA_0 to XFER_UDMA_6
+ *
+ * Set UDMA mode for device.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+static void pdc2027x_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+ unsigned int dma_mode = adev->dma_mode;
+ u32 ctcr0, ctcr1;
+
+ if ((dma_mode >= XFER_UDMA_0) &&
+ (dma_mode <= XFER_UDMA_6)) {
+ /* Set the UDMA timing registers with value table for 133MHz */
+ unsigned int udma_mode = dma_mode & 0x07;
+
+ if (dma_mode == XFER_UDMA_2) {
+ /*
+ * Turn off tHOLD.
+ * If tHOLD is '1', the hardware will add half clock for data hold time.
+ * This code segment seems to be no effect. tHOLD will be overwritten below.
+ */
+ ctcr1 = readl(dev_mmio(ap, adev, PDC_CTCR1));
+ writel(ctcr1 & ~(1 << 7), dev_mmio(ap, adev, PDC_CTCR1));
+ }
+
+ PDPRINTK("Set udma regs... \n");
+
+ ctcr1 = readl(dev_mmio(ap, adev, PDC_CTCR1));
+ ctcr1 &= 0xff000000;
+ ctcr1 |= pdc2027x_udma_timing_tbl[udma_mode].value0 |
+ (pdc2027x_udma_timing_tbl[udma_mode].value1 << 8) |
+ (pdc2027x_udma_timing_tbl[udma_mode].value2 << 16);
+ writel(ctcr1, dev_mmio(ap, adev, PDC_CTCR1));
+
+ PDPRINTK("Set udma regs done\n");
+
+ PDPRINTK("Set to udma mode[%u] \n", udma_mode);
+
+ } else if ((dma_mode >= XFER_MW_DMA_0) &&
+ (dma_mode <= XFER_MW_DMA_2)) {
+ /* Set the MDMA timing registers with value table for 133MHz */
+ unsigned int mdma_mode = dma_mode & 0x07;
+
+ PDPRINTK("Set mdma regs... \n");
+ ctcr0 = readl(dev_mmio(ap, adev, PDC_CTCR0));
+
+ ctcr0 &= 0x0000ffff;
+ ctcr0 |= (pdc2027x_mdma_timing_tbl[mdma_mode].value0 << 16) |
+ (pdc2027x_mdma_timing_tbl[mdma_mode].value1 << 24);
+
+ writel(ctcr0, dev_mmio(ap, adev, PDC_CTCR0));
+ PDPRINTK("Set mdma regs done\n");
+
+ PDPRINTK("Set to mdma mode[%u] \n", mdma_mode);
+ } else {
+ printk(KERN_ERR DRV_NAME ": Unknown dma mode [%u] ignored\n", dma_mode);
+ }
+}
+
+/**
+ * pdc2027x_post_set_mode - Set the timing registers back to correct values.
+ * @ap: Port to configure
+ *
+ * The pdc2027x hardware will look at "SET FEATURES" and change the timing registers
+ * automatically. The values set by the hardware might be incorrect, under 133Mhz PLL.
+ * This function overwrites the possibly incorrect values set by the hardware to be correct.
+ */
+static void pdc2027x_post_set_mode(struct ata_port *ap)
+{
+ int i;
+
+ for (i = 0; i < ATA_MAX_DEVICES; i++) {
+ struct ata_device *dev = &ap->device[i];
+
+ if (ata_dev_enabled(dev)) {
+
+ pdc2027x_set_piomode(ap, dev);
+
+ /*
+ * Enable prefetch if the device support PIO only.
+ */
+ if (dev->xfer_shift == ATA_SHIFT_PIO) {
+ u32 ctcr1 = readl(dev_mmio(ap, dev, PDC_CTCR1));
+ ctcr1 |= (1 << 25);
+ writel(ctcr1, dev_mmio(ap, dev, PDC_CTCR1));
+
+ PDPRINTK("Turn on prefetch\n");
+ } else {
+ pdc2027x_set_dmamode(ap, dev);
+ }
+ }
+ }
+}
+
+/**
+ * pdc2027x_check_atapi_dma - Check whether ATAPI DMA can be supported for this command
+ * @qc: Metadata associated with taskfile to check
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ *
+ * RETURNS: 0 when ATAPI DMA can be used
+ * 1 otherwise
+ */
+static int pdc2027x_check_atapi_dma(struct ata_queued_cmd *qc)
+{
+ struct scsi_cmnd *cmd = qc->scsicmd;
+ u8 *scsicmd = cmd->cmnd;
+ int rc = 1; /* atapi dma off by default */
+
+ /*
+ * This workaround is from Promise's GPL driver.
+ * If ATAPI DMA is used for commands not in the
+ * following white list, say MODE_SENSE and REQUEST_SENSE,
+ * pdc2027x might hit the irq lost problem.
+ */
+ switch (scsicmd[0]) {
+ case READ_10:
+ case WRITE_10:
+ case READ_12:
+ case WRITE_12:
+ case READ_6:
+ case WRITE_6:
+ case 0xad: /* READ_DVD_STRUCTURE */
+ case 0xbe: /* READ_CD */
+ /* ATAPI DMA is ok */
+ rc = 0;
+ break;
+ default:
+ ;
+ }
+
+ return rc;
+}
+
+/**
+ * pdc_read_counter - Read the ctr counter
+ * @probe_ent: for the port address
+ */
+
+static long pdc_read_counter(struct ata_probe_ent *probe_ent)
+{
+ long counter;
+ int retry = 1;
+ u32 bccrl, bccrh, bccrlv, bccrhv;
+
+retry:
+ bccrl = readl(probe_ent->mmio_base + PDC_BYTE_COUNT) & 0xffff;
+ bccrh = readl(probe_ent->mmio_base + PDC_BYTE_COUNT + 0x100) & 0xffff;
+ rmb();
+
+ /* Read the counter values again for verification */
+ bccrlv = readl(probe_ent->mmio_base + PDC_BYTE_COUNT) & 0xffff;
+ bccrhv = readl(probe_ent->mmio_base + PDC_BYTE_COUNT + 0x100) & 0xffff;
+ rmb();
+
+ counter = (bccrh << 15) | bccrl;
+
+ PDPRINTK("bccrh [%X] bccrl [%X]\n", bccrh, bccrl);
+ PDPRINTK("bccrhv[%X] bccrlv[%X]\n", bccrhv, bccrlv);
+
+ /*
+ * The 30-bit decreasing counter are read by 2 pieces.
+ * Incorrect value may be read when both bccrh and bccrl are changing.
+ * Ex. When 7900 decrease to 78FF, wrong value 7800 might be read.
+ */
+ if (retry && !(bccrh == bccrhv && bccrl >= bccrlv)) {
+ retry--;
+ PDPRINTK("rereading counter\n");
+ goto retry;
+ }
+
+ return counter;
+}
+
+/**
+ * adjust_pll - Adjust the PLL input clock in Hz.
+ *
+ * @pdc_controller: controller specific information
+ * @probe_ent: For the port address
+ * @pll_clock: The input of PLL in HZ
+ */
+static void pdc_adjust_pll(struct ata_probe_ent *probe_ent, long pll_clock, unsigned int board_idx)
+{
+
+ u16 pll_ctl;
+ long pll_clock_khz = pll_clock / 1000;
+ long pout_required = board_idx? PDC_133_MHZ:PDC_100_MHZ;
+ long ratio = pout_required / pll_clock_khz;
+ int F, R;
+
+ /* Sanity check */
+ if (unlikely(pll_clock_khz < 5000L || pll_clock_khz > 70000L)) {
+ printk(KERN_ERR DRV_NAME ": Invalid PLL input clock %ldkHz, give up!\n", pll_clock_khz);
+ return;
+ }
+
+#ifdef PDC_DEBUG
+ PDPRINTK("pout_required is %ld\n", pout_required);
+
+ /* Show the current clock value of PLL control register
+ * (maybe already configured by the firmware)
+ */
+ pll_ctl = readw(probe_ent->mmio_base + PDC_PLL_CTL);
+
+ PDPRINTK("pll_ctl[%X]\n", pll_ctl);
+#endif
+
+ /*
+ * Calculate the ratio of F, R and OD
+ * POUT = (F + 2) / (( R + 2) * NO)
+ */
+ if (ratio < 8600L) { /* 8.6x */
+ /* Using NO = 0x01, R = 0x0D */
+ R = 0x0d;
+ } else if (ratio < 12900L) { /* 12.9x */
+ /* Using NO = 0x01, R = 0x08 */
+ R = 0x08;
+ } else if (ratio < 16100L) { /* 16.1x */
+ /* Using NO = 0x01, R = 0x06 */
+ R = 0x06;
+ } else if (ratio < 64000L) { /* 64x */
+ R = 0x00;
+ } else {
+ /* Invalid ratio */
+ printk(KERN_ERR DRV_NAME ": Invalid ratio %ld, give up!\n", ratio);
+ return;
+ }
+
+ F = (ratio * (R+2)) / 1000 - 2;
+
+ if (unlikely(F < 0 || F > 127)) {
+ /* Invalid F */
+ printk(KERN_ERR DRV_NAME ": F[%d] invalid!\n", F);
+ return;
+ }
+
+ PDPRINTK("F[%d] R[%d] ratio*1000[%ld]\n", F, R, ratio);
+
+ pll_ctl = (R << 8) | F;
+
+ PDPRINTK("Writing pll_ctl[%X]\n", pll_ctl);
+
+ writew(pll_ctl, probe_ent->mmio_base + PDC_PLL_CTL);
+ readw(probe_ent->mmio_base + PDC_PLL_CTL); /* flush */
+
+ /* Wait the PLL circuit to be stable */
+ mdelay(30);
+
+#ifdef PDC_DEBUG
+ /*
+ * Show the current clock value of PLL control register
+ * (maybe configured by the firmware)
+ */
+ pll_ctl = readw(probe_ent->mmio_base + PDC_PLL_CTL);
+
+ PDPRINTK("pll_ctl[%X]\n", pll_ctl);
+#endif
+
+ return;
+}
+
+/**
+ * detect_pll_input_clock - Detect the PLL input clock in Hz.
+ * @probe_ent: for the port address
+ * Ex. 16949000 on 33MHz PCI bus for pdc20275.
+ * Half of the PCI clock.
+ */
+static long pdc_detect_pll_input_clock(struct ata_probe_ent *probe_ent)
+{
+ u32 scr;
+ long start_count, end_count;
+ long pll_clock;
+
+ /* Read current counter value */
+ start_count = pdc_read_counter(probe_ent);
+
+ /* Start the test mode */
+ scr = readl(probe_ent->mmio_base + PDC_SYS_CTL);
+ PDPRINTK("scr[%X]\n", scr);
+ writel(scr | (0x01 << 14), probe_ent->mmio_base + PDC_SYS_CTL);
+ readl(probe_ent->mmio_base + PDC_SYS_CTL); /* flush */
+
+ /* Let the counter run for 100 ms. */
+ mdelay(100);
+
+ /* Read the counter values again */
+ end_count = pdc_read_counter(probe_ent);
+
+ /* Stop the test mode */
+ scr = readl(probe_ent->mmio_base + PDC_SYS_CTL);
+ PDPRINTK("scr[%X]\n", scr);
+ writel(scr & ~(0x01 << 14), probe_ent->mmio_base + PDC_SYS_CTL);
+ readl(probe_ent->mmio_base + PDC_SYS_CTL); /* flush */
+
+ /* calculate the input clock in Hz */
+ pll_clock = (start_count - end_count) * 10;
+
+ PDPRINTK("start[%ld] end[%ld] \n", start_count, end_count);
+ PDPRINTK("PLL input clock[%ld]Hz\n", pll_clock);
+
+ return pll_clock;
+}
+
+/**
+ * pdc_hardware_init - Initialize the hardware.
+ * @pdev: instance of pci_dev found
+ * @pdc_controller: controller specific information
+ * @pe: for the port address
+ */
+static int pdc_hardware_init(struct pci_dev *pdev, struct ata_probe_ent *pe, unsigned int board_idx)
+{
+ long pll_clock;
+
+ /*
+ * Detect PLL input clock rate.
+ * On some system, where PCI bus is running at non-standard clock rate.
+ * Ex. 25MHz or 40MHz, we have to adjust the cycle_time.
+ * The pdc20275 controller employs PLL circuit to help correct timing registers setting.
+ */
+ pll_clock = pdc_detect_pll_input_clock(pe);
+
+ if (pll_clock < 0) /* counter overflow? Try again. */
+ pll_clock = pdc_detect_pll_input_clock(pe);
+
+ dev_printk(KERN_INFO, &pdev->dev, "PLL input clock %ld kHz\n", pll_clock/1000);
+
+ /* Adjust PLL control register */
+ pdc_adjust_pll(pe, pll_clock, board_idx);
+
+ return 0;
+}
+
+/**
+ * pdc_ata_setup_port - setup the mmio address
+ * @port: ata ioports to setup
+ * @base: base address
+ */
+static void pdc_ata_setup_port(struct ata_ioports *port, unsigned long base)
+{
+ port->cmd_addr =
+ port->data_addr = base;
+ port->feature_addr =
+ port->error_addr = base + 0x05;
+ port->nsect_addr = base + 0x0a;
+ port->lbal_addr = base + 0x0f;
+ port->lbam_addr = base + 0x10;
+ port->lbah_addr = base + 0x15;
+ port->device_addr = base + 0x1a;
+ port->command_addr =
+ port->status_addr = base + 0x1f;
+ port->altstatus_addr =
+ port->ctl_addr = base + 0x81a;
+}
+
+/**
+ * pdc2027x_init_one - PCI probe function
+ * Called when an instance of PCI adapter is inserted.
+ * This function checks whether the hardware is supported,
+ * initialize hardware and register an instance of ata_host to
+ * libata by providing struct ata_probe_ent and ata_device_add().
+ * (implements struct pci_driver.probe() )
+ *
+ * @pdev: instance of pci_dev found
+ * @ent: matching entry in the id_tbl[]
+ */
+static int __devinit pdc2027x_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ static int printed_version;
+ unsigned int board_idx = (unsigned int) ent->driver_data;
+
+ struct ata_probe_ent *probe_ent = NULL;
+ unsigned long base;
+ void __iomem *mmio_base;
+ int rc;
+
+ if (!printed_version++)
+ dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
+
+ rc = pci_enable_device(pdev);
+ if (rc)
+ return rc;
+
+ rc = pci_request_regions(pdev, DRV_NAME);
+ if (rc)
+ goto err_out;
+
+ rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
+ if (rc)
+ goto err_out_regions;
+
+ rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
+ if (rc)
+ goto err_out_regions;
+
+ /* Prepare the probe entry */
+ probe_ent = kzalloc(sizeof(*probe_ent), GFP_KERNEL);
+ if (probe_ent == NULL) {
+ rc = -ENOMEM;
+ goto err_out_regions;
+ }
+
+ probe_ent->dev = pci_dev_to_dev(pdev);
+ INIT_LIST_HEAD(&probe_ent->node);
+
+ mmio_base = pci_iomap(pdev, 5, 0);
+ if (!mmio_base) {
+ rc = -ENOMEM;
+ goto err_out_free_ent;
+ }
+
+ base = (unsigned long) mmio_base;
+
+ probe_ent->sht = pdc2027x_port_info[board_idx].sht;
+ probe_ent->port_flags = pdc2027x_port_info[board_idx].flags;
+ probe_ent->pio_mask = pdc2027x_port_info[board_idx].pio_mask;
+ probe_ent->mwdma_mask = pdc2027x_port_info[board_idx].mwdma_mask;
+ probe_ent->udma_mask = pdc2027x_port_info[board_idx].udma_mask;
+ probe_ent->port_ops = pdc2027x_port_info[board_idx].port_ops;
+
+ probe_ent->irq = pdev->irq;
+ probe_ent->irq_flags = SA_SHIRQ;
+ probe_ent->mmio_base = mmio_base;
+
+ pdc_ata_setup_port(&probe_ent->port[0], base + 0x17c0);
+ probe_ent->port[0].bmdma_addr = base + 0x1000;
+ pdc_ata_setup_port(&probe_ent->port[1], base + 0x15c0);
+ probe_ent->port[1].bmdma_addr = base + 0x1008;
+
+ probe_ent->n_ports = 2;
+
+ pci_set_master(pdev);
+ //pci_enable_intx(pdev);
+
+ /* initialize adapter */
+ if (pdc_hardware_init(pdev, probe_ent, board_idx) != 0)
+ goto err_out_free_ent;
+
+ ata_device_add(probe_ent);
+ kfree(probe_ent);
+
+ return 0;
+
+err_out_free_ent:
+ kfree(probe_ent);
+err_out_regions:
+ pci_release_regions(pdev);
+err_out:
+ pci_disable_device(pdev);
+ return rc;
+}
+
+/**
+ * pdc2027x_remove_one - Called to remove a single instance of the
+ * adapter.
+ *
+ * @dev: The PCI device to remove.
+ * FIXME: module load/unload not working yet
+ */
+static void __devexit pdc2027x_remove_one(struct pci_dev *pdev)
+{
+ ata_pci_remove_one(pdev);
+}
+
+/**
+ * pdc2027x_init - Called after this module is loaded into the kernel.
+ */
+static int __init pdc2027x_init(void)
+{
+ return pci_module_init(&pdc2027x_pci_driver);
+}
+
+/**
+ * pdc2027x_exit - Called before this module unloaded from the kernel
+ */
+static void __exit pdc2027x_exit(void)
+{
+ pci_unregister_driver(&pdc2027x_pci_driver);
+}
+
+module_init(pdc2027x_init);
+module_exit(pdc2027x_exit);
diff --git a/drivers/ata/pata_pdc202xx_old.c b/drivers/ata/pata_pdc202xx_old.c
new file mode 100644
index 00000000000..48f43432764
--- /dev/null
+++ b/drivers/ata/pata_pdc202xx_old.c
@@ -0,0 +1,423 @@
+/*
+ * pata_pdc202xx_old.c - Promise PDC202xx PATA for new ATA layer
+ * (C) 2005 Red Hat Inc
+ * Alan Cox <alan@redhat.com>
+ *
+ * Based in part on linux/drivers/ide/pci/pdc202xx_old.c
+ *
+ * First cut with LBA48/ATAPI
+ *
+ * TODO:
+ * Channel interlock/reset on both required ?
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+
+#define DRV_NAME "pata_pdc202xx_old"
+#define DRV_VERSION "0.2.1"
+
+/**
+ * pdc2024x_pre_reset - probe begin
+ * @ap: ATA port
+ *
+ * Set up cable type and use generic probe init
+ */
+
+static int pdc2024x_pre_reset(struct ata_port *ap)
+{
+ ap->cbl = ATA_CBL_PATA40;
+ return ata_std_prereset(ap);
+}
+
+
+static void pdc2024x_error_handler(struct ata_port *ap)
+{
+ ata_bmdma_drive_eh(ap, pdc2024x_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
+}
+
+
+static int pdc2026x_pre_reset(struct ata_port *ap)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u16 cis;
+
+ pci_read_config_word(pdev, 0x50, &cis);
+ if (cis & (1 << (10 + ap->port_no)))
+ ap->cbl = ATA_CBL_PATA80;
+ else
+ ap->cbl = ATA_CBL_PATA40;
+
+ return ata_std_prereset(ap);
+}
+
+static void pdc2026x_error_handler(struct ata_port *ap)
+{
+ ata_bmdma_drive_eh(ap, pdc2026x_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
+}
+
+/**
+ * pdc_configure_piomode - set chip PIO timing
+ * @ap: ATA interface
+ * @adev: ATA device
+ * @pio: PIO mode
+ *
+ * Called to do the PIO mode setup. Our timing registers are shared
+ * so a configure_dmamode call will undo any work we do here and vice
+ * versa
+ */
+
+static void pdc_configure_piomode(struct ata_port *ap, struct ata_device *adev, int pio)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ int port = 0x60 + 4 * ap->port_no + 2 * adev->devno;
+ static u16 pio_timing[5] = {
+ 0x0913, 0x050C , 0x0308, 0x0206, 0x0104
+ };
+ u8 r_ap, r_bp;
+
+ pci_read_config_byte(pdev, port, &r_ap);
+ pci_read_config_byte(pdev, port + 1, &r_bp);
+ r_ap &= ~0x3F; /* Preserve ERRDY_EN, SYNC_IN */
+ r_bp &= ~0x07;
+ r_ap |= (pio_timing[pio] >> 8);
+ r_bp |= (pio_timing[pio] & 0xFF);
+
+ if (ata_pio_need_iordy(adev))
+ r_ap |= 0x20; /* IORDY enable */
+ if (adev->class == ATA_DEV_ATA)
+ r_ap |= 0x10; /* FIFO enable */
+ pci_write_config_byte(pdev, port, r_ap);
+ pci_write_config_byte(pdev, port + 1, r_bp);
+}
+
+/**
+ * pdc_set_piomode - set initial PIO mode data
+ * @ap: ATA interface
+ * @adev: ATA device
+ *
+ * Called to do the PIO mode setup. Our timing registers are shared
+ * but we want to set the PIO timing by default.
+ */
+
+static void pdc_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ pdc_configure_piomode(ap, adev, adev->pio_mode - XFER_PIO_0);
+}
+
+/**
+ * pdc_configure_dmamode - set DMA mode in chip
+ * @ap: ATA interface
+ * @adev: ATA device
+ *
+ * Load DMA cycle times into the chip ready for a DMA transfer
+ * to occur.
+ */
+
+static void pdc_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ int port = 0x60 + 4 * ap->port_no + 2 * adev->devno;
+ static u8 udma_timing[6][2] = {
+ { 0x60, 0x03 }, /* 33 Mhz Clock */
+ { 0x40, 0x02 },
+ { 0x20, 0x01 },
+ { 0x40, 0x02 }, /* 66 Mhz Clock */
+ { 0x20, 0x01 },
+ { 0x20, 0x01 }
+ };
+ u8 r_bp, r_cp;
+
+ pci_read_config_byte(pdev, port + 1, &r_bp);
+ pci_read_config_byte(pdev, port + 2, &r_cp);
+
+ r_bp &= ~0xF0;
+ r_cp &= ~0x0F;
+
+ if (adev->dma_mode >= XFER_UDMA_0) {
+ int speed = adev->dma_mode - XFER_UDMA_0;
+ r_bp |= udma_timing[speed][0];
+ r_cp |= udma_timing[speed][1];
+
+ } else {
+ int speed = adev->dma_mode - XFER_MW_DMA_0;
+ r_bp |= 0x60;
+ r_cp |= (5 - speed);
+ }
+ pci_write_config_byte(pdev, port + 1, r_bp);
+ pci_write_config_byte(pdev, port + 2, r_cp);
+
+}
+
+/**
+ * pdc2026x_bmdma_start - DMA engine begin
+ * @qc: ATA command
+ *
+ * In UDMA3 or higher we have to clock switch for the duration of the
+ * DMA transfer sequence.
+ */
+
+static void pdc2026x_bmdma_start(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct ata_device *adev = qc->dev;
+ struct ata_taskfile *tf = &qc->tf;
+ int sel66 = ap->port_no ? 0x08: 0x02;
+
+ unsigned long master = ap->host->ports[0]->ioaddr.bmdma_addr;
+ unsigned long clock = master + 0x11;
+ unsigned long atapi_reg = master + 0x20 + (4 * ap->port_no);
+
+ u32 len;
+
+ /* Check we keep host level locking here */
+ if (adev->dma_mode >= XFER_UDMA_2)
+ outb(inb(clock) | sel66, clock);
+ else
+ outb(inb(clock) & ~sel66, clock);
+
+ /* The DMA clocks may have been trashed by a reset. FIXME: make conditional
+ and move to qc_issue ? */
+ pdc_set_dmamode(ap, qc->dev);
+
+ /* Cases the state machine will not complete correctly without help */
+ if ((tf->flags & ATA_TFLAG_LBA48) || tf->protocol == ATA_PROT_ATAPI_DMA)
+ {
+ if (tf->flags & ATA_TFLAG_LBA48)
+ len = qc->nsect * 512;
+ else
+ len = qc->nbytes;
+
+ if (tf->flags & ATA_TFLAG_WRITE)
+ len |= 0x06000000;
+ else
+ len |= 0x05000000;
+
+ outl(len, atapi_reg);
+ }
+
+ /* Activate DMA */
+ ata_bmdma_start(qc);
+}
+
+/**
+ * pdc2026x_bmdma_end - DMA engine stop
+ * @qc: ATA command
+ *
+ * After a DMA completes we need to put the clock back to 33MHz for
+ * PIO timings.
+ */
+
+static void pdc2026x_bmdma_stop(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct ata_device *adev = qc->dev;
+ struct ata_taskfile *tf = &qc->tf;
+
+ int sel66 = ap->port_no ? 0x08: 0x02;
+ /* The clock bits are in the same register for both channels */
+ unsigned long master = ap->host->ports[0]->ioaddr.bmdma_addr;
+ unsigned long clock = master + 0x11;
+ unsigned long atapi_reg = master + 0x20 + (4 * ap->port_no);
+
+ /* Cases the state machine will not complete correctly */
+ if (tf->protocol == ATA_PROT_ATAPI_DMA || ( tf->flags & ATA_TFLAG_LBA48)) {
+ outl(0, atapi_reg);
+ outb(inb(clock) & ~sel66, clock);
+ }
+ /* Check we keep host level locking here */
+ /* Flip back to 33Mhz for PIO */
+ if (adev->dma_mode >= XFER_UDMA_2)
+ outb(inb(clock) & ~sel66, clock);
+
+ ata_bmdma_stop(qc);
+}
+
+/**
+ * pdc2026x_dev_config - device setup hook
+ * @ap: ATA port
+ * @adev: newly found device
+ *
+ * Perform chip specific early setup. We need to lock the transfer
+ * sizes to 8bit to avoid making the state engine on the 2026x cards
+ * barf.
+ */
+
+static void pdc2026x_dev_config(struct ata_port *ap, struct ata_device *adev)
+{
+ adev->max_sectors = 256;
+}
+
+static struct scsi_host_template pdc_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .max_sectors = ATA_MAX_SECTORS,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .bios_param = ata_std_bios_param,
+};
+
+static struct ata_port_operations pdc2024x_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = pdc_set_piomode,
+ .set_dmamode = pdc_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = pdc2024x_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+static struct ata_port_operations pdc2026x_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = pdc_set_piomode,
+ .set_dmamode = pdc_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+ .dev_config = pdc2026x_dev_config,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = pdc2026x_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = pdc2026x_bmdma_start,
+ .bmdma_stop = pdc2026x_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+static int pdc_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ static struct ata_port_info info[3] = {
+ {
+ .sht = &pdc_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = ATA_UDMA2,
+ .port_ops = &pdc2024x_port_ops
+ },
+ {
+ .sht = &pdc_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = ATA_UDMA4,
+ .port_ops = &pdc2026x_port_ops
+ },
+ {
+ .sht = &pdc_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = ATA_UDMA5,
+ .port_ops = &pdc2026x_port_ops
+ }
+
+ };
+ static struct ata_port_info *port_info[2];
+
+ port_info[0] = port_info[1] = &info[id->driver_data];
+
+ if (dev->device == PCI_DEVICE_ID_PROMISE_20265) {
+ struct pci_dev *bridge = dev->bus->self;
+ /* Don't grab anything behind a Promise I2O RAID */
+ if (bridge && bridge->vendor == PCI_VENDOR_ID_INTEL) {
+ if( bridge->device == PCI_DEVICE_ID_INTEL_I960)
+ return -ENODEV;
+ if( bridge->device == PCI_DEVICE_ID_INTEL_I960RM)
+ return -ENODEV;
+ }
+ }
+ return ata_pci_init_one(dev, port_info, 2);
+}
+
+static struct pci_device_id pdc[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20246), 0},
+ { PCI_DEVICE(PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20262), 1},
+ { PCI_DEVICE(PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20263), 1},
+ { PCI_DEVICE(PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20265), 2},
+ { PCI_DEVICE(PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20267), 2},
+ { 0, },
+};
+
+static struct pci_driver pdc_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = pdc,
+ .probe = pdc_init_one,
+ .remove = ata_pci_remove_one
+};
+
+static int __init pdc_init(void)
+{
+ return pci_register_driver(&pdc_pci_driver);
+}
+
+
+static void __exit pdc_exit(void)
+{
+ pci_unregister_driver(&pdc_pci_driver);
+}
+
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("low-level driver for Promise 2024x and 20262-20267");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, pdc);
+MODULE_VERSION(DRV_VERSION);
+
+module_init(pdc_init);
+module_exit(pdc_exit);
diff --git a/drivers/ata/pata_qdi.c b/drivers/ata/pata_qdi.c
new file mode 100644
index 00000000000..7977f471d5e
--- /dev/null
+++ b/drivers/ata/pata_qdi.c
@@ -0,0 +1,403 @@
+/*
+ * pata_qdi.c - QDI VLB ATA controllers
+ * (C) 2006 Red Hat <alan@redhat.com>
+ *
+ * This driver mostly exists as a proof of concept for non PCI devices under
+ * libata. While the QDI6580 was 'neat' in 1993 it is no longer terribly
+ * useful.
+ *
+ * Tuning code written from the documentation at
+ * http://www.ryston.cz/petr/vlb/qd6500.html
+ * http://www.ryston.cz/petr/vlb/qd6580.html
+ *
+ * Probe code based on drivers/ide/legacy/qd65xx.c
+ * Rewritten from the work of Colten Edwards <pje120@cs.usask.ca> by
+ * Samuel Thibault <samuel.thibault@fnac.net>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+#include <linux/platform_device.h>
+
+#define DRV_NAME "pata_qdi"
+#define DRV_VERSION "0.2.4"
+
+#define NR_HOST 4 /* Two 6580s */
+
+struct qdi_data {
+ unsigned long timing;
+ u8 clock[2];
+ u8 last;
+ int fast;
+ struct platform_device *platform_dev;
+
+};
+
+static struct ata_host *qdi_host[NR_HOST];
+static struct qdi_data qdi_data[NR_HOST];
+static int nr_qdi_host;
+
+#ifdef MODULE
+static int probe_qdi = 1;
+#else
+static int probe_qdi;
+#endif
+
+static void qdi6500_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ struct ata_timing t;
+ struct qdi_data *qdi = ap->host->private_data;
+ int active, recovery;
+ u8 timing;
+
+ /* Get the timing data in cycles */
+ ata_timing_compute(adev, adev->pio_mode, &t, 30303, 1000);
+
+ if (qdi->fast) {
+ active = 8 - FIT(t.active, 1, 8);
+ recovery = 18 - FIT(t.recover, 3, 18);
+ } else {
+ active = 9 - FIT(t.active, 2, 9);
+ recovery = 15 - FIT(t.recover, 0, 15);
+ }
+ timing = (recovery << 4) | active | 0x08;
+
+ qdi->clock[adev->devno] = timing;
+
+ outb(timing, qdi->timing);
+}
+
+static void qdi6580_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ struct ata_timing t;
+ struct qdi_data *qdi = ap->host->private_data;
+ int active, recovery;
+ u8 timing;
+
+ /* Get the timing data in cycles */
+ ata_timing_compute(adev, adev->pio_mode, &t, 30303, 1000);
+
+ if (qdi->fast) {
+ active = 8 - FIT(t.active, 1, 8);
+ recovery = 18 - FIT(t.recover, 3, 18);
+ } else {
+ active = 9 - FIT(t.active, 2, 9);
+ recovery = 15 - FIT(t.recover, 0, 15);
+ }
+ timing = (recovery << 4) | active | 0x08;
+
+ qdi->clock[adev->devno] = timing;
+
+ outb(timing, qdi->timing);
+
+ /* Clear the FIFO */
+ if (adev->class != ATA_DEV_ATA)
+ outb(0x5F, (qdi->timing & 0xFFF0) + 3);
+}
+
+/**
+ * qdi_qc_issue_prot - command issue
+ * @qc: command pending
+ *
+ * Called when the libata layer is about to issue a command. We wrap
+ * this interface so that we can load the correct ATA timings.
+ */
+
+static unsigned int qdi_qc_issue_prot(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct ata_device *adev = qc->dev;
+ struct qdi_data *qdi = ap->host->private_data;
+
+ if (qdi->clock[adev->devno] != qdi->last) {
+ if (adev->pio_mode) {
+ qdi->last = qdi->clock[adev->devno];
+ outb(qdi->clock[adev->devno], qdi->timing);
+ }
+ }
+ return ata_qc_issue_prot(qc);
+}
+
+static void qdi_data_xfer(struct ata_device *adev, unsigned char *buf, unsigned int buflen, int write_data)
+{
+ struct ata_port *ap = adev->ap;
+ int slop = buflen & 3;
+
+ if (ata_id_has_dword_io(adev->id)) {
+ if (write_data)
+ outsl(ap->ioaddr.data_addr, buf, buflen >> 2);
+ else
+ insl(ap->ioaddr.data_addr, buf, buflen >> 2);
+
+ if (unlikely(slop)) {
+ u32 pad;
+ if (write_data) {
+ memcpy(&pad, buf + buflen - slop, slop);
+ outl(le32_to_cpu(pad), ap->ioaddr.data_addr);
+ } else {
+ pad = cpu_to_le16(inl(ap->ioaddr.data_addr));
+ memcpy(buf + buflen - slop, &pad, slop);
+ }
+ }
+ } else
+ ata_pio_data_xfer(adev, buf, buflen, write_data);
+}
+
+static struct scsi_host_template qdi_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .max_sectors = ATA_MAX_SECTORS,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .bios_param = ata_std_bios_param,
+};
+
+static struct ata_port_operations qdi6500_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = qdi6500_set_piomode,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = ata_bmdma_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = qdi_qc_issue_prot,
+
+ .data_xfer = qdi_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+static struct ata_port_operations qdi6580_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = qdi6580_set_piomode,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = ata_bmdma_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = qdi_qc_issue_prot,
+
+ .data_xfer = qdi_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+/**
+ * qdi_init_one - attach a qdi interface
+ * @type: Type to display
+ * @io: I/O port start
+ * @irq: interrupt line
+ * @fast: True if on a > 33Mhz VLB
+ *
+ * Register an ISA bus IDE interface. Such interfaces are PIO and we
+ * assume do not support IRQ sharing.
+ */
+
+static __init int qdi_init_one(unsigned long port, int type, unsigned long io, int irq, int fast)
+{
+ struct ata_probe_ent ae;
+ struct platform_device *pdev;
+ int ret;
+
+ unsigned long ctrl = io + 0x206;
+
+ /*
+ * Fill in a probe structure first of all
+ */
+
+ pdev = platform_device_register_simple(DRV_NAME, nr_qdi_host, NULL, 0);
+ if (pdev == NULL)
+ return -ENOMEM;
+
+ memset(&ae, 0, sizeof(struct ata_probe_ent));
+ INIT_LIST_HEAD(&ae.node);
+ ae.dev = &pdev->dev;
+
+ if (type == 6580) {
+ ae.port_ops = &qdi6580_port_ops;
+ ae.pio_mask = 0x1F;
+ } else {
+ ae.port_ops = &qdi6500_port_ops;
+ ae.pio_mask = 0x07; /* Actually PIO3 !IORDY is possible */
+ }
+
+ ae.sht = &qdi_sht;
+ ae.n_ports = 1;
+ ae.irq = irq;
+ ae.irq_flags = 0;
+ ae.port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST;
+ ae.port[0].cmd_addr = io;
+ ae.port[0].altstatus_addr = ctrl;
+ ae.port[0].ctl_addr = ctrl;
+ ata_std_ports(&ae.port[0]);
+
+ /*
+ * Hook in a private data structure per channel
+ */
+ ae.private_data = &qdi_data[nr_qdi_host];
+
+ qdi_data[nr_qdi_host].timing = port;
+ qdi_data[nr_qdi_host].fast = fast;
+ qdi_data[nr_qdi_host].platform_dev = pdev;
+
+ printk(KERN_INFO DRV_NAME": qd%d at 0x%lx.\n", type, io);
+ ret = ata_device_add(&ae);
+ if (ret == 0) {
+ platform_device_unregister(pdev);
+ return -ENODEV;
+ }
+
+ qdi_host[nr_qdi_host++] = dev_get_drvdata(&pdev->dev);
+ return 0;
+}
+
+/**
+ * qdi_init - attach qdi interfaces
+ *
+ * Attach qdi IDE interfaces by scanning the ports it may occupy.
+ */
+
+static __init int qdi_init(void)
+{
+ unsigned long flags;
+ static const unsigned long qd_port[2] = { 0x30, 0xB0 };
+ static const unsigned long ide_port[2] = { 0x170, 0x1F0 };
+ static const int ide_irq[2] = { 14, 15 };
+
+ int ct = 0;
+ int i;
+
+ if (probe_qdi == 0)
+ return -ENODEV;
+
+ /*
+ * Check each possible QD65xx base address
+ */
+
+ for (i = 0; i < 2; i++) {
+ unsigned long port = qd_port[i];
+ u8 r, res;
+
+
+ if (request_region(port, 2, "pata_qdi")) {
+ /* Check for a card */
+ local_irq_save(flags);
+ r = inb_p(port);
+ outb_p(0x19, port);
+ res = inb_p(port);
+ outb_p(r, port);
+ local_irq_restore(flags);
+
+ /* Fail */
+ if (res == 0x19)
+ {
+ release_region(port, 2);
+ continue;
+ }
+
+ /* Passes the presence test */
+ r = inb_p(port + 1); /* Check port agrees with port set */
+ if ((r & 2) >> 1 != i) {
+ release_region(port, 2);
+ continue;
+ }
+
+ /* Check card type */
+ if ((r & 0xF0) == 0xC0) {
+ /* QD6500: single channel */
+ if (r & 8) {
+ /* Disabled ? */
+ release_region(port, 2);
+ continue;
+ }
+ ct += qdi_init_one(port, 6500, ide_port[r & 0x01], ide_irq[r & 0x01], r & 0x04);
+ }
+ if (((r & 0xF0) == 0xA0) || (r & 0xF0) == 0x50) {
+ /* QD6580: dual channel */
+ if (!request_region(port + 2 , 2, "pata_qdi"))
+ {
+ release_region(port, 2);
+ continue;
+ }
+ res = inb(port + 3);
+ if (res & 1) {
+ /* Single channel mode */
+ ct += qdi_init_one(port, 6580, ide_port[r & 0x01], ide_irq[r & 0x01], r & 0x04);
+ } else {
+ /* Dual channel mode */
+ ct += qdi_init_one(port, 6580, 0x1F0, 14, r & 0x04);
+ ct += qdi_init_one(port + 2, 6580, 0x170, 15, r & 0x04);
+ }
+ }
+ }
+ }
+ if (ct != 0)
+ return 0;
+ return -ENODEV;
+}
+
+static __exit void qdi_exit(void)
+{
+ int i;
+
+ for (i = 0; i < nr_qdi_host; i++) {
+ ata_host_remove(qdi_host[i]);
+ /* Free the control resource. The 6580 dual channel has the resources
+ * claimed as a pair of 2 byte resources so we need no special cases...
+ */
+ release_region(qdi_data[i].timing, 2);
+ platform_device_unregister(qdi_data[i].platform_dev);
+ }
+}
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("low-level driver for qdi ATA");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
+module_init(qdi_init);
+module_exit(qdi_exit);
+
+module_param(probe_qdi, int, 0);
+
diff --git a/drivers/ata/pata_radisys.c b/drivers/ata/pata_radisys.c
new file mode 100644
index 00000000000..c20bcf43ed6
--- /dev/null
+++ b/drivers/ata/pata_radisys.c
@@ -0,0 +1,333 @@
+/*
+ * pata_radisys.c - Intel PATA/SATA controllers
+ *
+ * (C) 2006 Red Hat <alan@redhat.com>
+ *
+ * Some parts based on ata_piix.c by Jeff Garzik and others.
+ *
+ * A PIIX relative, this device has a single ATA channel and no
+ * slave timings, SITRE or PPE. In that sense it is a close relative
+ * of the original PIIX. It does however support UDMA 33/66 per channel
+ * although no other modes/timings. Also lacking is 32bit I/O on the ATA
+ * port.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+#include <linux/ata.h>
+
+#define DRV_NAME "pata_radisys"
+#define DRV_VERSION "0.4.1"
+
+/**
+ * radisys_probe_init - probe begin
+ * @ap: ATA port
+ *
+ * Set up cable type and use generic probe init
+ */
+
+static int radisys_pre_reset(struct ata_port *ap)
+{
+ ap->cbl = ATA_CBL_PATA80;
+ return ata_std_prereset(ap);
+}
+
+
+/**
+ * radisys_pata_error_handler - Probe specified port on PATA host controller
+ * @ap: Port to probe
+ * @classes:
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void radisys_pata_error_handler(struct ata_port *ap)
+{
+ ata_bmdma_drive_eh(ap, radisys_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
+}
+
+/**
+ * radisys_set_piomode - Initialize host controller PATA PIO timings
+ * @ap: Port whose timings we are configuring
+ * @adev: um
+ *
+ * Set PIO mode for device, in host controller PCI config space.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void radisys_set_piomode (struct ata_port *ap, struct ata_device *adev)
+{
+ unsigned int pio = adev->pio_mode - XFER_PIO_0;
+ struct pci_dev *dev = to_pci_dev(ap->host->dev);
+ u16 idetm_data;
+ int control = 0;
+
+ /*
+ * See Intel Document 298600-004 for the timing programing rules
+ * for PIIX/ICH. Note that the early PIIX does not have the slave
+ * timing port at 0x44. The Radisys is a relative of the PIIX
+ * but not the same so be careful.
+ */
+
+ static const /* ISP RTC */
+ u8 timings[][2] = { { 0, 0 }, /* Check me */
+ { 0, 0 },
+ { 1, 1 },
+ { 2, 2 },
+ { 3, 3 }, };
+
+ if (pio > 0)
+ control |= 1; /* TIME1 enable */
+ if (ata_pio_need_iordy(adev))
+ control |= 2; /* IE IORDY */
+
+ pci_read_config_word(dev, 0x40, &idetm_data);
+
+ /* Enable IE and TIME as appropriate. Clear the other
+ drive timing bits */
+ idetm_data &= 0xCCCC;
+ idetm_data |= (control << (4 * adev->devno));
+ idetm_data |= (timings[pio][0] << 12) |
+ (timings[pio][1] << 8);
+ pci_write_config_word(dev, 0x40, idetm_data);
+
+ /* Track which port is configured */
+ ap->private_data = adev;
+}
+
+/**
+ * radisys_set_dmamode - Initialize host controller PATA DMA timings
+ * @ap: Port whose timings we are configuring
+ * @adev: Device to program
+ * @isich: True if the device is an ICH and has IOCFG registers
+ *
+ * Set MWDMA mode for device, in host controller PCI config space.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void radisys_set_dmamode (struct ata_port *ap, struct ata_device *adev)
+{
+ struct pci_dev *dev = to_pci_dev(ap->host->dev);
+ u16 idetm_data;
+ u8 udma_enable;
+
+ static const /* ISP RTC */
+ u8 timings[][2] = { { 0, 0 },
+ { 0, 0 },
+ { 1, 1 },
+ { 2, 2 },
+ { 3, 3 }, };
+
+ /*
+ * MWDMA is driven by the PIO timings. We must also enable
+ * IORDY unconditionally.
+ */
+
+ pci_read_config_word(dev, 0x40, &idetm_data);
+ pci_read_config_byte(dev, 0x48, &udma_enable);
+
+ if (adev->dma_mode < XFER_UDMA_0) {
+ unsigned int mwdma = adev->dma_mode - XFER_MW_DMA_0;
+ const unsigned int needed_pio[3] = {
+ XFER_PIO_0, XFER_PIO_3, XFER_PIO_4
+ };
+ int pio = needed_pio[mwdma] - XFER_PIO_0;
+ int control = 3; /* IORDY|TIME0 */
+
+ /* If the drive MWDMA is faster than it can do PIO then
+ we must force PIO0 for PIO cycles. */
+
+ if (adev->pio_mode < needed_pio[mwdma])
+ control = 1;
+
+ /* Mask out the relevant control and timing bits we will load. Also
+ clear the other drive TIME register as a precaution */
+
+ idetm_data &= 0xCCCC;
+ idetm_data |= control << (4 * adev->devno);
+ idetm_data |= (timings[pio][0] << 12) | (timings[pio][1] << 8);
+
+ udma_enable &= ~(1 << adev->devno);
+ } else {
+ u8 udma_mode;
+
+ /* UDMA66 on: UDMA 33 and 66 are switchable via register 0x4A */
+
+ pci_read_config_byte(dev, 0x4A, &udma_mode);
+
+ if (adev->xfer_mode == XFER_UDMA_2)
+ udma_mode &= ~ (1 << adev->devno);
+ else /* UDMA 4 */
+ udma_mode |= (1 << adev->devno);
+
+ pci_write_config_byte(dev, 0x4A, udma_mode);
+
+ udma_enable |= (1 << adev->devno);
+ }
+ pci_write_config_word(dev, 0x40, idetm_data);
+ pci_write_config_byte(dev, 0x48, udma_enable);
+
+ /* Track which port is configured */
+ ap->private_data = adev;
+}
+
+/**
+ * radisys_qc_issue_prot - command issue
+ * @qc: command pending
+ *
+ * Called when the libata layer is about to issue a command. We wrap
+ * this interface so that we can load the correct ATA timings if
+ * neccessary. Our logic also clears TIME0/TIME1 for the other device so
+ * that, even if we get this wrong, cycles to the other device will
+ * be made PIO0.
+ */
+
+static unsigned int radisys_qc_issue_prot(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct ata_device *adev = qc->dev;
+
+ if (adev != ap->private_data) {
+ /* UDMA timing is not shared */
+ if (adev->dma_mode < XFER_UDMA_0) {
+ if (adev->dma_mode)
+ radisys_set_dmamode(ap, adev);
+ else if (adev->pio_mode)
+ radisys_set_piomode(ap, adev);
+ }
+ }
+ return ata_qc_issue_prot(qc);
+}
+
+
+static struct scsi_host_template radisys_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .max_sectors = ATA_MAX_SECTORS,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .bios_param = ata_std_bios_param,
+};
+
+static const struct ata_port_operations radisys_pata_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = radisys_set_piomode,
+ .set_dmamode = radisys_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = radisys_pata_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+ .qc_prep = ata_qc_prep,
+ .qc_issue = radisys_qc_issue_prot,
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop,
+};
+
+
+/**
+ * radisys_init_one - Register PIIX ATA PCI device with kernel services
+ * @pdev: PCI device to register
+ * @ent: Entry in radisys_pci_tbl matching with @pdev
+ *
+ * Called from kernel PCI layer. We probe for combined mode (sigh),
+ * and then hand over control to libata, for it to do the rest.
+ *
+ * LOCKING:
+ * Inherited from PCI layer (may sleep).
+ *
+ * RETURNS:
+ * Zero on success, or -ERRNO value.
+ */
+
+static int radisys_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ static int printed_version;
+ static struct ata_port_info info = {
+ .sht = &radisys_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .mwdma_mask = 0x07, /* mwdma1-2 */
+ .udma_mask = 0x14, /* UDMA33/66 only */
+ .port_ops = &radisys_pata_ops,
+ };
+ static struct ata_port_info *port_info[2] = { &info, &info };
+
+ if (!printed_version++)
+ dev_printk(KERN_DEBUG, &pdev->dev,
+ "version " DRV_VERSION "\n");
+
+ return ata_pci_init_one(pdev, port_info, 2);
+}
+
+static const struct pci_device_id radisys_pci_tbl[] = {
+ { 0x1331, 0x8201, PCI_ANY_ID, PCI_ANY_ID, },
+ { } /* terminate list */
+};
+
+static struct pci_driver radisys_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = radisys_pci_tbl,
+ .probe = radisys_init_one,
+ .remove = ata_pci_remove_one,
+};
+
+static int __init radisys_init(void)
+{
+ return pci_register_driver(&radisys_pci_driver);
+}
+
+static void __exit radisys_exit(void)
+{
+ pci_unregister_driver(&radisys_pci_driver);
+}
+
+
+module_init(radisys_init);
+module_exit(radisys_exit);
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("SCSI low-level driver for Radisys R82600 controllers");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, radisys_pci_tbl);
+MODULE_VERSION(DRV_VERSION);
+
diff --git a/drivers/ata/pata_rz1000.c b/drivers/ata/pata_rz1000.c
new file mode 100644
index 00000000000..eccc6fd4503
--- /dev/null
+++ b/drivers/ata/pata_rz1000.c
@@ -0,0 +1,205 @@
+/*
+ * RZ1000/1001 driver based upon
+ *
+ * linux/drivers/ide/pci/rz1000.c Version 0.06 January 12, 2003
+ * Copyright (C) 1995-1998 Linus Torvalds & author (see below)
+ * Principal Author: mlord@pobox.com (Mark Lord)
+ *
+ * See linux/MAINTAINERS for address of current maintainer.
+ *
+ * This file provides support for disabling the buggy read-ahead
+ * mode of the RZ1000 IDE chipset, commonly used on Intel motherboards.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+
+#define DRV_NAME "pata_rz1000"
+#define DRV_VERSION "0.2.2"
+
+
+/**
+ * rz1000_prereset - probe begin
+ * @ap: ATA port
+ *
+ * Set up cable type and use generics
+ */
+
+static int rz1000_prereset(struct ata_port *ap)
+{
+ ap->cbl = ATA_CBL_PATA40;
+ return ata_std_prereset(ap);
+}
+
+/**
+ * rz1000_error_handler - probe reset
+ * @ap: ATA port
+ *
+ * Perform the ATA standard reset sequence
+ */
+
+static void rz1000_error_handler(struct ata_port *ap)
+{
+ ata_bmdma_drive_eh(ap, rz1000_prereset, ata_std_softreset, NULL, ata_std_postreset);
+}
+
+/**
+ * rz1000_set_mode - mode setting function
+ * @ap: ATA interface
+ *
+ * Use a non standard set_mode function. We don't want to be tuned. We
+ * would prefer to be BIOS generic but for the fact our hardware is
+ * whacked out.
+ */
+
+static void rz1000_set_mode(struct ata_port *ap)
+{
+ int i;
+
+ for (i = 0; i < ATA_MAX_DEVICES; i++) {
+ struct ata_device *dev = &ap->device[i];
+ if (ata_dev_enabled(dev)) {
+ /* We don't really care */
+ dev->pio_mode = XFER_PIO_0;
+ dev->xfer_mode = XFER_PIO_0;
+ dev->xfer_shift = ATA_SHIFT_PIO;
+ dev->flags |= ATA_DFLAG_PIO;
+ }
+ }
+}
+
+
+static struct scsi_host_template rz1000_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .max_sectors = ATA_MAX_SECTORS,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .bios_param = ata_std_bios_param,
+};
+
+static struct ata_port_operations rz1000_port_ops = {
+ .set_mode = rz1000_set_mode,
+
+ .port_disable = ata_port_disable,
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .error_handler = rz1000_error_handler,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = rz1000_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+/**
+ * rz1000_init_one - Register RZ1000 ATA PCI device with kernel services
+ * @pdev: PCI device to register
+ * @ent: Entry in rz1000_pci_tbl matching with @pdev
+ *
+ * Configure an RZ1000 interface. This doesn't require much special
+ * handling except that we *MUST* kill the chipset readahead or the
+ * user may experience data corruption.
+ */
+
+static int rz1000_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ static int printed_version;
+ struct ata_port_info *port_info[2];
+ u16 reg;
+ static struct ata_port_info info = {
+ .sht = &rz1000_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .port_ops = &rz1000_port_ops
+ };
+
+ if (!printed_version++)
+ printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n");
+
+ /* Be exceptionally paranoid as we must be sure to apply the fix */
+ if (pci_read_config_word(pdev, 0x40, &reg) != 0)
+ goto fail;
+ reg &= 0xDFFF;
+ if (pci_write_config_word(pdev, 0x40, reg) != 0)
+ goto fail;
+ printk(KERN_INFO DRV_NAME ": disabled chipset readahead.\n");
+
+ port_info[0] = &info;
+ port_info[1] = &info;
+ return ata_pci_init_one(pdev, port_info, 2);
+fail:
+ printk(KERN_ERR DRV_NAME ": failed to disable read-ahead on chipset..\n");
+ /* Not safe to use so skip */
+ return -ENODEV;
+}
+
+static struct pci_device_id pata_rz1000[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1000), },
+ { PCI_DEVICE(PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1001), },
+ { 0, },
+};
+
+static struct pci_driver rz1000_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = pata_rz1000,
+ .probe = rz1000_init_one,
+ .remove = ata_pci_remove_one
+};
+
+
+static int __init rz1000_init(void)
+{
+ return pci_register_driver(&rz1000_pci_driver);
+}
+
+static void __exit rz1000_exit(void)
+{
+ pci_unregister_driver(&rz1000_pci_driver);
+}
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("low-level driver for RZ1000 PCI ATA");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, pata_rz1000);
+MODULE_VERSION(DRV_VERSION);
+
+module_init(rz1000_init);
+module_exit(rz1000_exit);
+
diff --git a/drivers/ata/pata_sc1200.c b/drivers/ata/pata_sc1200.c
new file mode 100644
index 00000000000..107e6cd3dc0
--- /dev/null
+++ b/drivers/ata/pata_sc1200.c
@@ -0,0 +1,287 @@
+/*
+ * New ATA layer SC1200 driver Alan Cox <alan@redhat.com>
+ *
+ * TODO: Mode selection filtering
+ * TODO: Can't enable second channel until ATA core has serialize
+ * TODO: Needs custom DMA cleanup code
+ *
+ * Based very heavily on
+ *
+ * linux/drivers/ide/pci/sc1200.c Version 0.91 28-Jan-2003
+ *
+ * Copyright (C) 2000-2002 Mark Lord <mlord@pobox.com>
+ * May be copied or modified under the terms of the GNU General Public License
+ *
+ * Development of this chipset driver was funded
+ * by the nice folks at National Semiconductor.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+
+#define DRV_NAME "sc1200"
+#define DRV_VERSION "0.2.3"
+
+#define SC1200_REV_A 0x00
+#define SC1200_REV_B1 0x01
+#define SC1200_REV_B3 0x02
+#define SC1200_REV_C1 0x03
+#define SC1200_REV_D1 0x04
+
+/**
+ * sc1200_clock - PCI clock
+ *
+ * Return the PCI bus clocking for the SC1200 chipset configuration
+ * in use. We return 0 for 33MHz 1 for 48MHz and 2 for 66Mhz
+ */
+
+static int sc1200_clock(void)
+{
+ /* Magic registers that give us the chipset data */
+ u8 chip_id = inb(0x903C);
+ u8 silicon_rev = inb(0x903D);
+ u16 pci_clock;
+
+ if (chip_id == 0x04 && silicon_rev < SC1200_REV_B1)
+ return 0; /* 33 MHz mode */
+
+ /* Clock generator configuration 0x901E its 8/9 are the PCI clocking
+ 0/3 is 33Mhz 1 is 48 2 is 66 */
+
+ pci_clock = inw(0x901E);
+ pci_clock >>= 8;
+ pci_clock &= 0x03;
+ if (pci_clock == 3)
+ pci_clock = 0;
+ return pci_clock;
+}
+
+/**
+ * sc1200_set_piomode - PIO setup
+ * @ap: ATA interface
+ * @adev: device on the interface
+ *
+ * Set our PIO requirements. This is fairly simple on the SC1200
+ */
+
+static void sc1200_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ static const u32 pio_timings[4][5] = {
+ {0x00009172, 0x00012171, 0x00020080, 0x00032010, 0x00040010}, // format0 33Mhz
+ {0xd1329172, 0x71212171, 0x30200080, 0x20102010, 0x00100010}, // format1, 33Mhz
+ {0xfaa3f4f3, 0xc23232b2, 0x513101c1, 0x31213121, 0x10211021}, // format1, 48Mhz
+ {0xfff4fff4, 0xf35353d3, 0x814102f1, 0x42314231, 0x11311131} // format1, 66Mhz
+ };
+
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u32 format;
+ unsigned int reg = 0x40 + 0x10 * ap->port_no;
+ int mode = adev->pio_mode - XFER_PIO_0;
+
+ pci_read_config_dword(pdev, reg + 4, &format);
+ format >>= 31;
+ format += sc1200_clock();
+ pci_write_config_dword(pdev, reg + 8 * adev->devno,
+ pio_timings[format][mode]);
+}
+
+/**
+ * sc1200_set_dmamode - DMA timing setup
+ * @ap: ATA interface
+ * @adev: Device being configured
+ *
+ * We cannot mix MWDMA and UDMA without reloading timings each switch
+ * master to slave.
+ */
+
+static void sc1200_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+ static const u32 udma_timing[3][3] = {
+ { 0x00921250, 0x00911140, 0x00911030 },
+ { 0x00932470, 0x00922260, 0x00922140 },
+ { 0x009436A1, 0x00933481, 0x00923261 }
+ };
+
+ static const u32 mwdma_timing[3][3] = {
+ { 0x00077771, 0x00012121, 0x00002020 },
+ { 0x000BBBB2, 0x00024241, 0x00013131 },
+ { 0x000FFFF3, 0x00035352, 0x00015151 }
+ };
+
+ int clock = sc1200_clock();
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ unsigned int reg = 0x40 + 0x10 * ap->port_no;
+ int mode = adev->dma_mode;
+ u32 format;
+
+ if (mode >= XFER_UDMA_0)
+ format = udma_timing[clock][mode - XFER_UDMA_0];
+ else
+ format = mwdma_timing[clock][mode - XFER_MW_DMA_0];
+
+ if (adev->devno == 0) {
+ u32 timings;
+
+ pci_read_config_dword(pdev, reg + 4, &timings);
+ timings &= 0x80000000UL;
+ timings |= format;
+ pci_write_config_dword(pdev, reg + 4, timings);
+ } else
+ pci_write_config_dword(pdev, reg + 12, format);
+}
+
+/**
+ * sc1200_qc_issue_prot - command issue
+ * @qc: command pending
+ *
+ * Called when the libata layer is about to issue a command. We wrap
+ * this interface so that we can load the correct ATA timings if
+ * neccessary. Specifically we have a problem that there is only
+ * one MWDMA/UDMA bit.
+ */
+
+static unsigned int sc1200_qc_issue_prot(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct ata_device *adev = qc->dev;
+ struct ata_device *prev = ap->private_data;
+
+ /* See if the DMA settings could be wrong */
+ if (adev->dma_mode != 0 && adev != prev && prev != NULL) {
+ /* Maybe, but do the channels match MWDMA/UDMA ? */
+ if ((adev->dma_mode >= XFER_UDMA_0 && prev->dma_mode < XFER_UDMA_0) ||
+ (adev->dma_mode < XFER_UDMA_0 && prev->dma_mode >= XFER_UDMA_0))
+ /* Switch the mode bits */
+ sc1200_set_dmamode(ap, adev);
+ }
+
+ return ata_qc_issue_prot(qc);
+}
+
+static struct scsi_host_template sc1200_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .max_sectors = ATA_MAX_SECTORS,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .bios_param = ata_std_bios_param,
+};
+
+static struct ata_port_operations sc1200_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = sc1200_set_piomode,
+ .set_dmamode = sc1200_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .error_handler = ata_bmdma_error_handler,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = sc1200_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+/**
+ * sc1200_init_one - Initialise an SC1200
+ * @dev: PCI device
+ * @id: Entry in match table
+ *
+ * Just throw the needed data at the libata helper and it does all
+ * our work.
+ */
+
+static int sc1200_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ static struct ata_port_info info = {
+ .sht = &sc1200_sht,
+ .flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x07,
+ .port_ops = &sc1200_port_ops
+ };
+ static struct ata_port_info *port_info[2] = { &info, &info };
+
+ /* Can't enable port 2 yet, see top comments */
+ return ata_pci_init_one(dev, port_info, 1);
+}
+
+static struct pci_device_id sc1200[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_IDE), },
+ { 0, },
+};
+
+static struct pci_driver sc1200_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = sc1200,
+ .probe = sc1200_init_one,
+ .remove = ata_pci_remove_one
+};
+
+static int __init sc1200_init(void)
+{
+ return pci_register_driver(&sc1200_pci_driver);
+}
+
+
+static void __exit sc1200_exit(void)
+{
+ pci_unregister_driver(&sc1200_pci_driver);
+}
+
+
+MODULE_AUTHOR("Alan Cox, Mark Lord");
+MODULE_DESCRIPTION("low-level driver for the NS/AMD SC1200");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, sc1200);
+MODULE_VERSION(DRV_VERSION);
+
+module_init(sc1200_init);
+module_exit(sc1200_exit);
diff --git a/drivers/ata/pata_serverworks.c b/drivers/ata/pata_serverworks.c
new file mode 100644
index 00000000000..a5c8d7e121d
--- /dev/null
+++ b/drivers/ata/pata_serverworks.c
@@ -0,0 +1,591 @@
+/*
+ * ata-serverworks.c - Serverworks PATA for new ATA layer
+ * (C) 2005 Red Hat Inc
+ * Alan Cox <alan@redhat.com>
+ *
+ * based upon
+ *
+ * serverworks.c
+ *
+ * Copyright (C) 1998-2000 Michel Aubry
+ * Copyright (C) 1998-2000 Andrzej Krzysztofowicz
+ * Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org>
+ * Portions copyright (c) 2001 Sun Microsystems
+ *
+ *
+ * RCC/ServerWorks IDE driver for Linux
+ *
+ * OSB4: `Open South Bridge' IDE Interface (fn 1)
+ * supports UDMA mode 2 (33 MB/s)
+ *
+ * CSB5: `Champion South Bridge' IDE Interface (fn 1)
+ * all revisions support UDMA mode 4 (66 MB/s)
+ * revision A2.0 and up support UDMA mode 5 (100 MB/s)
+ *
+ * *** The CSB5 does not provide ANY register ***
+ * *** to detect 80-conductor cable presence. ***
+ *
+ * CSB6: `Champion South Bridge' IDE Interface (optional: third channel)
+ *
+ * Documentation:
+ * Available under NDA only. Errata info very hard to get.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+
+#define DRV_NAME "pata_serverworks"
+#define DRV_VERSION "0.3.7"
+
+#define SVWKS_CSB5_REVISION_NEW 0x92 /* min PCI_REVISION_ID for UDMA5 (A2.0) */
+#define SVWKS_CSB6_REVISION 0xa0 /* min PCI_REVISION_ID for UDMA4 (A1.0) */
+
+/* Seagate Barracuda ATA IV Family drives in UDMA mode 5
+ * can overrun their FIFOs when used with the CSB5 */
+
+static const char *csb_bad_ata100[] = {
+ "ST320011A",
+ "ST340016A",
+ "ST360021A",
+ "ST380021A",
+ NULL
+};
+
+/**
+ * dell_cable - Dell serverworks cable detection
+ * @ap: ATA port to do cable detect
+ *
+ * Dell hide the 40/80 pin select for their interfaces in the top two
+ * bits of the subsystem ID.
+ */
+
+static int dell_cable(struct ata_port *ap) {
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+
+ if (pdev->subsystem_device & (1 << (ap->port_no + 14)))
+ return ATA_CBL_PATA80;
+ return ATA_CBL_PATA40;
+}
+
+/**
+ * sun_cable - Sun Cobalt 'Alpine' cable detection
+ * @ap: ATA port to do cable select
+ *
+ * Cobalt CSB5 IDE hides the 40/80pin in the top two bits of the
+ * subsystem ID the same as dell. We could use one function but we may
+ * need to extend the Dell one in future
+ */
+
+static int sun_cable(struct ata_port *ap) {
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+
+ if (pdev->subsystem_device & (1 << (ap->port_no + 14)))
+ return ATA_CBL_PATA80;
+ return ATA_CBL_PATA40;
+}
+
+/**
+ * osb4_cable - OSB4 cable detect
+ * @ap: ATA port to check
+ *
+ * The OSB4 isn't UDMA66 capable so this is easy
+ */
+
+static int osb4_cable(struct ata_port *ap) {
+ return ATA_CBL_PATA40;
+}
+
+/**
+ * csb4_cable - CSB5/6 cable detect
+ * @ap: ATA port to check
+ *
+ * Serverworks default arrangement is to use the drive side detection
+ * only.
+ */
+
+static int csb_cable(struct ata_port *ap) {
+ return ATA_CBL_PATA80;
+}
+
+struct sv_cable_table {
+ int device;
+ int subvendor;
+ int (*cable_detect)(struct ata_port *ap);
+};
+
+/*
+ * Note that we don't copy the old serverworks code because the old
+ * code contains obvious mistakes
+ */
+
+static struct sv_cable_table cable_detect[] = {
+ { PCI_DEVICE_ID_SERVERWORKS_CSB5IDE, PCI_VENDOR_ID_DELL, dell_cable },
+ { PCI_DEVICE_ID_SERVERWORKS_CSB6IDE, PCI_VENDOR_ID_DELL, dell_cable },
+ { PCI_DEVICE_ID_SERVERWORKS_CSB5IDE, PCI_VENDOR_ID_SUN, sun_cable },
+ { PCI_DEVICE_ID_SERVERWORKS_OSB4IDE, PCI_ANY_ID, osb4_cable },
+ { PCI_DEVICE_ID_SERVERWORKS_CSB5IDE, PCI_ANY_ID, csb_cable },
+ { PCI_DEVICE_ID_SERVERWORKS_CSB6IDE, PCI_ANY_ID, csb_cable },
+ { PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2, PCI_ANY_ID, csb_cable },
+ { PCI_DEVICE_ID_SERVERWORKS_HT1000IDE, PCI_ANY_ID, csb_cable },
+ { }
+};
+
+/**
+ * serverworks_pre_reset - cable detection
+ * @ap: ATA port
+ *
+ * Perform cable detection according to the device and subvendor
+ * identifications
+ */
+
+static int serverworks_pre_reset(struct ata_port *ap) {
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ struct sv_cable_table *cb = cable_detect;
+
+ while(cb->device) {
+ if (cb->device == pdev->device &&
+ (cb->subvendor == pdev->subsystem_vendor ||
+ cb->subvendor == PCI_ANY_ID)) {
+ ap->cbl = cb->cable_detect(ap);
+ return ata_std_prereset(ap);
+ }
+ cb++;
+ }
+
+ BUG();
+ return -1; /* kill compiler warning */
+}
+
+static void serverworks_error_handler(struct ata_port *ap)
+{
+ return ata_bmdma_drive_eh(ap, serverworks_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
+}
+
+/**
+ * serverworks_is_csb - Check for CSB or OSB
+ * @pdev: PCI device to check
+ *
+ * Returns true if the device being checked is known to be a CSB
+ * series device.
+ */
+
+static u8 serverworks_is_csb(struct pci_dev *pdev)
+{
+ switch (pdev->device) {
+ case PCI_DEVICE_ID_SERVERWORKS_CSB5IDE:
+ case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE:
+ case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2:
+ case PCI_DEVICE_ID_SERVERWORKS_HT1000IDE:
+ return 1;
+ default:
+ break;
+ }
+ return 0;
+}
+
+/**
+ * serverworks_osb4_filter - mode selection filter
+ * @ap: ATA interface
+ * @adev: ATA device
+ *
+ * Filter the offered modes for the device to apply controller
+ * specific rules. OSB4 requires no UDMA for disks due to a FIFO
+ * bug we hit.
+ */
+
+static unsigned long serverworks_osb4_filter(const struct ata_port *ap, struct ata_device *adev, unsigned long mask)
+{
+ if (adev->class == ATA_DEV_ATA)
+ mask &= ~ATA_MASK_UDMA;
+ return ata_pci_default_filter(ap, adev, mask);
+}
+
+
+/**
+ * serverworks_csb_filter - mode selection filter
+ * @ap: ATA interface
+ * @adev: ATA device
+ *
+ * Check the blacklist and disable UDMA5 if matched
+ */
+
+static unsigned long serverworks_csb_filter(const struct ata_port *ap, struct ata_device *adev, unsigned long mask)
+{
+ const char *p;
+ char model_num[40];
+ int len, i;
+
+ /* Disk, UDMA */
+ if (adev->class != ATA_DEV_ATA)
+ return ata_pci_default_filter(ap, adev, mask);
+
+ /* Actually do need to check */
+ ata_id_string(adev->id, model_num, ATA_ID_PROD_OFS, sizeof(model_num));
+ /* Precuationary - why not do this in the libata core ?? */
+
+ len = strlen(model_num);
+ while ((len > 0) && (model_num[len - 1] == ' ')) {
+ len--;
+ model_num[len] = 0;
+ }
+
+ for(i = 0; (p = csb_bad_ata100[i]) != NULL; i++) {
+ if (!strncmp(p, model_num, len))
+ mask &= ~(0x1F << ATA_SHIFT_UDMA);
+ }
+ return ata_pci_default_filter(ap, adev, mask);
+}
+
+
+/**
+ * serverworks_set_piomode - set initial PIO mode data
+ * @ap: ATA interface
+ * @adev: ATA device
+ *
+ * Program the OSB4/CSB5 timing registers for PIO. The PIO register
+ * load is done as a simple lookup.
+ */
+static void serverworks_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ static const u8 pio_mode[] = { 0x5d, 0x47, 0x34, 0x22, 0x20 };
+ int offset = 1 + (2 * ap->port_no) - adev->devno;
+ int devbits = (2 * ap->port_no + adev->devno) * 4;
+ u16 csb5_pio;
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ int pio = adev->pio_mode - XFER_PIO_0;
+
+ pci_write_config_byte(pdev, 0x40 + offset, pio_mode[pio]);
+
+ /* The OSB4 just requires the timing but the CSB series want the
+ mode number as well */
+ if (serverworks_is_csb(pdev)) {
+ pci_read_config_word(pdev, 0x4A, &csb5_pio);
+ csb5_pio &= ~(0x0F << devbits);
+ pci_write_config_byte(pdev, 0x4A, csb5_pio | (pio << devbits));
+ }
+}
+
+/**
+ * serverworks_set_dmamode - set initial DMA mode data
+ * @ap: ATA interface
+ * @adev: ATA device
+ *
+ * Program the MWDMA/UDMA modes for the serverworks OSB4/CSB5
+ * chipset. The MWDMA mode values are pulled from a lookup table
+ * while the chipset uses mode number for UDMA.
+ */
+
+static void serverworks_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+ static const u8 dma_mode[] = { 0x77, 0x21, 0x20 };
+ int offset = 1 + 2 * ap->port_no - adev->devno;
+ int devbits = (2 * ap->port_no + adev->devno);
+ u8 ultra;
+ u8 ultra_cfg;
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+
+ pci_read_config_byte(pdev, 0x54, &ultra_cfg);
+
+ if (adev->dma_mode >= XFER_UDMA_0) {
+ pci_write_config_byte(pdev, 0x44 + offset, 0x20);
+
+ pci_read_config_byte(pdev, 0x56 + ap->port_no, &ultra);
+ ultra &= ~(0x0F << (ap->port_no * 4));
+ ultra |= (adev->dma_mode - XFER_UDMA_0)
+ << (ap->port_no * 4);
+ pci_write_config_byte(pdev, 0x56 + ap->port_no, ultra);
+
+ ultra_cfg |= (1 << devbits);
+ } else {
+ pci_write_config_byte(pdev, 0x44 + offset,
+ dma_mode[adev->dma_mode - XFER_MW_DMA_0]);
+ ultra_cfg &= ~(1 << devbits);
+ }
+ pci_write_config_byte(pdev, 0x54, ultra_cfg);
+}
+
+static struct scsi_host_template serverworks_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .max_sectors = ATA_MAX_SECTORS,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .bios_param = ata_std_bios_param,
+};
+
+static struct ata_port_operations serverworks_osb4_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = serverworks_set_piomode,
+ .set_dmamode = serverworks_set_dmamode,
+ .mode_filter = serverworks_osb4_filter,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = serverworks_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+static struct ata_port_operations serverworks_csb_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = serverworks_set_piomode,
+ .set_dmamode = serverworks_set_dmamode,
+ .mode_filter = serverworks_csb_filter,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = serverworks_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+static int serverworks_fixup_osb4(struct pci_dev *pdev)
+{
+ u32 reg;
+ struct pci_dev *isa_dev = pci_get_device(PCI_VENDOR_ID_SERVERWORKS,
+ PCI_DEVICE_ID_SERVERWORKS_OSB4, NULL);
+ if (isa_dev) {
+ pci_read_config_dword(isa_dev, 0x64, &reg);
+ reg &= ~0x00002000; /* disable 600ns interrupt mask */
+ if (!(reg & 0x00004000))
+ printk(KERN_DEBUG DRV_NAME ": UDMA not BIOS enabled.\n");
+ reg |= 0x00004000; /* enable UDMA/33 support */
+ pci_write_config_dword(isa_dev, 0x64, reg);
+ pci_dev_put(isa_dev);
+ return 0;
+ }
+ printk(KERN_WARNING "ata_serverworks: Unable to find bridge.\n");
+ return -ENODEV;
+}
+
+static int serverworks_fixup_csb(struct pci_dev *pdev)
+{
+ u8 rev;
+ u8 btr;
+
+ pci_read_config_byte(pdev, PCI_REVISION_ID, &rev);
+
+ /* Third Channel Test */
+ if (!(PCI_FUNC(pdev->devfn) & 1)) {
+ struct pci_dev * findev = NULL;
+ u32 reg4c = 0;
+ findev = pci_get_device(PCI_VENDOR_ID_SERVERWORKS,
+ PCI_DEVICE_ID_SERVERWORKS_CSB5, NULL);
+ if (findev) {
+ pci_read_config_dword(findev, 0x4C, &reg4c);
+ reg4c &= ~0x000007FF;
+ reg4c |= 0x00000040;
+ reg4c |= 0x00000020;
+ pci_write_config_dword(findev, 0x4C, reg4c);
+ pci_dev_put(findev);
+ }
+ } else {
+ struct pci_dev * findev = NULL;
+ u8 reg41 = 0;
+
+ findev = pci_get_device(PCI_VENDOR_ID_SERVERWORKS,
+ PCI_DEVICE_ID_SERVERWORKS_CSB6, NULL);
+ if (findev) {
+ pci_read_config_byte(findev, 0x41, &reg41);
+ reg41 &= ~0x40;
+ pci_write_config_byte(findev, 0x41, reg41);
+ pci_dev_put(findev);
+ }
+ }
+ /* setup the UDMA Control register
+ *
+ * 1. clear bit 6 to enable DMA
+ * 2. enable DMA modes with bits 0-1
+ * 00 : legacy
+ * 01 : udma2
+ * 10 : udma2/udma4
+ * 11 : udma2/udma4/udma5
+ */
+ pci_read_config_byte(pdev, 0x5A, &btr);
+ btr &= ~0x40;
+ if (!(PCI_FUNC(pdev->devfn) & 1))
+ btr |= 0x2;
+ else
+ btr |= (rev >= SVWKS_CSB5_REVISION_NEW) ? 0x3 : 0x2;
+ pci_write_config_byte(pdev, 0x5A, btr);
+
+ return btr;
+}
+
+static void serverworks_fixup_ht1000(struct pci_dev *pdev)
+{
+ u8 btr;
+ /* Setup HT1000 SouthBridge Controller - Single Channel Only */
+ pci_read_config_byte(pdev, 0x5A, &btr);
+ btr &= ~0x40;
+ btr |= 0x3;
+ pci_write_config_byte(pdev, 0x5A, btr);
+}
+
+
+static int serverworks_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ int ports = 2;
+ static struct ata_port_info info[4] = {
+ { /* OSB4 */
+ .sht = &serverworks_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x07,
+ .port_ops = &serverworks_osb4_port_ops
+ }, { /* OSB4 no UDMA */
+ .sht = &serverworks_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x00,
+ .port_ops = &serverworks_osb4_port_ops
+ }, { /* CSB5 */
+ .sht = &serverworks_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x1f,
+ .port_ops = &serverworks_csb_port_ops
+ }, { /* CSB5 - later revisions*/
+ .sht = &serverworks_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x3f,
+ .port_ops = &serverworks_csb_port_ops
+ }
+ };
+ static struct ata_port_info *port_info[2];
+ struct ata_port_info *devinfo = &info[id->driver_data];
+
+ /* Force master latency timer to 64 PCI clocks */
+ pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x40);
+
+ /* OSB4 : South Bridge and IDE */
+ if (pdev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) {
+ /* Select non UDMA capable OSB4 if we can't do fixups */
+ if ( serverworks_fixup_osb4(pdev) < 0)
+ devinfo = &info[1];
+ }
+ /* setup CSB5/CSB6 : South Bridge and IDE option RAID */
+ else if ((pdev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) ||
+ (pdev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) ||
+ (pdev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2)) {
+
+ /* If the returned btr is the newer revision then
+ select the right info block */
+ if (serverworks_fixup_csb(pdev) == 3)
+ devinfo = &info[3];
+
+ /* Is this the 3rd channel CSB6 IDE ? */
+ if (pdev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2)
+ ports = 1;
+ }
+ /* setup HT1000E */
+ else if (pdev->device == PCI_DEVICE_ID_SERVERWORKS_HT1000IDE)
+ serverworks_fixup_ht1000(pdev);
+
+ if (pdev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE)
+ ata_pci_clear_simplex(pdev);
+
+ port_info[0] = port_info[1] = devinfo;
+ return ata_pci_init_one(pdev, port_info, ports);
+}
+
+static struct pci_device_id serverworks[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4IDE), 0},
+ { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5IDE), 2},
+ { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6IDE), 2},
+ { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2), 2},
+ { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_HT1000IDE), 2},
+ { 0, },
+};
+
+static struct pci_driver serverworks_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = serverworks,
+ .probe = serverworks_init_one,
+ .remove = ata_pci_remove_one
+};
+
+static int __init serverworks_init(void)
+{
+ return pci_register_driver(&serverworks_pci_driver);
+}
+
+
+static void __exit serverworks_exit(void)
+{
+ pci_unregister_driver(&serverworks_pci_driver);
+}
+
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("low-level driver for Serverworks OSB4/CSB5/CSB6");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, serverworks);
+MODULE_VERSION(DRV_VERSION);
+
+module_init(serverworks_init);
+module_exit(serverworks_exit);
diff --git a/drivers/ata/pata_sil680.c b/drivers/ata/pata_sil680.c
new file mode 100644
index 00000000000..c8b2e26db70
--- /dev/null
+++ b/drivers/ata/pata_sil680.c
@@ -0,0 +1,381 @@
+/*
+ * pata_sil680.c - SIL680 PATA for new ATA layer
+ * (C) 2005 Red Hat Inc
+ * Alan Cox <alan@redhat.com>
+ *
+ * based upon
+ *
+ * linux/drivers/ide/pci/siimage.c Version 1.07 Nov 30, 2003
+ *
+ * Copyright (C) 2001-2002 Andre Hedrick <andre@linux-ide.org>
+ * Copyright (C) 2003 Red Hat <alan@redhat.com>
+ *
+ * May be copied or modified under the terms of the GNU General Public License
+ *
+ * Documentation publically available.
+ *
+ * If you have strange problems with nVidia chipset systems please
+ * see the SI support documentation and update your system BIOS
+ * if neccessary
+ *
+ * TODO
+ * If we know all our devices are LBA28 (or LBA28 sized) we could use
+ * the command fifo mode.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+
+#define DRV_NAME "pata_sil680"
+#define DRV_VERSION "0.3.2"
+
+/**
+ * sil680_selreg - return register base
+ * @hwif: interface
+ * @r: config offset
+ *
+ * Turn a config register offset into the right address in either
+ * PCI space or MMIO space to access the control register in question
+ * Thankfully this is a configuration operation so isnt performance
+ * criticial.
+ */
+
+static unsigned long sil680_selreg(struct ata_port *ap, int r)
+{
+ unsigned long base = 0xA0 + r;
+ base += (ap->port_no << 4);
+ return base;
+}
+
+/**
+ * sil680_seldev - return register base
+ * @hwif: interface
+ * @r: config offset
+ *
+ * Turn a config register offset into the right address in either
+ * PCI space or MMIO space to access the control register in question
+ * including accounting for the unit shift.
+ */
+
+static unsigned long sil680_seldev(struct ata_port *ap, struct ata_device *adev, int r)
+{
+ unsigned long base = 0xA0 + r;
+ base += (ap->port_no << 4);
+ base |= adev->devno ? 2 : 0;
+ return base;
+}
+
+
+/**
+ * sil680_cable_detect - cable detection
+ * @ap: ATA port
+ *
+ * Perform cable detection. The SIL680 stores this in PCI config
+ * space for us.
+ */
+
+static int sil680_cable_detect(struct ata_port *ap) {
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ unsigned long addr = sil680_selreg(ap, 0);
+ u8 ata66;
+ pci_read_config_byte(pdev, addr, &ata66);
+ if (ata66 & 1)
+ return ATA_CBL_PATA80;
+ else
+ return ATA_CBL_PATA40;
+}
+
+static int sil680_pre_reset(struct ata_port *ap)
+{
+ ap->cbl = sil680_cable_detect(ap);
+ return ata_std_prereset(ap);
+}
+
+/**
+ * sil680_bus_reset - reset the SIL680 bus
+ * @ap: ATA port to reset
+ *
+ * Perform the SIL680 housekeeping when doing an ATA bus reset
+ */
+
+static int sil680_bus_reset(struct ata_port *ap,unsigned int *classes)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ unsigned long addr = sil680_selreg(ap, 0);
+ u8 reset;
+
+ pci_read_config_byte(pdev, addr, &reset);
+ pci_write_config_byte(pdev, addr, reset | 0x03);
+ udelay(25);
+ pci_write_config_byte(pdev, addr, reset);
+ return ata_std_softreset(ap, classes);
+}
+
+static void sil680_error_handler(struct ata_port *ap)
+{
+ ata_bmdma_drive_eh(ap, sil680_pre_reset, sil680_bus_reset, NULL, ata_std_postreset);
+}
+
+/**
+ * sil680_set_piomode - set initial PIO mode data
+ * @ap: ATA interface
+ * @adev: ATA device
+ *
+ * Program the SIL680 registers for PIO mode. Note that the task speed
+ * registers are shared between the devices so we must pick the lowest
+ * mode for command work.
+ */
+
+static void sil680_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ static u16 speed_p[5] = { 0x328A, 0x2283, 0x1104, 0x10C3, 0x10C1 };
+ static u16 speed_t[5] = { 0x328A, 0x1281, 0x1281, 0x10C3, 0x10C1 };
+
+ unsigned long tfaddr = sil680_selreg(ap, 0x02);
+ unsigned long addr = sil680_seldev(ap, adev, 0x04);
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ int pio = adev->pio_mode - XFER_PIO_0;
+ int lowest_pio = pio;
+ u16 reg;
+
+ struct ata_device *pair = ata_dev_pair(adev);
+
+ if (pair != NULL && adev->pio_mode > pair->pio_mode)
+ lowest_pio = pair->pio_mode - XFER_PIO_0;
+
+ pci_write_config_word(pdev, addr, speed_p[pio]);
+ pci_write_config_word(pdev, tfaddr, speed_t[lowest_pio]);
+
+ pci_read_config_word(pdev, tfaddr-2, &reg);
+ reg &= ~0x0200; /* Clear IORDY */
+ if (ata_pio_need_iordy(adev))
+ reg |= 0x0200; /* Enable IORDY */
+ pci_write_config_word(pdev, tfaddr-2, reg);
+}
+
+/**
+ * sil680_set_dmamode - set initial DMA mode data
+ * @ap: ATA interface
+ * @adev: ATA device
+ *
+ * Program the MWDMA/UDMA modes for the sil680 k
+ * chipset. The MWDMA mode values are pulled from a lookup table
+ * while the chipset uses mode number for UDMA.
+ */
+
+static void sil680_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+ static u8 ultra_table[2][7] = {
+ { 0x0C, 0x07, 0x05, 0x04, 0x02, 0x01, 0xFF }, /* 100MHz */
+ { 0x0F, 0x0B, 0x07, 0x05, 0x03, 0x02, 0x01 }, /* 133Mhz */
+ };
+ static u16 dma_table[3] = { 0x2208, 0x10C2, 0x10C1 };
+
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ unsigned long ma = sil680_seldev(ap, adev, 0x08);
+ unsigned long ua = sil680_seldev(ap, adev, 0x0C);
+ unsigned long addr_mask = 0x80 + 4 * ap->port_no;
+ int port_shift = adev->devno * 4;
+ u8 scsc, mode;
+ u16 multi, ultra;
+
+ pci_read_config_byte(pdev, 0x8A, &scsc);
+ pci_read_config_byte(pdev, addr_mask, &mode);
+ pci_read_config_word(pdev, ma, &multi);
+ pci_read_config_word(pdev, ua, &ultra);
+
+ /* Mask timing bits */
+ ultra &= ~0x3F;
+ mode &= ~(0x03 << port_shift);
+
+ /* Extract scsc */
+ scsc = (scsc & 0x30) ? 1: 0;
+
+ if (adev->dma_mode >= XFER_UDMA_0) {
+ multi = 0x10C1;
+ ultra |= ultra_table[scsc][adev->dma_mode - XFER_UDMA_0];
+ mode |= (0x03 << port_shift);
+ } else {
+ multi = dma_table[adev->dma_mode - XFER_MW_DMA_0];
+ mode |= (0x02 << port_shift);
+ }
+ pci_write_config_byte(pdev, addr_mask, mode);
+ pci_write_config_word(pdev, ma, multi);
+ pci_write_config_word(pdev, ua, ultra);
+}
+
+static struct scsi_host_template sil680_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .max_sectors = ATA_MAX_SECTORS,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .bios_param = ata_std_bios_param,
+};
+
+static struct ata_port_operations sil680_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = sil680_set_piomode,
+ .set_dmamode = sil680_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = sil680_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+static int sil680_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ static struct ata_port_info info = {
+ .sht = &sil680_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x7f,
+ .port_ops = &sil680_port_ops
+ };
+ static struct ata_port_info info_slow = {
+ .sht = &sil680_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x3f,
+ .port_ops = &sil680_port_ops
+ };
+ static struct ata_port_info *port_info[2] = {&info, &info};
+ static int printed_version;
+ u32 class_rev = 0;
+ u8 tmpbyte = 0;
+
+ if (!printed_version++)
+ dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
+
+ pci_read_config_dword(pdev, PCI_CLASS_REVISION, &class_rev);
+ class_rev &= 0xff;
+ /* FIXME: double check */
+ pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, (class_rev) ? 1 : 255);
+
+ pci_write_config_byte(pdev, 0x80, 0x00);
+ pci_write_config_byte(pdev, 0x84, 0x00);
+
+ pci_read_config_byte(pdev, 0x8A, &tmpbyte);
+
+ printk(KERN_INFO "sil680: BA5_EN = %d clock = %02X\n",
+ tmpbyte & 1, tmpbyte & 0x30);
+
+ switch(tmpbyte & 0x30) {
+ case 0x00:
+ /* 133 clock attempt to force it on */
+ pci_write_config_byte(pdev, 0x8A, tmpbyte|0x10);
+ break;
+ case 0x30:
+ /* if clocking is disabled */
+ /* 133 clock attempt to force it on */
+ pci_write_config_byte(pdev, 0x8A, tmpbyte & ~0x20);
+ break;
+ case 0x10:
+ /* 133 already */
+ break;
+ case 0x20:
+ /* BIOS set PCI x2 clocking */
+ break;
+ }
+
+ pci_read_config_byte(pdev, 0x8A, &tmpbyte);
+ printk(KERN_INFO "sil680: BA5_EN = %d clock = %02X\n",
+ tmpbyte & 1, tmpbyte & 0x30);
+ if ((tmpbyte & 0x30) == 0)
+ port_info[0] = port_info[1] = &info_slow;
+
+ pci_write_config_byte(pdev, 0xA1, 0x72);
+ pci_write_config_word(pdev, 0xA2, 0x328A);
+ pci_write_config_dword(pdev, 0xA4, 0x62DD62DD);
+ pci_write_config_dword(pdev, 0xA8, 0x43924392);
+ pci_write_config_dword(pdev, 0xAC, 0x40094009);
+ pci_write_config_byte(pdev, 0xB1, 0x72);
+ pci_write_config_word(pdev, 0xB2, 0x328A);
+ pci_write_config_dword(pdev, 0xB4, 0x62DD62DD);
+ pci_write_config_dword(pdev, 0xB8, 0x43924392);
+ pci_write_config_dword(pdev, 0xBC, 0x40094009);
+
+ switch(tmpbyte & 0x30) {
+ case 0x00: printk(KERN_INFO "sil680: 100MHz clock.\n");break;
+ case 0x10: printk(KERN_INFO "sil680: 133MHz clock.\n");break;
+ case 0x20: printk(KERN_INFO "sil680: Using PCI clock.\n");break;
+ /* This last case is _NOT_ ok */
+ case 0x30: printk(KERN_ERR "sil680: Clock disabled ?\n");
+ return -EIO;
+ }
+ return ata_pci_init_one(pdev, port_info, 2);
+}
+
+static const struct pci_device_id sil680[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_SII_680), },
+ { 0, },
+};
+
+static struct pci_driver sil680_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = sil680,
+ .probe = sil680_init_one,
+ .remove = ata_pci_remove_one
+};
+
+static int __init sil680_init(void)
+{
+ return pci_register_driver(&sil680_pci_driver);
+}
+
+
+static void __exit sil680_exit(void)
+{
+ pci_unregister_driver(&sil680_pci_driver);
+}
+
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("low-level driver for SI680 PATA");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, sil680);
+MODULE_VERSION(DRV_VERSION);
+
+module_init(sil680_init);
+module_exit(sil680_exit);
diff --git a/drivers/ata/pata_sis.c b/drivers/ata/pata_sis.c
new file mode 100644
index 00000000000..17791e2785f
--- /dev/null
+++ b/drivers/ata/pata_sis.c
@@ -0,0 +1,1022 @@
+/*
+ * pata_sis.c - SiS ATA driver
+ *
+ * (C) 2005 Red Hat <alan@redhat.com>
+ *
+ * Based upon linux/drivers/ide/pci/sis5513.c
+ * Copyright (C) 1999-2000 Andre Hedrick <andre@linux-ide.org>
+ * Copyright (C) 2002 Lionel Bouton <Lionel.Bouton@inet6.fr>, Maintainer
+ * Copyright (C) 2003 Vojtech Pavlik <vojtech@suse.cz>
+ * SiS Taiwan : for direct support and hardware.
+ * Daniela Engert : for initial ATA100 advices and numerous others.
+ * John Fremlin, Manfred Spraul, Dave Morgan, Peter Kjellerstedt :
+ * for checking code correctness, providing patches.
+ * Original tests and design on the SiS620 chipset.
+ * ATA100 tests and design on the SiS735 chipset.
+ * ATA16/33 support from specs
+ * ATA133 support for SiS961/962 by L.C. Chang <lcchang@sis.com.tw>
+ *
+ *
+ * TODO
+ * Check MWDMA on drives that don't support MWDMA speed pio cycles ?
+ * More Testing
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+#include <linux/ata.h>
+
+#define DRV_NAME "pata_sis"
+#define DRV_VERSION "0.4.4"
+
+struct sis_chipset {
+ u16 device; /* PCI host ID */
+ struct ata_port_info *info; /* Info block */
+ /* Probably add family, cable detect type etc here to clean
+ up code later */
+};
+
+/**
+ * sis_port_base - return PCI configuration base for dev
+ * @adev: device
+ *
+ * Returns the base of the PCI configuration registers for this port
+ * number.
+ */
+
+static int sis_port_base(struct ata_device *adev)
+{
+ return 0x40 + (4 * adev->ap->port_no) + (2 * adev->devno);
+}
+
+/**
+ * sis_133_pre_reset - check for 40/80 pin
+ * @ap: Port
+ *
+ * Perform cable detection for the later UDMA133 capable
+ * SiS chipset.
+ */
+
+static int sis_133_pre_reset(struct ata_port *ap)
+{
+ static const struct pci_bits sis_enable_bits[] = {
+ { 0x4aU, 1U, 0x02UL, 0x02UL }, /* port 0 */
+ { 0x4aU, 1U, 0x04UL, 0x04UL }, /* port 1 */
+ };
+
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u16 tmp;
+
+ if (!pci_test_config_bits(pdev, &sis_enable_bits[ap->port_no]))
+ return -ENOENT;
+
+ /* The top bit of this register is the cable detect bit */
+ pci_read_config_word(pdev, 0x50 + 2 * ap->port_no, &tmp);
+ if (tmp & 0x8000)
+ ap->cbl = ATA_CBL_PATA40;
+ else
+ ap->cbl = ATA_CBL_PATA80;
+
+ return ata_std_prereset(ap);
+}
+
+/**
+ * sis_error_handler - Probe specified port on PATA host controller
+ * @ap: Port to probe
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void sis_133_error_handler(struct ata_port *ap)
+{
+ ata_bmdma_drive_eh(ap, sis_133_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
+}
+
+
+/**
+ * sis_66_pre_reset - check for 40/80 pin
+ * @ap: Port
+ *
+ * Perform cable detection on the UDMA66, UDMA100 and early UDMA133
+ * SiS IDE controllers.
+ */
+
+static int sis_66_pre_reset(struct ata_port *ap)
+{
+ static const struct pci_bits sis_enable_bits[] = {
+ { 0x4aU, 1U, 0x02UL, 0x02UL }, /* port 0 */
+ { 0x4aU, 1U, 0x04UL, 0x04UL }, /* port 1 */
+ };
+
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u8 tmp;
+
+ if (!pci_test_config_bits(pdev, &sis_enable_bits[ap->port_no])) {
+ ata_port_disable(ap);
+ printk(KERN_INFO "ata%u: port disabled. ignoring.\n", ap->id);
+ return 0;
+ }
+ /* Older chips keep cable detect in bits 4/5 of reg 0x48 */
+ pci_read_config_byte(pdev, 0x48, &tmp);
+ tmp >>= ap->port_no;
+ if (tmp & 0x10)
+ ap->cbl = ATA_CBL_PATA40;
+ else
+ ap->cbl = ATA_CBL_PATA80;
+
+ return ata_std_prereset(ap);
+}
+
+/**
+ * sis_66_error_handler - Probe specified port on PATA host controller
+ * @ap: Port to probe
+ * @classes:
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void sis_66_error_handler(struct ata_port *ap)
+{
+ ata_bmdma_drive_eh(ap, sis_66_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
+}
+
+/**
+ * sis_old_pre_reset - probe begin
+ * @ap: ATA port
+ *
+ * Set up cable type and use generic probe init
+ */
+
+static int sis_old_pre_reset(struct ata_port *ap)
+{
+ static const struct pci_bits sis_enable_bits[] = {
+ { 0x4aU, 1U, 0x02UL, 0x02UL }, /* port 0 */
+ { 0x4aU, 1U, 0x04UL, 0x04UL }, /* port 1 */
+ };
+
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+
+ if (!pci_test_config_bits(pdev, &sis_enable_bits[ap->port_no])) {
+ ata_port_disable(ap);
+ printk(KERN_INFO "ata%u: port disabled. ignoring.\n", ap->id);
+ return 0;
+ }
+ ap->cbl = ATA_CBL_PATA40;
+ return ata_std_prereset(ap);
+}
+
+
+/**
+ * sis_old_error_handler - Probe specified port on PATA host controller
+ * @ap: Port to probe
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void sis_old_error_handler(struct ata_port *ap)
+{
+ ata_bmdma_drive_eh(ap, sis_old_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
+}
+
+/**
+ * sis_set_fifo - Set RWP fifo bits for this device
+ * @ap: Port
+ * @adev: Device
+ *
+ * SIS chipsets implement prefetch/postwrite bits for each device
+ * on both channels. This functionality is not ATAPI compatible and
+ * must be configured according to the class of device present
+ */
+
+static void sis_set_fifo(struct ata_port *ap, struct ata_device *adev)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u8 fifoctrl;
+ u8 mask = 0x11;
+
+ mask <<= (2 * ap->port_no);
+ mask <<= adev->devno;
+
+ /* This holds various bits including the FIFO control */
+ pci_read_config_byte(pdev, 0x4B, &fifoctrl);
+ fifoctrl &= ~mask;
+
+ /* Enable for ATA (disk) only */
+ if (adev->class == ATA_DEV_ATA)
+ fifoctrl |= mask;
+ pci_write_config_byte(pdev, 0x4B, fifoctrl);
+}
+
+/**
+ * sis_old_set_piomode - Initialize host controller PATA PIO timings
+ * @ap: Port whose timings we are configuring
+ * @adev: Device we are configuring for.
+ *
+ * Set PIO mode for device, in host controller PCI config space. This
+ * function handles PIO set up for all chips that are pre ATA100 and
+ * also early ATA100 devices.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void sis_old_set_piomode (struct ata_port *ap, struct ata_device *adev)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ int port = sis_port_base(adev);
+ u8 t1, t2;
+ int speed = adev->pio_mode - XFER_PIO_0;
+
+ const u8 active[] = { 0x00, 0x07, 0x04, 0x03, 0x01 };
+ const u8 recovery[] = { 0x00, 0x06, 0x04, 0x03, 0x03 };
+
+ sis_set_fifo(ap, adev);
+
+ pci_read_config_byte(pdev, port, &t1);
+ pci_read_config_byte(pdev, port + 1, &t2);
+
+ t1 &= ~0x0F; /* Clear active/recovery timings */
+ t2 &= ~0x07;
+
+ t1 |= active[speed];
+ t2 |= recovery[speed];
+
+ pci_write_config_byte(pdev, port, t1);
+ pci_write_config_byte(pdev, port + 1, t2);
+}
+
+/**
+ * sis_100_set_pioode - Initialize host controller PATA PIO timings
+ * @ap: Port whose timings we are configuring
+ * @adev: Device we are configuring for.
+ *
+ * Set PIO mode for device, in host controller PCI config space. This
+ * function handles PIO set up for ATA100 devices and early ATA133.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void sis_100_set_piomode (struct ata_port *ap, struct ata_device *adev)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ int port = sis_port_base(adev);
+ int speed = adev->pio_mode - XFER_PIO_0;
+
+ const u8 actrec[] = { 0x00, 0x67, 0x44, 0x33, 0x31 };
+
+ sis_set_fifo(ap, adev);
+
+ pci_write_config_byte(pdev, port, actrec[speed]);
+}
+
+/**
+ * sis_133_set_pioode - Initialize host controller PATA PIO timings
+ * @ap: Port whose timings we are configuring
+ * @adev: Device we are configuring for.
+ *
+ * Set PIO mode for device, in host controller PCI config space. This
+ * function handles PIO set up for the later ATA133 devices.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void sis_133_set_piomode (struct ata_port *ap, struct ata_device *adev)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ int port = 0x40;
+ u32 t1;
+ u32 reg54;
+ int speed = adev->pio_mode - XFER_PIO_0;
+
+ const u32 timing133[] = {
+ 0x28269000, /* Recovery << 24 | Act << 16 | Ini << 12 */
+ 0x0C266000,
+ 0x04263000,
+ 0x0C0A3000,
+ 0x05093000
+ };
+ const u32 timing100[] = {
+ 0x1E1C6000, /* Recovery << 24 | Act << 16 | Ini << 12 */
+ 0x091C4000,
+ 0x031C2000,
+ 0x09072000,
+ 0x04062000
+ };
+
+ sis_set_fifo(ap, adev);
+
+ /* If bit 14 is set then the registers are mapped at 0x70 not 0x40 */
+ pci_read_config_dword(pdev, 0x54, &reg54);
+ if (reg54 & 0x40000000)
+ port = 0x70;
+ port += 8 * ap->port_no + 4 * adev->devno;
+
+ pci_read_config_dword(pdev, port, &t1);
+ t1 &= 0xC0C00FFF; /* Mask out timing */
+
+ if (t1 & 0x08) /* 100 or 133 ? */
+ t1 |= timing133[speed];
+ else
+ t1 |= timing100[speed];
+ pci_write_config_byte(pdev, port, t1);
+}
+
+/**
+ * sis_old_set_dmamode - Initialize host controller PATA DMA timings
+ * @ap: Port whose timings we are configuring
+ * @adev: Device to program
+ *
+ * Set UDMA/MWDMA mode for device, in host controller PCI config space.
+ * Handles pre UDMA and UDMA33 devices. Supports MWDMA as well unlike
+ * the old ide/pci driver.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void sis_old_set_dmamode (struct ata_port *ap, struct ata_device *adev)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ int speed = adev->dma_mode - XFER_MW_DMA_0;
+ int drive_pci = sis_port_base(adev);
+ u16 timing;
+
+ const u16 mwdma_bits[] = { 0x707, 0x202, 0x202 };
+ const u16 udma_bits[] = { 0xE000, 0xC000, 0xA000 };
+
+ pci_read_config_word(pdev, drive_pci, &timing);
+
+ if (adev->dma_mode < XFER_UDMA_0) {
+ /* bits 3-0 hold recovery timing bits 8-10 active timing and
+ the higer bits are dependant on the device */
+ timing &= ~ 0x870F;
+ timing |= mwdma_bits[speed];
+ pci_write_config_word(pdev, drive_pci, timing);
+ } else {
+ /* Bit 15 is UDMA on/off, bit 13-14 are cycle time */
+ speed = adev->dma_mode - XFER_UDMA_0;
+ timing &= ~0x6000;
+ timing |= udma_bits[speed];
+ }
+}
+
+/**
+ * sis_66_set_dmamode - Initialize host controller PATA DMA timings
+ * @ap: Port whose timings we are configuring
+ * @adev: Device to program
+ *
+ * Set UDMA/MWDMA mode for device, in host controller PCI config space.
+ * Handles UDMA66 and early UDMA100 devices. Supports MWDMA as well unlike
+ * the old ide/pci driver.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void sis_66_set_dmamode (struct ata_port *ap, struct ata_device *adev)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ int speed = adev->dma_mode - XFER_MW_DMA_0;
+ int drive_pci = sis_port_base(adev);
+ u16 timing;
+
+ const u16 mwdma_bits[] = { 0x707, 0x202, 0x202 };
+ const u16 udma_bits[] = { 0xF000, 0xD000, 0xB000, 0xA000, 0x9000};
+
+ pci_read_config_word(pdev, drive_pci, &timing);
+
+ if (adev->dma_mode < XFER_UDMA_0) {
+ /* bits 3-0 hold recovery timing bits 8-10 active timing and
+ the higer bits are dependant on the device, bit 15 udma */
+ timing &= ~ 0x870F;
+ timing |= mwdma_bits[speed];
+ } else {
+ /* Bit 15 is UDMA on/off, bit 12-14 are cycle time */
+ speed = adev->dma_mode - XFER_UDMA_0;
+ timing &= ~0x6000;
+ timing |= udma_bits[speed];
+ }
+ pci_write_config_word(pdev, drive_pci, timing);
+}
+
+/**
+ * sis_100_set_dmamode - Initialize host controller PATA DMA timings
+ * @ap: Port whose timings we are configuring
+ * @adev: Device to program
+ *
+ * Set UDMA/MWDMA mode for device, in host controller PCI config space.
+ * Handles UDMA66 and early UDMA100 devices.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void sis_100_set_dmamode (struct ata_port *ap, struct ata_device *adev)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ int speed = adev->dma_mode - XFER_MW_DMA_0;
+ int drive_pci = sis_port_base(adev);
+ u16 timing;
+
+ const u16 udma_bits[] = { 0x8B00, 0x8700, 0x8500, 0x8300, 0x8200, 0x8100};
+
+ pci_read_config_word(pdev, drive_pci, &timing);
+
+ if (adev->dma_mode < XFER_UDMA_0) {
+ /* NOT SUPPORTED YET: NEED DATA SHEET. DITTO IN OLD DRIVER */
+ } else {
+ /* Bit 15 is UDMA on/off, bit 12-14 are cycle time */
+ speed = adev->dma_mode - XFER_UDMA_0;
+ timing &= ~0x0F00;
+ timing |= udma_bits[speed];
+ }
+ pci_write_config_word(pdev, drive_pci, timing);
+}
+
+/**
+ * sis_133_early_set_dmamode - Initialize host controller PATA DMA timings
+ * @ap: Port whose timings we are configuring
+ * @adev: Device to program
+ *
+ * Set UDMA/MWDMA mode for device, in host controller PCI config space.
+ * Handles early SiS 961 bridges. Supports MWDMA as well unlike
+ * the old ide/pci driver.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void sis_133_early_set_dmamode (struct ata_port *ap, struct ata_device *adev)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ int speed = adev->dma_mode - XFER_MW_DMA_0;
+ int drive_pci = sis_port_base(adev);
+ u16 timing;
+
+ const u16 udma_bits[] = { 0x8F00, 0x8A00, 0x8700, 0x8500, 0x8300, 0x8200, 0x8100};
+
+ pci_read_config_word(pdev, drive_pci, &timing);
+
+ if (adev->dma_mode < XFER_UDMA_0) {
+ /* NOT SUPPORTED YET: NEED DATA SHEET. DITTO IN OLD DRIVER */
+ } else {
+ /* Bit 15 is UDMA on/off, bit 12-14 are cycle time */
+ speed = adev->dma_mode - XFER_UDMA_0;
+ timing &= ~0x0F00;
+ timing |= udma_bits[speed];
+ }
+ pci_write_config_word(pdev, drive_pci, timing);
+}
+
+/**
+ * sis_133_set_dmamode - Initialize host controller PATA DMA timings
+ * @ap: Port whose timings we are configuring
+ * @adev: Device to program
+ *
+ * Set UDMA/MWDMA mode for device, in host controller PCI config space.
+ * Handles early SiS 961 bridges. Supports MWDMA as well unlike
+ * the old ide/pci driver.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void sis_133_set_dmamode (struct ata_port *ap, struct ata_device *adev)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ int speed = adev->dma_mode - XFER_MW_DMA_0;
+ int port = 0x40;
+ u32 t1;
+ u32 reg54;
+
+ /* bits 4- cycle time 8 - cvs time */
+ const u32 timing_u100[] = { 0x6B0, 0x470, 0x350, 0x140, 0x120, 0x110, 0x000 };
+ const u32 timing_u133[] = { 0x9F0, 0x6A0, 0x470, 0x250, 0x230, 0x220, 0x210 };
+
+ /* If bit 14 is set then the registers are mapped at 0x70 not 0x40 */
+ pci_read_config_dword(pdev, 0x54, &reg54);
+ if (reg54 & 0x40000000)
+ port = 0x70;
+ port += (8 * ap->port_no) + (4 * adev->devno);
+
+ pci_read_config_dword(pdev, port, &t1);
+
+ if (adev->dma_mode < XFER_UDMA_0) {
+ t1 &= ~0x00000004;
+ /* FIXME: need data sheet to add MWDMA here. Also lacking on
+ ide/pci driver */
+ } else {
+ speed = adev->dma_mode - XFER_UDMA_0;
+ /* if & 8 no UDMA133 - need info for ... */
+ t1 &= ~0x00000FF0;
+ t1 |= 0x00000004;
+ if (t1 & 0x08)
+ t1 |= timing_u133[speed];
+ else
+ t1 |= timing_u100[speed];
+ }
+ pci_write_config_dword(pdev, port, t1);
+}
+
+static struct scsi_host_template sis_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .max_sectors = ATA_MAX_SECTORS,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .bios_param = ata_std_bios_param,
+};
+
+static const struct ata_port_operations sis_133_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = sis_133_set_piomode,
+ .set_dmamode = sis_133_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = sis_133_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop,
+};
+
+static const struct ata_port_operations sis_133_early_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = sis_100_set_piomode,
+ .set_dmamode = sis_133_early_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = sis_66_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop,
+};
+
+static const struct ata_port_operations sis_100_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = sis_100_set_piomode,
+ .set_dmamode = sis_100_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = sis_66_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop,
+};
+
+static const struct ata_port_operations sis_66_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = sis_old_set_piomode,
+ .set_dmamode = sis_66_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = sis_66_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop,
+};
+
+static const struct ata_port_operations sis_old_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = sis_old_set_piomode,
+ .set_dmamode = sis_old_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = sis_old_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop,
+};
+
+static struct ata_port_info sis_info = {
+ .sht = &sis_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .mwdma_mask = 0x07,
+ .udma_mask = 0,
+ .port_ops = &sis_old_ops,
+};
+static struct ata_port_info sis_info33 = {
+ .sht = &sis_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .mwdma_mask = 0x07,
+ .udma_mask = ATA_UDMA2, /* UDMA 33 */
+ .port_ops = &sis_old_ops,
+};
+static struct ata_port_info sis_info66 = {
+ .sht = &sis_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .udma_mask = ATA_UDMA4, /* UDMA 66 */
+ .port_ops = &sis_66_ops,
+};
+static struct ata_port_info sis_info100 = {
+ .sht = &sis_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .udma_mask = ATA_UDMA5,
+ .port_ops = &sis_100_ops,
+};
+static struct ata_port_info sis_info100_early = {
+ .sht = &sis_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .udma_mask = ATA_UDMA5,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .port_ops = &sis_66_ops,
+};
+static struct ata_port_info sis_info133 = {
+ .sht = &sis_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &sis_133_ops,
+};
+static struct ata_port_info sis_info133_early = {
+ .sht = &sis_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &sis_133_early_ops,
+};
+
+
+static void sis_fixup(struct pci_dev *pdev, struct sis_chipset *sis)
+{
+ u16 regw;
+ u8 reg;
+
+ if (sis->info == &sis_info133) {
+ pci_read_config_word(pdev, 0x50, &regw);
+ if (regw & 0x08)
+ pci_write_config_word(pdev, 0x50, regw & ~0x08);
+ pci_read_config_word(pdev, 0x52, &regw);
+ if (regw & 0x08)
+ pci_write_config_word(pdev, 0x52, regw & ~0x08);
+ return;
+ }
+
+ if (sis->info == &sis_info133_early || sis->info == &sis_info100) {
+ /* Fix up latency */
+ pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x80);
+ /* Set compatibility bit */
+ pci_read_config_byte(pdev, 0x49, &reg);
+ if (!(reg & 0x01))
+ pci_write_config_byte(pdev, 0x49, reg | 0x01);
+ return;
+ }
+
+ if (sis->info == &sis_info66 || sis->info == &sis_info100_early) {
+ /* Fix up latency */
+ pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x80);
+ /* Set compatibility bit */
+ pci_read_config_byte(pdev, 0x52, &reg);
+ if (!(reg & 0x04))
+ pci_write_config_byte(pdev, 0x52, reg | 0x04);
+ return;
+ }
+
+ if (sis->info == &sis_info33) {
+ pci_read_config_byte(pdev, PCI_CLASS_PROG, &reg);
+ if (( reg & 0x0F ) != 0x00)
+ pci_write_config_byte(pdev, PCI_CLASS_PROG, reg & 0xF0);
+ /* Fall through to ATA16 fixup below */
+ }
+
+ if (sis->info == &sis_info || sis->info == &sis_info33) {
+ /* force per drive recovery and active timings
+ needed on ATA_33 and below chips */
+ pci_read_config_byte(pdev, 0x52, &reg);
+ if (!(reg & 0x08))
+ pci_write_config_byte(pdev, 0x52, reg|0x08);
+ return;
+ }
+
+ BUG();
+}
+
+/**
+ * sis_init_one - Register SiS ATA PCI device with kernel services
+ * @pdev: PCI device to register
+ * @ent: Entry in sis_pci_tbl matching with @pdev
+ *
+ * Called from kernel PCI layer. We probe for combined mode (sigh),
+ * and then hand over control to libata, for it to do the rest.
+ *
+ * LOCKING:
+ * Inherited from PCI layer (may sleep).
+ *
+ * RETURNS:
+ * Zero on success, or -ERRNO value.
+ */
+
+static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ static int printed_version;
+ static struct ata_port_info *port_info[2];
+ struct ata_port_info *port;
+ struct pci_dev *host = NULL;
+ struct sis_chipset *chipset = NULL;
+
+ static struct sis_chipset sis_chipsets[] = {
+
+ { 0x0968, &sis_info133 },
+ { 0x0966, &sis_info133 },
+ { 0x0965, &sis_info133 },
+ { 0x0745, &sis_info100 },
+ { 0x0735, &sis_info100 },
+ { 0x0733, &sis_info100 },
+ { 0x0635, &sis_info100 },
+ { 0x0633, &sis_info100 },
+
+ { 0x0730, &sis_info100_early }, /* 100 with ATA 66 layout */
+ { 0x0550, &sis_info100_early }, /* 100 with ATA 66 layout */
+
+ { 0x0640, &sis_info66 },
+ { 0x0630, &sis_info66 },
+ { 0x0620, &sis_info66 },
+ { 0x0540, &sis_info66 },
+ { 0x0530, &sis_info66 },
+
+ { 0x5600, &sis_info33 },
+ { 0x5598, &sis_info33 },
+ { 0x5597, &sis_info33 },
+ { 0x5591, &sis_info33 },
+ { 0x5582, &sis_info33 },
+ { 0x5581, &sis_info33 },
+
+ { 0x5596, &sis_info },
+ { 0x5571, &sis_info },
+ { 0x5517, &sis_info },
+ { 0x5511, &sis_info },
+
+ {0}
+ };
+ static struct sis_chipset sis133_early = {
+ 0x0, &sis_info133_early
+ };
+ static struct sis_chipset sis133 = {
+ 0x0, &sis_info133
+ };
+ static struct sis_chipset sis100_early = {
+ 0x0, &sis_info100_early
+ };
+ static struct sis_chipset sis100 = {
+ 0x0, &sis_info100
+ };
+
+ if (!printed_version++)
+ dev_printk(KERN_DEBUG, &pdev->dev,
+ "version " DRV_VERSION "\n");
+
+ /* We have to find the bridge first */
+
+ for (chipset = &sis_chipsets[0]; chipset->device; chipset++) {
+ host = pci_get_device(PCI_VENDOR_ID_SI, chipset->device, NULL);
+ if (host != NULL) {
+ if (chipset->device == 0x630) { /* SIS630 */
+ u8 host_rev;
+ pci_read_config_byte(host, PCI_REVISION_ID, &host_rev);
+ if (host_rev >= 0x30) /* 630 ET */
+ chipset = &sis100_early;
+ }
+ break;
+ }
+ }
+
+ /* Look for concealed bridges */
+ if (host == NULL) {
+ /* Second check */
+ u32 idemisc;
+ u16 trueid;
+
+ /* Disable ID masking and register remapping then
+ see what the real ID is */
+
+ pci_read_config_dword(pdev, 0x54, &idemisc);
+ pci_write_config_dword(pdev, 0x54, idemisc & 0x7fffffff);
+ pci_read_config_word(pdev, PCI_DEVICE_ID, &trueid);
+ pci_write_config_dword(pdev, 0x54, idemisc);
+
+ switch(trueid) {
+ case 0x5518: /* SIS 962/963 */
+ chipset = &sis133;
+ if ((idemisc & 0x40000000) == 0) {
+ pci_write_config_dword(pdev, 0x54, idemisc | 0x40000000);
+ printk(KERN_INFO "SIS5513: Switching to 5513 register mapping\n");
+ }
+ break;
+ case 0x0180: /* SIS 965/965L */
+ chipset = &sis133;
+ break;
+ case 0x1180: /* SIS 966/966L */
+ chipset = &sis133;
+ break;
+ }
+ }
+
+ /* Further check */
+ if (chipset == NULL) {
+ struct pci_dev *lpc_bridge;
+ u16 trueid;
+ u8 prefctl;
+ u8 idecfg;
+ u8 sbrev;
+
+ /* Try the second unmasking technique */
+ pci_read_config_byte(pdev, 0x4a, &idecfg);
+ pci_write_config_byte(pdev, 0x4a, idecfg | 0x10);
+ pci_read_config_word(pdev, PCI_DEVICE_ID, &trueid);
+ pci_write_config_byte(pdev, 0x4a, idecfg);
+
+ switch(trueid) {
+ case 0x5517:
+ lpc_bridge = pci_get_slot(pdev->bus, 0x10); /* Bus 0 Dev 2 Fn 0 */
+ if (lpc_bridge == NULL)
+ break;
+ pci_read_config_byte(lpc_bridge, PCI_REVISION_ID, &sbrev);
+ pci_read_config_byte(pdev, 0x49, &prefctl);
+ pci_dev_put(lpc_bridge);
+
+ if (sbrev == 0x10 && (prefctl & 0x80)) {
+ chipset = &sis133_early;
+ break;
+ }
+ chipset = &sis100;
+ break;
+ }
+ }
+ pci_dev_put(host);
+
+ /* No chipset info, no support */
+ if (chipset == NULL)
+ return -ENODEV;
+
+ port = chipset->info;
+ port->private_data = chipset;
+
+ sis_fixup(pdev, chipset);
+
+ port_info[0] = port_info[1] = port;
+ return ata_pci_init_one(pdev, port_info, 2);
+}
+
+static const struct pci_device_id sis_pci_tbl[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_SI, 0x5513), }, /* SiS 5513 */
+ { PCI_DEVICE(PCI_VENDOR_ID_SI, 0x5518), }, /* SiS 5518 */
+ { }
+};
+
+static struct pci_driver sis_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = sis_pci_tbl,
+ .probe = sis_init_one,
+ .remove = ata_pci_remove_one,
+};
+
+static int __init sis_init(void)
+{
+ return pci_register_driver(&sis_pci_driver);
+}
+
+static void __exit sis_exit(void)
+{
+ pci_unregister_driver(&sis_pci_driver);
+}
+
+
+module_init(sis_init);
+module_exit(sis_exit);
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("SCSI low-level driver for SiS ATA");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, sis_pci_tbl);
+MODULE_VERSION(DRV_VERSION);
+
diff --git a/drivers/ata/pata_sl82c105.c b/drivers/ata/pata_sl82c105.c
new file mode 100644
index 00000000000..5b762acc568
--- /dev/null
+++ b/drivers/ata/pata_sl82c105.c
@@ -0,0 +1,385 @@
+/*
+ * pata_sl82c105.c - SL82C105 PATA for new ATA layer
+ * (C) 2005 Red Hat Inc
+ * Alan Cox <alan@redhat.com>
+ *
+ * Based in part on linux/drivers/ide/pci/sl82c105.c
+ * SL82C105/Winbond 553 IDE driver
+ *
+ * and in part on the documentation and errata sheet
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+
+#define DRV_NAME "pata_sl82c105"
+#define DRV_VERSION "0.2.3"
+
+enum {
+ /*
+ * SL82C105 PCI config register 0x40 bits.
+ */
+ CTRL_IDE_IRQB = (1 << 30),
+ CTRL_IDE_IRQA = (1 << 28),
+ CTRL_LEGIRQ = (1 << 11),
+ CTRL_P1F16 = (1 << 5),
+ CTRL_P1EN = (1 << 4),
+ CTRL_P0F16 = (1 << 1),
+ CTRL_P0EN = (1 << 0)
+};
+
+/**
+ * sl82c105_pre_reset - probe begin
+ * @ap: ATA port
+ *
+ * Set up cable type and use generic probe init
+ */
+
+static int sl82c105_pre_reset(struct ata_port *ap)
+{
+ static const struct pci_bits sl82c105_enable_bits[] = {
+ { 0x40, 1, 0x01, 0x01 },
+ { 0x40, 1, 0x10, 0x10 }
+ };
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+
+ if (ap->port_no && !pci_test_config_bits(pdev, &sl82c105_enable_bits[ap->port_no]))
+ return -ENOENT;
+ ap->cbl = ATA_CBL_PATA40;
+ return ata_std_prereset(ap);
+}
+
+
+static void sl82c105_error_handler(struct ata_port *ap)
+{
+ ata_bmdma_drive_eh(ap, sl82c105_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
+}
+
+
+/**
+ * sl82c105_configure_piomode - set chip PIO timing
+ * @ap: ATA interface
+ * @adev: ATA device
+ * @pio: PIO mode
+ *
+ * Called to do the PIO mode setup. Our timing registers are shared
+ * so a configure_dmamode call will undo any work we do here and vice
+ * versa
+ */
+
+static void sl82c105_configure_piomode(struct ata_port *ap, struct ata_device *adev, int pio)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ static u16 pio_timing[5] = {
+ 0x50D, 0x407, 0x304, 0x242, 0x240
+ };
+ u16 dummy;
+ int timing = 0x44 + (8 * ap->port_no) + (4 * adev->devno);
+
+ pci_write_config_word(pdev, timing, pio_timing[pio]);
+ /* Can we lose this oddity of the old driver */
+ pci_read_config_word(pdev, timing, &dummy);
+}
+
+/**
+ * sl82c105_set_piomode - set initial PIO mode data
+ * @ap: ATA interface
+ * @adev: ATA device
+ *
+ * Called to do the PIO mode setup. Our timing registers are shared
+ * but we want to set the PIO timing by default.
+ */
+
+static void sl82c105_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ sl82c105_configure_piomode(ap, adev, adev->pio_mode - XFER_PIO_0);
+}
+
+/**
+ * sl82c105_configure_dmamode - set DMA mode in chip
+ * @ap: ATA interface
+ * @adev: ATA device
+ *
+ * Load DMA cycle times into the chip ready for a DMA transfer
+ * to occur.
+ */
+
+static void sl82c105_configure_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ static u16 dma_timing[3] = {
+ 0x707, 0x201, 0x200
+ };
+ u16 dummy;
+ int timing = 0x44 + (8 * ap->port_no) + (4 * adev->devno);
+ int dma = adev->dma_mode - XFER_MW_DMA_0;
+
+ pci_write_config_word(pdev, timing, dma_timing[dma]);
+ /* Can we lose this oddity of the old driver */
+ pci_read_config_word(pdev, timing, &dummy);
+}
+
+/**
+ * sl82c105_set_dmamode - set initial DMA mode data
+ * @ap: ATA interface
+ * @adev: ATA device
+ *
+ * Called to do the DMA mode setup. This replaces the PIO timings
+ * for the device in question. Set appropriate PIO timings not DMA
+ * timings at this point.
+ */
+
+static void sl82c105_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+ switch(adev->dma_mode) {
+ case XFER_MW_DMA_0:
+ sl82c105_configure_piomode(ap, adev, 1);
+ break;
+ case XFER_MW_DMA_1:
+ sl82c105_configure_piomode(ap, adev, 3);
+ break;
+ case XFER_MW_DMA_2:
+ sl82c105_configure_piomode(ap, adev, 3);
+ break;
+ default:
+ BUG();
+ }
+}
+
+/**
+ * sl82c105_reset_engine - Reset the DMA engine
+ * @ap: ATA interface
+ *
+ * The sl82c105 has some serious problems with the DMA engine
+ * when transfers don't run as expected or ATAPI is used. The
+ * recommended fix is to reset the engine each use using a chip
+ * test register.
+ */
+
+static void sl82c105_reset_engine(struct ata_port *ap)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u16 val;
+
+ pci_read_config_word(pdev, 0x7E, &val);
+ pci_write_config_word(pdev, 0x7E, val | 4);
+ pci_write_config_word(pdev, 0x7E, val & ~4);
+}
+
+/**
+ * sl82c105_bmdma_start - DMA engine begin
+ * @qc: ATA command
+ *
+ * Reset the DMA engine each use as recommended by the errata
+ * document.
+ *
+ * FIXME: if we switch clock at BMDMA start/end we might get better
+ * PIO performance on DMA capable devices.
+ */
+
+static void sl82c105_bmdma_start(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+
+ sl82c105_reset_engine(ap);
+
+ /* Set the clocks for DMA */
+ sl82c105_configure_dmamode(ap, qc->dev);
+ /* Activate DMA */
+ ata_bmdma_start(qc);
+}
+
+/**
+ * sl82c105_bmdma_end - DMA engine stop
+ * @qc: ATA command
+ *
+ * Reset the DMA engine each use as recommended by the errata
+ * document.
+ *
+ * This function is also called to turn off DMA when a timeout occurs
+ * during DMA operation. In both cases we need to reset the engine,
+ * so no actual eng_timeout handler is required.
+ *
+ * We assume bmdma_stop is always called if bmdma_start as called. If
+ * not then we may need to wrap qc_issue.
+ */
+
+static void sl82c105_bmdma_stop(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+
+ ata_bmdma_stop(qc);
+ sl82c105_reset_engine(ap);
+
+ /* This will redo the initial setup of the DMA device to matching
+ PIO timings */
+ sl82c105_set_dmamode(ap, qc->dev);
+}
+
+static struct scsi_host_template sl82c105_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .max_sectors = ATA_MAX_SECTORS,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .bios_param = ata_std_bios_param,
+};
+
+static struct ata_port_operations sl82c105_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = sl82c105_set_piomode,
+ .set_dmamode = sl82c105_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .error_handler = sl82c105_error_handler,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = sl82c105_bmdma_start,
+ .bmdma_stop = sl82c105_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+/**
+ * sl82c105_bridge_revision - find bridge version
+ * @pdev: PCI device for the ATA function
+ *
+ * Locates the PCI bridge associated with the ATA function and
+ * providing it is a Winbond 553 reports the revision. If it cannot
+ * find a revision or the right device it returns -1
+ */
+
+static int sl82c105_bridge_revision(struct pci_dev *pdev)
+{
+ struct pci_dev *bridge;
+ u8 rev;
+
+ /*
+ * The bridge should be part of the same device, but function 0.
+ */
+ bridge = pci_get_slot(pdev->bus,
+ PCI_DEVFN(PCI_SLOT(pdev->devfn), 0));
+ if (!bridge)
+ return -1;
+
+ /*
+ * Make sure it is a Winbond 553 and is an ISA bridge.
+ */
+ if (bridge->vendor != PCI_VENDOR_ID_WINBOND ||
+ bridge->device != PCI_DEVICE_ID_WINBOND_83C553 ||
+ bridge->class >> 8 != PCI_CLASS_BRIDGE_ISA) {
+ pci_dev_put(bridge);
+ return -1;
+ }
+ /*
+ * We need to find function 0's revision, not function 1
+ */
+ pci_read_config_byte(bridge, PCI_REVISION_ID, &rev);
+
+ pci_dev_put(bridge);
+ return rev;
+}
+
+
+static int sl82c105_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ static struct ata_port_info info_dma = {
+ .sht = &sl82c105_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .port_ops = &sl82c105_port_ops
+ };
+ static struct ata_port_info info_early = {
+ .sht = &sl82c105_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .port_ops = &sl82c105_port_ops
+ };
+ static struct ata_port_info *port_info[2] = { &info_early, &info_early };
+ u32 val;
+ int rev;
+
+ rev = sl82c105_bridge_revision(dev);
+
+ if (rev == -1)
+ dev_printk(KERN_WARNING, &dev->dev, "pata_sl82c105: Unable to find bridge, disabling DMA.\n");
+ else if (rev <= 5)
+ dev_printk(KERN_WARNING, &dev->dev, "pata_sl82c105: Early bridge revision, no DMA available.\n");
+ else {
+ port_info[0] = &info_dma;
+ port_info[1] = &info_dma;
+ }
+
+ pci_read_config_dword(dev, 0x40, &val);
+ val |= CTRL_P0EN | CTRL_P0F16 | CTRL_P1F16;
+ pci_write_config_dword(dev, 0x40, val);
+
+
+ return ata_pci_init_one(dev, port_info, 1); /* For now */
+}
+
+static struct pci_device_id sl82c105[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105), },
+ { 0, },
+};
+
+static struct pci_driver sl82c105_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = sl82c105,
+ .probe = sl82c105_init_one,
+ .remove = ata_pci_remove_one
+};
+
+static int __init sl82c105_init(void)
+{
+ return pci_register_driver(&sl82c105_pci_driver);
+}
+
+
+static void __exit sl82c105_exit(void)
+{
+ pci_unregister_driver(&sl82c105_pci_driver);
+}
+
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("low-level driver for Sl82c105");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, sl82c105);
+MODULE_VERSION(DRV_VERSION);
+
+module_init(sl82c105_init);
+module_exit(sl82c105_exit);
diff --git a/drivers/ata/pata_triflex.c b/drivers/ata/pata_triflex.c
new file mode 100644
index 00000000000..a954ed93a40
--- /dev/null
+++ b/drivers/ata/pata_triflex.c
@@ -0,0 +1,282 @@
+/*
+ * pata_triflex.c - Compaq PATA for new ATA layer
+ * (C) 2005 Red Hat Inc
+ * Alan Cox <alan@redhat.com>
+ *
+ * based upon
+ *
+ * triflex.c
+ *
+ * IDE Chipset driver for the Compaq TriFlex IDE controller.
+ *
+ * Known to work with the Compaq Workstation 5x00 series.
+ *
+ * Copyright (C) 2002 Hewlett-Packard Development Group, L.P.
+ * Author: Torben Mathiasen <torben.mathiasen@hp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Loosely based on the piix & svwks drivers.
+ *
+ * Documentation:
+ * Not publically available.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+
+#define DRV_NAME "pata_triflex"
+#define DRV_VERSION "0.2.5"
+
+/**
+ * triflex_prereset - probe begin
+ * @ap: ATA port
+ *
+ * Set up cable type and use generic probe init
+ */
+
+static int triflex_prereset(struct ata_port *ap)
+{
+ static const struct pci_bits triflex_enable_bits[] = {
+ { 0x80, 1, 0x01, 0x01 },
+ { 0x80, 1, 0x02, 0x02 }
+ };
+
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+
+ if (!pci_test_config_bits(pdev, &triflex_enable_bits[ap->port_no]))
+ return -ENOENT;
+ ap->cbl = ATA_CBL_PATA40;
+ return ata_std_prereset(ap);
+}
+
+
+
+static void triflex_error_handler(struct ata_port *ap)
+{
+ ata_bmdma_drive_eh(ap, triflex_prereset, ata_std_softreset, NULL, ata_std_postreset);
+}
+
+/**
+ * triflex_load_timing - timing configuration
+ * @ap: ATA interface
+ * @adev: Device on the bus
+ * @speed: speed to configure
+ *
+ * The Triflex has one set of timings per device per channel. This
+ * means we must do some switching. As the PIO and DMA timings don't
+ * match we have to do some reloading unlike PIIX devices where tuning
+ * tricks can avoid it.
+ */
+
+static void triflex_load_timing(struct ata_port *ap, struct ata_device *adev, int speed)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u32 timing = 0;
+ u32 triflex_timing, old_triflex_timing;
+ int channel_offset = ap->port_no ? 0x74: 0x70;
+ unsigned int is_slave = (adev->devno != 0);
+
+
+ pci_read_config_dword(pdev, channel_offset, &old_triflex_timing);
+ triflex_timing = old_triflex_timing;
+
+ switch(speed)
+ {
+ case XFER_MW_DMA_2:
+ timing = 0x0103;break;
+ case XFER_MW_DMA_1:
+ timing = 0x0203;break;
+ case XFER_MW_DMA_0:
+ timing = 0x0808;break;
+ case XFER_SW_DMA_2:
+ case XFER_SW_DMA_1:
+ case XFER_SW_DMA_0:
+ timing = 0x0F0F;break;
+ case XFER_PIO_4:
+ timing = 0x0202;break;
+ case XFER_PIO_3:
+ timing = 0x0204;break;
+ case XFER_PIO_2:
+ timing = 0x0404;break;
+ case XFER_PIO_1:
+ timing = 0x0508;break;
+ case XFER_PIO_0:
+ timing = 0x0808;break;
+ default:
+ BUG();
+ }
+ triflex_timing &= ~ (0xFFFF << (16 * is_slave));
+ triflex_timing |= (timing << (16 * is_slave));
+
+ if (triflex_timing != old_triflex_timing)
+ pci_write_config_dword(pdev, channel_offset, triflex_timing);
+}
+
+/**
+ * triflex_set_piomode - set initial PIO mode data
+ * @ap: ATA interface
+ * @adev: ATA device
+ *
+ * Use the timing loader to set up the PIO mode. We have to do this
+ * because DMA start/stop will only be called once DMA occurs. If there
+ * has been no DMA then the PIO timings are still needed.
+ */
+static void triflex_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ triflex_load_timing(ap, adev, adev->pio_mode);
+}
+
+/**
+ * triflex_dma_start - DMA start callback
+ * @qc: Command in progress
+ *
+ * Usually drivers set the DMA timing at the point the set_dmamode call
+ * is made. Triflex however requires we load new timings on the
+ * transition or keep matching PIO/DMA pairs (ie MWDMA2/PIO4 etc).
+ * We load the DMA timings just before starting DMA and then restore
+ * the PIO timing when the DMA is finished.
+ */
+
+static void triflex_bmdma_start(struct ata_queued_cmd *qc)
+{
+ triflex_load_timing(qc->ap, qc->dev, qc->dev->dma_mode);
+ ata_bmdma_start(qc);
+}
+
+/**
+ * triflex_dma_stop - DMA stop callback
+ * @ap: ATA interface
+ * @adev: ATA device
+ *
+ * We loaded new timings in dma_start, as a result we need to restore
+ * the PIO timings in dma_stop so that the next command issue gets the
+ * right clock values.
+ */
+
+static void triflex_bmdma_stop(struct ata_queued_cmd *qc)
+{
+ ata_bmdma_stop(qc);
+ triflex_load_timing(qc->ap, qc->dev, qc->dev->pio_mode);
+}
+
+static struct scsi_host_template triflex_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .max_sectors = ATA_MAX_SECTORS,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .bios_param = ata_std_bios_param,
+};
+
+static struct ata_port_operations triflex_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = triflex_set_piomode,
+ .mode_filter = ata_pci_default_filter,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = triflex_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = triflex_bmdma_start,
+ .bmdma_stop = triflex_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+static int triflex_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ static struct ata_port_info info = {
+ .sht = &triflex_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .port_ops = &triflex_port_ops
+ };
+ static struct ata_port_info *port_info[2] = { &info, &info };
+ static int printed_version;
+
+ if (!printed_version++)
+ dev_printk(KERN_DEBUG, &dev->dev, "version " DRV_VERSION "\n");
+
+ return ata_pci_init_one(dev, port_info, 2);
+}
+
+static const struct pci_device_id triflex[] = {
+ { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_TRIFLEX_IDE,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { 0, },
+};
+
+static struct pci_driver triflex_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = triflex,
+ .probe = triflex_init_one,
+ .remove = ata_pci_remove_one
+};
+
+static int __init triflex_init(void)
+{
+ return pci_register_driver(&triflex_pci_driver);
+}
+
+
+static void __exit triflex_exit(void)
+{
+ pci_unregister_driver(&triflex_pci_driver);
+}
+
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("low-level driver for Compaq Triflex");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, triflex);
+MODULE_VERSION(DRV_VERSION);
+
+module_init(triflex_init);
+module_exit(triflex_exit);
diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c
new file mode 100644
index 00000000000..7b5dd2343b9
--- /dev/null
+++ b/drivers/ata/pata_via.c
@@ -0,0 +1,565 @@
+/*
+ * pata_via.c - VIA PATA for new ATA layer
+ * (C) 2005-2006 Red Hat Inc
+ * Alan Cox <alan@redhat.com>
+ *
+ * Documentation
+ * Most chipset documentation available under NDA only
+ *
+ * VIA version guide
+ * VIA VT82C561 - early design, uses ata_generic currently
+ * VIA VT82C576 - MWDMA, 33Mhz
+ * VIA VT82C586 - MWDMA, 33Mhz
+ * VIA VT82C586a - Added UDMA to 33Mhz
+ * VIA VT82C586b - UDMA33
+ * VIA VT82C596a - Nonfunctional UDMA66
+ * VIA VT82C596b - Working UDMA66
+ * VIA VT82C686 - Nonfunctional UDMA66
+ * VIA VT82C686a - Working UDMA66
+ * VIA VT82C686b - Updated to UDMA100
+ * VIA VT8231 - UDMA100
+ * VIA VT8233 - UDMA100
+ * VIA VT8233a - UDMA133
+ * VIA VT8233c - UDMA100
+ * VIA VT8235 - UDMA133
+ * VIA VT8237 - UDMA133
+ *
+ * Most registers remain compatible across chips. Others start reserved
+ * and acquire sensible semantics if set to 1 (eg cable detect). A few
+ * exceptions exist, notably around the FIFO settings.
+ *
+ * One additional quirk of the VIA design is that like ALi they use few
+ * PCI IDs for a lot of chips.
+ *
+ * Based heavily on:
+ *
+ * Version 3.38
+ *
+ * VIA IDE driver for Linux. Supported southbridges:
+ *
+ * vt82c576, vt82c586, vt82c586a, vt82c586b, vt82c596a, vt82c596b,
+ * vt82c686, vt82c686a, vt82c686b, vt8231, vt8233, vt8233c, vt8233a,
+ * vt8235, vt8237
+ *
+ * Copyright (c) 2000-2002 Vojtech Pavlik
+ *
+ * Based on the work of:
+ * Michel Aubry
+ * Jeff Garzik
+ * Andre Hedrick
+
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+
+#define DRV_NAME "pata_via"
+#define DRV_VERSION "0.1.14"
+
+/*
+ * The following comes directly from Vojtech Pavlik's ide/pci/via82cxxx
+ * driver.
+ */
+
+enum {
+ VIA_UDMA = 0x007,
+ VIA_UDMA_NONE = 0x000,
+ VIA_UDMA_33 = 0x001,
+ VIA_UDMA_66 = 0x002,
+ VIA_UDMA_100 = 0x003,
+ VIA_UDMA_133 = 0x004,
+ VIA_BAD_PREQ = 0x010, /* Crashes if PREQ# till DDACK# set */
+ VIA_BAD_CLK66 = 0x020, /* 66 MHz clock doesn't work correctly */
+ VIA_SET_FIFO = 0x040, /* Needs to have FIFO split set */
+ VIA_NO_UNMASK = 0x080, /* Doesn't work with IRQ unmasking on */
+ VIA_BAD_ID = 0x100, /* Has wrong vendor ID (0x1107) */
+ VIA_BAD_AST = 0x200, /* Don't touch Address Setup Timing */
+ VIA_NO_ENABLES = 0x400, /* Has no enablebits */
+};
+
+/*
+ * VIA SouthBridge chips.
+ */
+
+static const struct via_isa_bridge {
+ const char *name;
+ u16 id;
+ u8 rev_min;
+ u8 rev_max;
+ u16 flags;
+} via_isa_bridges[] = {
+ { "cx700", PCI_DEVICE_ID_VIA_CX700, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
+ { "vt6410", PCI_DEVICE_ID_VIA_6410, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST | VIA_NO_ENABLES},
+ { "vt8237a", PCI_DEVICE_ID_VIA_8237A, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
+ { "vt8237", PCI_DEVICE_ID_VIA_8237, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
+ { "vt8235", PCI_DEVICE_ID_VIA_8235, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
+ { "vt8233a", PCI_DEVICE_ID_VIA_8233A, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
+ { "vt8233c", PCI_DEVICE_ID_VIA_8233C_0, 0x00, 0x2f, VIA_UDMA_100 },
+ { "vt8233", PCI_DEVICE_ID_VIA_8233_0, 0x00, 0x2f, VIA_UDMA_100 },
+ { "vt8231", PCI_DEVICE_ID_VIA_8231, 0x00, 0x2f, VIA_UDMA_100 },
+ { "vt82c686b", PCI_DEVICE_ID_VIA_82C686, 0x40, 0x4f, VIA_UDMA_100 },
+ { "vt82c686a", PCI_DEVICE_ID_VIA_82C686, 0x10, 0x2f, VIA_UDMA_66 },
+ { "vt82c686", PCI_DEVICE_ID_VIA_82C686, 0x00, 0x0f, VIA_UDMA_33 | VIA_BAD_CLK66 },
+ { "vt82c596b", PCI_DEVICE_ID_VIA_82C596, 0x10, 0x2f, VIA_UDMA_66 },
+ { "vt82c596a", PCI_DEVICE_ID_VIA_82C596, 0x00, 0x0f, VIA_UDMA_33 | VIA_BAD_CLK66 },
+ { "vt82c586b", PCI_DEVICE_ID_VIA_82C586_0, 0x47, 0x4f, VIA_UDMA_33 | VIA_SET_FIFO },
+ { "vt82c586b", PCI_DEVICE_ID_VIA_82C586_0, 0x40, 0x46, VIA_UDMA_33 | VIA_SET_FIFO | VIA_BAD_PREQ },
+ { "vt82c586b", PCI_DEVICE_ID_VIA_82C586_0, 0x30, 0x3f, VIA_UDMA_33 | VIA_SET_FIFO },
+ { "vt82c586a", PCI_DEVICE_ID_VIA_82C586_0, 0x20, 0x2f, VIA_UDMA_33 | VIA_SET_FIFO },
+ { "vt82c586", PCI_DEVICE_ID_VIA_82C586_0, 0x00, 0x0f, VIA_UDMA_NONE | VIA_SET_FIFO },
+ { "vt82c576", PCI_DEVICE_ID_VIA_82C576, 0x00, 0x2f, VIA_UDMA_NONE | VIA_SET_FIFO | VIA_NO_UNMASK },
+ { "vt82c576", PCI_DEVICE_ID_VIA_82C576, 0x00, 0x2f, VIA_UDMA_NONE | VIA_SET_FIFO | VIA_NO_UNMASK | VIA_BAD_ID },
+ { NULL }
+};
+
+/**
+ * via_cable_detect - cable detection
+ * @ap: ATA port
+ *
+ * Perform cable detection. Actually for the VIA case the BIOS
+ * already did this for us. We read the values provided by the
+ * BIOS. If you are using an 8235 in a non-PC configuration you
+ * may need to update this code.
+ *
+ * Hotplug also impacts on this.
+ */
+
+static int via_cable_detect(struct ata_port *ap) {
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u32 ata66;
+
+ pci_read_config_dword(pdev, 0x50, &ata66);
+ /* Check both the drive cable reporting bits, we might not have
+ two drives */
+ if (ata66 & (0x10100000 >> (16 * ap->port_no)))
+ return ATA_CBL_PATA80;
+ else
+ return ATA_CBL_PATA40;
+}
+
+static int via_pre_reset(struct ata_port *ap)
+{
+ const struct via_isa_bridge *config = ap->host->private_data;
+
+ if (!(config->flags & VIA_NO_ENABLES)) {
+ static const struct pci_bits via_enable_bits[] = {
+ { 0x40, 1, 0x02, 0x02 },
+ { 0x40, 1, 0x01, 0x01 }
+ };
+
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+
+ if (!pci_test_config_bits(pdev, &via_enable_bits[ap->port_no]))
+ return -ENOENT;
+ }
+
+ if ((config->flags & VIA_UDMA) >= VIA_UDMA_66)
+ ap->cbl = via_cable_detect(ap);
+ else
+ ap->cbl = ATA_CBL_PATA40;
+ return ata_std_prereset(ap);
+}
+
+
+/**
+ * via_error_handler - reset for VIA chips
+ * @ap: ATA port
+ *
+ * Handle the reset callback for the later chips with cable detect
+ */
+
+static void via_error_handler(struct ata_port *ap)
+{
+ ata_bmdma_drive_eh(ap, via_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
+}
+
+/**
+ * via_do_set_mode - set initial PIO mode data
+ * @ap: ATA interface
+ * @adev: ATA device
+ * @mode: ATA mode being programmed
+ * @tdiv: Clocks per PCI clock
+ * @set_ast: Set to program address setup
+ * @udma_type: UDMA mode/format of registers
+ *
+ * Program the VIA registers for DMA and PIO modes. Uses the ata timing
+ * support in order to compute modes.
+ *
+ * FIXME: Hotplug will require we serialize multiple mode changes
+ * on the two channels.
+ */
+
+static void via_do_set_mode(struct ata_port *ap, struct ata_device *adev, int mode, int tdiv, int set_ast, int udma_type)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ struct ata_device *peer = ata_dev_pair(adev);
+ struct ata_timing t, p;
+ static int via_clock = 33333; /* Bus clock in kHZ - ought to be tunable one day */
+ unsigned long T = 1000000000 / via_clock;
+ unsigned long UT = T/tdiv;
+ int ut;
+ int offset = 3 - (2*ap->port_no) - adev->devno;
+
+
+ /* Calculate the timing values we require */
+ ata_timing_compute(adev, mode, &t, T, UT);
+
+ /* We share 8bit timing so we must merge the constraints */
+ if (peer) {
+ if (peer->pio_mode) {
+ ata_timing_compute(peer, peer->pio_mode, &p, T, UT);
+ ata_timing_merge(&p, &t, &t, ATA_TIMING_8BIT);
+ }
+ }
+
+ /* Address setup is programmable but breaks on UDMA133 setups */
+ if (set_ast) {
+ u8 setup; /* 2 bits per drive */
+ int shift = 2 * offset;
+
+ pci_read_config_byte(pdev, 0x4C, &setup);
+ setup &= ~(3 << shift);
+ setup |= FIT(t.setup, 1, 4) << shift; /* 1,4 or 1,4 - 1 FIXME */
+ pci_write_config_byte(pdev, 0x4C, setup);
+ }
+
+ /* Load the PIO mode bits */
+ pci_write_config_byte(pdev, 0x4F - ap->port_no,
+ ((FIT(t.act8b, 1, 16) - 1) << 4) | (FIT(t.rec8b, 1, 16) - 1));
+ pci_write_config_byte(pdev, 0x48 + offset,
+ ((FIT(t.active, 1, 16) - 1) << 4) | (FIT(t.recover, 1, 16) - 1));
+
+ /* Load the UDMA bits according to type */
+ switch(udma_type) {
+ default:
+ /* BUG() ? */
+ /* fall through */
+ case 33:
+ ut = t.udma ? (0xe0 | (FIT(t.udma, 2, 5) - 2)) : 0x03;
+ break;
+ case 66:
+ ut = t.udma ? (0xe8 | (FIT(t.udma, 2, 9) - 2)) : 0x0f;
+ break;
+ case 100:
+ ut = t.udma ? (0xe0 | (FIT(t.udma, 2, 9) - 2)) : 0x07;
+ break;
+ case 133:
+ ut = t.udma ? (0xe0 | (FIT(t.udma, 2, 9) - 2)) : 0x07;
+ break;
+ }
+ /* Set UDMA unless device is not UDMA capable */
+ if (udma_type)
+ pci_write_config_byte(pdev, 0x50 + offset, ut);
+}
+
+static void via_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ const struct via_isa_bridge *config = ap->host->private_data;
+ int set_ast = (config->flags & VIA_BAD_AST) ? 0 : 1;
+ int mode = config->flags & VIA_UDMA;
+ static u8 tclock[5] = { 1, 1, 2, 3, 4 };
+ static u8 udma[5] = { 0, 33, 66, 100, 133 };
+
+ via_do_set_mode(ap, adev, adev->pio_mode, tclock[mode], set_ast, udma[mode]);
+}
+
+static void via_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+ const struct via_isa_bridge *config = ap->host->private_data;
+ int set_ast = (config->flags & VIA_BAD_AST) ? 0 : 1;
+ int mode = config->flags & VIA_UDMA;
+ static u8 tclock[5] = { 1, 1, 2, 3, 4 };
+ static u8 udma[5] = { 0, 33, 66, 100, 133 };
+
+ via_do_set_mode(ap, adev, adev->dma_mode, tclock[mode], set_ast, udma[mode]);
+}
+
+static struct scsi_host_template via_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .max_sectors = ATA_MAX_SECTORS,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .bios_param = ata_std_bios_param,
+};
+
+static struct ata_port_operations via_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = via_set_piomode,
+ .set_dmamode = via_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = via_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+static struct ata_port_operations via_port_ops_noirq = {
+ .port_disable = ata_port_disable,
+ .set_piomode = via_set_piomode,
+ .set_dmamode = via_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = via_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer_noirq,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+/**
+ * via_init_one - discovery callback
+ * @pdev: PCI device ID
+ * @id: PCI table info
+ *
+ * A VIA IDE interface has been discovered. Figure out what revision
+ * and perform configuration work before handing it to the ATA layer
+ */
+
+static int via_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ /* Early VIA without UDMA support */
+ static struct ata_port_info via_mwdma_info = {
+ .sht = &via_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .port_ops = &via_port_ops
+ };
+ /* Ditto with IRQ masking required */
+ static struct ata_port_info via_mwdma_info_borked = {
+ .sht = &via_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .port_ops = &via_port_ops_noirq,
+ };
+ /* VIA UDMA 33 devices (and borked 66) */
+ static struct ata_port_info via_udma33_info = {
+ .sht = &via_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x7,
+ .port_ops = &via_port_ops
+ };
+ /* VIA UDMA 66 devices */
+ static struct ata_port_info via_udma66_info = {
+ .sht = &via_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x1f,
+ .port_ops = &via_port_ops
+ };
+ /* VIA UDMA 100 devices */
+ static struct ata_port_info via_udma100_info = {
+ .sht = &via_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x3f,
+ .port_ops = &via_port_ops
+ };
+ /* UDMA133 with bad AST (All current 133) */
+ static struct ata_port_info via_udma133_info = {
+ .sht = &via_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x7f, /* FIXME: should check north bridge */
+ .port_ops = &via_port_ops
+ };
+ struct ata_port_info *port_info[2], *type;
+ struct pci_dev *isa = NULL;
+ const struct via_isa_bridge *config;
+ static int printed_version;
+ u8 t;
+ u8 enable;
+ u32 timing;
+
+ if (!printed_version++)
+ dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
+
+ /* To find out how the IDE will behave and what features we
+ actually have to look at the bridge not the IDE controller */
+ for (config = via_isa_bridges; config->id; config++)
+ if ((isa = pci_get_device(PCI_VENDOR_ID_VIA +
+ !!(config->flags & VIA_BAD_ID),
+ config->id, NULL))) {
+
+ pci_read_config_byte(isa, PCI_REVISION_ID, &t);
+ if (t >= config->rev_min &&
+ t <= config->rev_max)
+ break;
+ pci_dev_put(isa);
+ }
+
+ if (!config->id) {
+ printk(KERN_WARNING "via: Unknown VIA SouthBridge, disabling.\n");
+ return -ENODEV;
+ }
+ pci_dev_put(isa);
+
+ /* 0x40 low bits indicate enabled channels */
+ pci_read_config_byte(pdev, 0x40 , &enable);
+ enable &= 3;
+ if (enable == 0) {
+ return -ENODEV;
+ }
+
+ /* Initialise the FIFO for the enabled channels. */
+ if (config->flags & VIA_SET_FIFO) {
+ u8 fifo_setting[4] = {0x00, 0x60, 0x00, 0x20};
+ u8 fifo;
+
+ pci_read_config_byte(pdev, 0x43, &fifo);
+
+ /* Clear PREQ# until DDACK# for errata */
+ if (config->flags & VIA_BAD_PREQ)
+ fifo &= 0x7F;
+ else
+ fifo &= 0x9f;
+ /* Turn on FIFO for enabled channels */
+ fifo |= fifo_setting[enable];
+ pci_write_config_byte(pdev, 0x43, fifo);
+ }
+ /* Clock set up */
+ switch(config->flags & VIA_UDMA) {
+ case VIA_UDMA_NONE:
+ if (config->flags & VIA_NO_UNMASK)
+ type = &via_mwdma_info_borked;
+ else
+ type = &via_mwdma_info;
+ break;
+ case VIA_UDMA_33:
+ type = &via_udma33_info;
+ break;
+ case VIA_UDMA_66:
+ type = &via_udma66_info;
+ /* The 66 MHz devices require we enable the clock */
+ pci_read_config_dword(pdev, 0x50, &timing);
+ timing |= 0x80008;
+ pci_write_config_dword(pdev, 0x50, timing);
+ break;
+ case VIA_UDMA_100:
+ type = &via_udma100_info;
+ break;
+ case VIA_UDMA_133:
+ type = &via_udma133_info;
+ break;
+ default:
+ WARN_ON(1);
+ return -ENODEV;
+ }
+
+ if (config->flags & VIA_BAD_CLK66) {
+ /* Disable the 66MHz clock on problem devices */
+ pci_read_config_dword(pdev, 0x50, &timing);
+ timing &= ~0x80008;
+ pci_write_config_dword(pdev, 0x50, timing);
+ }
+
+ /* We have established the device type, now fire it up */
+ type->private_data = (void *)config;
+
+ port_info[0] = port_info[1] = type;
+ return ata_pci_init_one(pdev, port_info, 2);
+}
+
+static const struct pci_device_id via[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C576_1), },
+ { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1), },
+ { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_6410), },
+ { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_SATA_EIDE), },
+ { 0, },
+};
+
+static struct pci_driver via_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = via,
+ .probe = via_init_one,
+ .remove = ata_pci_remove_one
+};
+
+static int __init via_init(void)
+{
+ return pci_register_driver(&via_pci_driver);
+}
+
+
+static void __exit via_exit(void)
+{
+ pci_unregister_driver(&via_pci_driver);
+}
+
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("low-level driver for VIA PATA");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, via);
+MODULE_VERSION(DRV_VERSION);
+
+module_init(via_init);
+module_exit(via_exit);
diff --git a/drivers/ata/pdc_adma.c b/drivers/ata/pdc_adma.c
new file mode 100644
index 00000000000..0e23ecb77bc
--- /dev/null
+++ b/drivers/ata/pdc_adma.c
@@ -0,0 +1,740 @@
+/*
+ * pdc_adma.c - Pacific Digital Corporation ADMA
+ *
+ * Maintained by: Mark Lord <mlord@pobox.com>
+ *
+ * Copyright 2005 Mark Lord
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * libata documentation is available via 'make {ps|pdf}docs',
+ * as Documentation/DocBook/libata.*
+ *
+ *
+ * Supports ATA disks in single-packet ADMA mode.
+ * Uses PIO for everything else.
+ *
+ * TODO: Use ADMA transfers for ATAPI devices, when possible.
+ * This requires careful attention to a number of quirks of the chip.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/device.h>
+#include <scsi/scsi_host.h>
+#include <asm/io.h>
+#include <linux/libata.h>
+
+#define DRV_NAME "pdc_adma"
+#define DRV_VERSION "0.04"
+
+/* macro to calculate base address for ATA regs */
+#define ADMA_ATA_REGS(base,port_no) ((base) + ((port_no) * 0x40))
+
+/* macro to calculate base address for ADMA regs */
+#define ADMA_REGS(base,port_no) ((base) + 0x80 + ((port_no) * 0x20))
+
+enum {
+ ADMA_PORTS = 2,
+ ADMA_CPB_BYTES = 40,
+ ADMA_PRD_BYTES = LIBATA_MAX_PRD * 16,
+ ADMA_PKT_BYTES = ADMA_CPB_BYTES + ADMA_PRD_BYTES,
+
+ ADMA_DMA_BOUNDARY = 0xffffffff,
+
+ /* global register offsets */
+ ADMA_MODE_LOCK = 0x00c7,
+
+ /* per-channel register offsets */
+ ADMA_CONTROL = 0x0000, /* ADMA control */
+ ADMA_STATUS = 0x0002, /* ADMA status */
+ ADMA_CPB_COUNT = 0x0004, /* CPB count */
+ ADMA_CPB_CURRENT = 0x000c, /* current CPB address */
+ ADMA_CPB_NEXT = 0x000c, /* next CPB address */
+ ADMA_CPB_LOOKUP = 0x0010, /* CPB lookup table */
+ ADMA_FIFO_IN = 0x0014, /* input FIFO threshold */
+ ADMA_FIFO_OUT = 0x0016, /* output FIFO threshold */
+
+ /* ADMA_CONTROL register bits */
+ aNIEN = (1 << 8), /* irq mask: 1==masked */
+ aGO = (1 << 7), /* packet trigger ("Go!") */
+ aRSTADM = (1 << 5), /* ADMA logic reset */
+ aPIOMD4 = 0x0003, /* PIO mode 4 */
+
+ /* ADMA_STATUS register bits */
+ aPSD = (1 << 6),
+ aUIRQ = (1 << 4),
+ aPERR = (1 << 0),
+
+ /* CPB bits */
+ cDONE = (1 << 0),
+ cVLD = (1 << 0),
+ cDAT = (1 << 2),
+ cIEN = (1 << 3),
+
+ /* PRD bits */
+ pORD = (1 << 4),
+ pDIRO = (1 << 5),
+ pEND = (1 << 7),
+
+ /* ATA register flags */
+ rIGN = (1 << 5),
+ rEND = (1 << 7),
+
+ /* ATA register addresses */
+ ADMA_REGS_CONTROL = 0x0e,
+ ADMA_REGS_SECTOR_COUNT = 0x12,
+ ADMA_REGS_LBA_LOW = 0x13,
+ ADMA_REGS_LBA_MID = 0x14,
+ ADMA_REGS_LBA_HIGH = 0x15,
+ ADMA_REGS_DEVICE = 0x16,
+ ADMA_REGS_COMMAND = 0x17,
+
+ /* PCI device IDs */
+ board_1841_idx = 0, /* ADMA 2-port controller */
+};
+
+typedef enum { adma_state_idle, adma_state_pkt, adma_state_mmio } adma_state_t;
+
+struct adma_port_priv {
+ u8 *pkt;
+ dma_addr_t pkt_dma;
+ adma_state_t state;
+};
+
+static int adma_ata_init_one (struct pci_dev *pdev,
+ const struct pci_device_id *ent);
+static irqreturn_t adma_intr (int irq, void *dev_instance,
+ struct pt_regs *regs);
+static int adma_port_start(struct ata_port *ap);
+static void adma_host_stop(struct ata_host *host);
+static void adma_port_stop(struct ata_port *ap);
+static void adma_phy_reset(struct ata_port *ap);
+static void adma_qc_prep(struct ata_queued_cmd *qc);
+static unsigned int adma_qc_issue(struct ata_queued_cmd *qc);
+static int adma_check_atapi_dma(struct ata_queued_cmd *qc);
+static void adma_bmdma_stop(struct ata_queued_cmd *qc);
+static u8 adma_bmdma_status(struct ata_port *ap);
+static void adma_irq_clear(struct ata_port *ap);
+static void adma_eng_timeout(struct ata_port *ap);
+
+static struct scsi_host_template adma_ata_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ENABLE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ADMA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .slave_destroy = ata_scsi_slave_destroy,
+ .bios_param = ata_std_bios_param,
+};
+
+static const struct ata_port_operations adma_ata_ops = {
+ .port_disable = ata_port_disable,
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .check_atapi_dma = adma_check_atapi_dma,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+ .phy_reset = adma_phy_reset,
+ .qc_prep = adma_qc_prep,
+ .qc_issue = adma_qc_issue,
+ .eng_timeout = adma_eng_timeout,
+ .data_xfer = ata_mmio_data_xfer,
+ .irq_handler = adma_intr,
+ .irq_clear = adma_irq_clear,
+ .port_start = adma_port_start,
+ .port_stop = adma_port_stop,
+ .host_stop = adma_host_stop,
+ .bmdma_stop = adma_bmdma_stop,
+ .bmdma_status = adma_bmdma_status,
+};
+
+static struct ata_port_info adma_port_info[] = {
+ /* board_1841_idx */
+ {
+ .sht = &adma_ata_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST |
+ ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO |
+ ATA_FLAG_PIO_POLLING,
+ .pio_mask = 0x10, /* pio4 */
+ .udma_mask = 0x1f, /* udma0-4 */
+ .port_ops = &adma_ata_ops,
+ },
+};
+
+static const struct pci_device_id adma_ata_pci_tbl[] = {
+ { PCI_VENDOR_ID_PDC, 0x1841, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ board_1841_idx },
+
+ { } /* terminate list */
+};
+
+static struct pci_driver adma_ata_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = adma_ata_pci_tbl,
+ .probe = adma_ata_init_one,
+ .remove = ata_pci_remove_one,
+};
+
+static int adma_check_atapi_dma(struct ata_queued_cmd *qc)
+{
+ return 1; /* ATAPI DMA not yet supported */
+}
+
+static void adma_bmdma_stop(struct ata_queued_cmd *qc)
+{
+ /* nothing */
+}
+
+static u8 adma_bmdma_status(struct ata_port *ap)
+{
+ return 0;
+}
+
+static void adma_irq_clear(struct ata_port *ap)
+{
+ /* nothing */
+}
+
+static void adma_reset_engine(void __iomem *chan)
+{
+ /* reset ADMA to idle state */
+ writew(aPIOMD4 | aNIEN | aRSTADM, chan + ADMA_CONTROL);
+ udelay(2);
+ writew(aPIOMD4, chan + ADMA_CONTROL);
+ udelay(2);
+}
+
+static void adma_reinit_engine(struct ata_port *ap)
+{
+ struct adma_port_priv *pp = ap->private_data;
+ void __iomem *mmio_base = ap->host->mmio_base;
+ void __iomem *chan = ADMA_REGS(mmio_base, ap->port_no);
+
+ /* mask/clear ATA interrupts */
+ writeb(ATA_NIEN, (void __iomem *)ap->ioaddr.ctl_addr);
+ ata_check_status(ap);
+
+ /* reset the ADMA engine */
+ adma_reset_engine(chan);
+
+ /* set in-FIFO threshold to 0x100 */
+ writew(0x100, chan + ADMA_FIFO_IN);
+
+ /* set CPB pointer */
+ writel((u32)pp->pkt_dma, chan + ADMA_CPB_NEXT);
+
+ /* set out-FIFO threshold to 0x100 */
+ writew(0x100, chan + ADMA_FIFO_OUT);
+
+ /* set CPB count */
+ writew(1, chan + ADMA_CPB_COUNT);
+
+ /* read/discard ADMA status */
+ readb(chan + ADMA_STATUS);
+}
+
+static inline void adma_enter_reg_mode(struct ata_port *ap)
+{
+ void __iomem *chan = ADMA_REGS(ap->host->mmio_base, ap->port_no);
+
+ writew(aPIOMD4, chan + ADMA_CONTROL);
+ readb(chan + ADMA_STATUS); /* flush */
+}
+
+static void adma_phy_reset(struct ata_port *ap)
+{
+ struct adma_port_priv *pp = ap->private_data;
+
+ pp->state = adma_state_idle;
+ adma_reinit_engine(ap);
+ ata_port_probe(ap);
+ ata_bus_reset(ap);
+}
+
+static void adma_eng_timeout(struct ata_port *ap)
+{
+ struct adma_port_priv *pp = ap->private_data;
+
+ if (pp->state != adma_state_idle) /* healthy paranoia */
+ pp->state = adma_state_mmio;
+ adma_reinit_engine(ap);
+ ata_eng_timeout(ap);
+}
+
+static int adma_fill_sg(struct ata_queued_cmd *qc)
+{
+ struct scatterlist *sg;
+ struct ata_port *ap = qc->ap;
+ struct adma_port_priv *pp = ap->private_data;
+ u8 *buf = pp->pkt;
+ int i = (2 + buf[3]) * 8;
+ u8 pFLAGS = pORD | ((qc->tf.flags & ATA_TFLAG_WRITE) ? pDIRO : 0);
+
+ ata_for_each_sg(sg, qc) {
+ u32 addr;
+ u32 len;
+
+ addr = (u32)sg_dma_address(sg);
+ *(__le32 *)(buf + i) = cpu_to_le32(addr);
+ i += 4;
+
+ len = sg_dma_len(sg) >> 3;
+ *(__le32 *)(buf + i) = cpu_to_le32(len);
+ i += 4;
+
+ if (ata_sg_is_last(sg, qc))
+ pFLAGS |= pEND;
+ buf[i++] = pFLAGS;
+ buf[i++] = qc->dev->dma_mode & 0xf;
+ buf[i++] = 0; /* pPKLW */
+ buf[i++] = 0; /* reserved */
+
+ *(__le32 *)(buf + i)
+ = (pFLAGS & pEND) ? 0 : cpu_to_le32(pp->pkt_dma + i + 4);
+ i += 4;
+
+ VPRINTK("PRD[%u] = (0x%lX, 0x%X)\n", i/4,
+ (unsigned long)addr, len);
+ }
+ return i;
+}
+
+static void adma_qc_prep(struct ata_queued_cmd *qc)
+{
+ struct adma_port_priv *pp = qc->ap->private_data;
+ u8 *buf = pp->pkt;
+ u32 pkt_dma = (u32)pp->pkt_dma;
+ int i = 0;
+
+ VPRINTK("ENTER\n");
+
+ adma_enter_reg_mode(qc->ap);
+ if (qc->tf.protocol != ATA_PROT_DMA) {
+ ata_qc_prep(qc);
+ return;
+ }
+
+ buf[i++] = 0; /* Response flags */
+ buf[i++] = 0; /* reserved */
+ buf[i++] = cVLD | cDAT | cIEN;
+ i++; /* cLEN, gets filled in below */
+
+ *(__le32 *)(buf+i) = cpu_to_le32(pkt_dma); /* cNCPB */
+ i += 4; /* cNCPB */
+ i += 4; /* cPRD, gets filled in below */
+
+ buf[i++] = 0; /* reserved */
+ buf[i++] = 0; /* reserved */
+ buf[i++] = 0; /* reserved */
+ buf[i++] = 0; /* reserved */
+
+ /* ATA registers; must be a multiple of 4 */
+ buf[i++] = qc->tf.device;
+ buf[i++] = ADMA_REGS_DEVICE;
+ if ((qc->tf.flags & ATA_TFLAG_LBA48)) {
+ buf[i++] = qc->tf.hob_nsect;
+ buf[i++] = ADMA_REGS_SECTOR_COUNT;
+ buf[i++] = qc->tf.hob_lbal;
+ buf[i++] = ADMA_REGS_LBA_LOW;
+ buf[i++] = qc->tf.hob_lbam;
+ buf[i++] = ADMA_REGS_LBA_MID;
+ buf[i++] = qc->tf.hob_lbah;
+ buf[i++] = ADMA_REGS_LBA_HIGH;
+ }
+ buf[i++] = qc->tf.nsect;
+ buf[i++] = ADMA_REGS_SECTOR_COUNT;
+ buf[i++] = qc->tf.lbal;
+ buf[i++] = ADMA_REGS_LBA_LOW;
+ buf[i++] = qc->tf.lbam;
+ buf[i++] = ADMA_REGS_LBA_MID;
+ buf[i++] = qc->tf.lbah;
+ buf[i++] = ADMA_REGS_LBA_HIGH;
+ buf[i++] = 0;
+ buf[i++] = ADMA_REGS_CONTROL;
+ buf[i++] = rIGN;
+ buf[i++] = 0;
+ buf[i++] = qc->tf.command;
+ buf[i++] = ADMA_REGS_COMMAND | rEND;
+
+ buf[3] = (i >> 3) - 2; /* cLEN */
+ *(__le32 *)(buf+8) = cpu_to_le32(pkt_dma + i); /* cPRD */
+
+ i = adma_fill_sg(qc);
+ wmb(); /* flush PRDs and pkt to memory */
+#if 0
+ /* dump out CPB + PRDs for debug */
+ {
+ int j, len = 0;
+ static char obuf[2048];
+ for (j = 0; j < i; ++j) {
+ len += sprintf(obuf+len, "%02x ", buf[j]);
+ if ((j & 7) == 7) {
+ printk("%s\n", obuf);
+ len = 0;
+ }
+ }
+ if (len)
+ printk("%s\n", obuf);
+ }
+#endif
+}
+
+static inline void adma_packet_start(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ void __iomem *chan = ADMA_REGS(ap->host->mmio_base, ap->port_no);
+
+ VPRINTK("ENTER, ap %p\n", ap);
+
+ /* fire up the ADMA engine */
+ writew(aPIOMD4 | aGO, chan + ADMA_CONTROL);
+}
+
+static unsigned int adma_qc_issue(struct ata_queued_cmd *qc)
+{
+ struct adma_port_priv *pp = qc->ap->private_data;
+
+ switch (qc->tf.protocol) {
+ case ATA_PROT_DMA:
+ pp->state = adma_state_pkt;
+ adma_packet_start(qc);
+ return 0;
+
+ case ATA_PROT_ATAPI_DMA:
+ BUG();
+ break;
+
+ default:
+ break;
+ }
+
+ pp->state = adma_state_mmio;
+ return ata_qc_issue_prot(qc);
+}
+
+static inline unsigned int adma_intr_pkt(struct ata_host *host)
+{
+ unsigned int handled = 0, port_no;
+ u8 __iomem *mmio_base = host->mmio_base;
+
+ for (port_no = 0; port_no < host->n_ports; ++port_no) {
+ struct ata_port *ap = host->ports[port_no];
+ struct adma_port_priv *pp;
+ struct ata_queued_cmd *qc;
+ void __iomem *chan = ADMA_REGS(mmio_base, port_no);
+ u8 status = readb(chan + ADMA_STATUS);
+
+ if (status == 0)
+ continue;
+ handled = 1;
+ adma_enter_reg_mode(ap);
+ if (ap->flags & ATA_FLAG_DISABLED)
+ continue;
+ pp = ap->private_data;
+ if (!pp || pp->state != adma_state_pkt)
+ continue;
+ qc = ata_qc_from_tag(ap, ap->active_tag);
+ if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) {
+ if ((status & (aPERR | aPSD | aUIRQ)))
+ qc->err_mask |= AC_ERR_OTHER;
+ else if (pp->pkt[0] != cDONE)
+ qc->err_mask |= AC_ERR_OTHER;
+
+ ata_qc_complete(qc);
+ }
+ }
+ return handled;
+}
+
+static inline unsigned int adma_intr_mmio(struct ata_host *host)
+{
+ unsigned int handled = 0, port_no;
+
+ for (port_no = 0; port_no < host->n_ports; ++port_no) {
+ struct ata_port *ap;
+ ap = host->ports[port_no];
+ if (ap && (!(ap->flags & ATA_FLAG_DISABLED))) {
+ struct ata_queued_cmd *qc;
+ struct adma_port_priv *pp = ap->private_data;
+ if (!pp || pp->state != adma_state_mmio)
+ continue;
+ qc = ata_qc_from_tag(ap, ap->active_tag);
+ if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) {
+
+ /* check main status, clearing INTRQ */
+ u8 status = ata_check_status(ap);
+ if ((status & ATA_BUSY))
+ continue;
+ DPRINTK("ata%u: protocol %d (dev_stat 0x%X)\n",
+ ap->id, qc->tf.protocol, status);
+
+ /* complete taskfile transaction */
+ pp->state = adma_state_idle;
+ qc->err_mask |= ac_err_mask(status);
+ ata_qc_complete(qc);
+ handled = 1;
+ }
+ }
+ }
+ return handled;
+}
+
+static irqreturn_t adma_intr(int irq, void *dev_instance, struct pt_regs *regs)
+{
+ struct ata_host *host = dev_instance;
+ unsigned int handled = 0;
+
+ VPRINTK("ENTER\n");
+
+ spin_lock(&host->lock);
+ handled = adma_intr_pkt(host) | adma_intr_mmio(host);
+ spin_unlock(&host->lock);
+
+ VPRINTK("EXIT\n");
+
+ return IRQ_RETVAL(handled);
+}
+
+static void adma_ata_setup_port(struct ata_ioports *port, unsigned long base)
+{
+ port->cmd_addr =
+ port->data_addr = base + 0x000;
+ port->error_addr =
+ port->feature_addr = base + 0x004;
+ port->nsect_addr = base + 0x008;
+ port->lbal_addr = base + 0x00c;
+ port->lbam_addr = base + 0x010;
+ port->lbah_addr = base + 0x014;
+ port->device_addr = base + 0x018;
+ port->status_addr =
+ port->command_addr = base + 0x01c;
+ port->altstatus_addr =
+ port->ctl_addr = base + 0x038;
+}
+
+static int adma_port_start(struct ata_port *ap)
+{
+ struct device *dev = ap->host->dev;
+ struct adma_port_priv *pp;
+ int rc;
+
+ rc = ata_port_start(ap);
+ if (rc)
+ return rc;
+ adma_enter_reg_mode(ap);
+ rc = -ENOMEM;
+ pp = kcalloc(1, sizeof(*pp), GFP_KERNEL);
+ if (!pp)
+ goto err_out;
+ pp->pkt = dma_alloc_coherent(dev, ADMA_PKT_BYTES, &pp->pkt_dma,
+ GFP_KERNEL);
+ if (!pp->pkt)
+ goto err_out_kfree;
+ /* paranoia? */
+ if ((pp->pkt_dma & 7) != 0) {
+ printk("bad alignment for pp->pkt_dma: %08x\n",
+ (u32)pp->pkt_dma);
+ dma_free_coherent(dev, ADMA_PKT_BYTES,
+ pp->pkt, pp->pkt_dma);
+ goto err_out_kfree;
+ }
+ memset(pp->pkt, 0, ADMA_PKT_BYTES);
+ ap->private_data = pp;
+ adma_reinit_engine(ap);
+ return 0;
+
+err_out_kfree:
+ kfree(pp);
+err_out:
+ ata_port_stop(ap);
+ return rc;
+}
+
+static void adma_port_stop(struct ata_port *ap)
+{
+ struct device *dev = ap->host->dev;
+ struct adma_port_priv *pp = ap->private_data;
+
+ adma_reset_engine(ADMA_REGS(ap->host->mmio_base, ap->port_no));
+ if (pp != NULL) {
+ ap->private_data = NULL;
+ if (pp->pkt != NULL)
+ dma_free_coherent(dev, ADMA_PKT_BYTES,
+ pp->pkt, pp->pkt_dma);
+ kfree(pp);
+ }
+ ata_port_stop(ap);
+}
+
+static void adma_host_stop(struct ata_host *host)
+{
+ unsigned int port_no;
+
+ for (port_no = 0; port_no < ADMA_PORTS; ++port_no)
+ adma_reset_engine(ADMA_REGS(host->mmio_base, port_no));
+
+ ata_pci_host_stop(host);
+}
+
+static void adma_host_init(unsigned int chip_id,
+ struct ata_probe_ent *probe_ent)
+{
+ unsigned int port_no;
+ void __iomem *mmio_base = probe_ent->mmio_base;
+
+ /* enable/lock aGO operation */
+ writeb(7, mmio_base + ADMA_MODE_LOCK);
+
+ /* reset the ADMA logic */
+ for (port_no = 0; port_no < ADMA_PORTS; ++port_no)
+ adma_reset_engine(ADMA_REGS(mmio_base, port_no));
+}
+
+static int adma_set_dma_masks(struct pci_dev *pdev, void __iomem *mmio_base)
+{
+ int rc;
+
+ rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+ if (rc) {
+ dev_printk(KERN_ERR, &pdev->dev,
+ "32-bit DMA enable failed\n");
+ return rc;
+ }
+ rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+ if (rc) {
+ dev_printk(KERN_ERR, &pdev->dev,
+ "32-bit consistent DMA enable failed\n");
+ return rc;
+ }
+ return 0;
+}
+
+static int adma_ata_init_one(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ static int printed_version;
+ struct ata_probe_ent *probe_ent = NULL;
+ void __iomem *mmio_base;
+ unsigned int board_idx = (unsigned int) ent->driver_data;
+ int rc, port_no;
+
+ if (!printed_version++)
+ dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
+
+ rc = pci_enable_device(pdev);
+ if (rc)
+ return rc;
+
+ rc = pci_request_regions(pdev, DRV_NAME);
+ if (rc)
+ goto err_out;
+
+ if ((pci_resource_flags(pdev, 4) & IORESOURCE_MEM) == 0) {
+ rc = -ENODEV;
+ goto err_out_regions;
+ }
+
+ mmio_base = pci_iomap(pdev, 4, 0);
+ if (mmio_base == NULL) {
+ rc = -ENOMEM;
+ goto err_out_regions;
+ }
+
+ rc = adma_set_dma_masks(pdev, mmio_base);
+ if (rc)
+ goto err_out_iounmap;
+
+ probe_ent = kcalloc(1, sizeof(*probe_ent), GFP_KERNEL);
+ if (probe_ent == NULL) {
+ rc = -ENOMEM;
+ goto err_out_iounmap;
+ }
+
+ probe_ent->dev = pci_dev_to_dev(pdev);
+ INIT_LIST_HEAD(&probe_ent->node);
+
+ probe_ent->sht = adma_port_info[board_idx].sht;
+ probe_ent->port_flags = adma_port_info[board_idx].flags;
+ probe_ent->pio_mask = adma_port_info[board_idx].pio_mask;
+ probe_ent->mwdma_mask = adma_port_info[board_idx].mwdma_mask;
+ probe_ent->udma_mask = adma_port_info[board_idx].udma_mask;
+ probe_ent->port_ops = adma_port_info[board_idx].port_ops;
+
+ probe_ent->irq = pdev->irq;
+ probe_ent->irq_flags = IRQF_SHARED;
+ probe_ent->mmio_base = mmio_base;
+ probe_ent->n_ports = ADMA_PORTS;
+
+ for (port_no = 0; port_no < probe_ent->n_ports; ++port_no) {
+ adma_ata_setup_port(&probe_ent->port[port_no],
+ ADMA_ATA_REGS((unsigned long)mmio_base, port_no));
+ }
+
+ pci_set_master(pdev);
+
+ /* initialize adapter */
+ adma_host_init(board_idx, probe_ent);
+
+ rc = ata_device_add(probe_ent);
+ kfree(probe_ent);
+ if (rc != ADMA_PORTS)
+ goto err_out_iounmap;
+ return 0;
+
+err_out_iounmap:
+ pci_iounmap(pdev, mmio_base);
+err_out_regions:
+ pci_release_regions(pdev);
+err_out:
+ pci_disable_device(pdev);
+ return rc;
+}
+
+static int __init adma_ata_init(void)
+{
+ return pci_register_driver(&adma_ata_pci_driver);
+}
+
+static void __exit adma_ata_exit(void)
+{
+ pci_unregister_driver(&adma_ata_pci_driver);
+}
+
+MODULE_AUTHOR("Mark Lord");
+MODULE_DESCRIPTION("Pacific Digital Corporation ADMA low-level driver");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, adma_ata_pci_tbl);
+MODULE_VERSION(DRV_VERSION);
+
+module_init(adma_ata_init);
+module_exit(adma_ata_exit);
diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c
new file mode 100644
index 00000000000..c01496df4a9
--- /dev/null
+++ b/drivers/ata/sata_mv.c
@@ -0,0 +1,2466 @@
+/*
+ * sata_mv.c - Marvell SATA support
+ *
+ * Copyright 2005: EMC Corporation, all rights reserved.
+ * Copyright 2005 Red Hat, Inc. All rights reserved.
+ *
+ * Please ALWAYS copy linux-ide@vger.kernel.org on emails.
+ *
+ * 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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/dma-mapping.h>
+#include <linux/device.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_cmnd.h>
+#include <linux/libata.h>
+#include <asm/io.h>
+
+#define DRV_NAME "sata_mv"
+#define DRV_VERSION "0.7"
+
+enum {
+ /* BAR's are enumerated in terms of pci_resource_start() terms */
+ MV_PRIMARY_BAR = 0, /* offset 0x10: memory space */
+ MV_IO_BAR = 2, /* offset 0x18: IO space */
+ MV_MISC_BAR = 3, /* offset 0x1c: FLASH, NVRAM, SRAM */
+
+ MV_MAJOR_REG_AREA_SZ = 0x10000, /* 64KB */
+ MV_MINOR_REG_AREA_SZ = 0x2000, /* 8KB */
+
+ MV_PCI_REG_BASE = 0,
+ MV_IRQ_COAL_REG_BASE = 0x18000, /* 6xxx part only */
+ MV_IRQ_COAL_CAUSE = (MV_IRQ_COAL_REG_BASE + 0x08),
+ MV_IRQ_COAL_CAUSE_LO = (MV_IRQ_COAL_REG_BASE + 0x88),
+ MV_IRQ_COAL_CAUSE_HI = (MV_IRQ_COAL_REG_BASE + 0x8c),
+ MV_IRQ_COAL_THRESHOLD = (MV_IRQ_COAL_REG_BASE + 0xcc),
+ MV_IRQ_COAL_TIME_THRESHOLD = (MV_IRQ_COAL_REG_BASE + 0xd0),
+
+ MV_SATAHC0_REG_BASE = 0x20000,
+ MV_FLASH_CTL = 0x1046c,
+ MV_GPIO_PORT_CTL = 0x104f0,
+ MV_RESET_CFG = 0x180d8,
+
+ MV_PCI_REG_SZ = MV_MAJOR_REG_AREA_SZ,
+ MV_SATAHC_REG_SZ = MV_MAJOR_REG_AREA_SZ,
+ MV_SATAHC_ARBTR_REG_SZ = MV_MINOR_REG_AREA_SZ, /* arbiter */
+ MV_PORT_REG_SZ = MV_MINOR_REG_AREA_SZ,
+
+ MV_USE_Q_DEPTH = ATA_DEF_QUEUE,
+
+ MV_MAX_Q_DEPTH = 32,
+ MV_MAX_Q_DEPTH_MASK = MV_MAX_Q_DEPTH - 1,
+
+ /* CRQB needs alignment on a 1KB boundary. Size == 1KB
+ * CRPB needs alignment on a 256B boundary. Size == 256B
+ * SG count of 176 leads to MV_PORT_PRIV_DMA_SZ == 4KB
+ * ePRD (SG) entries need alignment on a 16B boundary. Size == 16B
+ */
+ MV_CRQB_Q_SZ = (32 * MV_MAX_Q_DEPTH),
+ MV_CRPB_Q_SZ = (8 * MV_MAX_Q_DEPTH),
+ MV_MAX_SG_CT = 176,
+ MV_SG_TBL_SZ = (16 * MV_MAX_SG_CT),
+ MV_PORT_PRIV_DMA_SZ = (MV_CRQB_Q_SZ + MV_CRPB_Q_SZ + MV_SG_TBL_SZ),
+
+ MV_PORTS_PER_HC = 4,
+ /* == (port / MV_PORTS_PER_HC) to determine HC from 0-7 port */
+ MV_PORT_HC_SHIFT = 2,
+ /* == (port % MV_PORTS_PER_HC) to determine hard port from 0-7 port */
+ MV_PORT_MASK = 3,
+
+ /* Host Flags */
+ MV_FLAG_DUAL_HC = (1 << 30), /* two SATA Host Controllers */
+ MV_FLAG_IRQ_COALESCE = (1 << 29), /* IRQ coalescing capability */
+ MV_COMMON_FLAGS = (ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+ ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO |
+ ATA_FLAG_NO_ATAPI | ATA_FLAG_PIO_POLLING),
+ MV_6XXX_FLAGS = MV_FLAG_IRQ_COALESCE,
+
+ CRQB_FLAG_READ = (1 << 0),
+ CRQB_TAG_SHIFT = 1,
+ CRQB_CMD_ADDR_SHIFT = 8,
+ CRQB_CMD_CS = (0x2 << 11),
+ CRQB_CMD_LAST = (1 << 15),
+
+ CRPB_FLAG_STATUS_SHIFT = 8,
+
+ EPRD_FLAG_END_OF_TBL = (1 << 31),
+
+ /* PCI interface registers */
+
+ PCI_COMMAND_OFS = 0xc00,
+
+ PCI_MAIN_CMD_STS_OFS = 0xd30,
+ STOP_PCI_MASTER = (1 << 2),
+ PCI_MASTER_EMPTY = (1 << 3),
+ GLOB_SFT_RST = (1 << 4),
+
+ MV_PCI_MODE = 0xd00,
+ MV_PCI_EXP_ROM_BAR_CTL = 0xd2c,
+ MV_PCI_DISC_TIMER = 0xd04,
+ MV_PCI_MSI_TRIGGER = 0xc38,
+ MV_PCI_SERR_MASK = 0xc28,
+ MV_PCI_XBAR_TMOUT = 0x1d04,
+ MV_PCI_ERR_LOW_ADDRESS = 0x1d40,
+ MV_PCI_ERR_HIGH_ADDRESS = 0x1d44,
+ MV_PCI_ERR_ATTRIBUTE = 0x1d48,
+ MV_PCI_ERR_COMMAND = 0x1d50,
+
+ PCI_IRQ_CAUSE_OFS = 0x1d58,
+ PCI_IRQ_MASK_OFS = 0x1d5c,
+ PCI_UNMASK_ALL_IRQS = 0x7fffff, /* bits 22-0 */
+
+ HC_MAIN_IRQ_CAUSE_OFS = 0x1d60,
+ HC_MAIN_IRQ_MASK_OFS = 0x1d64,
+ PORT0_ERR = (1 << 0), /* shift by port # */
+ PORT0_DONE = (1 << 1), /* shift by port # */
+ HC0_IRQ_PEND = 0x1ff, /* bits 0-8 = HC0's ports */
+ HC_SHIFT = 9, /* bits 9-17 = HC1's ports */
+ PCI_ERR = (1 << 18),
+ TRAN_LO_DONE = (1 << 19), /* 6xxx: IRQ coalescing */
+ TRAN_HI_DONE = (1 << 20), /* 6xxx: IRQ coalescing */
+ PORTS_0_7_COAL_DONE = (1 << 21), /* 6xxx: IRQ coalescing */
+ GPIO_INT = (1 << 22),
+ SELF_INT = (1 << 23),
+ TWSI_INT = (1 << 24),
+ HC_MAIN_RSVD = (0x7f << 25), /* bits 31-25 */
+ HC_MAIN_MASKED_IRQS = (TRAN_LO_DONE | TRAN_HI_DONE |
+ PORTS_0_7_COAL_DONE | GPIO_INT | TWSI_INT |
+ HC_MAIN_RSVD),
+
+ /* SATAHC registers */
+ HC_CFG_OFS = 0,
+
+ HC_IRQ_CAUSE_OFS = 0x14,
+ CRPB_DMA_DONE = (1 << 0), /* shift by port # */
+ HC_IRQ_COAL = (1 << 4), /* IRQ coalescing */
+ DEV_IRQ = (1 << 8), /* shift by port # */
+
+ /* Shadow block registers */
+ SHD_BLK_OFS = 0x100,
+ SHD_CTL_AST_OFS = 0x20, /* ofs from SHD_BLK_OFS */
+
+ /* SATA registers */
+ SATA_STATUS_OFS = 0x300, /* ctrl, err regs follow status */
+ SATA_ACTIVE_OFS = 0x350,
+ PHY_MODE3 = 0x310,
+ PHY_MODE4 = 0x314,
+ PHY_MODE2 = 0x330,
+ MV5_PHY_MODE = 0x74,
+ MV5_LT_MODE = 0x30,
+ MV5_PHY_CTL = 0x0C,
+ SATA_INTERFACE_CTL = 0x050,
+
+ MV_M2_PREAMP_MASK = 0x7e0,
+
+ /* Port registers */
+ EDMA_CFG_OFS = 0,
+ EDMA_CFG_Q_DEPTH = 0, /* queueing disabled */
+ EDMA_CFG_NCQ = (1 << 5),
+ EDMA_CFG_NCQ_GO_ON_ERR = (1 << 14), /* continue on error */
+ EDMA_CFG_RD_BRST_EXT = (1 << 11), /* read burst 512B */
+ EDMA_CFG_WR_BUFF_LEN = (1 << 13), /* write buffer 512B */
+
+ EDMA_ERR_IRQ_CAUSE_OFS = 0x8,
+ EDMA_ERR_IRQ_MASK_OFS = 0xc,
+ EDMA_ERR_D_PAR = (1 << 0),
+ EDMA_ERR_PRD_PAR = (1 << 1),
+ EDMA_ERR_DEV = (1 << 2),
+ EDMA_ERR_DEV_DCON = (1 << 3),
+ EDMA_ERR_DEV_CON = (1 << 4),
+ EDMA_ERR_SERR = (1 << 5),
+ EDMA_ERR_SELF_DIS = (1 << 7),
+ EDMA_ERR_BIST_ASYNC = (1 << 8),
+ EDMA_ERR_CRBQ_PAR = (1 << 9),
+ EDMA_ERR_CRPB_PAR = (1 << 10),
+ EDMA_ERR_INTRL_PAR = (1 << 11),
+ EDMA_ERR_IORDY = (1 << 12),
+ EDMA_ERR_LNK_CTRL_RX = (0xf << 13),
+ EDMA_ERR_LNK_CTRL_RX_2 = (1 << 15),
+ EDMA_ERR_LNK_DATA_RX = (0xf << 17),
+ EDMA_ERR_LNK_CTRL_TX = (0x1f << 21),
+ EDMA_ERR_LNK_DATA_TX = (0x1f << 26),
+ EDMA_ERR_TRANS_PROTO = (1 << 31),
+ EDMA_ERR_FATAL = (EDMA_ERR_D_PAR | EDMA_ERR_PRD_PAR |
+ EDMA_ERR_DEV_DCON | EDMA_ERR_CRBQ_PAR |
+ EDMA_ERR_CRPB_PAR | EDMA_ERR_INTRL_PAR |
+ EDMA_ERR_IORDY | EDMA_ERR_LNK_CTRL_RX_2 |
+ EDMA_ERR_LNK_DATA_RX |
+ EDMA_ERR_LNK_DATA_TX |
+ EDMA_ERR_TRANS_PROTO),
+
+ EDMA_REQ_Q_BASE_HI_OFS = 0x10,
+ EDMA_REQ_Q_IN_PTR_OFS = 0x14, /* also contains BASE_LO */
+
+ EDMA_REQ_Q_OUT_PTR_OFS = 0x18,
+ EDMA_REQ_Q_PTR_SHIFT = 5,
+
+ EDMA_RSP_Q_BASE_HI_OFS = 0x1c,
+ EDMA_RSP_Q_IN_PTR_OFS = 0x20,
+ EDMA_RSP_Q_OUT_PTR_OFS = 0x24, /* also contains BASE_LO */
+ EDMA_RSP_Q_PTR_SHIFT = 3,
+
+ EDMA_CMD_OFS = 0x28,
+ EDMA_EN = (1 << 0),
+ EDMA_DS = (1 << 1),
+ ATA_RST = (1 << 2),
+
+ EDMA_IORDY_TMOUT = 0x34,
+ EDMA_ARB_CFG = 0x38,
+
+ /* Host private flags (hp_flags) */
+ MV_HP_FLAG_MSI = (1 << 0),
+ MV_HP_ERRATA_50XXB0 = (1 << 1),
+ MV_HP_ERRATA_50XXB2 = (1 << 2),
+ MV_HP_ERRATA_60X1B2 = (1 << 3),
+ MV_HP_ERRATA_60X1C0 = (1 << 4),
+ MV_HP_ERRATA_XX42A0 = (1 << 5),
+ MV_HP_50XX = (1 << 6),
+ MV_HP_GEN_IIE = (1 << 7),
+
+ /* Port private flags (pp_flags) */
+ MV_PP_FLAG_EDMA_EN = (1 << 0),
+ MV_PP_FLAG_EDMA_DS_ACT = (1 << 1),
+};
+
+#define IS_50XX(hpriv) ((hpriv)->hp_flags & MV_HP_50XX)
+#define IS_60XX(hpriv) (((hpriv)->hp_flags & MV_HP_50XX) == 0)
+#define IS_GEN_I(hpriv) IS_50XX(hpriv)
+#define IS_GEN_II(hpriv) IS_60XX(hpriv)
+#define IS_GEN_IIE(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_IIE)
+
+enum {
+ /* Our DMA boundary is determined by an ePRD being unable to handle
+ * anything larger than 64KB
+ */
+ MV_DMA_BOUNDARY = 0xffffU,
+
+ EDMA_REQ_Q_BASE_LO_MASK = 0xfffffc00U,
+
+ EDMA_RSP_Q_BASE_LO_MASK = 0xffffff00U,
+};
+
+enum chip_type {
+ chip_504x,
+ chip_508x,
+ chip_5080,
+ chip_604x,
+ chip_608x,
+ chip_6042,
+ chip_7042,
+};
+
+/* Command ReQuest Block: 32B */
+struct mv_crqb {
+ __le32 sg_addr;
+ __le32 sg_addr_hi;
+ __le16 ctrl_flags;
+ __le16 ata_cmd[11];
+};
+
+struct mv_crqb_iie {
+ __le32 addr;
+ __le32 addr_hi;
+ __le32 flags;
+ __le32 len;
+ __le32 ata_cmd[4];
+};
+
+/* Command ResPonse Block: 8B */
+struct mv_crpb {
+ __le16 id;
+ __le16 flags;
+ __le32 tmstmp;
+};
+
+/* EDMA Physical Region Descriptor (ePRD); A.K.A. SG */
+struct mv_sg {
+ __le32 addr;
+ __le32 flags_size;
+ __le32 addr_hi;
+ __le32 reserved;
+};
+
+struct mv_port_priv {
+ struct mv_crqb *crqb;
+ dma_addr_t crqb_dma;
+ struct mv_crpb *crpb;
+ dma_addr_t crpb_dma;
+ struct mv_sg *sg_tbl;
+ dma_addr_t sg_tbl_dma;
+ u32 pp_flags;
+};
+
+struct mv_port_signal {
+ u32 amps;
+ u32 pre;
+};
+
+struct mv_host_priv;
+struct mv_hw_ops {
+ void (*phy_errata)(struct mv_host_priv *hpriv, void __iomem *mmio,
+ unsigned int port);
+ void (*enable_leds)(struct mv_host_priv *hpriv, void __iomem *mmio);
+ void (*read_preamp)(struct mv_host_priv *hpriv, int idx,
+ void __iomem *mmio);
+ int (*reset_hc)(struct mv_host_priv *hpriv, void __iomem *mmio,
+ unsigned int n_hc);
+ void (*reset_flash)(struct mv_host_priv *hpriv, void __iomem *mmio);
+ void (*reset_bus)(struct pci_dev *pdev, void __iomem *mmio);
+};
+
+struct mv_host_priv {
+ u32 hp_flags;
+ struct mv_port_signal signal[8];
+ const struct mv_hw_ops *ops;
+};
+
+static void mv_irq_clear(struct ata_port *ap);
+static u32 mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in);
+static void mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val);
+static u32 mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in);
+static void mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val);
+static void mv_phy_reset(struct ata_port *ap);
+static void __mv_phy_reset(struct ata_port *ap, int can_sleep);
+static void mv_host_stop(struct ata_host *host);
+static int mv_port_start(struct ata_port *ap);
+static void mv_port_stop(struct ata_port *ap);
+static void mv_qc_prep(struct ata_queued_cmd *qc);
+static void mv_qc_prep_iie(struct ata_queued_cmd *qc);
+static unsigned int mv_qc_issue(struct ata_queued_cmd *qc);
+static irqreturn_t mv_interrupt(int irq, void *dev_instance,
+ struct pt_regs *regs);
+static void mv_eng_timeout(struct ata_port *ap);
+static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
+
+static void mv5_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,
+ unsigned int port);
+static void mv5_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio);
+static void mv5_read_preamp(struct mv_host_priv *hpriv, int idx,
+ void __iomem *mmio);
+static int mv5_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio,
+ unsigned int n_hc);
+static void mv5_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio);
+static void mv5_reset_bus(struct pci_dev *pdev, void __iomem *mmio);
+
+static void mv6_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,
+ unsigned int port);
+static void mv6_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio);
+static void mv6_read_preamp(struct mv_host_priv *hpriv, int idx,
+ void __iomem *mmio);
+static int mv6_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio,
+ unsigned int n_hc);
+static void mv6_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio);
+static void mv_reset_pci_bus(struct pci_dev *pdev, void __iomem *mmio);
+static void mv_channel_reset(struct mv_host_priv *hpriv, void __iomem *mmio,
+ unsigned int port_no);
+static void mv_stop_and_reset(struct ata_port *ap);
+
+static struct scsi_host_template mv_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = MV_USE_Q_DEPTH,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = MV_MAX_SG_CT / 2,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = MV_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .slave_destroy = ata_scsi_slave_destroy,
+ .bios_param = ata_std_bios_param,
+};
+
+static const struct ata_port_operations mv5_ops = {
+ .port_disable = ata_port_disable,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .phy_reset = mv_phy_reset,
+
+ .qc_prep = mv_qc_prep,
+ .qc_issue = mv_qc_issue,
+ .data_xfer = ata_mmio_data_xfer,
+
+ .eng_timeout = mv_eng_timeout,
+
+ .irq_handler = mv_interrupt,
+ .irq_clear = mv_irq_clear,
+
+ .scr_read = mv5_scr_read,
+ .scr_write = mv5_scr_write,
+
+ .port_start = mv_port_start,
+ .port_stop = mv_port_stop,
+ .host_stop = mv_host_stop,
+};
+
+static const struct ata_port_operations mv6_ops = {
+ .port_disable = ata_port_disable,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .phy_reset = mv_phy_reset,
+
+ .qc_prep = mv_qc_prep,
+ .qc_issue = mv_qc_issue,
+ .data_xfer = ata_mmio_data_xfer,
+
+ .eng_timeout = mv_eng_timeout,
+
+ .irq_handler = mv_interrupt,
+ .irq_clear = mv_irq_clear,
+
+ .scr_read = mv_scr_read,
+ .scr_write = mv_scr_write,
+
+ .port_start = mv_port_start,
+ .port_stop = mv_port_stop,
+ .host_stop = mv_host_stop,
+};
+
+static const struct ata_port_operations mv_iie_ops = {
+ .port_disable = ata_port_disable,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .phy_reset = mv_phy_reset,
+
+ .qc_prep = mv_qc_prep_iie,
+ .qc_issue = mv_qc_issue,
+ .data_xfer = ata_mmio_data_xfer,
+
+ .eng_timeout = mv_eng_timeout,
+
+ .irq_handler = mv_interrupt,
+ .irq_clear = mv_irq_clear,
+
+ .scr_read = mv_scr_read,
+ .scr_write = mv_scr_write,
+
+ .port_start = mv_port_start,
+ .port_stop = mv_port_stop,
+ .host_stop = mv_host_stop,
+};
+
+static const struct ata_port_info mv_port_info[] = {
+ { /* chip_504x */
+ .sht = &mv_sht,
+ .flags = MV_COMMON_FLAGS,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .udma_mask = 0x7f, /* udma0-6 */
+ .port_ops = &mv5_ops,
+ },
+ { /* chip_508x */
+ .sht = &mv_sht,
+ .flags = (MV_COMMON_FLAGS | MV_FLAG_DUAL_HC),
+ .pio_mask = 0x1f, /* pio0-4 */
+ .udma_mask = 0x7f, /* udma0-6 */
+ .port_ops = &mv5_ops,
+ },
+ { /* chip_5080 */
+ .sht = &mv_sht,
+ .flags = (MV_COMMON_FLAGS | MV_FLAG_DUAL_HC),
+ .pio_mask = 0x1f, /* pio0-4 */
+ .udma_mask = 0x7f, /* udma0-6 */
+ .port_ops = &mv5_ops,
+ },
+ { /* chip_604x */
+ .sht = &mv_sht,
+ .flags = (MV_COMMON_FLAGS | MV_6XXX_FLAGS),
+ .pio_mask = 0x1f, /* pio0-4 */
+ .udma_mask = 0x7f, /* udma0-6 */
+ .port_ops = &mv6_ops,
+ },
+ { /* chip_608x */
+ .sht = &mv_sht,
+ .flags = (MV_COMMON_FLAGS | MV_6XXX_FLAGS |
+ MV_FLAG_DUAL_HC),
+ .pio_mask = 0x1f, /* pio0-4 */
+ .udma_mask = 0x7f, /* udma0-6 */
+ .port_ops = &mv6_ops,
+ },
+ { /* chip_6042 */
+ .sht = &mv_sht,
+ .flags = (MV_COMMON_FLAGS | MV_6XXX_FLAGS),
+ .pio_mask = 0x1f, /* pio0-4 */
+ .udma_mask = 0x7f, /* udma0-6 */
+ .port_ops = &mv_iie_ops,
+ },
+ { /* chip_7042 */
+ .sht = &mv_sht,
+ .flags = (MV_COMMON_FLAGS | MV_6XXX_FLAGS |
+ MV_FLAG_DUAL_HC),
+ .pio_mask = 0x1f, /* pio0-4 */
+ .udma_mask = 0x7f, /* udma0-6 */
+ .port_ops = &mv_iie_ops,
+ },
+};
+
+static const struct pci_device_id mv_pci_tbl[] = {
+ {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5040), 0, 0, chip_504x},
+ {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5041), 0, 0, chip_504x},
+ {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5080), 0, 0, chip_5080},
+ {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5081), 0, 0, chip_508x},
+
+ {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x6040), 0, 0, chip_604x},
+ {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x6041), 0, 0, chip_604x},
+ {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x6042), 0, 0, chip_6042},
+ {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x6080), 0, 0, chip_608x},
+ {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x6081), 0, 0, chip_608x},
+
+ {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x0241), 0, 0, chip_604x},
+ {} /* terminate list */
+};
+
+static struct pci_driver mv_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = mv_pci_tbl,
+ .probe = mv_init_one,
+ .remove = ata_pci_remove_one,
+};
+
+static const struct mv_hw_ops mv5xxx_ops = {
+ .phy_errata = mv5_phy_errata,
+ .enable_leds = mv5_enable_leds,
+ .read_preamp = mv5_read_preamp,
+ .reset_hc = mv5_reset_hc,
+ .reset_flash = mv5_reset_flash,
+ .reset_bus = mv5_reset_bus,
+};
+
+static const struct mv_hw_ops mv6xxx_ops = {
+ .phy_errata = mv6_phy_errata,
+ .enable_leds = mv6_enable_leds,
+ .read_preamp = mv6_read_preamp,
+ .reset_hc = mv6_reset_hc,
+ .reset_flash = mv6_reset_flash,
+ .reset_bus = mv_reset_pci_bus,
+};
+
+/*
+ * module options
+ */
+static int msi; /* Use PCI msi; either zero (off, default) or non-zero */
+
+
+/*
+ * Functions
+ */
+
+static inline void writelfl(unsigned long data, void __iomem *addr)
+{
+ writel(data, addr);
+ (void) readl(addr); /* flush to avoid PCI posted write */
+}
+
+static inline void __iomem *mv_hc_base(void __iomem *base, unsigned int hc)
+{
+ return (base + MV_SATAHC0_REG_BASE + (hc * MV_SATAHC_REG_SZ));
+}
+
+static inline unsigned int mv_hc_from_port(unsigned int port)
+{
+ return port >> MV_PORT_HC_SHIFT;
+}
+
+static inline unsigned int mv_hardport_from_port(unsigned int port)
+{
+ return port & MV_PORT_MASK;
+}
+
+static inline void __iomem *mv_hc_base_from_port(void __iomem *base,
+ unsigned int port)
+{
+ return mv_hc_base(base, mv_hc_from_port(port));
+}
+
+static inline void __iomem *mv_port_base(void __iomem *base, unsigned int port)
+{
+ return mv_hc_base_from_port(base, port) +
+ MV_SATAHC_ARBTR_REG_SZ +
+ (mv_hardport_from_port(port) * MV_PORT_REG_SZ);
+}
+
+static inline void __iomem *mv_ap_base(struct ata_port *ap)
+{
+ return mv_port_base(ap->host->mmio_base, ap->port_no);
+}
+
+static inline int mv_get_hc_count(unsigned long port_flags)
+{
+ return ((port_flags & MV_FLAG_DUAL_HC) ? 2 : 1);
+}
+
+static void mv_irq_clear(struct ata_port *ap)
+{
+}
+
+/**
+ * mv_start_dma - Enable eDMA engine
+ * @base: port base address
+ * @pp: port private data
+ *
+ * Verify the local cache of the eDMA state is accurate with a
+ * WARN_ON.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+static void mv_start_dma(void __iomem *base, struct mv_port_priv *pp)
+{
+ if (!(MV_PP_FLAG_EDMA_EN & pp->pp_flags)) {
+ writelfl(EDMA_EN, base + EDMA_CMD_OFS);
+ pp->pp_flags |= MV_PP_FLAG_EDMA_EN;
+ }
+ WARN_ON(!(EDMA_EN & readl(base + EDMA_CMD_OFS)));
+}
+
+/**
+ * mv_stop_dma - Disable eDMA engine
+ * @ap: ATA channel to manipulate
+ *
+ * Verify the local cache of the eDMA state is accurate with a
+ * WARN_ON.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+static void mv_stop_dma(struct ata_port *ap)
+{
+ void __iomem *port_mmio = mv_ap_base(ap);
+ struct mv_port_priv *pp = ap->private_data;
+ u32 reg;
+ int i;
+
+ if (MV_PP_FLAG_EDMA_EN & pp->pp_flags) {
+ /* Disable EDMA if active. The disable bit auto clears.
+ */
+ writelfl(EDMA_DS, port_mmio + EDMA_CMD_OFS);
+ pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN;
+ } else {
+ WARN_ON(EDMA_EN & readl(port_mmio + EDMA_CMD_OFS));
+ }
+
+ /* now properly wait for the eDMA to stop */
+ for (i = 1000; i > 0; i--) {
+ reg = readl(port_mmio + EDMA_CMD_OFS);
+ if (!(EDMA_EN & reg)) {
+ break;
+ }
+ udelay(100);
+ }
+
+ if (EDMA_EN & reg) {
+ ata_port_printk(ap, KERN_ERR, "Unable to stop eDMA\n");
+ /* FIXME: Consider doing a reset here to recover */
+ }
+}
+
+#ifdef ATA_DEBUG
+static void mv_dump_mem(void __iomem *start, unsigned bytes)
+{
+ int b, w;
+ for (b = 0; b < bytes; ) {
+ DPRINTK("%p: ", start + b);
+ for (w = 0; b < bytes && w < 4; w++) {
+ printk("%08x ",readl(start + b));
+ b += sizeof(u32);
+ }
+ printk("\n");
+ }
+}
+#endif
+
+static void mv_dump_pci_cfg(struct pci_dev *pdev, unsigned bytes)
+{
+#ifdef ATA_DEBUG
+ int b, w;
+ u32 dw;
+ for (b = 0; b < bytes; ) {
+ DPRINTK("%02x: ", b);
+ for (w = 0; b < bytes && w < 4; w++) {
+ (void) pci_read_config_dword(pdev,b,&dw);
+ printk("%08x ",dw);
+ b += sizeof(u32);
+ }
+ printk("\n");
+ }
+#endif
+}
+static void mv_dump_all_regs(void __iomem *mmio_base, int port,
+ struct pci_dev *pdev)
+{
+#ifdef ATA_DEBUG
+ void __iomem *hc_base = mv_hc_base(mmio_base,
+ port >> MV_PORT_HC_SHIFT);
+ void __iomem *port_base;
+ int start_port, num_ports, p, start_hc, num_hcs, hc;
+
+ if (0 > port) {
+ start_hc = start_port = 0;
+ num_ports = 8; /* shld be benign for 4 port devs */
+ num_hcs = 2;
+ } else {
+ start_hc = port >> MV_PORT_HC_SHIFT;
+ start_port = port;
+ num_ports = num_hcs = 1;
+ }
+ DPRINTK("All registers for port(s) %u-%u:\n", start_port,
+ num_ports > 1 ? num_ports - 1 : start_port);
+
+ if (NULL != pdev) {
+ DPRINTK("PCI config space regs:\n");
+ mv_dump_pci_cfg(pdev, 0x68);
+ }
+ DPRINTK("PCI regs:\n");
+ mv_dump_mem(mmio_base+0xc00, 0x3c);
+ mv_dump_mem(mmio_base+0xd00, 0x34);
+ mv_dump_mem(mmio_base+0xf00, 0x4);
+ mv_dump_mem(mmio_base+0x1d00, 0x6c);
+ for (hc = start_hc; hc < start_hc + num_hcs; hc++) {
+ hc_base = mv_hc_base(mmio_base, hc);
+ DPRINTK("HC regs (HC %i):\n", hc);
+ mv_dump_mem(hc_base, 0x1c);
+ }
+ for (p = start_port; p < start_port + num_ports; p++) {
+ port_base = mv_port_base(mmio_base, p);
+ DPRINTK("EDMA regs (port %i):\n",p);
+ mv_dump_mem(port_base, 0x54);
+ DPRINTK("SATA regs (port %i):\n",p);
+ mv_dump_mem(port_base+0x300, 0x60);
+ }
+#endif
+}
+
+static unsigned int mv_scr_offset(unsigned int sc_reg_in)
+{
+ unsigned int ofs;
+
+ switch (sc_reg_in) {
+ case SCR_STATUS:
+ case SCR_CONTROL:
+ case SCR_ERROR:
+ ofs = SATA_STATUS_OFS + (sc_reg_in * sizeof(u32));
+ break;
+ case SCR_ACTIVE:
+ ofs = SATA_ACTIVE_OFS; /* active is not with the others */
+ break;
+ default:
+ ofs = 0xffffffffU;
+ break;
+ }
+ return ofs;
+}
+
+static u32 mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in)
+{
+ unsigned int ofs = mv_scr_offset(sc_reg_in);
+
+ if (0xffffffffU != ofs) {
+ return readl(mv_ap_base(ap) + ofs);
+ } else {
+ return (u32) ofs;
+ }
+}
+
+static void mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
+{
+ unsigned int ofs = mv_scr_offset(sc_reg_in);
+
+ if (0xffffffffU != ofs) {
+ writelfl(val, mv_ap_base(ap) + ofs);
+ }
+}
+
+/**
+ * mv_host_stop - Host specific cleanup/stop routine.
+ * @host: host data structure
+ *
+ * Disable ints, cleanup host memory, call general purpose
+ * host_stop.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+static void mv_host_stop(struct ata_host *host)
+{
+ struct mv_host_priv *hpriv = host->private_data;
+ struct pci_dev *pdev = to_pci_dev(host->dev);
+
+ if (hpriv->hp_flags & MV_HP_FLAG_MSI) {
+ pci_disable_msi(pdev);
+ } else {
+ pci_intx(pdev, 0);
+ }
+ kfree(hpriv);
+ ata_host_stop(host);
+}
+
+static inline void mv_priv_free(struct mv_port_priv *pp, struct device *dev)
+{
+ dma_free_coherent(dev, MV_PORT_PRIV_DMA_SZ, pp->crpb, pp->crpb_dma);
+}
+
+static void mv_edma_cfg(struct mv_host_priv *hpriv, void __iomem *port_mmio)
+{
+ u32 cfg = readl(port_mmio + EDMA_CFG_OFS);
+
+ /* set up non-NCQ EDMA configuration */
+ cfg &= ~0x1f; /* clear queue depth */
+ cfg &= ~EDMA_CFG_NCQ; /* clear NCQ mode */
+ cfg &= ~(1 << 9); /* disable equeue */
+
+ if (IS_GEN_I(hpriv))
+ cfg |= (1 << 8); /* enab config burst size mask */
+
+ else if (IS_GEN_II(hpriv))
+ cfg |= EDMA_CFG_RD_BRST_EXT | EDMA_CFG_WR_BUFF_LEN;
+
+ else if (IS_GEN_IIE(hpriv)) {
+ cfg |= (1 << 23); /* dis RX PM port mask */
+ cfg &= ~(1 << 16); /* dis FIS-based switching (for now) */
+ cfg &= ~(1 << 19); /* dis 128-entry queue (for now?) */
+ cfg |= (1 << 18); /* enab early completion */
+ cfg |= (1 << 17); /* enab host q cache */
+ cfg |= (1 << 22); /* enab cutthrough */
+ }
+
+ writelfl(cfg, port_mmio + EDMA_CFG_OFS);
+}
+
+/**
+ * mv_port_start - Port specific init/start routine.
+ * @ap: ATA channel to manipulate
+ *
+ * Allocate and point to DMA memory, init port private memory,
+ * zero indices.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+static int mv_port_start(struct ata_port *ap)
+{
+ struct device *dev = ap->host->dev;
+ struct mv_host_priv *hpriv = ap->host->private_data;
+ struct mv_port_priv *pp;
+ void __iomem *port_mmio = mv_ap_base(ap);
+ void *mem;
+ dma_addr_t mem_dma;
+ int rc = -ENOMEM;
+
+ pp = kmalloc(sizeof(*pp), GFP_KERNEL);
+ if (!pp)
+ goto err_out;
+ memset(pp, 0, sizeof(*pp));
+
+ mem = dma_alloc_coherent(dev, MV_PORT_PRIV_DMA_SZ, &mem_dma,
+ GFP_KERNEL);
+ if (!mem)
+ goto err_out_pp;
+ memset(mem, 0, MV_PORT_PRIV_DMA_SZ);
+
+ rc = ata_pad_alloc(ap, dev);
+ if (rc)
+ goto err_out_priv;
+
+ /* First item in chunk of DMA memory:
+ * 32-slot command request table (CRQB), 32 bytes each in size
+ */
+ pp->crqb = mem;
+ pp->crqb_dma = mem_dma;
+ mem += MV_CRQB_Q_SZ;
+ mem_dma += MV_CRQB_Q_SZ;
+
+ /* Second item:
+ * 32-slot command response table (CRPB), 8 bytes each in size
+ */
+ pp->crpb = mem;
+ pp->crpb_dma = mem_dma;
+ mem += MV_CRPB_Q_SZ;
+ mem_dma += MV_CRPB_Q_SZ;
+
+ /* Third item:
+ * Table of scatter-gather descriptors (ePRD), 16 bytes each
+ */
+ pp->sg_tbl = mem;
+ pp->sg_tbl_dma = mem_dma;
+
+ mv_edma_cfg(hpriv, port_mmio);
+
+ writel((pp->crqb_dma >> 16) >> 16, port_mmio + EDMA_REQ_Q_BASE_HI_OFS);
+ writelfl(pp->crqb_dma & EDMA_REQ_Q_BASE_LO_MASK,
+ port_mmio + EDMA_REQ_Q_IN_PTR_OFS);
+
+ if (hpriv->hp_flags & MV_HP_ERRATA_XX42A0)
+ writelfl(pp->crqb_dma & 0xffffffff,
+ port_mmio + EDMA_REQ_Q_OUT_PTR_OFS);
+ else
+ writelfl(0, port_mmio + EDMA_REQ_Q_OUT_PTR_OFS);
+
+ writel((pp->crpb_dma >> 16) >> 16, port_mmio + EDMA_RSP_Q_BASE_HI_OFS);
+
+ if (hpriv->hp_flags & MV_HP_ERRATA_XX42A0)
+ writelfl(pp->crpb_dma & 0xffffffff,
+ port_mmio + EDMA_RSP_Q_IN_PTR_OFS);
+ else
+ writelfl(0, port_mmio + EDMA_RSP_Q_IN_PTR_OFS);
+
+ writelfl(pp->crpb_dma & EDMA_RSP_Q_BASE_LO_MASK,
+ port_mmio + EDMA_RSP_Q_OUT_PTR_OFS);
+
+ /* Don't turn on EDMA here...do it before DMA commands only. Else
+ * we'll be unable to send non-data, PIO, etc due to restricted access
+ * to shadow regs.
+ */
+ ap->private_data = pp;
+ return 0;
+
+err_out_priv:
+ mv_priv_free(pp, dev);
+err_out_pp:
+ kfree(pp);
+err_out:
+ return rc;
+}
+
+/**
+ * mv_port_stop - Port specific cleanup/stop routine.
+ * @ap: ATA channel to manipulate
+ *
+ * Stop DMA, cleanup port memory.
+ *
+ * LOCKING:
+ * This routine uses the host lock to protect the DMA stop.
+ */
+static void mv_port_stop(struct ata_port *ap)
+{
+ struct device *dev = ap->host->dev;
+ struct mv_port_priv *pp = ap->private_data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ap->host->lock, flags);
+ mv_stop_dma(ap);
+ spin_unlock_irqrestore(&ap->host->lock, flags);
+
+ ap->private_data = NULL;
+ ata_pad_free(ap, dev);
+ mv_priv_free(pp, dev);
+ kfree(pp);
+}
+
+/**
+ * mv_fill_sg - Fill out the Marvell ePRD (scatter gather) entries
+ * @qc: queued command whose SG list to source from
+ *
+ * Populate the SG list and mark the last entry.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+static void mv_fill_sg(struct ata_queued_cmd *qc)
+{
+ struct mv_port_priv *pp = qc->ap->private_data;
+ unsigned int i = 0;
+ struct scatterlist *sg;
+
+ ata_for_each_sg(sg, qc) {
+ dma_addr_t addr;
+ u32 sg_len, len, offset;
+
+ addr = sg_dma_address(sg);
+ sg_len = sg_dma_len(sg);
+
+ while (sg_len) {
+ offset = addr & MV_DMA_BOUNDARY;
+ len = sg_len;
+ if ((offset + sg_len) > 0x10000)
+ len = 0x10000 - offset;
+
+ pp->sg_tbl[i].addr = cpu_to_le32(addr & 0xffffffff);
+ pp->sg_tbl[i].addr_hi = cpu_to_le32((addr >> 16) >> 16);
+ pp->sg_tbl[i].flags_size = cpu_to_le32(len & 0xffff);
+
+ sg_len -= len;
+ addr += len;
+
+ if (!sg_len && ata_sg_is_last(sg, qc))
+ pp->sg_tbl[i].flags_size |= cpu_to_le32(EPRD_FLAG_END_OF_TBL);
+
+ i++;
+ }
+ }
+}
+
+static inline unsigned mv_inc_q_index(unsigned index)
+{
+ return (index + 1) & MV_MAX_Q_DEPTH_MASK;
+}
+
+static inline void mv_crqb_pack_cmd(__le16 *cmdw, u8 data, u8 addr, unsigned last)
+{
+ u16 tmp = data | (addr << CRQB_CMD_ADDR_SHIFT) | CRQB_CMD_CS |
+ (last ? CRQB_CMD_LAST : 0);
+ *cmdw = cpu_to_le16(tmp);
+}
+
+/**
+ * mv_qc_prep - Host specific command preparation.
+ * @qc: queued command to prepare
+ *
+ * This routine simply redirects to the general purpose routine
+ * if command is not DMA. Else, it handles prep of the CRQB
+ * (command request block), does some sanity checking, and calls
+ * the SG load routine.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+static void mv_qc_prep(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct mv_port_priv *pp = ap->private_data;
+ __le16 *cw;
+ struct ata_taskfile *tf;
+ u16 flags = 0;
+ unsigned in_index;
+
+ if (ATA_PROT_DMA != qc->tf.protocol)
+ return;
+
+ /* Fill in command request block
+ */
+ if (!(qc->tf.flags & ATA_TFLAG_WRITE))
+ flags |= CRQB_FLAG_READ;
+ WARN_ON(MV_MAX_Q_DEPTH <= qc->tag);
+ flags |= qc->tag << CRQB_TAG_SHIFT;
+
+ /* get current queue index from hardware */
+ in_index = (readl(mv_ap_base(ap) + EDMA_REQ_Q_IN_PTR_OFS)
+ >> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK;
+
+ pp->crqb[in_index].sg_addr =
+ cpu_to_le32(pp->sg_tbl_dma & 0xffffffff);
+ pp->crqb[in_index].sg_addr_hi =
+ cpu_to_le32((pp->sg_tbl_dma >> 16) >> 16);
+ pp->crqb[in_index].ctrl_flags = cpu_to_le16(flags);
+
+ cw = &pp->crqb[in_index].ata_cmd[0];
+ tf = &qc->tf;
+
+ /* Sadly, the CRQB cannot accomodate all registers--there are
+ * only 11 bytes...so we must pick and choose required
+ * registers based on the command. So, we drop feature and
+ * hob_feature for [RW] DMA commands, but they are needed for
+ * NCQ. NCQ will drop hob_nsect.
+ */
+ switch (tf->command) {
+ case ATA_CMD_READ:
+ case ATA_CMD_READ_EXT:
+ case ATA_CMD_WRITE:
+ case ATA_CMD_WRITE_EXT:
+ case ATA_CMD_WRITE_FUA_EXT:
+ mv_crqb_pack_cmd(cw++, tf->hob_nsect, ATA_REG_NSECT, 0);
+ break;
+#ifdef LIBATA_NCQ /* FIXME: remove this line when NCQ added */
+ case ATA_CMD_FPDMA_READ:
+ case ATA_CMD_FPDMA_WRITE:
+ mv_crqb_pack_cmd(cw++, tf->hob_feature, ATA_REG_FEATURE, 0);
+ mv_crqb_pack_cmd(cw++, tf->feature, ATA_REG_FEATURE, 0);
+ break;
+#endif /* FIXME: remove this line when NCQ added */
+ default:
+ /* The only other commands EDMA supports in non-queued and
+ * non-NCQ mode are: [RW] STREAM DMA and W DMA FUA EXT, none
+ * of which are defined/used by Linux. If we get here, this
+ * driver needs work.
+ *
+ * FIXME: modify libata to give qc_prep a return value and
+ * return error here.
+ */
+ BUG_ON(tf->command);
+ break;
+ }
+ mv_crqb_pack_cmd(cw++, tf->nsect, ATA_REG_NSECT, 0);
+ mv_crqb_pack_cmd(cw++, tf->hob_lbal, ATA_REG_LBAL, 0);
+ mv_crqb_pack_cmd(cw++, tf->lbal, ATA_REG_LBAL, 0);
+ mv_crqb_pack_cmd(cw++, tf->hob_lbam, ATA_REG_LBAM, 0);
+ mv_crqb_pack_cmd(cw++, tf->lbam, ATA_REG_LBAM, 0);
+ mv_crqb_pack_cmd(cw++, tf->hob_lbah, ATA_REG_LBAH, 0);
+ mv_crqb_pack_cmd(cw++, tf->lbah, ATA_REG_LBAH, 0);
+ mv_crqb_pack_cmd(cw++, tf->device, ATA_REG_DEVICE, 0);
+ mv_crqb_pack_cmd(cw++, tf->command, ATA_REG_CMD, 1); /* last */
+
+ if (!(qc->flags & ATA_QCFLAG_DMAMAP))
+ return;
+ mv_fill_sg(qc);
+}
+
+/**
+ * mv_qc_prep_iie - Host specific command preparation.
+ * @qc: queued command to prepare
+ *
+ * This routine simply redirects to the general purpose routine
+ * if command is not DMA. Else, it handles prep of the CRQB
+ * (command request block), does some sanity checking, and calls
+ * the SG load routine.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+static void mv_qc_prep_iie(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct mv_port_priv *pp = ap->private_data;
+ struct mv_crqb_iie *crqb;
+ struct ata_taskfile *tf;
+ unsigned in_index;
+ u32 flags = 0;
+
+ if (ATA_PROT_DMA != qc->tf.protocol)
+ return;
+
+ /* Fill in Gen IIE command request block
+ */
+ if (!(qc->tf.flags & ATA_TFLAG_WRITE))
+ flags |= CRQB_FLAG_READ;
+
+ WARN_ON(MV_MAX_Q_DEPTH <= qc->tag);
+ flags |= qc->tag << CRQB_TAG_SHIFT;
+
+ /* get current queue index from hardware */
+ in_index = (readl(mv_ap_base(ap) + EDMA_REQ_Q_IN_PTR_OFS)
+ >> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK;
+
+ crqb = (struct mv_crqb_iie *) &pp->crqb[in_index];
+ crqb->addr = cpu_to_le32(pp->sg_tbl_dma & 0xffffffff);
+ crqb->addr_hi = cpu_to_le32((pp->sg_tbl_dma >> 16) >> 16);
+ crqb->flags = cpu_to_le32(flags);
+
+ tf = &qc->tf;
+ crqb->ata_cmd[0] = cpu_to_le32(
+ (tf->command << 16) |
+ (tf->feature << 24)
+ );
+ crqb->ata_cmd[1] = cpu_to_le32(
+ (tf->lbal << 0) |
+ (tf->lbam << 8) |
+ (tf->lbah << 16) |
+ (tf->device << 24)
+ );
+ crqb->ata_cmd[2] = cpu_to_le32(
+ (tf->hob_lbal << 0) |
+ (tf->hob_lbam << 8) |
+ (tf->hob_lbah << 16) |
+ (tf->hob_feature << 24)
+ );
+ crqb->ata_cmd[3] = cpu_to_le32(
+ (tf->nsect << 0) |
+ (tf->hob_nsect << 8)
+ );
+
+ if (!(qc->flags & ATA_QCFLAG_DMAMAP))
+ return;
+ mv_fill_sg(qc);
+}
+
+/**
+ * mv_qc_issue - Initiate a command to the host
+ * @qc: queued command to start
+ *
+ * This routine simply redirects to the general purpose routine
+ * if command is not DMA. Else, it sanity checks our local
+ * caches of the request producer/consumer indices then enables
+ * DMA and bumps the request producer index.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+static unsigned int mv_qc_issue(struct ata_queued_cmd *qc)
+{
+ void __iomem *port_mmio = mv_ap_base(qc->ap);
+ struct mv_port_priv *pp = qc->ap->private_data;
+ unsigned in_index;
+ u32 in_ptr;
+
+ if (ATA_PROT_DMA != qc->tf.protocol) {
+ /* We're about to send a non-EDMA capable command to the
+ * port. Turn off EDMA so there won't be problems accessing
+ * shadow block, etc registers.
+ */
+ mv_stop_dma(qc->ap);
+ return ata_qc_issue_prot(qc);
+ }
+
+ in_ptr = readl(port_mmio + EDMA_REQ_Q_IN_PTR_OFS);
+ in_index = (in_ptr >> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK;
+
+ /* until we do queuing, the queue should be empty at this point */
+ WARN_ON(in_index != ((readl(port_mmio + EDMA_REQ_Q_OUT_PTR_OFS)
+ >> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK));
+
+ in_index = mv_inc_q_index(in_index); /* now incr producer index */
+
+ mv_start_dma(port_mmio, pp);
+
+ /* and write the request in pointer to kick the EDMA to life */
+ in_ptr &= EDMA_REQ_Q_BASE_LO_MASK;
+ in_ptr |= in_index << EDMA_REQ_Q_PTR_SHIFT;
+ writelfl(in_ptr, port_mmio + EDMA_REQ_Q_IN_PTR_OFS);
+
+ return 0;
+}
+
+/**
+ * mv_get_crpb_status - get status from most recently completed cmd
+ * @ap: ATA channel to manipulate
+ *
+ * This routine is for use when the port is in DMA mode, when it
+ * will be using the CRPB (command response block) method of
+ * returning command completion information. We check indices
+ * are good, grab status, and bump the response consumer index to
+ * prove that we're up to date.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+static u8 mv_get_crpb_status(struct ata_port *ap)
+{
+ void __iomem *port_mmio = mv_ap_base(ap);
+ struct mv_port_priv *pp = ap->private_data;
+ unsigned out_index;
+ u32 out_ptr;
+ u8 ata_status;
+
+ out_ptr = readl(port_mmio + EDMA_RSP_Q_OUT_PTR_OFS);
+ out_index = (out_ptr >> EDMA_RSP_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK;
+
+ ata_status = le16_to_cpu(pp->crpb[out_index].flags)
+ >> CRPB_FLAG_STATUS_SHIFT;
+
+ /* increment our consumer index... */
+ out_index = mv_inc_q_index(out_index);
+
+ /* and, until we do NCQ, there should only be 1 CRPB waiting */
+ WARN_ON(out_index != ((readl(port_mmio + EDMA_RSP_Q_IN_PTR_OFS)
+ >> EDMA_RSP_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK));
+
+ /* write out our inc'd consumer index so EDMA knows we're caught up */
+ out_ptr &= EDMA_RSP_Q_BASE_LO_MASK;
+ out_ptr |= out_index << EDMA_RSP_Q_PTR_SHIFT;
+ writelfl(out_ptr, port_mmio + EDMA_RSP_Q_OUT_PTR_OFS);
+
+ /* Return ATA status register for completed CRPB */
+ return ata_status;
+}
+
+/**
+ * mv_err_intr - Handle error interrupts on the port
+ * @ap: ATA channel to manipulate
+ * @reset_allowed: bool: 0 == don't trigger from reset here
+ *
+ * In most cases, just clear the interrupt and move on. However,
+ * some cases require an eDMA reset, which is done right before
+ * the COMRESET in mv_phy_reset(). The SERR case requires a
+ * clear of pending errors in the SATA SERROR register. Finally,
+ * if the port disabled DMA, update our cached copy to match.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+static void mv_err_intr(struct ata_port *ap, int reset_allowed)
+{
+ void __iomem *port_mmio = mv_ap_base(ap);
+ u32 edma_err_cause, serr = 0;
+
+ edma_err_cause = readl(port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
+
+ if (EDMA_ERR_SERR & edma_err_cause) {
+ sata_scr_read(ap, SCR_ERROR, &serr);
+ sata_scr_write_flush(ap, SCR_ERROR, serr);
+ }
+ if (EDMA_ERR_SELF_DIS & edma_err_cause) {
+ struct mv_port_priv *pp = ap->private_data;
+ pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN;
+ }
+ DPRINTK(KERN_ERR "ata%u: port error; EDMA err cause: 0x%08x "
+ "SERR: 0x%08x\n", ap->id, edma_err_cause, serr);
+
+ /* Clear EDMA now that SERR cleanup done */
+ writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
+
+ /* check for fatal here and recover if needed */
+ if (reset_allowed && (EDMA_ERR_FATAL & edma_err_cause))
+ mv_stop_and_reset(ap);
+}
+
+/**
+ * mv_host_intr - Handle all interrupts on the given host controller
+ * @host: host specific structure
+ * @relevant: port error bits relevant to this host controller
+ * @hc: which host controller we're to look at
+ *
+ * Read then write clear the HC interrupt status then walk each
+ * port connected to the HC and see if it needs servicing. Port
+ * success ints are reported in the HC interrupt status reg, the
+ * port error ints are reported in the higher level main
+ * interrupt status register and thus are passed in via the
+ * 'relevant' argument.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+static void mv_host_intr(struct ata_host *host, u32 relevant, unsigned int hc)
+{
+ void __iomem *mmio = host->mmio_base;
+ void __iomem *hc_mmio = mv_hc_base(mmio, hc);
+ struct ata_queued_cmd *qc;
+ u32 hc_irq_cause;
+ int shift, port, port0, hard_port, handled;
+ unsigned int err_mask;
+
+ if (hc == 0) {
+ port0 = 0;
+ } else {
+ port0 = MV_PORTS_PER_HC;
+ }
+
+ /* we'll need the HC success int register in most cases */
+ hc_irq_cause = readl(hc_mmio + HC_IRQ_CAUSE_OFS);
+ if (hc_irq_cause) {
+ writelfl(~hc_irq_cause, hc_mmio + HC_IRQ_CAUSE_OFS);
+ }
+
+ VPRINTK("ENTER, hc%u relevant=0x%08x HC IRQ cause=0x%08x\n",
+ hc,relevant,hc_irq_cause);
+
+ for (port = port0; port < port0 + MV_PORTS_PER_HC; port++) {
+ u8 ata_status = 0;
+ struct ata_port *ap = host->ports[port];
+ struct mv_port_priv *pp = ap->private_data;
+
+ hard_port = mv_hardport_from_port(port); /* range 0..3 */
+ handled = 0; /* ensure ata_status is set if handled++ */
+
+ /* Note that DEV_IRQ might happen spuriously during EDMA,
+ * and should be ignored in such cases.
+ * The cause of this is still under investigation.
+ */
+ if (pp->pp_flags & MV_PP_FLAG_EDMA_EN) {
+ /* EDMA: check for response queue interrupt */
+ if ((CRPB_DMA_DONE << hard_port) & hc_irq_cause) {
+ ata_status = mv_get_crpb_status(ap);
+ handled = 1;
+ }
+ } else {
+ /* PIO: check for device (drive) interrupt */
+ if ((DEV_IRQ << hard_port) & hc_irq_cause) {
+ ata_status = readb((void __iomem *)
+ ap->ioaddr.status_addr);
+ handled = 1;
+ /* ignore spurious intr if drive still BUSY */
+ if (ata_status & ATA_BUSY) {
+ ata_status = 0;
+ handled = 0;
+ }
+ }
+ }
+
+ if (ap && (ap->flags & ATA_FLAG_DISABLED))
+ continue;
+
+ err_mask = ac_err_mask(ata_status);
+
+ shift = port << 1; /* (port * 2) */
+ if (port >= MV_PORTS_PER_HC) {
+ shift++; /* skip bit 8 in the HC Main IRQ reg */
+ }
+ if ((PORT0_ERR << shift) & relevant) {
+ mv_err_intr(ap, 1);
+ err_mask |= AC_ERR_OTHER;
+ handled = 1;
+ }
+
+ if (handled) {
+ qc = ata_qc_from_tag(ap, ap->active_tag);
+ if (qc && (qc->flags & ATA_QCFLAG_ACTIVE)) {
+ VPRINTK("port %u IRQ found for qc, "
+ "ata_status 0x%x\n", port,ata_status);
+ /* mark qc status appropriately */
+ if (!(qc->tf.flags & ATA_TFLAG_POLLING)) {
+ qc->err_mask |= err_mask;
+ ata_qc_complete(qc);
+ }
+ }
+ }
+ }
+ VPRINTK("EXIT\n");
+}
+
+/**
+ * mv_interrupt -
+ * @irq: unused
+ * @dev_instance: private data; in this case the host structure
+ * @regs: unused
+ *
+ * Read the read only register to determine if any host
+ * controllers have pending interrupts. If so, call lower level
+ * routine to handle. Also check for PCI errors which are only
+ * reported here.
+ *
+ * LOCKING:
+ * This routine holds the host lock while processing pending
+ * interrupts.
+ */
+static irqreturn_t mv_interrupt(int irq, void *dev_instance,
+ struct pt_regs *regs)
+{
+ struct ata_host *host = dev_instance;
+ unsigned int hc, handled = 0, n_hcs;
+ void __iomem *mmio = host->mmio_base;
+ struct mv_host_priv *hpriv;
+ u32 irq_stat;
+
+ irq_stat = readl(mmio + HC_MAIN_IRQ_CAUSE_OFS);
+
+ /* check the cases where we either have nothing pending or have read
+ * a bogus register value which can indicate HW removal or PCI fault
+ */
+ if (!irq_stat || (0xffffffffU == irq_stat)) {
+ return IRQ_NONE;
+ }
+
+ n_hcs = mv_get_hc_count(host->ports[0]->flags);
+ spin_lock(&host->lock);
+
+ for (hc = 0; hc < n_hcs; hc++) {
+ u32 relevant = irq_stat & (HC0_IRQ_PEND << (hc * HC_SHIFT));
+ if (relevant) {
+ mv_host_intr(host, relevant, hc);
+ handled++;
+ }
+ }
+
+ hpriv = host->private_data;
+ if (IS_60XX(hpriv)) {
+ /* deal with the interrupt coalescing bits */
+ if (irq_stat & (TRAN_LO_DONE | TRAN_HI_DONE | PORTS_0_7_COAL_DONE)) {
+ writelfl(0, mmio + MV_IRQ_COAL_CAUSE_LO);
+ writelfl(0, mmio + MV_IRQ_COAL_CAUSE_HI);
+ writelfl(0, mmio + MV_IRQ_COAL_CAUSE);
+ }
+ }
+
+ if (PCI_ERR & irq_stat) {
+ printk(KERN_ERR DRV_NAME ": PCI ERROR; PCI IRQ cause=0x%08x\n",
+ readl(mmio + PCI_IRQ_CAUSE_OFS));
+
+ DPRINTK("All regs @ PCI error\n");
+ mv_dump_all_regs(mmio, -1, to_pci_dev(host->dev));
+
+ writelfl(0, mmio + PCI_IRQ_CAUSE_OFS);
+ handled++;
+ }
+ spin_unlock(&host->lock);
+
+ return IRQ_RETVAL(handled);
+}
+
+static void __iomem *mv5_phy_base(void __iomem *mmio, unsigned int port)
+{
+ void __iomem *hc_mmio = mv_hc_base_from_port(mmio, port);
+ unsigned long ofs = (mv_hardport_from_port(port) + 1) * 0x100UL;
+
+ return hc_mmio + ofs;
+}
+
+static unsigned int mv5_scr_offset(unsigned int sc_reg_in)
+{
+ unsigned int ofs;
+
+ switch (sc_reg_in) {
+ case SCR_STATUS:
+ case SCR_ERROR:
+ case SCR_CONTROL:
+ ofs = sc_reg_in * sizeof(u32);
+ break;
+ default:
+ ofs = 0xffffffffU;
+ break;
+ }
+ return ofs;
+}
+
+static u32 mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in)
+{
+ void __iomem *mmio = mv5_phy_base(ap->host->mmio_base, ap->port_no);
+ unsigned int ofs = mv5_scr_offset(sc_reg_in);
+
+ if (ofs != 0xffffffffU)
+ return readl(mmio + ofs);
+ else
+ return (u32) ofs;
+}
+
+static void mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
+{
+ void __iomem *mmio = mv5_phy_base(ap->host->mmio_base, ap->port_no);
+ unsigned int ofs = mv5_scr_offset(sc_reg_in);
+
+ if (ofs != 0xffffffffU)
+ writelfl(val, mmio + ofs);
+}
+
+static void mv5_reset_bus(struct pci_dev *pdev, void __iomem *mmio)
+{
+ u8 rev_id;
+ int early_5080;
+
+ pci_read_config_byte(pdev, PCI_REVISION_ID, &rev_id);
+
+ early_5080 = (pdev->device == 0x5080) && (rev_id == 0);
+
+ if (!early_5080) {
+ u32 tmp = readl(mmio + MV_PCI_EXP_ROM_BAR_CTL);
+ tmp |= (1 << 0);
+ writel(tmp, mmio + MV_PCI_EXP_ROM_BAR_CTL);
+ }
+
+ mv_reset_pci_bus(pdev, mmio);
+}
+
+static void mv5_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio)
+{
+ writel(0x0fcfffff, mmio + MV_FLASH_CTL);
+}
+
+static void mv5_read_preamp(struct mv_host_priv *hpriv, int idx,
+ void __iomem *mmio)
+{
+ void __iomem *phy_mmio = mv5_phy_base(mmio, idx);
+ u32 tmp;
+
+ tmp = readl(phy_mmio + MV5_PHY_MODE);
+
+ hpriv->signal[idx].pre = tmp & 0x1800; /* bits 12:11 */
+ hpriv->signal[idx].amps = tmp & 0xe0; /* bits 7:5 */
+}
+
+static void mv5_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio)
+{
+ u32 tmp;
+
+ writel(0, mmio + MV_GPIO_PORT_CTL);
+
+ /* FIXME: handle MV_HP_ERRATA_50XXB2 errata */
+
+ tmp = readl(mmio + MV_PCI_EXP_ROM_BAR_CTL);
+ tmp |= ~(1 << 0);
+ writel(tmp, mmio + MV_PCI_EXP_ROM_BAR_CTL);
+}
+
+static void mv5_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,
+ unsigned int port)
+{
+ void __iomem *phy_mmio = mv5_phy_base(mmio, port);
+ const u32 mask = (1<<12) | (1<<11) | (1<<7) | (1<<6) | (1<<5);
+ u32 tmp;
+ int fix_apm_sq = (hpriv->hp_flags & MV_HP_ERRATA_50XXB0);
+
+ if (fix_apm_sq) {
+ tmp = readl(phy_mmio + MV5_LT_MODE);
+ tmp |= (1 << 19);
+ writel(tmp, phy_mmio + MV5_LT_MODE);
+
+ tmp = readl(phy_mmio + MV5_PHY_CTL);
+ tmp &= ~0x3;
+ tmp |= 0x1;
+ writel(tmp, phy_mmio + MV5_PHY_CTL);
+ }
+
+ tmp = readl(phy_mmio + MV5_PHY_MODE);
+ tmp &= ~mask;
+ tmp |= hpriv->signal[port].pre;
+ tmp |= hpriv->signal[port].amps;
+ writel(tmp, phy_mmio + MV5_PHY_MODE);
+}
+
+
+#undef ZERO
+#define ZERO(reg) writel(0, port_mmio + (reg))
+static void mv5_reset_hc_port(struct mv_host_priv *hpriv, void __iomem *mmio,
+ unsigned int port)
+{
+ void __iomem *port_mmio = mv_port_base(mmio, port);
+
+ writelfl(EDMA_DS, port_mmio + EDMA_CMD_OFS);
+
+ mv_channel_reset(hpriv, mmio, port);
+
+ ZERO(0x028); /* command */
+ writel(0x11f, port_mmio + EDMA_CFG_OFS);
+ ZERO(0x004); /* timer */
+ ZERO(0x008); /* irq err cause */
+ ZERO(0x00c); /* irq err mask */
+ ZERO(0x010); /* rq bah */
+ ZERO(0x014); /* rq inp */
+ ZERO(0x018); /* rq outp */
+ ZERO(0x01c); /* respq bah */
+ ZERO(0x024); /* respq outp */
+ ZERO(0x020); /* respq inp */
+ ZERO(0x02c); /* test control */
+ writel(0xbc, port_mmio + EDMA_IORDY_TMOUT);
+}
+#undef ZERO
+
+#define ZERO(reg) writel(0, hc_mmio + (reg))
+static void mv5_reset_one_hc(struct mv_host_priv *hpriv, void __iomem *mmio,
+ unsigned int hc)
+{
+ void __iomem *hc_mmio = mv_hc_base(mmio, hc);
+ u32 tmp;
+
+ ZERO(0x00c);
+ ZERO(0x010);
+ ZERO(0x014);
+ ZERO(0x018);
+
+ tmp = readl(hc_mmio + 0x20);
+ tmp &= 0x1c1c1c1c;
+ tmp |= 0x03030303;
+ writel(tmp, hc_mmio + 0x20);
+}
+#undef ZERO
+
+static int mv5_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio,
+ unsigned int n_hc)
+{
+ unsigned int hc, port;
+
+ for (hc = 0; hc < n_hc; hc++) {
+ for (port = 0; port < MV_PORTS_PER_HC; port++)
+ mv5_reset_hc_port(hpriv, mmio,
+ (hc * MV_PORTS_PER_HC) + port);
+
+ mv5_reset_one_hc(hpriv, mmio, hc);
+ }
+
+ return 0;
+}
+
+#undef ZERO
+#define ZERO(reg) writel(0, mmio + (reg))
+static void mv_reset_pci_bus(struct pci_dev *pdev, void __iomem *mmio)
+{
+ u32 tmp;
+
+ tmp = readl(mmio + MV_PCI_MODE);
+ tmp &= 0xff00ffff;
+ writel(tmp, mmio + MV_PCI_MODE);
+
+ ZERO(MV_PCI_DISC_TIMER);
+ ZERO(MV_PCI_MSI_TRIGGER);
+ writel(0x000100ff, mmio + MV_PCI_XBAR_TMOUT);
+ ZERO(HC_MAIN_IRQ_MASK_OFS);
+ ZERO(MV_PCI_SERR_MASK);
+ ZERO(PCI_IRQ_CAUSE_OFS);
+ ZERO(PCI_IRQ_MASK_OFS);
+ ZERO(MV_PCI_ERR_LOW_ADDRESS);
+ ZERO(MV_PCI_ERR_HIGH_ADDRESS);
+ ZERO(MV_PCI_ERR_ATTRIBUTE);
+ ZERO(MV_PCI_ERR_COMMAND);
+}
+#undef ZERO
+
+static void mv6_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio)
+{
+ u32 tmp;
+
+ mv5_reset_flash(hpriv, mmio);
+
+ tmp = readl(mmio + MV_GPIO_PORT_CTL);
+ tmp &= 0x3;
+ tmp |= (1 << 5) | (1 << 6);
+ writel(tmp, mmio + MV_GPIO_PORT_CTL);
+}
+
+/**
+ * mv6_reset_hc - Perform the 6xxx global soft reset
+ * @mmio: base address of the HBA
+ *
+ * This routine only applies to 6xxx parts.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+static int mv6_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio,
+ unsigned int n_hc)
+{
+ void __iomem *reg = mmio + PCI_MAIN_CMD_STS_OFS;
+ int i, rc = 0;
+ u32 t;
+
+ /* Following procedure defined in PCI "main command and status
+ * register" table.
+ */
+ t = readl(reg);
+ writel(t | STOP_PCI_MASTER, reg);
+
+ for (i = 0; i < 1000; i++) {
+ udelay(1);
+ t = readl(reg);
+ if (PCI_MASTER_EMPTY & t) {
+ break;
+ }
+ }
+ if (!(PCI_MASTER_EMPTY & t)) {
+ printk(KERN_ERR DRV_NAME ": PCI master won't flush\n");
+ rc = 1;
+ goto done;
+ }
+
+ /* set reset */
+ i = 5;
+ do {
+ writel(t | GLOB_SFT_RST, reg);
+ t = readl(reg);
+ udelay(1);
+ } while (!(GLOB_SFT_RST & t) && (i-- > 0));
+
+ if (!(GLOB_SFT_RST & t)) {
+ printk(KERN_ERR DRV_NAME ": can't set global reset\n");
+ rc = 1;
+ goto done;
+ }
+
+ /* clear reset and *reenable the PCI master* (not mentioned in spec) */
+ i = 5;
+ do {
+ writel(t & ~(GLOB_SFT_RST | STOP_PCI_MASTER), reg);
+ t = readl(reg);
+ udelay(1);
+ } while ((GLOB_SFT_RST & t) && (i-- > 0));
+
+ if (GLOB_SFT_RST & t) {
+ printk(KERN_ERR DRV_NAME ": can't clear global reset\n");
+ rc = 1;
+ }
+done:
+ return rc;
+}
+
+static void mv6_read_preamp(struct mv_host_priv *hpriv, int idx,
+ void __iomem *mmio)
+{
+ void __iomem *port_mmio;
+ u32 tmp;
+
+ tmp = readl(mmio + MV_RESET_CFG);
+ if ((tmp & (1 << 0)) == 0) {
+ hpriv->signal[idx].amps = 0x7 << 8;
+ hpriv->signal[idx].pre = 0x1 << 5;
+ return;
+ }
+
+ port_mmio = mv_port_base(mmio, idx);
+ tmp = readl(port_mmio + PHY_MODE2);
+
+ hpriv->signal[idx].amps = tmp & 0x700; /* bits 10:8 */
+ hpriv->signal[idx].pre = tmp & 0xe0; /* bits 7:5 */
+}
+
+static void mv6_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio)
+{
+ writel(0x00000060, mmio + MV_GPIO_PORT_CTL);
+}
+
+static void mv6_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,
+ unsigned int port)
+{
+ void __iomem *port_mmio = mv_port_base(mmio, port);
+
+ u32 hp_flags = hpriv->hp_flags;
+ int fix_phy_mode2 =
+ hp_flags & (MV_HP_ERRATA_60X1B2 | MV_HP_ERRATA_60X1C0);
+ int fix_phy_mode4 =
+ hp_flags & (MV_HP_ERRATA_60X1B2 | MV_HP_ERRATA_60X1C0);
+ u32 m2, tmp;
+
+ if (fix_phy_mode2) {
+ m2 = readl(port_mmio + PHY_MODE2);
+ m2 &= ~(1 << 16);
+ m2 |= (1 << 31);
+ writel(m2, port_mmio + PHY_MODE2);
+
+ udelay(200);
+
+ m2 = readl(port_mmio + PHY_MODE2);
+ m2 &= ~((1 << 16) | (1 << 31));
+ writel(m2, port_mmio + PHY_MODE2);
+
+ udelay(200);
+ }
+
+ /* who knows what this magic does */
+ tmp = readl(port_mmio + PHY_MODE3);
+ tmp &= ~0x7F800000;
+ tmp |= 0x2A800000;
+ writel(tmp, port_mmio + PHY_MODE3);
+
+ if (fix_phy_mode4) {
+ u32 m4;
+
+ m4 = readl(port_mmio + PHY_MODE4);
+
+ if (hp_flags & MV_HP_ERRATA_60X1B2)
+ tmp = readl(port_mmio + 0x310);
+
+ m4 = (m4 & ~(1 << 1)) | (1 << 0);
+
+ writel(m4, port_mmio + PHY_MODE4);
+
+ if (hp_flags & MV_HP_ERRATA_60X1B2)
+ writel(tmp, port_mmio + 0x310);
+ }
+
+ /* Revert values of pre-emphasis and signal amps to the saved ones */
+ m2 = readl(port_mmio + PHY_MODE2);
+
+ m2 &= ~MV_M2_PREAMP_MASK;
+ m2 |= hpriv->signal[port].amps;
+ m2 |= hpriv->signal[port].pre;
+ m2 &= ~(1 << 16);
+
+ /* according to mvSata 3.6.1, some IIE values are fixed */
+ if (IS_GEN_IIE(hpriv)) {
+ m2 &= ~0xC30FF01F;
+ m2 |= 0x0000900F;
+ }
+
+ writel(m2, port_mmio + PHY_MODE2);
+}
+
+static void mv_channel_reset(struct mv_host_priv *hpriv, void __iomem *mmio,
+ unsigned int port_no)
+{
+ void __iomem *port_mmio = mv_port_base(mmio, port_no);
+
+ writelfl(ATA_RST, port_mmio + EDMA_CMD_OFS);
+
+ if (IS_60XX(hpriv)) {
+ u32 ifctl = readl(port_mmio + SATA_INTERFACE_CTL);
+ ifctl |= (1 << 7); /* enable gen2i speed */
+ ifctl = (ifctl & 0xfff) | 0x9b1000; /* from chip spec */
+ writelfl(ifctl, port_mmio + SATA_INTERFACE_CTL);
+ }
+
+ udelay(25); /* allow reset propagation */
+
+ /* Spec never mentions clearing the bit. Marvell's driver does
+ * clear the bit, however.
+ */
+ writelfl(0, port_mmio + EDMA_CMD_OFS);
+
+ hpriv->ops->phy_errata(hpriv, mmio, port_no);
+
+ if (IS_50XX(hpriv))
+ mdelay(1);
+}
+
+static void mv_stop_and_reset(struct ata_port *ap)
+{
+ struct mv_host_priv *hpriv = ap->host->private_data;
+ void __iomem *mmio = ap->host->mmio_base;
+
+ mv_stop_dma(ap);
+
+ mv_channel_reset(hpriv, mmio, ap->port_no);
+
+ __mv_phy_reset(ap, 0);
+}
+
+static inline void __msleep(unsigned int msec, int can_sleep)
+{
+ if (can_sleep)
+ msleep(msec);
+ else
+ mdelay(msec);
+}
+
+/**
+ * __mv_phy_reset - Perform eDMA reset followed by COMRESET
+ * @ap: ATA channel to manipulate
+ *
+ * Part of this is taken from __sata_phy_reset and modified to
+ * not sleep since this routine gets called from interrupt level.
+ *
+ * LOCKING:
+ * Inherited from caller. This is coded to safe to call at
+ * interrupt level, i.e. it does not sleep.
+ */
+static void __mv_phy_reset(struct ata_port *ap, int can_sleep)
+{
+ struct mv_port_priv *pp = ap->private_data;
+ struct mv_host_priv *hpriv = ap->host->private_data;
+ void __iomem *port_mmio = mv_ap_base(ap);
+ struct ata_taskfile tf;
+ struct ata_device *dev = &ap->device[0];
+ unsigned long timeout;
+ int retry = 5;
+ u32 sstatus;
+
+ VPRINTK("ENTER, port %u, mmio 0x%p\n", ap->port_no, port_mmio);
+
+ DPRINTK("S-regs after ATA_RST: SStat 0x%08x SErr 0x%08x "
+ "SCtrl 0x%08x\n", mv_scr_read(ap, SCR_STATUS),
+ mv_scr_read(ap, SCR_ERROR), mv_scr_read(ap, SCR_CONTROL));
+
+ /* Issue COMRESET via SControl */
+comreset_retry:
+ sata_scr_write_flush(ap, SCR_CONTROL, 0x301);
+ __msleep(1, can_sleep);
+
+ sata_scr_write_flush(ap, SCR_CONTROL, 0x300);
+ __msleep(20, can_sleep);
+
+ timeout = jiffies + msecs_to_jiffies(200);
+ do {
+ sata_scr_read(ap, SCR_STATUS, &sstatus);
+ if (((sstatus & 0x3) == 3) || ((sstatus & 0x3) == 0))
+ break;
+
+ __msleep(1, can_sleep);
+ } while (time_before(jiffies, timeout));
+
+ /* work around errata */
+ if (IS_60XX(hpriv) &&
+ (sstatus != 0x0) && (sstatus != 0x113) && (sstatus != 0x123) &&
+ (retry-- > 0))
+ goto comreset_retry;
+
+ DPRINTK("S-regs after PHY wake: SStat 0x%08x SErr 0x%08x "
+ "SCtrl 0x%08x\n", mv_scr_read(ap, SCR_STATUS),
+ mv_scr_read(ap, SCR_ERROR), mv_scr_read(ap, SCR_CONTROL));
+
+ if (ata_port_online(ap)) {
+ ata_port_probe(ap);
+ } else {
+ sata_scr_read(ap, SCR_STATUS, &sstatus);
+ ata_port_printk(ap, KERN_INFO,
+ "no device found (phy stat %08x)\n", sstatus);
+ ata_port_disable(ap);
+ return;
+ }
+ ap->cbl = ATA_CBL_SATA;
+
+ /* even after SStatus reflects that device is ready,
+ * it seems to take a while for link to be fully
+ * established (and thus Status no longer 0x80/0x7F),
+ * so we poll a bit for that, here.
+ */
+ retry = 20;
+ while (1) {
+ u8 drv_stat = ata_check_status(ap);
+ if ((drv_stat != 0x80) && (drv_stat != 0x7f))
+ break;
+ __msleep(500, can_sleep);
+ if (retry-- <= 0)
+ break;
+ }
+
+ tf.lbah = readb((void __iomem *) ap->ioaddr.lbah_addr);
+ tf.lbam = readb((void __iomem *) ap->ioaddr.lbam_addr);
+ tf.lbal = readb((void __iomem *) ap->ioaddr.lbal_addr);
+ tf.nsect = readb((void __iomem *) ap->ioaddr.nsect_addr);
+
+ dev->class = ata_dev_classify(&tf);
+ if (!ata_dev_enabled(dev)) {
+ VPRINTK("Port disabled post-sig: No device present.\n");
+ ata_port_disable(ap);
+ }
+
+ writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
+
+ pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN;
+
+ VPRINTK("EXIT\n");
+}
+
+static void mv_phy_reset(struct ata_port *ap)
+{
+ __mv_phy_reset(ap, 1);
+}
+
+/**
+ * mv_eng_timeout - Routine called by libata when SCSI times out I/O
+ * @ap: ATA channel to manipulate
+ *
+ * Intent is to clear all pending error conditions, reset the
+ * chip/bus, fail the command, and move on.
+ *
+ * LOCKING:
+ * This routine holds the host lock while failing the command.
+ */
+static void mv_eng_timeout(struct ata_port *ap)
+{
+ struct ata_queued_cmd *qc;
+ unsigned long flags;
+
+ ata_port_printk(ap, KERN_ERR, "Entering mv_eng_timeout\n");
+ DPRINTK("All regs @ start of eng_timeout\n");
+ mv_dump_all_regs(ap->host->mmio_base, ap->port_no,
+ to_pci_dev(ap->host->dev));
+
+ qc = ata_qc_from_tag(ap, ap->active_tag);
+ printk(KERN_ERR "mmio_base %p ap %p qc %p scsi_cmnd %p &cmnd %p\n",
+ ap->host->mmio_base, ap, qc, qc->scsicmd, &qc->scsicmd->cmnd);
+
+ spin_lock_irqsave(&ap->host->lock, flags);
+ mv_err_intr(ap, 0);
+ mv_stop_and_reset(ap);
+ spin_unlock_irqrestore(&ap->host->lock, flags);
+
+ WARN_ON(!(qc->flags & ATA_QCFLAG_ACTIVE));
+ if (qc->flags & ATA_QCFLAG_ACTIVE) {
+ qc->err_mask |= AC_ERR_TIMEOUT;
+ ata_eh_qc_complete(qc);
+ }
+}
+
+/**
+ * mv_port_init - Perform some early initialization on a single port.
+ * @port: libata data structure storing shadow register addresses
+ * @port_mmio: base address of the port
+ *
+ * Initialize shadow register mmio addresses, clear outstanding
+ * interrupts on the port, and unmask interrupts for the future
+ * start of the port.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+static void mv_port_init(struct ata_ioports *port, void __iomem *port_mmio)
+{
+ unsigned long shd_base = (unsigned long) port_mmio + SHD_BLK_OFS;
+ unsigned serr_ofs;
+
+ /* PIO related setup
+ */
+ port->data_addr = shd_base + (sizeof(u32) * ATA_REG_DATA);
+ port->error_addr =
+ port->feature_addr = shd_base + (sizeof(u32) * ATA_REG_ERR);
+ port->nsect_addr = shd_base + (sizeof(u32) * ATA_REG_NSECT);
+ port->lbal_addr = shd_base + (sizeof(u32) * ATA_REG_LBAL);
+ port->lbam_addr = shd_base + (sizeof(u32) * ATA_REG_LBAM);
+ port->lbah_addr = shd_base + (sizeof(u32) * ATA_REG_LBAH);
+ port->device_addr = shd_base + (sizeof(u32) * ATA_REG_DEVICE);
+ port->status_addr =
+ port->command_addr = shd_base + (sizeof(u32) * ATA_REG_STATUS);
+ /* special case: control/altstatus doesn't have ATA_REG_ address */
+ port->altstatus_addr = port->ctl_addr = shd_base + SHD_CTL_AST_OFS;
+
+ /* unused: */
+ port->cmd_addr = port->bmdma_addr = port->scr_addr = 0;
+
+ /* Clear any currently outstanding port interrupt conditions */
+ serr_ofs = mv_scr_offset(SCR_ERROR);
+ writelfl(readl(port_mmio + serr_ofs), port_mmio + serr_ofs);
+ writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
+
+ /* unmask all EDMA error interrupts */
+ writelfl(~0, port_mmio + EDMA_ERR_IRQ_MASK_OFS);
+
+ VPRINTK("EDMA cfg=0x%08x EDMA IRQ err cause/mask=0x%08x/0x%08x\n",
+ readl(port_mmio + EDMA_CFG_OFS),
+ readl(port_mmio + EDMA_ERR_IRQ_CAUSE_OFS),
+ readl(port_mmio + EDMA_ERR_IRQ_MASK_OFS));
+}
+
+static int mv_chip_id(struct pci_dev *pdev, struct mv_host_priv *hpriv,
+ unsigned int board_idx)
+{
+ u8 rev_id;
+ u32 hp_flags = hpriv->hp_flags;
+
+ pci_read_config_byte(pdev, PCI_REVISION_ID, &rev_id);
+
+ switch(board_idx) {
+ case chip_5080:
+ hpriv->ops = &mv5xxx_ops;
+ hp_flags |= MV_HP_50XX;
+
+ switch (rev_id) {
+ case 0x1:
+ hp_flags |= MV_HP_ERRATA_50XXB0;
+ break;
+ case 0x3:
+ hp_flags |= MV_HP_ERRATA_50XXB2;
+ break;
+ default:
+ dev_printk(KERN_WARNING, &pdev->dev,
+ "Applying 50XXB2 workarounds to unknown rev\n");
+ hp_flags |= MV_HP_ERRATA_50XXB2;
+ break;
+ }
+ break;
+
+ case chip_504x:
+ case chip_508x:
+ hpriv->ops = &mv5xxx_ops;
+ hp_flags |= MV_HP_50XX;
+
+ switch (rev_id) {
+ case 0x0:
+ hp_flags |= MV_HP_ERRATA_50XXB0;
+ break;
+ case 0x3:
+ hp_flags |= MV_HP_ERRATA_50XXB2;
+ break;
+ default:
+ dev_printk(KERN_WARNING, &pdev->dev,
+ "Applying B2 workarounds to unknown rev\n");
+ hp_flags |= MV_HP_ERRATA_50XXB2;
+ break;
+ }
+ break;
+
+ case chip_604x:
+ case chip_608x:
+ hpriv->ops = &mv6xxx_ops;
+
+ switch (rev_id) {
+ case 0x7:
+ hp_flags |= MV_HP_ERRATA_60X1B2;
+ break;
+ case 0x9:
+ hp_flags |= MV_HP_ERRATA_60X1C0;
+ break;
+ default:
+ dev_printk(KERN_WARNING, &pdev->dev,
+ "Applying B2 workarounds to unknown rev\n");
+ hp_flags |= MV_HP_ERRATA_60X1B2;
+ break;
+ }
+ break;
+
+ case chip_7042:
+ case chip_6042:
+ hpriv->ops = &mv6xxx_ops;
+
+ hp_flags |= MV_HP_GEN_IIE;
+
+ switch (rev_id) {
+ case 0x0:
+ hp_flags |= MV_HP_ERRATA_XX42A0;
+ break;
+ case 0x1:
+ hp_flags |= MV_HP_ERRATA_60X1C0;
+ break;
+ default:
+ dev_printk(KERN_WARNING, &pdev->dev,
+ "Applying 60X1C0 workarounds to unknown rev\n");
+ hp_flags |= MV_HP_ERRATA_60X1C0;
+ break;
+ }
+ break;
+
+ default:
+ printk(KERN_ERR DRV_NAME ": BUG: invalid board index %u\n", board_idx);
+ return 1;
+ }
+
+ hpriv->hp_flags = hp_flags;
+
+ return 0;
+}
+
+/**
+ * mv_init_host - Perform some early initialization of the host.
+ * @pdev: host PCI device
+ * @probe_ent: early data struct representing the host
+ *
+ * If possible, do an early global reset of the host. Then do
+ * our port init and clear/unmask all/relevant host interrupts.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+static int mv_init_host(struct pci_dev *pdev, struct ata_probe_ent *probe_ent,
+ unsigned int board_idx)
+{
+ int rc = 0, n_hc, port, hc;
+ void __iomem *mmio = probe_ent->mmio_base;
+ struct mv_host_priv *hpriv = probe_ent->private_data;
+
+ /* global interrupt mask */
+ writel(0, mmio + HC_MAIN_IRQ_MASK_OFS);
+
+ rc = mv_chip_id(pdev, hpriv, board_idx);
+ if (rc)
+ goto done;
+
+ n_hc = mv_get_hc_count(probe_ent->port_flags);
+ probe_ent->n_ports = MV_PORTS_PER_HC * n_hc;
+
+ for (port = 0; port < probe_ent->n_ports; port++)
+ hpriv->ops->read_preamp(hpriv, port, mmio);
+
+ rc = hpriv->ops->reset_hc(hpriv, mmio, n_hc);
+ if (rc)
+ goto done;
+
+ hpriv->ops->reset_flash(hpriv, mmio);
+ hpriv->ops->reset_bus(pdev, mmio);
+ hpriv->ops->enable_leds(hpriv, mmio);
+
+ for (port = 0; port < probe_ent->n_ports; port++) {
+ if (IS_60XX(hpriv)) {
+ void __iomem *port_mmio = mv_port_base(mmio, port);
+
+ u32 ifctl = readl(port_mmio + SATA_INTERFACE_CTL);
+ ifctl |= (1 << 7); /* enable gen2i speed */
+ ifctl = (ifctl & 0xfff) | 0x9b1000; /* from chip spec */
+ writelfl(ifctl, port_mmio + SATA_INTERFACE_CTL);
+ }
+
+ hpriv->ops->phy_errata(hpriv, mmio, port);
+ }
+
+ for (port = 0; port < probe_ent->n_ports; port++) {
+ void __iomem *port_mmio = mv_port_base(mmio, port);
+ mv_port_init(&probe_ent->port[port], port_mmio);
+ }
+
+ for (hc = 0; hc < n_hc; hc++) {
+ void __iomem *hc_mmio = mv_hc_base(mmio, hc);
+
+ VPRINTK("HC%i: HC config=0x%08x HC IRQ cause "
+ "(before clear)=0x%08x\n", hc,
+ readl(hc_mmio + HC_CFG_OFS),
+ readl(hc_mmio + HC_IRQ_CAUSE_OFS));
+
+ /* Clear any currently outstanding hc interrupt conditions */
+ writelfl(0, hc_mmio + HC_IRQ_CAUSE_OFS);
+ }
+
+ /* Clear any currently outstanding host interrupt conditions */
+ writelfl(0, mmio + PCI_IRQ_CAUSE_OFS);
+
+ /* and unmask interrupt generation for host regs */
+ writelfl(PCI_UNMASK_ALL_IRQS, mmio + PCI_IRQ_MASK_OFS);
+ writelfl(~HC_MAIN_MASKED_IRQS, mmio + HC_MAIN_IRQ_MASK_OFS);
+
+ VPRINTK("HC MAIN IRQ cause/mask=0x%08x/0x%08x "
+ "PCI int cause/mask=0x%08x/0x%08x\n",
+ readl(mmio + HC_MAIN_IRQ_CAUSE_OFS),
+ readl(mmio + HC_MAIN_IRQ_MASK_OFS),
+ readl(mmio + PCI_IRQ_CAUSE_OFS),
+ readl(mmio + PCI_IRQ_MASK_OFS));
+
+done:
+ return rc;
+}
+
+/**
+ * mv_print_info - Dump key info to kernel log for perusal.
+ * @probe_ent: early data struct representing the host
+ *
+ * FIXME: complete this.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+static void mv_print_info(struct ata_probe_ent *probe_ent)
+{
+ struct pci_dev *pdev = to_pci_dev(probe_ent->dev);
+ struct mv_host_priv *hpriv = probe_ent->private_data;
+ u8 rev_id, scc;
+ const char *scc_s;
+
+ /* Use this to determine the HW stepping of the chip so we know
+ * what errata to workaround
+ */
+ pci_read_config_byte(pdev, PCI_REVISION_ID, &rev_id);
+
+ pci_read_config_byte(pdev, PCI_CLASS_DEVICE, &scc);
+ if (scc == 0)
+ scc_s = "SCSI";
+ else if (scc == 0x01)
+ scc_s = "RAID";
+ else
+ scc_s = "unknown";
+
+ dev_printk(KERN_INFO, &pdev->dev,
+ "%u slots %u ports %s mode IRQ via %s\n",
+ (unsigned)MV_MAX_Q_DEPTH, probe_ent->n_ports,
+ scc_s, (MV_HP_FLAG_MSI & hpriv->hp_flags) ? "MSI" : "INTx");
+}
+
+/**
+ * mv_init_one - handle a positive probe of a Marvell host
+ * @pdev: PCI device found
+ * @ent: PCI device ID entry for the matched host
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ static int printed_version = 0;
+ struct ata_probe_ent *probe_ent = NULL;
+ struct mv_host_priv *hpriv;
+ unsigned int board_idx = (unsigned int)ent->driver_data;
+ void __iomem *mmio_base;
+ int pci_dev_busy = 0, rc;
+
+ if (!printed_version++)
+ dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n");
+
+ rc = pci_enable_device(pdev);
+ if (rc) {
+ return rc;
+ }
+ pci_set_master(pdev);
+
+ rc = pci_request_regions(pdev, DRV_NAME);
+ if (rc) {
+ pci_dev_busy = 1;
+ goto err_out;
+ }
+
+ probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
+ if (probe_ent == NULL) {
+ rc = -ENOMEM;
+ goto err_out_regions;
+ }
+
+ memset(probe_ent, 0, sizeof(*probe_ent));
+ probe_ent->dev = pci_dev_to_dev(pdev);
+ INIT_LIST_HEAD(&probe_ent->node);
+
+ mmio_base = pci_iomap(pdev, MV_PRIMARY_BAR, 0);
+ if (mmio_base == NULL) {
+ rc = -ENOMEM;
+ goto err_out_free_ent;
+ }
+
+ hpriv = kmalloc(sizeof(*hpriv), GFP_KERNEL);
+ if (!hpriv) {
+ rc = -ENOMEM;
+ goto err_out_iounmap;
+ }
+ memset(hpriv, 0, sizeof(*hpriv));
+
+ probe_ent->sht = mv_port_info[board_idx].sht;
+ probe_ent->port_flags = mv_port_info[board_idx].flags;
+ probe_ent->pio_mask = mv_port_info[board_idx].pio_mask;
+ probe_ent->udma_mask = mv_port_info[board_idx].udma_mask;
+ probe_ent->port_ops = mv_port_info[board_idx].port_ops;
+
+ probe_ent->irq = pdev->irq;
+ probe_ent->irq_flags = IRQF_SHARED;
+ probe_ent->mmio_base = mmio_base;
+ probe_ent->private_data = hpriv;
+
+ /* initialize adapter */
+ rc = mv_init_host(pdev, probe_ent, board_idx);
+ if (rc) {
+ goto err_out_hpriv;
+ }
+
+ /* Enable interrupts */
+ if (msi && pci_enable_msi(pdev) == 0) {
+ hpriv->hp_flags |= MV_HP_FLAG_MSI;
+ } else {
+ pci_intx(pdev, 1);
+ }
+
+ mv_dump_pci_cfg(pdev, 0x68);
+ mv_print_info(probe_ent);
+
+ if (ata_device_add(probe_ent) == 0) {
+ rc = -ENODEV; /* No devices discovered */
+ goto err_out_dev_add;
+ }
+
+ kfree(probe_ent);
+ return 0;
+
+err_out_dev_add:
+ if (MV_HP_FLAG_MSI & hpriv->hp_flags) {
+ pci_disable_msi(pdev);
+ } else {
+ pci_intx(pdev, 0);
+ }
+err_out_hpriv:
+ kfree(hpriv);
+err_out_iounmap:
+ pci_iounmap(pdev, mmio_base);
+err_out_free_ent:
+ kfree(probe_ent);
+err_out_regions:
+ pci_release_regions(pdev);
+err_out:
+ if (!pci_dev_busy) {
+ pci_disable_device(pdev);
+ }
+
+ return rc;
+}
+
+static int __init mv_init(void)
+{
+ return pci_register_driver(&mv_pci_driver);
+}
+
+static void __exit mv_exit(void)
+{
+ pci_unregister_driver(&mv_pci_driver);
+}
+
+MODULE_AUTHOR("Brett Russ");
+MODULE_DESCRIPTION("SCSI low-level driver for Marvell SATA controllers");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, mv_pci_tbl);
+MODULE_VERSION(DRV_VERSION);
+
+module_param(msi, int, 0444);
+MODULE_PARM_DESC(msi, "Enable use of PCI MSI (0=off, 1=on)");
+
+module_init(mv_init);
+module_exit(mv_exit);
diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c
new file mode 100644
index 00000000000..8cd730fe5dd
--- /dev/null
+++ b/drivers/ata/sata_nv.c
@@ -0,0 +1,595 @@
+/*
+ * sata_nv.c - NVIDIA nForce SATA
+ *
+ * Copyright 2004 NVIDIA Corp. All rights reserved.
+ * Copyright 2004 Andrew Chew
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * libata documentation is available via 'make {ps|pdf}docs',
+ * as Documentation/DocBook/libata.*
+ *
+ * No hardware documentation available outside of NVIDIA.
+ * This driver programs the NVIDIA SATA controller in a similar
+ * fashion as with other PCI IDE BMDMA controllers, with a few
+ * NV-specific details such as register offsets, SATA phy location,
+ * hotplug info, etc.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+
+#define DRV_NAME "sata_nv"
+#define DRV_VERSION "2.0"
+
+enum {
+ NV_PORTS = 2,
+ NV_PIO_MASK = 0x1f,
+ NV_MWDMA_MASK = 0x07,
+ NV_UDMA_MASK = 0x7f,
+ NV_PORT0_SCR_REG_OFFSET = 0x00,
+ NV_PORT1_SCR_REG_OFFSET = 0x40,
+
+ /* INT_STATUS/ENABLE */
+ NV_INT_STATUS = 0x10,
+ NV_INT_ENABLE = 0x11,
+ NV_INT_STATUS_CK804 = 0x440,
+ NV_INT_ENABLE_CK804 = 0x441,
+
+ /* INT_STATUS/ENABLE bits */
+ NV_INT_DEV = 0x01,
+ NV_INT_PM = 0x02,
+ NV_INT_ADDED = 0x04,
+ NV_INT_REMOVED = 0x08,
+
+ NV_INT_PORT_SHIFT = 4, /* each port occupies 4 bits */
+
+ NV_INT_ALL = 0x0f,
+ NV_INT_MASK = NV_INT_DEV |
+ NV_INT_ADDED | NV_INT_REMOVED,
+
+ /* INT_CONFIG */
+ NV_INT_CONFIG = 0x12,
+ NV_INT_CONFIG_METHD = 0x01, // 0 = INT, 1 = SMI
+
+ // For PCI config register 20
+ NV_MCP_SATA_CFG_20 = 0x50,
+ NV_MCP_SATA_CFG_20_SATA_SPACE_EN = 0x04,
+};
+
+static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
+static void nv_ck804_host_stop(struct ata_host *host);
+static irqreturn_t nv_generic_interrupt(int irq, void *dev_instance,
+ struct pt_regs *regs);
+static irqreturn_t nv_nf2_interrupt(int irq, void *dev_instance,
+ struct pt_regs *regs);
+static irqreturn_t nv_ck804_interrupt(int irq, void *dev_instance,
+ struct pt_regs *regs);
+static u32 nv_scr_read (struct ata_port *ap, unsigned int sc_reg);
+static void nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+
+static void nv_nf2_freeze(struct ata_port *ap);
+static void nv_nf2_thaw(struct ata_port *ap);
+static void nv_ck804_freeze(struct ata_port *ap);
+static void nv_ck804_thaw(struct ata_port *ap);
+static void nv_error_handler(struct ata_port *ap);
+
+enum nv_host_type
+{
+ GENERIC,
+ NFORCE2,
+ NFORCE3 = NFORCE2, /* NF2 == NF3 as far as sata_nv is concerned */
+ CK804
+};
+
+static const struct pci_device_id nv_pci_tbl[] = {
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_SATA,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, NFORCE2 },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, NFORCE3 },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA2,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, NFORCE3 },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, CK804 },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA2,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, CK804 },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, CK804 },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA2,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, CK804 },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA2,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA2,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA2,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA3,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
+ { PCI_VENDOR_ID_NVIDIA, 0x045c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
+ { PCI_VENDOR_ID_NVIDIA, 0x045d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
+ { PCI_VENDOR_ID_NVIDIA, 0x045e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
+ { PCI_VENDOR_ID_NVIDIA, 0x045f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
+ { PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID,
+ PCI_ANY_ID, PCI_ANY_ID,
+ PCI_CLASS_STORAGE_IDE<<8, 0xffff00, GENERIC },
+ { PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID,
+ PCI_ANY_ID, PCI_ANY_ID,
+ PCI_CLASS_STORAGE_RAID<<8, 0xffff00, GENERIC },
+ { 0, } /* terminate list */
+};
+
+static struct pci_driver nv_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = nv_pci_tbl,
+ .probe = nv_init_one,
+ .remove = ata_pci_remove_one,
+};
+
+static struct scsi_host_template nv_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .slave_destroy = ata_scsi_slave_destroy,
+ .bios_param = ata_std_bios_param,
+};
+
+static const struct ata_port_operations nv_generic_ops = {
+ .port_disable = ata_port_disable,
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .exec_command = ata_exec_command,
+ .check_status = ata_check_status,
+ .dev_select = ata_std_dev_select,
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = nv_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .data_xfer = ata_pio_data_xfer,
+ .irq_handler = nv_generic_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+ .scr_read = nv_scr_read,
+ .scr_write = nv_scr_write,
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_pci_host_stop,
+};
+
+static const struct ata_port_operations nv_nf2_ops = {
+ .port_disable = ata_port_disable,
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .exec_command = ata_exec_command,
+ .check_status = ata_check_status,
+ .dev_select = ata_std_dev_select,
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+ .freeze = nv_nf2_freeze,
+ .thaw = nv_nf2_thaw,
+ .error_handler = nv_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .data_xfer = ata_pio_data_xfer,
+ .irq_handler = nv_nf2_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+ .scr_read = nv_scr_read,
+ .scr_write = nv_scr_write,
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_pci_host_stop,
+};
+
+static const struct ata_port_operations nv_ck804_ops = {
+ .port_disable = ata_port_disable,
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .exec_command = ata_exec_command,
+ .check_status = ata_check_status,
+ .dev_select = ata_std_dev_select,
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+ .freeze = nv_ck804_freeze,
+ .thaw = nv_ck804_thaw,
+ .error_handler = nv_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .data_xfer = ata_pio_data_xfer,
+ .irq_handler = nv_ck804_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+ .scr_read = nv_scr_read,
+ .scr_write = nv_scr_write,
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = nv_ck804_host_stop,
+};
+
+static struct ata_port_info nv_port_info[] = {
+ /* generic */
+ {
+ .sht = &nv_sht,
+ .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
+ .pio_mask = NV_PIO_MASK,
+ .mwdma_mask = NV_MWDMA_MASK,
+ .udma_mask = NV_UDMA_MASK,
+ .port_ops = &nv_generic_ops,
+ },
+ /* nforce2/3 */
+ {
+ .sht = &nv_sht,
+ .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
+ .pio_mask = NV_PIO_MASK,
+ .mwdma_mask = NV_MWDMA_MASK,
+ .udma_mask = NV_UDMA_MASK,
+ .port_ops = &nv_nf2_ops,
+ },
+ /* ck804 */
+ {
+ .sht = &nv_sht,
+ .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
+ .pio_mask = NV_PIO_MASK,
+ .mwdma_mask = NV_MWDMA_MASK,
+ .udma_mask = NV_UDMA_MASK,
+ .port_ops = &nv_ck804_ops,
+ },
+};
+
+MODULE_AUTHOR("NVIDIA");
+MODULE_DESCRIPTION("low-level driver for NVIDIA nForce SATA controller");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, nv_pci_tbl);
+MODULE_VERSION(DRV_VERSION);
+
+static irqreturn_t nv_generic_interrupt(int irq, void *dev_instance,
+ struct pt_regs *regs)
+{
+ struct ata_host *host = dev_instance;
+ unsigned int i;
+ unsigned int handled = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&host->lock, flags);
+
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap;
+
+ ap = host->ports[i];
+ if (ap &&
+ !(ap->flags & ATA_FLAG_DISABLED)) {
+ struct ata_queued_cmd *qc;
+
+ qc = ata_qc_from_tag(ap, ap->active_tag);
+ if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)))
+ handled += ata_host_intr(ap, qc);
+ else
+ // No request pending? Clear interrupt status
+ // anyway, in case there's one pending.
+ ap->ops->check_status(ap);
+ }
+
+ }
+
+ spin_unlock_irqrestore(&host->lock, flags);
+
+ return IRQ_RETVAL(handled);
+}
+
+static int nv_host_intr(struct ata_port *ap, u8 irq_stat)
+{
+ struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag);
+ int handled;
+
+ /* freeze if hotplugged */
+ if (unlikely(irq_stat & (NV_INT_ADDED | NV_INT_REMOVED))) {
+ ata_port_freeze(ap);
+ return 1;
+ }
+
+ /* bail out if not our interrupt */
+ if (!(irq_stat & NV_INT_DEV))
+ return 0;
+
+ /* DEV interrupt w/ no active qc? */
+ if (unlikely(!qc || (qc->tf.flags & ATA_TFLAG_POLLING))) {
+ ata_check_status(ap);
+ return 1;
+ }
+
+ /* handle interrupt */
+ handled = ata_host_intr(ap, qc);
+ if (unlikely(!handled)) {
+ /* spurious, clear it */
+ ata_check_status(ap);
+ }
+
+ return 1;
+}
+
+static irqreturn_t nv_do_interrupt(struct ata_host *host, u8 irq_stat)
+{
+ int i, handled = 0;
+
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap = host->ports[i];
+
+ if (ap && !(ap->flags & ATA_FLAG_DISABLED))
+ handled += nv_host_intr(ap, irq_stat);
+
+ irq_stat >>= NV_INT_PORT_SHIFT;
+ }
+
+ return IRQ_RETVAL(handled);
+}
+
+static irqreturn_t nv_nf2_interrupt(int irq, void *dev_instance,
+ struct pt_regs *regs)
+{
+ struct ata_host *host = dev_instance;
+ u8 irq_stat;
+ irqreturn_t ret;
+
+ spin_lock(&host->lock);
+ irq_stat = inb(host->ports[0]->ioaddr.scr_addr + NV_INT_STATUS);
+ ret = nv_do_interrupt(host, irq_stat);
+ spin_unlock(&host->lock);
+
+ return ret;
+}
+
+static irqreturn_t nv_ck804_interrupt(int irq, void *dev_instance,
+ struct pt_regs *regs)
+{
+ struct ata_host *host = dev_instance;
+ u8 irq_stat;
+ irqreturn_t ret;
+
+ spin_lock(&host->lock);
+ irq_stat = readb(host->mmio_base + NV_INT_STATUS_CK804);
+ ret = nv_do_interrupt(host, irq_stat);
+ spin_unlock(&host->lock);
+
+ return ret;
+}
+
+static u32 nv_scr_read (struct ata_port *ap, unsigned int sc_reg)
+{
+ if (sc_reg > SCR_CONTROL)
+ return 0xffffffffU;
+
+ return ioread32((void __iomem *)ap->ioaddr.scr_addr + (sc_reg * 4));
+}
+
+static void nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
+{
+ if (sc_reg > SCR_CONTROL)
+ return;
+
+ iowrite32(val, (void __iomem *)ap->ioaddr.scr_addr + (sc_reg * 4));
+}
+
+static void nv_nf2_freeze(struct ata_port *ap)
+{
+ unsigned long scr_addr = ap->host->ports[0]->ioaddr.scr_addr;
+ int shift = ap->port_no * NV_INT_PORT_SHIFT;
+ u8 mask;
+
+ mask = inb(scr_addr + NV_INT_ENABLE);
+ mask &= ~(NV_INT_ALL << shift);
+ outb(mask, scr_addr + NV_INT_ENABLE);
+}
+
+static void nv_nf2_thaw(struct ata_port *ap)
+{
+ unsigned long scr_addr = ap->host->ports[0]->ioaddr.scr_addr;
+ int shift = ap->port_no * NV_INT_PORT_SHIFT;
+ u8 mask;
+
+ outb(NV_INT_ALL << shift, scr_addr + NV_INT_STATUS);
+
+ mask = inb(scr_addr + NV_INT_ENABLE);
+ mask |= (NV_INT_MASK << shift);
+ outb(mask, scr_addr + NV_INT_ENABLE);
+}
+
+static void nv_ck804_freeze(struct ata_port *ap)
+{
+ void __iomem *mmio_base = ap->host->mmio_base;
+ int shift = ap->port_no * NV_INT_PORT_SHIFT;
+ u8 mask;
+
+ mask = readb(mmio_base + NV_INT_ENABLE_CK804);
+ mask &= ~(NV_INT_ALL << shift);
+ writeb(mask, mmio_base + NV_INT_ENABLE_CK804);
+}
+
+static void nv_ck804_thaw(struct ata_port *ap)
+{
+ void __iomem *mmio_base = ap->host->mmio_base;
+ int shift = ap->port_no * NV_INT_PORT_SHIFT;
+ u8 mask;
+
+ writeb(NV_INT_ALL << shift, mmio_base + NV_INT_STATUS_CK804);
+
+ mask = readb(mmio_base + NV_INT_ENABLE_CK804);
+ mask |= (NV_INT_MASK << shift);
+ writeb(mask, mmio_base + NV_INT_ENABLE_CK804);
+}
+
+static int nv_hardreset(struct ata_port *ap, unsigned int *class)
+{
+ unsigned int dummy;
+
+ /* SATA hardreset fails to retrieve proper device signature on
+ * some controllers. Don't classify on hardreset. For more
+ * info, see http://bugme.osdl.org/show_bug.cgi?id=3352
+ */
+ return sata_std_hardreset(ap, &dummy);
+}
+
+static void nv_error_handler(struct ata_port *ap)
+{
+ ata_bmdma_drive_eh(ap, ata_std_prereset, ata_std_softreset,
+ nv_hardreset, ata_std_postreset);
+}
+
+static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ static int printed_version = 0;
+ struct ata_port_info *ppi[2];
+ struct ata_probe_ent *probe_ent;
+ int pci_dev_busy = 0;
+ int rc;
+ u32 bar;
+ unsigned long base;
+
+ // Make sure this is a SATA controller by counting the number of bars
+ // (NVIDIA SATA controllers will always have six bars). Otherwise,
+ // it's an IDE controller and we ignore it.
+ for (bar=0; bar<6; bar++)
+ if (pci_resource_start(pdev, bar) == 0)
+ return -ENODEV;
+
+ if (!printed_version++)
+ dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
+
+ rc = pci_enable_device(pdev);
+ if (rc)
+ goto err_out;
+
+ rc = pci_request_regions(pdev, DRV_NAME);
+ if (rc) {
+ pci_dev_busy = 1;
+ goto err_out_disable;
+ }
+
+ rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
+ if (rc)
+ goto err_out_regions;
+ rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
+ if (rc)
+ goto err_out_regions;
+
+ rc = -ENOMEM;
+
+ ppi[0] = ppi[1] = &nv_port_info[ent->driver_data];
+ probe_ent = ata_pci_init_native_mode(pdev, ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY);
+ if (!probe_ent)
+ goto err_out_regions;
+
+ probe_ent->mmio_base = pci_iomap(pdev, 5, 0);
+ if (!probe_ent->mmio_base) {
+ rc = -EIO;
+ goto err_out_free_ent;
+ }
+
+ base = (unsigned long)probe_ent->mmio_base;
+
+ probe_ent->port[0].scr_addr = base + NV_PORT0_SCR_REG_OFFSET;
+ probe_ent->port[1].scr_addr = base + NV_PORT1_SCR_REG_OFFSET;
+
+ /* enable SATA space for CK804 */
+ if (ent->driver_data == CK804) {
+ u8 regval;
+
+ pci_read_config_byte(pdev, NV_MCP_SATA_CFG_20, &regval);
+ regval |= NV_MCP_SATA_CFG_20_SATA_SPACE_EN;
+ pci_write_config_byte(pdev, NV_MCP_SATA_CFG_20, regval);
+ }
+
+ pci_set_master(pdev);
+
+ rc = ata_device_add(probe_ent);
+ if (rc != NV_PORTS)
+ goto err_out_iounmap;
+
+ kfree(probe_ent);
+
+ return 0;
+
+err_out_iounmap:
+ pci_iounmap(pdev, probe_ent->mmio_base);
+err_out_free_ent:
+ kfree(probe_ent);
+err_out_regions:
+ pci_release_regions(pdev);
+err_out_disable:
+ if (!pci_dev_busy)
+ pci_disable_device(pdev);
+err_out:
+ return rc;
+}
+
+static void nv_ck804_host_stop(struct ata_host *host)
+{
+ struct pci_dev *pdev = to_pci_dev(host->dev);
+ u8 regval;
+
+ /* disable SATA space for CK804 */
+ pci_read_config_byte(pdev, NV_MCP_SATA_CFG_20, &regval);
+ regval &= ~NV_MCP_SATA_CFG_20_SATA_SPACE_EN;
+ pci_write_config_byte(pdev, NV_MCP_SATA_CFG_20, regval);
+
+ ata_pci_host_stop(host);
+}
+
+static int __init nv_init(void)
+{
+ return pci_register_driver(&nv_pci_driver);
+}
+
+static void __exit nv_exit(void)
+{
+ pci_unregister_driver(&nv_pci_driver);
+}
+
+module_init(nv_init);
+module_exit(nv_exit);
diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c
new file mode 100644
index 00000000000..d627812ea73
--- /dev/null
+++ b/drivers/ata/sata_promise.c
@@ -0,0 +1,844 @@
+/*
+ * sata_promise.c - Promise SATA
+ *
+ * Maintained by: Jeff Garzik <jgarzik@pobox.com>
+ * Please ALWAYS copy linux-ide@vger.kernel.org
+ * on emails.
+ *
+ * Copyright 2003-2004 Red Hat, Inc.
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * libata documentation is available via 'make {ps|pdf}docs',
+ * as Documentation/DocBook/libata.*
+ *
+ * Hardware information only available under NDA.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/device.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_cmnd.h>
+#include <linux/libata.h>
+#include <asm/io.h>
+#include "sata_promise.h"
+
+#define DRV_NAME "sata_promise"
+#define DRV_VERSION "1.04"
+
+
+enum {
+ PDC_PKT_SUBMIT = 0x40, /* Command packet pointer addr */
+ PDC_INT_SEQMASK = 0x40, /* Mask of asserted SEQ INTs */
+ PDC_TBG_MODE = 0x41, /* TBG mode */
+ PDC_FLASH_CTL = 0x44, /* Flash control register */
+ PDC_PCI_CTL = 0x48, /* PCI control and status register */
+ PDC_GLOBAL_CTL = 0x48, /* Global control/status (per port) */
+ PDC_CTLSTAT = 0x60, /* IDE control and status (per port) */
+ PDC_SATA_PLUG_CSR = 0x6C, /* SATA Plug control/status reg */
+ PDC2_SATA_PLUG_CSR = 0x60, /* SATAII Plug control/status reg */
+ PDC_SLEW_CTL = 0x470, /* slew rate control reg */
+
+ PDC_ERR_MASK = (1<<19) | (1<<20) | (1<<21) | (1<<22) |
+ (1<<8) | (1<<9) | (1<<10),
+
+ board_2037x = 0, /* FastTrak S150 TX2plus */
+ board_20319 = 1, /* FastTrak S150 TX4 */
+ board_20619 = 2, /* FastTrak TX4000 */
+ board_20771 = 3, /* FastTrak TX2300 */
+ board_2057x = 4, /* SATAII150 Tx2plus */
+ board_40518 = 5, /* SATAII150 Tx4 */
+
+ PDC_HAS_PATA = (1 << 1), /* PDC20375/20575 has PATA */
+
+ PDC_RESET = (1 << 11), /* HDMA reset */
+
+ PDC_COMMON_FLAGS = ATA_FLAG_NO_LEGACY | ATA_FLAG_SRST |
+ ATA_FLAG_MMIO | ATA_FLAG_NO_ATAPI |
+ ATA_FLAG_PIO_POLLING,
+};
+
+
+struct pdc_port_priv {
+ u8 *pkt;
+ dma_addr_t pkt_dma;
+};
+
+struct pdc_host_priv {
+ int hotplug_offset;
+};
+
+static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg);
+static void pdc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
+static irqreturn_t pdc_interrupt (int irq, void *dev_instance, struct pt_regs *regs);
+static void pdc_eng_timeout(struct ata_port *ap);
+static int pdc_port_start(struct ata_port *ap);
+static void pdc_port_stop(struct ata_port *ap);
+static void pdc_pata_phy_reset(struct ata_port *ap);
+static void pdc_sata_phy_reset(struct ata_port *ap);
+static void pdc_qc_prep(struct ata_queued_cmd *qc);
+static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf);
+static void pdc_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf);
+static void pdc_irq_clear(struct ata_port *ap);
+static unsigned int pdc_qc_issue_prot(struct ata_queued_cmd *qc);
+static void pdc_host_stop(struct ata_host *host);
+
+
+static struct scsi_host_template pdc_ata_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .slave_destroy = ata_scsi_slave_destroy,
+ .bios_param = ata_std_bios_param,
+};
+
+static const struct ata_port_operations pdc_sata_ops = {
+ .port_disable = ata_port_disable,
+ .tf_load = pdc_tf_load_mmio,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = pdc_exec_command_mmio,
+ .dev_select = ata_std_dev_select,
+
+ .phy_reset = pdc_sata_phy_reset,
+
+ .qc_prep = pdc_qc_prep,
+ .qc_issue = pdc_qc_issue_prot,
+ .eng_timeout = pdc_eng_timeout,
+ .data_xfer = ata_mmio_data_xfer,
+ .irq_handler = pdc_interrupt,
+ .irq_clear = pdc_irq_clear,
+
+ .scr_read = pdc_sata_scr_read,
+ .scr_write = pdc_sata_scr_write,
+ .port_start = pdc_port_start,
+ .port_stop = pdc_port_stop,
+ .host_stop = pdc_host_stop,
+};
+
+static const struct ata_port_operations pdc_pata_ops = {
+ .port_disable = ata_port_disable,
+ .tf_load = pdc_tf_load_mmio,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = pdc_exec_command_mmio,
+ .dev_select = ata_std_dev_select,
+
+ .phy_reset = pdc_pata_phy_reset,
+
+ .qc_prep = pdc_qc_prep,
+ .qc_issue = pdc_qc_issue_prot,
+ .data_xfer = ata_mmio_data_xfer,
+ .eng_timeout = pdc_eng_timeout,
+ .irq_handler = pdc_interrupt,
+ .irq_clear = pdc_irq_clear,
+
+ .port_start = pdc_port_start,
+ .port_stop = pdc_port_stop,
+ .host_stop = pdc_host_stop,
+};
+
+static const struct ata_port_info pdc_port_info[] = {
+ /* board_2037x */
+ {
+ .sht = &pdc_ata_sht,
+ .flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .mwdma_mask = 0x07, /* mwdma0-2 */
+ .udma_mask = 0x7f, /* udma0-6 ; FIXME */
+ .port_ops = &pdc_sata_ops,
+ },
+
+ /* board_20319 */
+ {
+ .sht = &pdc_ata_sht,
+ .flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .mwdma_mask = 0x07, /* mwdma0-2 */
+ .udma_mask = 0x7f, /* udma0-6 ; FIXME */
+ .port_ops = &pdc_sata_ops,
+ },
+
+ /* board_20619 */
+ {
+ .sht = &pdc_ata_sht,
+ .flags = PDC_COMMON_FLAGS | ATA_FLAG_SLAVE_POSS,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .mwdma_mask = 0x07, /* mwdma0-2 */
+ .udma_mask = 0x7f, /* udma0-6 ; FIXME */
+ .port_ops = &pdc_pata_ops,
+ },
+
+ /* board_20771 */
+ {
+ .sht = &pdc_ata_sht,
+ .flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .mwdma_mask = 0x07, /* mwdma0-2 */
+ .udma_mask = 0x7f, /* udma0-6 ; FIXME */
+ .port_ops = &pdc_sata_ops,
+ },
+
+ /* board_2057x */
+ {
+ .sht = &pdc_ata_sht,
+ .flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .mwdma_mask = 0x07, /* mwdma0-2 */
+ .udma_mask = 0x7f, /* udma0-6 ; FIXME */
+ .port_ops = &pdc_sata_ops,
+ },
+
+ /* board_40518 */
+ {
+ .sht = &pdc_ata_sht,
+ .flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .mwdma_mask = 0x07, /* mwdma0-2 */
+ .udma_mask = 0x7f, /* udma0-6 ; FIXME */
+ .port_ops = &pdc_sata_ops,
+ },
+};
+
+static const struct pci_device_id pdc_ata_pci_tbl[] = {
+ { PCI_VENDOR_ID_PROMISE, 0x3371, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ board_2037x },
+ { PCI_VENDOR_ID_PROMISE, 0x3570, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ board_2037x },
+ { PCI_VENDOR_ID_PROMISE, 0x3571, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ board_2037x },
+ { PCI_VENDOR_ID_PROMISE, 0x3373, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ board_2037x },
+ { PCI_VENDOR_ID_PROMISE, 0x3375, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ board_2037x },
+ { PCI_VENDOR_ID_PROMISE, 0x3376, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ board_2037x },
+ { PCI_VENDOR_ID_PROMISE, 0x3574, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ board_2057x },
+ { PCI_VENDOR_ID_PROMISE, 0x3d75, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ board_2057x },
+ { PCI_VENDOR_ID_PROMISE, 0x3d73, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ board_2037x },
+
+ { PCI_VENDOR_ID_PROMISE, 0x3318, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ board_20319 },
+ { PCI_VENDOR_ID_PROMISE, 0x3319, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ board_20319 },
+ { PCI_VENDOR_ID_PROMISE, 0x3515, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ board_20319 },
+ { PCI_VENDOR_ID_PROMISE, 0x3519, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ board_20319 },
+ { PCI_VENDOR_ID_PROMISE, 0x3d17, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ board_20319 },
+ { PCI_VENDOR_ID_PROMISE, 0x3d18, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ board_40518 },
+
+ { PCI_VENDOR_ID_PROMISE, 0x6629, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ board_20619 },
+
+/* TODO: remove all associated board_20771 code, as it completely
+ * duplicates board_2037x code, unless reason for separation can be
+ * divined.
+ */
+#if 0
+ { PCI_VENDOR_ID_PROMISE, 0x3570, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ board_20771 },
+#endif
+
+ { } /* terminate list */
+};
+
+
+static struct pci_driver pdc_ata_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = pdc_ata_pci_tbl,
+ .probe = pdc_ata_init_one,
+ .remove = ata_pci_remove_one,
+};
+
+
+static int pdc_port_start(struct ata_port *ap)
+{
+ struct device *dev = ap->host->dev;
+ struct pdc_port_priv *pp;
+ int rc;
+
+ rc = ata_port_start(ap);
+ if (rc)
+ return rc;
+
+ pp = kzalloc(sizeof(*pp), GFP_KERNEL);
+ if (!pp) {
+ rc = -ENOMEM;
+ goto err_out;
+ }
+
+ pp->pkt = dma_alloc_coherent(dev, 128, &pp->pkt_dma, GFP_KERNEL);
+ if (!pp->pkt) {
+ rc = -ENOMEM;
+ goto err_out_kfree;
+ }
+
+ ap->private_data = pp;
+
+ return 0;
+
+err_out_kfree:
+ kfree(pp);
+err_out:
+ ata_port_stop(ap);
+ return rc;
+}
+
+
+static void pdc_port_stop(struct ata_port *ap)
+{
+ struct device *dev = ap->host->dev;
+ struct pdc_port_priv *pp = ap->private_data;
+
+ ap->private_data = NULL;
+ dma_free_coherent(dev, 128, pp->pkt, pp->pkt_dma);
+ kfree(pp);
+ ata_port_stop(ap);
+}
+
+
+static void pdc_host_stop(struct ata_host *host)
+{
+ struct pdc_host_priv *hp = host->private_data;
+
+ ata_pci_host_stop(host);
+
+ kfree(hp);
+}
+
+
+static void pdc_reset_port(struct ata_port *ap)
+{
+ void __iomem *mmio = (void __iomem *) ap->ioaddr.cmd_addr + PDC_CTLSTAT;
+ unsigned int i;
+ u32 tmp;
+
+ for (i = 11; i > 0; i--) {
+ tmp = readl(mmio);
+ if (tmp & PDC_RESET)
+ break;
+
+ udelay(100);
+
+ tmp |= PDC_RESET;
+ writel(tmp, mmio);
+ }
+
+ tmp &= ~PDC_RESET;
+ writel(tmp, mmio);
+ readl(mmio); /* flush */
+}
+
+static void pdc_sata_phy_reset(struct ata_port *ap)
+{
+ pdc_reset_port(ap);
+ sata_phy_reset(ap);
+}
+
+static void pdc_pata_cbl_detect(struct ata_port *ap)
+{
+ u8 tmp;
+ void __iomem *mmio = (void *) ap->ioaddr.cmd_addr + PDC_CTLSTAT + 0x03;
+
+ tmp = readb(mmio);
+
+ if (tmp & 0x01) {
+ ap->cbl = ATA_CBL_PATA40;
+ ap->udma_mask &= ATA_UDMA_MASK_40C;
+ } else
+ ap->cbl = ATA_CBL_PATA80;
+}
+
+static void pdc_pata_phy_reset(struct ata_port *ap)
+{
+ pdc_pata_cbl_detect(ap);
+ pdc_reset_port(ap);
+ ata_port_probe(ap);
+ ata_bus_reset(ap);
+}
+
+static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg)
+{
+ if (sc_reg > SCR_CONTROL)
+ return 0xffffffffU;
+ return readl((void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4));
+}
+
+
+static void pdc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg,
+ u32 val)
+{
+ if (sc_reg > SCR_CONTROL)
+ return;
+ writel(val, (void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4));
+}
+
+static void pdc_qc_prep(struct ata_queued_cmd *qc)
+{
+ struct pdc_port_priv *pp = qc->ap->private_data;
+ unsigned int i;
+
+ VPRINTK("ENTER\n");
+
+ switch (qc->tf.protocol) {
+ case ATA_PROT_DMA:
+ ata_qc_prep(qc);
+ /* fall through */
+
+ case ATA_PROT_NODATA:
+ i = pdc_pkt_header(&qc->tf, qc->ap->prd_dma,
+ qc->dev->devno, pp->pkt);
+
+ if (qc->tf.flags & ATA_TFLAG_LBA48)
+ i = pdc_prep_lba48(&qc->tf, pp->pkt, i);
+ else
+ i = pdc_prep_lba28(&qc->tf, pp->pkt, i);
+
+ pdc_pkt_footer(&qc->tf, pp->pkt, i);
+ break;
+
+ default:
+ break;
+ }
+}
+
+static void pdc_eng_timeout(struct ata_port *ap)
+{
+ struct ata_host *host = ap->host;
+ u8 drv_stat;
+ struct ata_queued_cmd *qc;
+ unsigned long flags;
+
+ DPRINTK("ENTER\n");
+
+ spin_lock_irqsave(&host->lock, flags);
+
+ qc = ata_qc_from_tag(ap, ap->active_tag);
+
+ switch (qc->tf.protocol) {
+ case ATA_PROT_DMA:
+ case ATA_PROT_NODATA:
+ ata_port_printk(ap, KERN_ERR, "command timeout\n");
+ drv_stat = ata_wait_idle(ap);
+ qc->err_mask |= __ac_err_mask(drv_stat);
+ break;
+
+ default:
+ drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000);
+
+ ata_port_printk(ap, KERN_ERR,
+ "unknown timeout, cmd 0x%x stat 0x%x\n",
+ qc->tf.command, drv_stat);
+
+ qc->err_mask |= ac_err_mask(drv_stat);
+ break;
+ }
+
+ spin_unlock_irqrestore(&host->lock, flags);
+ ata_eh_qc_complete(qc);
+ DPRINTK("EXIT\n");
+}
+
+static inline unsigned int pdc_host_intr( struct ata_port *ap,
+ struct ata_queued_cmd *qc)
+{
+ unsigned int handled = 0;
+ u32 tmp;
+ void __iomem *mmio = (void __iomem *) ap->ioaddr.cmd_addr + PDC_GLOBAL_CTL;
+
+ tmp = readl(mmio);
+ if (tmp & PDC_ERR_MASK) {
+ qc->err_mask |= AC_ERR_DEV;
+ pdc_reset_port(ap);
+ }
+
+ switch (qc->tf.protocol) {
+ case ATA_PROT_DMA:
+ case ATA_PROT_NODATA:
+ qc->err_mask |= ac_err_mask(ata_wait_idle(ap));
+ ata_qc_complete(qc);
+ handled = 1;
+ break;
+
+ default:
+ ap->stats.idle_irq++;
+ break;
+ }
+
+ return handled;
+}
+
+static void pdc_irq_clear(struct ata_port *ap)
+{
+ struct ata_host *host = ap->host;
+ void __iomem *mmio = host->mmio_base;
+
+ readl(mmio + PDC_INT_SEQMASK);
+}
+
+static irqreturn_t pdc_interrupt (int irq, void *dev_instance, struct pt_regs *regs)
+{
+ struct ata_host *host = dev_instance;
+ struct ata_port *ap;
+ u32 mask = 0;
+ unsigned int i, tmp;
+ unsigned int handled = 0;
+ void __iomem *mmio_base;
+
+ VPRINTK("ENTER\n");
+
+ if (!host || !host->mmio_base) {
+ VPRINTK("QUICK EXIT\n");
+ return IRQ_NONE;
+ }
+
+ mmio_base = host->mmio_base;
+
+ /* reading should also clear interrupts */
+ mask = readl(mmio_base + PDC_INT_SEQMASK);
+
+ if (mask == 0xffffffff) {
+ VPRINTK("QUICK EXIT 2\n");
+ return IRQ_NONE;
+ }
+
+ spin_lock(&host->lock);
+
+ mask &= 0xffff; /* only 16 tags possible */
+ if (!mask) {
+ VPRINTK("QUICK EXIT 3\n");
+ goto done_irq;
+ }
+
+ writel(mask, mmio_base + PDC_INT_SEQMASK);
+
+ for (i = 0; i < host->n_ports; i++) {
+ VPRINTK("port %u\n", i);
+ ap = host->ports[i];
+ tmp = mask & (1 << (i + 1));
+ if (tmp && ap &&
+ !(ap->flags & ATA_FLAG_DISABLED)) {
+ struct ata_queued_cmd *qc;
+
+ qc = ata_qc_from_tag(ap, ap->active_tag);
+ if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)))
+ handled += pdc_host_intr(ap, qc);
+ }
+ }
+
+ VPRINTK("EXIT\n");
+
+done_irq:
+ spin_unlock(&host->lock);
+ return IRQ_RETVAL(handled);
+}
+
+static inline void pdc_packet_start(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct pdc_port_priv *pp = ap->private_data;
+ unsigned int port_no = ap->port_no;
+ u8 seq = (u8) (port_no + 1);
+
+ VPRINTK("ENTER, ap %p\n", ap);
+
+ writel(0x00000001, ap->host->mmio_base + (seq * 4));
+ readl(ap->host->mmio_base + (seq * 4)); /* flush */
+
+ pp->pkt[2] = seq;
+ wmb(); /* flush PRD, pkt writes */
+ writel(pp->pkt_dma, (void __iomem *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
+ readl((void __iomem *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); /* flush */
+}
+
+static unsigned int pdc_qc_issue_prot(struct ata_queued_cmd *qc)
+{
+ switch (qc->tf.protocol) {
+ case ATA_PROT_DMA:
+ case ATA_PROT_NODATA:
+ pdc_packet_start(qc);
+ return 0;
+
+ case ATA_PROT_ATAPI_DMA:
+ BUG();
+ break;
+
+ default:
+ break;
+ }
+
+ return ata_qc_issue_prot(qc);
+}
+
+static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf)
+{
+ WARN_ON (tf->protocol == ATA_PROT_DMA ||
+ tf->protocol == ATA_PROT_NODATA);
+ ata_tf_load(ap, tf);
+}
+
+
+static void pdc_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf)
+{
+ WARN_ON (tf->protocol == ATA_PROT_DMA ||
+ tf->protocol == ATA_PROT_NODATA);
+ ata_exec_command(ap, tf);
+}
+
+
+static void pdc_ata_setup_port(struct ata_ioports *port, unsigned long base)
+{
+ port->cmd_addr = base;
+ port->data_addr = base;
+ port->feature_addr =
+ port->error_addr = base + 0x4;
+ port->nsect_addr = base + 0x8;
+ port->lbal_addr = base + 0xc;
+ port->lbam_addr = base + 0x10;
+ port->lbah_addr = base + 0x14;
+ port->device_addr = base + 0x18;
+ port->command_addr =
+ port->status_addr = base + 0x1c;
+ port->altstatus_addr =
+ port->ctl_addr = base + 0x38;
+}
+
+
+static void pdc_host_init(unsigned int chip_id, struct ata_probe_ent *pe)
+{
+ void __iomem *mmio = pe->mmio_base;
+ struct pdc_host_priv *hp = pe->private_data;
+ int hotplug_offset = hp->hotplug_offset;
+ u32 tmp;
+
+ /*
+ * Except for the hotplug stuff, this is voodoo from the
+ * Promise driver. Label this entire section
+ * "TODO: figure out why we do this"
+ */
+
+ /* change FIFO_SHD to 8 dwords, enable BMR_BURST */
+ tmp = readl(mmio + PDC_FLASH_CTL);
+ tmp |= 0x12000; /* bit 16 (fifo 8 dw) and 13 (bmr burst?) */
+ writel(tmp, mmio + PDC_FLASH_CTL);
+
+ /* clear plug/unplug flags for all ports */
+ tmp = readl(mmio + hotplug_offset);
+ writel(tmp | 0xff, mmio + hotplug_offset);
+
+ /* mask plug/unplug ints */
+ tmp = readl(mmio + hotplug_offset);
+ writel(tmp | 0xff0000, mmio + hotplug_offset);
+
+ /* reduce TBG clock to 133 Mhz. */
+ tmp = readl(mmio + PDC_TBG_MODE);
+ tmp &= ~0x30000; /* clear bit 17, 16*/
+ tmp |= 0x10000; /* set bit 17:16 = 0:1 */
+ writel(tmp, mmio + PDC_TBG_MODE);
+
+ readl(mmio + PDC_TBG_MODE); /* flush */
+ msleep(10);
+
+ /* adjust slew rate control register. */
+ tmp = readl(mmio + PDC_SLEW_CTL);
+ tmp &= 0xFFFFF03F; /* clear bit 11 ~ 6 */
+ tmp |= 0x00000900; /* set bit 11-9 = 100b , bit 8-6 = 100 */
+ writel(tmp, mmio + PDC_SLEW_CTL);
+}
+
+static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ static int printed_version;
+ struct ata_probe_ent *probe_ent = NULL;
+ struct pdc_host_priv *hp;
+ unsigned long base;
+ void __iomem *mmio_base;
+ unsigned int board_idx = (unsigned int) ent->driver_data;
+ int pci_dev_busy = 0;
+ int rc;
+
+ if (!printed_version++)
+ dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
+
+ rc = pci_enable_device(pdev);
+ if (rc)
+ return rc;
+
+ rc = pci_request_regions(pdev, DRV_NAME);
+ if (rc) {
+ pci_dev_busy = 1;
+ goto err_out;
+ }
+
+ rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
+ if (rc)
+ goto err_out_regions;
+ rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
+ if (rc)
+ goto err_out_regions;
+
+ probe_ent = kzalloc(sizeof(*probe_ent), GFP_KERNEL);
+ if (probe_ent == NULL) {
+ rc = -ENOMEM;
+ goto err_out_regions;
+ }
+
+ probe_ent->dev = pci_dev_to_dev(pdev);
+ INIT_LIST_HEAD(&probe_ent->node);
+
+ mmio_base = pci_iomap(pdev, 3, 0);
+ if (mmio_base == NULL) {
+ rc = -ENOMEM;
+ goto err_out_free_ent;
+ }
+ base = (unsigned long) mmio_base;
+
+ hp = kzalloc(sizeof(*hp), GFP_KERNEL);
+ if (hp == NULL) {
+ rc = -ENOMEM;
+ goto err_out_free_ent;
+ }
+
+ /* Set default hotplug offset */
+ hp->hotplug_offset = PDC_SATA_PLUG_CSR;
+ probe_ent->private_data = hp;
+
+ probe_ent->sht = pdc_port_info[board_idx].sht;
+ probe_ent->port_flags = pdc_port_info[board_idx].flags;
+ probe_ent->pio_mask = pdc_port_info[board_idx].pio_mask;
+ probe_ent->mwdma_mask = pdc_port_info[board_idx].mwdma_mask;
+ probe_ent->udma_mask = pdc_port_info[board_idx].udma_mask;
+ probe_ent->port_ops = pdc_port_info[board_idx].port_ops;
+
+ probe_ent->irq = pdev->irq;
+ probe_ent->irq_flags = IRQF_SHARED;
+ probe_ent->mmio_base = mmio_base;
+
+ pdc_ata_setup_port(&probe_ent->port[0], base + 0x200);
+ pdc_ata_setup_port(&probe_ent->port[1], base + 0x280);
+
+ probe_ent->port[0].scr_addr = base + 0x400;
+ probe_ent->port[1].scr_addr = base + 0x500;
+
+ /* notice 4-port boards */
+ switch (board_idx) {
+ case board_40518:
+ /* Override hotplug offset for SATAII150 */
+ hp->hotplug_offset = PDC2_SATA_PLUG_CSR;
+ /* Fall through */
+ case board_20319:
+ probe_ent->n_ports = 4;
+
+ pdc_ata_setup_port(&probe_ent->port[2], base + 0x300);
+ pdc_ata_setup_port(&probe_ent->port[3], base + 0x380);
+
+ probe_ent->port[2].scr_addr = base + 0x600;
+ probe_ent->port[3].scr_addr = base + 0x700;
+ break;
+ case board_2057x:
+ /* Override hotplug offset for SATAII150 */
+ hp->hotplug_offset = PDC2_SATA_PLUG_CSR;
+ /* Fall through */
+ case board_2037x:
+ probe_ent->n_ports = 2;
+ break;
+ case board_20771:
+ probe_ent->n_ports = 2;
+ break;
+ case board_20619:
+ probe_ent->n_ports = 4;
+
+ pdc_ata_setup_port(&probe_ent->port[2], base + 0x300);
+ pdc_ata_setup_port(&probe_ent->port[3], base + 0x380);
+
+ probe_ent->port[2].scr_addr = base + 0x600;
+ probe_ent->port[3].scr_addr = base + 0x700;
+ break;
+ default:
+ BUG();
+ break;
+ }
+
+ pci_set_master(pdev);
+
+ /* initialize adapter */
+ pdc_host_init(board_idx, probe_ent);
+
+ /* FIXME: Need any other frees than hp? */
+ if (!ata_device_add(probe_ent))
+ kfree(hp);
+
+ kfree(probe_ent);
+
+ return 0;
+
+err_out_free_ent:
+ kfree(probe_ent);
+err_out_regions:
+ pci_release_regions(pdev);
+err_out:
+ if (!pci_dev_busy)
+ pci_disable_device(pdev);
+ return rc;
+}
+
+
+static int __init pdc_ata_init(void)
+{
+ return pci_register_driver(&pdc_ata_pci_driver);
+}
+
+
+static void __exit pdc_ata_exit(void)
+{
+ pci_unregister_driver(&pdc_ata_pci_driver);
+}
+
+
+MODULE_AUTHOR("Jeff Garzik");
+MODULE_DESCRIPTION("Promise ATA TX2/TX4/TX4000 low-level driver");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, pdc_ata_pci_tbl);
+MODULE_VERSION(DRV_VERSION);
+
+module_init(pdc_ata_init);
+module_exit(pdc_ata_exit);
diff --git a/drivers/ata/sata_promise.h b/drivers/ata/sata_promise.h
new file mode 100644
index 00000000000..6ee5e190262
--- /dev/null
+++ b/drivers/ata/sata_promise.h
@@ -0,0 +1,157 @@
+/*
+ * sata_promise.h - Promise SATA common definitions and inline funcs
+ *
+ * Copyright 2003-2004 Red Hat, Inc.
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * libata documentation is available via 'make {ps|pdf}docs',
+ * as Documentation/DocBook/libata.*
+ *
+ */
+
+#ifndef __SATA_PROMISE_H__
+#define __SATA_PROMISE_H__
+
+#include <linux/ata.h>
+
+enum pdc_packet_bits {
+ PDC_PKT_READ = (1 << 2),
+ PDC_PKT_NODATA = (1 << 3),
+
+ PDC_PKT_SIZEMASK = (1 << 7) | (1 << 6) | (1 << 5),
+ PDC_PKT_CLEAR_BSY = (1 << 4),
+ PDC_PKT_WAIT_DRDY = (1 << 3) | (1 << 4),
+ PDC_LAST_REG = (1 << 3),
+
+ PDC_REG_DEVCTL = (1 << 3) | (1 << 2) | (1 << 1),
+};
+
+static inline unsigned int pdc_pkt_header(struct ata_taskfile *tf,
+ dma_addr_t sg_table,
+ unsigned int devno, u8 *buf)
+{
+ u8 dev_reg;
+ u32 *buf32 = (u32 *) buf;
+
+ /* set control bits (byte 0), zero delay seq id (byte 3),
+ * and seq id (byte 2)
+ */
+ switch (tf->protocol) {
+ case ATA_PROT_DMA:
+ if (!(tf->flags & ATA_TFLAG_WRITE))
+ buf32[0] = cpu_to_le32(PDC_PKT_READ);
+ else
+ buf32[0] = 0;
+ break;
+
+ case ATA_PROT_NODATA:
+ buf32[0] = cpu_to_le32(PDC_PKT_NODATA);
+ break;
+
+ default:
+ BUG();
+ break;
+ }
+
+ buf32[1] = cpu_to_le32(sg_table); /* S/G table addr */
+ buf32[2] = 0; /* no next-packet */
+
+ if (devno == 0)
+ dev_reg = ATA_DEVICE_OBS;
+ else
+ dev_reg = ATA_DEVICE_OBS | ATA_DEV1;
+
+ /* select device */
+ buf[12] = (1 << 5) | PDC_PKT_CLEAR_BSY | ATA_REG_DEVICE;
+ buf[13] = dev_reg;
+
+ /* device control register */
+ buf[14] = (1 << 5) | PDC_REG_DEVCTL;
+ buf[15] = tf->ctl;
+
+ return 16; /* offset of next byte */
+}
+
+static inline unsigned int pdc_pkt_footer(struct ata_taskfile *tf, u8 *buf,
+ unsigned int i)
+{
+ if (tf->flags & ATA_TFLAG_DEVICE) {
+ buf[i++] = (1 << 5) | ATA_REG_DEVICE;
+ buf[i++] = tf->device;
+ }
+
+ /* and finally the command itself; also includes end-of-pkt marker */
+ buf[i++] = (1 << 5) | PDC_LAST_REG | ATA_REG_CMD;
+ buf[i++] = tf->command;
+
+ return i;
+}
+
+static inline unsigned int pdc_prep_lba28(struct ata_taskfile *tf, u8 *buf, unsigned int i)
+{
+ /* the "(1 << 5)" should be read "(count << 5)" */
+
+ /* ATA command block registers */
+ buf[i++] = (1 << 5) | ATA_REG_FEATURE;
+ buf[i++] = tf->feature;
+
+ buf[i++] = (1 << 5) | ATA_REG_NSECT;
+ buf[i++] = tf->nsect;
+
+ buf[i++] = (1 << 5) | ATA_REG_LBAL;
+ buf[i++] = tf->lbal;
+
+ buf[i++] = (1 << 5) | ATA_REG_LBAM;
+ buf[i++] = tf->lbam;
+
+ buf[i++] = (1 << 5) | ATA_REG_LBAH;
+ buf[i++] = tf->lbah;
+
+ return i;
+}
+
+static inline unsigned int pdc_prep_lba48(struct ata_taskfile *tf, u8 *buf, unsigned int i)
+{
+ /* the "(2 << 5)" should be read "(count << 5)" */
+
+ /* ATA command block registers */
+ buf[i++] = (2 << 5) | ATA_REG_FEATURE;
+ buf[i++] = tf->hob_feature;
+ buf[i++] = tf->feature;
+
+ buf[i++] = (2 << 5) | ATA_REG_NSECT;
+ buf[i++] = tf->hob_nsect;
+ buf[i++] = tf->nsect;
+
+ buf[i++] = (2 << 5) | ATA_REG_LBAL;
+ buf[i++] = tf->hob_lbal;
+ buf[i++] = tf->lbal;
+
+ buf[i++] = (2 << 5) | ATA_REG_LBAM;
+ buf[i++] = tf->hob_lbam;
+ buf[i++] = tf->lbam;
+
+ buf[i++] = (2 << 5) | ATA_REG_LBAH;
+ buf[i++] = tf->hob_lbah;
+ buf[i++] = tf->lbah;
+
+ return i;
+}
+
+
+#endif /* __SATA_PROMISE_H__ */
diff --git a/drivers/ata/sata_qstor.c b/drivers/ata/sata_qstor.c
new file mode 100644
index 00000000000..fa29dfe2a7b
--- /dev/null
+++ b/drivers/ata/sata_qstor.c
@@ -0,0 +1,730 @@
+/*
+ * sata_qstor.c - Pacific Digital Corporation QStor SATA
+ *
+ * Maintained by: Mark Lord <mlord@pobox.com>
+ *
+ * Copyright 2005 Pacific Digital Corporation.
+ * (OSL/GPL code release authorized by Jalil Fadavi).
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * libata documentation is available via 'make {ps|pdf}docs',
+ * as Documentation/DocBook/libata.*
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/device.h>
+#include <scsi/scsi_host.h>
+#include <asm/io.h>
+#include <linux/libata.h>
+
+#define DRV_NAME "sata_qstor"
+#define DRV_VERSION "0.06"
+
+enum {
+ QS_PORTS = 4,
+ QS_MAX_PRD = LIBATA_MAX_PRD,
+ QS_CPB_ORDER = 6,
+ QS_CPB_BYTES = (1 << QS_CPB_ORDER),
+ QS_PRD_BYTES = QS_MAX_PRD * 16,
+ QS_PKT_BYTES = QS_CPB_BYTES + QS_PRD_BYTES,
+
+ /* global register offsets */
+ QS_HCF_CNFG3 = 0x0003, /* host configuration offset */
+ QS_HID_HPHY = 0x0004, /* host physical interface info */
+ QS_HCT_CTRL = 0x00e4, /* global interrupt mask offset */
+ QS_HST_SFF = 0x0100, /* host status fifo offset */
+ QS_HVS_SERD3 = 0x0393, /* PHY enable offset */
+
+ /* global control bits */
+ QS_HPHY_64BIT = (1 << 1), /* 64-bit bus detected */
+ QS_CNFG3_GSRST = 0x01, /* global chip reset */
+ QS_SERD3_PHY_ENA = 0xf0, /* PHY detection ENAble*/
+
+ /* per-channel register offsets */
+ QS_CCF_CPBA = 0x0710, /* chan CPB base address */
+ QS_CCF_CSEP = 0x0718, /* chan CPB separation factor */
+ QS_CFC_HUFT = 0x0800, /* host upstream fifo threshold */
+ QS_CFC_HDFT = 0x0804, /* host downstream fifo threshold */
+ QS_CFC_DUFT = 0x0808, /* dev upstream fifo threshold */
+ QS_CFC_DDFT = 0x080c, /* dev downstream fifo threshold */
+ QS_CCT_CTR0 = 0x0900, /* chan control-0 offset */
+ QS_CCT_CTR1 = 0x0901, /* chan control-1 offset */
+ QS_CCT_CFF = 0x0a00, /* chan command fifo offset */
+
+ /* channel control bits */
+ QS_CTR0_REG = (1 << 1), /* register mode (vs. pkt mode) */
+ QS_CTR0_CLER = (1 << 2), /* clear channel errors */
+ QS_CTR1_RDEV = (1 << 1), /* sata phy/comms reset */
+ QS_CTR1_RCHN = (1 << 4), /* reset channel logic */
+ QS_CCF_RUN_PKT = 0x107, /* RUN a new dma PKT */
+
+ /* pkt sub-field headers */
+ QS_HCB_HDR = 0x01, /* Host Control Block header */
+ QS_DCB_HDR = 0x02, /* Device Control Block header */
+
+ /* pkt HCB flag bits */
+ QS_HF_DIRO = (1 << 0), /* data DIRection Out */
+ QS_HF_DAT = (1 << 3), /* DATa pkt */
+ QS_HF_IEN = (1 << 4), /* Interrupt ENable */
+ QS_HF_VLD = (1 << 5), /* VaLiD pkt */
+
+ /* pkt DCB flag bits */
+ QS_DF_PORD = (1 << 2), /* Pio OR Dma */
+ QS_DF_ELBA = (1 << 3), /* Extended LBA (lba48) */
+
+ /* PCI device IDs */
+ board_2068_idx = 0, /* QStor 4-port SATA/RAID */
+};
+
+enum {
+ QS_DMA_BOUNDARY = ~0UL
+};
+
+typedef enum { qs_state_idle, qs_state_pkt, qs_state_mmio } qs_state_t;
+
+struct qs_port_priv {
+ u8 *pkt;
+ dma_addr_t pkt_dma;
+ qs_state_t state;
+};
+
+static u32 qs_scr_read (struct ata_port *ap, unsigned int sc_reg);
+static void qs_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int qs_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
+static irqreturn_t qs_intr (int irq, void *dev_instance, struct pt_regs *regs);
+static int qs_port_start(struct ata_port *ap);
+static void qs_host_stop(struct ata_host *host);
+static void qs_port_stop(struct ata_port *ap);
+static void qs_phy_reset(struct ata_port *ap);
+static void qs_qc_prep(struct ata_queued_cmd *qc);
+static unsigned int qs_qc_issue(struct ata_queued_cmd *qc);
+static int qs_check_atapi_dma(struct ata_queued_cmd *qc);
+static void qs_bmdma_stop(struct ata_queued_cmd *qc);
+static u8 qs_bmdma_status(struct ata_port *ap);
+static void qs_irq_clear(struct ata_port *ap);
+static void qs_eng_timeout(struct ata_port *ap);
+
+static struct scsi_host_template qs_ata_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = QS_MAX_PRD,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ //FIXME .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .use_clustering = ENABLE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = QS_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .slave_destroy = ata_scsi_slave_destroy,
+ .bios_param = ata_std_bios_param,
+};
+
+static const struct ata_port_operations qs_ata_ops = {
+ .port_disable = ata_port_disable,
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .check_atapi_dma = qs_check_atapi_dma,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+ .phy_reset = qs_phy_reset,
+ .qc_prep = qs_qc_prep,
+ .qc_issue = qs_qc_issue,
+ .data_xfer = ata_mmio_data_xfer,
+ .eng_timeout = qs_eng_timeout,
+ .irq_handler = qs_intr,
+ .irq_clear = qs_irq_clear,
+ .scr_read = qs_scr_read,
+ .scr_write = qs_scr_write,
+ .port_start = qs_port_start,
+ .port_stop = qs_port_stop,
+ .host_stop = qs_host_stop,
+ .bmdma_stop = qs_bmdma_stop,
+ .bmdma_status = qs_bmdma_status,
+};
+
+static const struct ata_port_info qs_port_info[] = {
+ /* board_2068_idx */
+ {
+ .sht = &qs_ata_sht,
+ .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+ ATA_FLAG_SATA_RESET |
+ //FIXME ATA_FLAG_SRST |
+ ATA_FLAG_MMIO | ATA_FLAG_PIO_POLLING,
+ .pio_mask = 0x10, /* pio4 */
+ .udma_mask = 0x7f, /* udma0-6 */
+ .port_ops = &qs_ata_ops,
+ },
+};
+
+static const struct pci_device_id qs_ata_pci_tbl[] = {
+ { PCI_VENDOR_ID_PDC, 0x2068, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ board_2068_idx },
+
+ { } /* terminate list */
+};
+
+static struct pci_driver qs_ata_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = qs_ata_pci_tbl,
+ .probe = qs_ata_init_one,
+ .remove = ata_pci_remove_one,
+};
+
+static int qs_check_atapi_dma(struct ata_queued_cmd *qc)
+{
+ return 1; /* ATAPI DMA not supported */
+}
+
+static void qs_bmdma_stop(struct ata_queued_cmd *qc)
+{
+ /* nothing */
+}
+
+static u8 qs_bmdma_status(struct ata_port *ap)
+{
+ return 0;
+}
+
+static void qs_irq_clear(struct ata_port *ap)
+{
+ /* nothing */
+}
+
+static inline void qs_enter_reg_mode(struct ata_port *ap)
+{
+ u8 __iomem *chan = ap->host->mmio_base + (ap->port_no * 0x4000);
+
+ writeb(QS_CTR0_REG, chan + QS_CCT_CTR0);
+ readb(chan + QS_CCT_CTR0); /* flush */
+}
+
+static inline void qs_reset_channel_logic(struct ata_port *ap)
+{
+ u8 __iomem *chan = ap->host->mmio_base + (ap->port_no * 0x4000);
+
+ writeb(QS_CTR1_RCHN, chan + QS_CCT_CTR1);
+ readb(chan + QS_CCT_CTR0); /* flush */
+ qs_enter_reg_mode(ap);
+}
+
+static void qs_phy_reset(struct ata_port *ap)
+{
+ struct qs_port_priv *pp = ap->private_data;
+
+ pp->state = qs_state_idle;
+ qs_reset_channel_logic(ap);
+ sata_phy_reset(ap);
+}
+
+static void qs_eng_timeout(struct ata_port *ap)
+{
+ struct qs_port_priv *pp = ap->private_data;
+
+ if (pp->state != qs_state_idle) /* healthy paranoia */
+ pp->state = qs_state_mmio;
+ qs_reset_channel_logic(ap);
+ ata_eng_timeout(ap);
+}
+
+static u32 qs_scr_read (struct ata_port *ap, unsigned int sc_reg)
+{
+ if (sc_reg > SCR_CONTROL)
+ return ~0U;
+ return readl((void __iomem *)(ap->ioaddr.scr_addr + (sc_reg * 8)));
+}
+
+static void qs_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
+{
+ if (sc_reg > SCR_CONTROL)
+ return;
+ writel(val, (void __iomem *)(ap->ioaddr.scr_addr + (sc_reg * 8)));
+}
+
+static unsigned int qs_fill_sg(struct ata_queued_cmd *qc)
+{
+ struct scatterlist *sg;
+ struct ata_port *ap = qc->ap;
+ struct qs_port_priv *pp = ap->private_data;
+ unsigned int nelem;
+ u8 *prd = pp->pkt + QS_CPB_BYTES;
+
+ WARN_ON(qc->__sg == NULL);
+ WARN_ON(qc->n_elem == 0 && qc->pad_len == 0);
+
+ nelem = 0;
+ ata_for_each_sg(sg, qc) {
+ u64 addr;
+ u32 len;
+
+ addr = sg_dma_address(sg);
+ *(__le64 *)prd = cpu_to_le64(addr);
+ prd += sizeof(u64);
+
+ len = sg_dma_len(sg);
+ *(__le32 *)prd = cpu_to_le32(len);
+ prd += sizeof(u64);
+
+ VPRINTK("PRD[%u] = (0x%llX, 0x%X)\n", nelem,
+ (unsigned long long)addr, len);
+ nelem++;
+ }
+
+ return nelem;
+}
+
+static void qs_qc_prep(struct ata_queued_cmd *qc)
+{
+ struct qs_port_priv *pp = qc->ap->private_data;
+ u8 dflags = QS_DF_PORD, *buf = pp->pkt;
+ u8 hflags = QS_HF_DAT | QS_HF_IEN | QS_HF_VLD;
+ u64 addr;
+ unsigned int nelem;
+
+ VPRINTK("ENTER\n");
+
+ qs_enter_reg_mode(qc->ap);
+ if (qc->tf.protocol != ATA_PROT_DMA) {
+ ata_qc_prep(qc);
+ return;
+ }
+
+ nelem = qs_fill_sg(qc);
+
+ if ((qc->tf.flags & ATA_TFLAG_WRITE))
+ hflags |= QS_HF_DIRO;
+ if ((qc->tf.flags & ATA_TFLAG_LBA48))
+ dflags |= QS_DF_ELBA;
+
+ /* host control block (HCB) */
+ buf[ 0] = QS_HCB_HDR;
+ buf[ 1] = hflags;
+ *(__le32 *)(&buf[ 4]) = cpu_to_le32(qc->nsect * ATA_SECT_SIZE);
+ *(__le32 *)(&buf[ 8]) = cpu_to_le32(nelem);
+ addr = ((u64)pp->pkt_dma) + QS_CPB_BYTES;
+ *(__le64 *)(&buf[16]) = cpu_to_le64(addr);
+
+ /* device control block (DCB) */
+ buf[24] = QS_DCB_HDR;
+ buf[28] = dflags;
+
+ /* frame information structure (FIS) */
+ ata_tf_to_fis(&qc->tf, &buf[32], 0);
+}
+
+static inline void qs_packet_start(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ u8 __iomem *chan = ap->host->mmio_base + (ap->port_no * 0x4000);
+
+ VPRINTK("ENTER, ap %p\n", ap);
+
+ writeb(QS_CTR0_CLER, chan + QS_CCT_CTR0);
+ wmb(); /* flush PRDs and pkt to memory */
+ writel(QS_CCF_RUN_PKT, chan + QS_CCT_CFF);
+ readl(chan + QS_CCT_CFF); /* flush */
+}
+
+static unsigned int qs_qc_issue(struct ata_queued_cmd *qc)
+{
+ struct qs_port_priv *pp = qc->ap->private_data;
+
+ switch (qc->tf.protocol) {
+ case ATA_PROT_DMA:
+
+ pp->state = qs_state_pkt;
+ qs_packet_start(qc);
+ return 0;
+
+ case ATA_PROT_ATAPI_DMA:
+ BUG();
+ break;
+
+ default:
+ break;
+ }
+
+ pp->state = qs_state_mmio;
+ return ata_qc_issue_prot(qc);
+}
+
+static inline unsigned int qs_intr_pkt(struct ata_host *host)
+{
+ unsigned int handled = 0;
+ u8 sFFE;
+ u8 __iomem *mmio_base = host->mmio_base;
+
+ do {
+ u32 sff0 = readl(mmio_base + QS_HST_SFF);
+ u32 sff1 = readl(mmio_base + QS_HST_SFF + 4);
+ u8 sEVLD = (sff1 >> 30) & 0x01; /* valid flag */
+ sFFE = sff1 >> 31; /* empty flag */
+
+ if (sEVLD) {
+ u8 sDST = sff0 >> 16; /* dev status */
+ u8 sHST = sff1 & 0x3f; /* host status */
+ unsigned int port_no = (sff1 >> 8) & 0x03;
+ struct ata_port *ap = host->ports[port_no];
+
+ DPRINTK("SFF=%08x%08x: sCHAN=%u sHST=%d sDST=%02x\n",
+ sff1, sff0, port_no, sHST, sDST);
+ handled = 1;
+ if (ap && !(ap->flags & ATA_FLAG_DISABLED)) {
+ struct ata_queued_cmd *qc;
+ struct qs_port_priv *pp = ap->private_data;
+ if (!pp || pp->state != qs_state_pkt)
+ continue;
+ qc = ata_qc_from_tag(ap, ap->active_tag);
+ if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) {
+ switch (sHST) {
+ case 0: /* successful CPB */
+ case 3: /* device error */
+ pp->state = qs_state_idle;
+ qs_enter_reg_mode(qc->ap);
+ qc->err_mask |= ac_err_mask(sDST);
+ ata_qc_complete(qc);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+ } while (!sFFE);
+ return handled;
+}
+
+static inline unsigned int qs_intr_mmio(struct ata_host *host)
+{
+ unsigned int handled = 0, port_no;
+
+ for (port_no = 0; port_no < host->n_ports; ++port_no) {
+ struct ata_port *ap;
+ ap = host->ports[port_no];
+ if (ap &&
+ !(ap->flags & ATA_FLAG_DISABLED)) {
+ struct ata_queued_cmd *qc;
+ struct qs_port_priv *pp = ap->private_data;
+ if (!pp || pp->state != qs_state_mmio)
+ continue;
+ qc = ata_qc_from_tag(ap, ap->active_tag);
+ if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) {
+
+ /* check main status, clearing INTRQ */
+ u8 status = ata_check_status(ap);
+ if ((status & ATA_BUSY))
+ continue;
+ DPRINTK("ata%u: protocol %d (dev_stat 0x%X)\n",
+ ap->id, qc->tf.protocol, status);
+
+ /* complete taskfile transaction */
+ pp->state = qs_state_idle;
+ qc->err_mask |= ac_err_mask(status);
+ ata_qc_complete(qc);
+ handled = 1;
+ }
+ }
+ }
+ return handled;
+}
+
+static irqreturn_t qs_intr(int irq, void *dev_instance, struct pt_regs *regs)
+{
+ struct ata_host *host = dev_instance;
+ unsigned int handled = 0;
+
+ VPRINTK("ENTER\n");
+
+ spin_lock(&host->lock);
+ handled = qs_intr_pkt(host) | qs_intr_mmio(host);
+ spin_unlock(&host->lock);
+
+ VPRINTK("EXIT\n");
+
+ return IRQ_RETVAL(handled);
+}
+
+static void qs_ata_setup_port(struct ata_ioports *port, unsigned long base)
+{
+ port->cmd_addr =
+ port->data_addr = base + 0x400;
+ port->error_addr =
+ port->feature_addr = base + 0x408; /* hob_feature = 0x409 */
+ port->nsect_addr = base + 0x410; /* hob_nsect = 0x411 */
+ port->lbal_addr = base + 0x418; /* hob_lbal = 0x419 */
+ port->lbam_addr = base + 0x420; /* hob_lbam = 0x421 */
+ port->lbah_addr = base + 0x428; /* hob_lbah = 0x429 */
+ port->device_addr = base + 0x430;
+ port->status_addr =
+ port->command_addr = base + 0x438;
+ port->altstatus_addr =
+ port->ctl_addr = base + 0x440;
+ port->scr_addr = base + 0xc00;
+}
+
+static int qs_port_start(struct ata_port *ap)
+{
+ struct device *dev = ap->host->dev;
+ struct qs_port_priv *pp;
+ void __iomem *mmio_base = ap->host->mmio_base;
+ void __iomem *chan = mmio_base + (ap->port_no * 0x4000);
+ u64 addr;
+ int rc;
+
+ rc = ata_port_start(ap);
+ if (rc)
+ return rc;
+ qs_enter_reg_mode(ap);
+ pp = kzalloc(sizeof(*pp), GFP_KERNEL);
+ if (!pp) {
+ rc = -ENOMEM;
+ goto err_out;
+ }
+ pp->pkt = dma_alloc_coherent(dev, QS_PKT_BYTES, &pp->pkt_dma,
+ GFP_KERNEL);
+ if (!pp->pkt) {
+ rc = -ENOMEM;
+ goto err_out_kfree;
+ }
+ memset(pp->pkt, 0, QS_PKT_BYTES);
+ ap->private_data = pp;
+
+ addr = (u64)pp->pkt_dma;
+ writel((u32) addr, chan + QS_CCF_CPBA);
+ writel((u32)(addr >> 32), chan + QS_CCF_CPBA + 4);
+ return 0;
+
+err_out_kfree:
+ kfree(pp);
+err_out:
+ ata_port_stop(ap);
+ return rc;
+}
+
+static void qs_port_stop(struct ata_port *ap)
+{
+ struct device *dev = ap->host->dev;
+ struct qs_port_priv *pp = ap->private_data;
+
+ if (pp != NULL) {
+ ap->private_data = NULL;
+ if (pp->pkt != NULL)
+ dma_free_coherent(dev, QS_PKT_BYTES, pp->pkt,
+ pp->pkt_dma);
+ kfree(pp);
+ }
+ ata_port_stop(ap);
+}
+
+static void qs_host_stop(struct ata_host *host)
+{
+ void __iomem *mmio_base = host->mmio_base;
+ struct pci_dev *pdev = to_pci_dev(host->dev);
+
+ writeb(0, mmio_base + QS_HCT_CTRL); /* disable host interrupts */
+ writeb(QS_CNFG3_GSRST, mmio_base + QS_HCF_CNFG3); /* global reset */
+
+ pci_iounmap(pdev, mmio_base);
+}
+
+static void qs_host_init(unsigned int chip_id, struct ata_probe_ent *pe)
+{
+ void __iomem *mmio_base = pe->mmio_base;
+ unsigned int port_no;
+
+ writeb(0, mmio_base + QS_HCT_CTRL); /* disable host interrupts */
+ writeb(QS_CNFG3_GSRST, mmio_base + QS_HCF_CNFG3); /* global reset */
+
+ /* reset each channel in turn */
+ for (port_no = 0; port_no < pe->n_ports; ++port_no) {
+ u8 __iomem *chan = mmio_base + (port_no * 0x4000);
+ writeb(QS_CTR1_RDEV|QS_CTR1_RCHN, chan + QS_CCT_CTR1);
+ writeb(QS_CTR0_REG, chan + QS_CCT_CTR0);
+ readb(chan + QS_CCT_CTR0); /* flush */
+ }
+ writeb(QS_SERD3_PHY_ENA, mmio_base + QS_HVS_SERD3); /* enable phy */
+
+ for (port_no = 0; port_no < pe->n_ports; ++port_no) {
+ u8 __iomem *chan = mmio_base + (port_no * 0x4000);
+ /* set FIFO depths to same settings as Windows driver */
+ writew(32, chan + QS_CFC_HUFT);
+ writew(32, chan + QS_CFC_HDFT);
+ writew(10, chan + QS_CFC_DUFT);
+ writew( 8, chan + QS_CFC_DDFT);
+ /* set CPB size in bytes, as a power of two */
+ writeb(QS_CPB_ORDER, chan + QS_CCF_CSEP);
+ }
+ writeb(1, mmio_base + QS_HCT_CTRL); /* enable host interrupts */
+}
+
+/*
+ * The QStor understands 64-bit buses, and uses 64-bit fields
+ * for DMA pointers regardless of bus width. We just have to
+ * make sure our DMA masks are set appropriately for whatever
+ * bridge lies between us and the QStor, and then the DMA mapping
+ * code will ensure we only ever "see" appropriate buffer addresses.
+ * If we're 32-bit limited somewhere, then our 64-bit fields will
+ * just end up with zeros in the upper 32-bits, without any special
+ * logic required outside of this routine (below).
+ */
+static int qs_set_dma_masks(struct pci_dev *pdev, void __iomem *mmio_base)
+{
+ u32 bus_info = readl(mmio_base + QS_HID_HPHY);
+ int rc, have_64bit_bus = (bus_info & QS_HPHY_64BIT);
+
+ if (have_64bit_bus &&
+ !pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
+ rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
+ if (rc) {
+ rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+ if (rc) {
+ dev_printk(KERN_ERR, &pdev->dev,
+ "64-bit DMA enable failed\n");
+ return rc;
+ }
+ }
+ } else {
+ rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+ if (rc) {
+ dev_printk(KERN_ERR, &pdev->dev,
+ "32-bit DMA enable failed\n");
+ return rc;
+ }
+ rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+ if (rc) {
+ dev_printk(KERN_ERR, &pdev->dev,
+ "32-bit consistent DMA enable failed\n");
+ return rc;
+ }
+ }
+ return 0;
+}
+
+static int qs_ata_init_one(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ static int printed_version;
+ struct ata_probe_ent *probe_ent = NULL;
+ void __iomem *mmio_base;
+ unsigned int board_idx = (unsigned int) ent->driver_data;
+ int rc, port_no;
+
+ if (!printed_version++)
+ dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
+
+ rc = pci_enable_device(pdev);
+ if (rc)
+ return rc;
+
+ rc = pci_request_regions(pdev, DRV_NAME);
+ if (rc)
+ goto err_out;
+
+ if ((pci_resource_flags(pdev, 4) & IORESOURCE_MEM) == 0) {
+ rc = -ENODEV;
+ goto err_out_regions;
+ }
+
+ mmio_base = pci_iomap(pdev, 4, 0);
+ if (mmio_base == NULL) {
+ rc = -ENOMEM;
+ goto err_out_regions;
+ }
+
+ rc = qs_set_dma_masks(pdev, mmio_base);
+ if (rc)
+ goto err_out_iounmap;
+
+ probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
+ if (probe_ent == NULL) {
+ rc = -ENOMEM;
+ goto err_out_iounmap;
+ }
+
+ memset(probe_ent, 0, sizeof(*probe_ent));
+ probe_ent->dev = pci_dev_to_dev(pdev);
+ INIT_LIST_HEAD(&probe_ent->node);
+
+ probe_ent->sht = qs_port_info[board_idx].sht;
+ probe_ent->port_flags = qs_port_info[board_idx].flags;
+ probe_ent->pio_mask = qs_port_info[board_idx].pio_mask;
+ probe_ent->mwdma_mask = qs_port_info[board_idx].mwdma_mask;
+ probe_ent->udma_mask = qs_port_info[board_idx].udma_mask;
+ probe_ent->port_ops = qs_port_info[board_idx].port_ops;
+
+ probe_ent->irq = pdev->irq;
+ probe_ent->irq_flags = IRQF_SHARED;
+ probe_ent->mmio_base = mmio_base;
+ probe_ent->n_ports = QS_PORTS;
+
+ for (port_no = 0; port_no < probe_ent->n_ports; ++port_no) {
+ unsigned long chan = (unsigned long)mmio_base +
+ (port_no * 0x4000);
+ qs_ata_setup_port(&probe_ent->port[port_no], chan);
+ }
+
+ pci_set_master(pdev);
+
+ /* initialize adapter */
+ qs_host_init(board_idx, probe_ent);
+
+ rc = ata_device_add(probe_ent);
+ kfree(probe_ent);
+ if (rc != QS_PORTS)
+ goto err_out_iounmap;
+ return 0;
+
+err_out_iounmap:
+ pci_iounmap(pdev, mmio_base);
+err_out_regions:
+ pci_release_regions(pdev);
+err_out:
+ pci_disable_device(pdev);
+ return rc;
+}
+
+static int __init qs_ata_init(void)
+{
+ return pci_register_driver(&qs_ata_pci_driver);
+}
+
+static void __exit qs_ata_exit(void)
+{
+ pci_unregister_driver(&qs_ata_pci_driver);
+}
+
+MODULE_AUTHOR("Mark Lord");
+MODULE_DESCRIPTION("Pacific Digital Corporation QStor SATA low-level driver");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, qs_ata_pci_tbl);
+MODULE_VERSION(DRV_VERSION);
+
+module_init(qs_ata_init);
+module_exit(qs_ata_exit);
diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c
new file mode 100644
index 00000000000..c63dbabc0cd
--- /dev/null
+++ b/drivers/ata/sata_sil.c
@@ -0,0 +1,728 @@
+/*
+ * sata_sil.c - Silicon Image SATA
+ *
+ * Maintained by: Jeff Garzik <jgarzik@pobox.com>
+ * Please ALWAYS copy linux-ide@vger.kernel.org
+ * on emails.
+ *
+ * Copyright 2003-2005 Red Hat, Inc.
+ * Copyright 2003 Benjamin Herrenschmidt
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * libata documentation is available via 'make {ps|pdf}docs',
+ * as Documentation/DocBook/libata.*
+ *
+ * Documentation for SiI 3112:
+ * http://gkernel.sourceforge.net/specs/sii/3112A_SiI-DS-0095-B2.pdf.bz2
+ *
+ * Other errata and documentation available under NDA.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+
+#define DRV_NAME "sata_sil"
+#define DRV_VERSION "2.0"
+
+enum {
+ /*
+ * host flags
+ */
+ SIL_FLAG_NO_SATA_IRQ = (1 << 28),
+ SIL_FLAG_RERR_ON_DMA_ACT = (1 << 29),
+ SIL_FLAG_MOD15WRITE = (1 << 30),
+
+ SIL_DFL_PORT_FLAGS = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+ ATA_FLAG_MMIO | ATA_FLAG_HRST_TO_RESUME,
+
+ /*
+ * Controller IDs
+ */
+ sil_3112 = 0,
+ sil_3112_no_sata_irq = 1,
+ sil_3512 = 2,
+ sil_3114 = 3,
+
+ /*
+ * Register offsets
+ */
+ SIL_SYSCFG = 0x48,
+
+ /*
+ * Register bits
+ */
+ /* SYSCFG */
+ SIL_MASK_IDE0_INT = (1 << 22),
+ SIL_MASK_IDE1_INT = (1 << 23),
+ SIL_MASK_IDE2_INT = (1 << 24),
+ SIL_MASK_IDE3_INT = (1 << 25),
+ SIL_MASK_2PORT = SIL_MASK_IDE0_INT | SIL_MASK_IDE1_INT,
+ SIL_MASK_4PORT = SIL_MASK_2PORT |
+ SIL_MASK_IDE2_INT | SIL_MASK_IDE3_INT,
+
+ /* BMDMA/BMDMA2 */
+ SIL_INTR_STEERING = (1 << 1),
+
+ SIL_DMA_ENABLE = (1 << 0), /* DMA run switch */
+ SIL_DMA_RDWR = (1 << 3), /* DMA Rd-Wr */
+ SIL_DMA_SATA_IRQ = (1 << 4), /* OR of all SATA IRQs */
+ SIL_DMA_ACTIVE = (1 << 16), /* DMA running */
+ SIL_DMA_ERROR = (1 << 17), /* PCI bus error */
+ SIL_DMA_COMPLETE = (1 << 18), /* cmd complete / IRQ pending */
+ SIL_DMA_N_SATA_IRQ = (1 << 6), /* SATA_IRQ for the next channel */
+ SIL_DMA_N_ACTIVE = (1 << 24), /* ACTIVE for the next channel */
+ SIL_DMA_N_ERROR = (1 << 25), /* ERROR for the next channel */
+ SIL_DMA_N_COMPLETE = (1 << 26), /* COMPLETE for the next channel */
+
+ /* SIEN */
+ SIL_SIEN_N = (1 << 16), /* triggered by SError.N */
+
+ /*
+ * Others
+ */
+ SIL_QUIRK_MOD15WRITE = (1 << 0),
+ SIL_QUIRK_UDMA5MAX = (1 << 1),
+};
+
+static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
+#ifdef CONFIG_PM
+static int sil_pci_device_resume(struct pci_dev *pdev);
+#endif
+static void sil_dev_config(struct ata_port *ap, struct ata_device *dev);
+static u32 sil_scr_read (struct ata_port *ap, unsigned int sc_reg);
+static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+static void sil_post_set_mode (struct ata_port *ap);
+static irqreturn_t sil_interrupt(int irq, void *dev_instance,
+ struct pt_regs *regs);
+static void sil_freeze(struct ata_port *ap);
+static void sil_thaw(struct ata_port *ap);
+
+
+static const struct pci_device_id sil_pci_tbl[] = {
+ { 0x1095, 0x3112, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 },
+ { 0x1095, 0x0240, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 },
+ { 0x1095, 0x3512, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3512 },
+ { 0x1095, 0x3114, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3114 },
+ { 0x1002, 0x436e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 },
+ { 0x1002, 0x4379, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112_no_sata_irq },
+ { 0x1002, 0x437a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112_no_sata_irq },
+ { } /* terminate list */
+};
+
+
+/* TODO firmware versions should be added - eric */
+static const struct sil_drivelist {
+ const char * product;
+ unsigned int quirk;
+} sil_blacklist [] = {
+ { "ST320012AS", SIL_QUIRK_MOD15WRITE },
+ { "ST330013AS", SIL_QUIRK_MOD15WRITE },
+ { "ST340017AS", SIL_QUIRK_MOD15WRITE },
+ { "ST360015AS", SIL_QUIRK_MOD15WRITE },
+ { "ST380023AS", SIL_QUIRK_MOD15WRITE },
+ { "ST3120023AS", SIL_QUIRK_MOD15WRITE },
+ { "ST340014ASL", SIL_QUIRK_MOD15WRITE },
+ { "ST360014ASL", SIL_QUIRK_MOD15WRITE },
+ { "ST380011ASL", SIL_QUIRK_MOD15WRITE },
+ { "ST3120022ASL", SIL_QUIRK_MOD15WRITE },
+ { "ST3160021ASL", SIL_QUIRK_MOD15WRITE },
+ { "Maxtor 4D060H3", SIL_QUIRK_UDMA5MAX },
+ { }
+};
+
+static struct pci_driver sil_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = sil_pci_tbl,
+ .probe = sil_init_one,
+ .remove = ata_pci_remove_one,
+#ifdef CONFIG_PM
+ .suspend = ata_pci_device_suspend,
+ .resume = sil_pci_device_resume,
+#endif
+};
+
+static struct scsi_host_template sil_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .slave_destroy = ata_scsi_slave_destroy,
+ .bios_param = ata_std_bios_param,
+ .suspend = ata_scsi_device_suspend,
+ .resume = ata_scsi_device_resume,
+};
+
+static const struct ata_port_operations sil_ops = {
+ .port_disable = ata_port_disable,
+ .dev_config = sil_dev_config,
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+ .post_set_mode = sil_post_set_mode,
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+ .data_xfer = ata_mmio_data_xfer,
+ .freeze = sil_freeze,
+ .thaw = sil_thaw,
+ .error_handler = ata_bmdma_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .irq_handler = sil_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+ .scr_read = sil_scr_read,
+ .scr_write = sil_scr_write,
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_pci_host_stop,
+};
+
+static const struct ata_port_info sil_port_info[] = {
+ /* sil_3112 */
+ {
+ .sht = &sil_sht,
+ .flags = SIL_DFL_PORT_FLAGS | SIL_FLAG_MOD15WRITE,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .mwdma_mask = 0x07, /* mwdma0-2 */
+ .udma_mask = 0x3f, /* udma0-5 */
+ .port_ops = &sil_ops,
+ },
+ /* sil_3112_no_sata_irq */
+ {
+ .sht = &sil_sht,
+ .flags = SIL_DFL_PORT_FLAGS | SIL_FLAG_MOD15WRITE |
+ SIL_FLAG_NO_SATA_IRQ,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .mwdma_mask = 0x07, /* mwdma0-2 */
+ .udma_mask = 0x3f, /* udma0-5 */
+ .port_ops = &sil_ops,
+ },
+ /* sil_3512 */
+ {
+ .sht = &sil_sht,
+ .flags = SIL_DFL_PORT_FLAGS | SIL_FLAG_RERR_ON_DMA_ACT,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .mwdma_mask = 0x07, /* mwdma0-2 */
+ .udma_mask = 0x3f, /* udma0-5 */
+ .port_ops = &sil_ops,
+ },
+ /* sil_3114 */
+ {
+ .sht = &sil_sht,
+ .flags = SIL_DFL_PORT_FLAGS | SIL_FLAG_RERR_ON_DMA_ACT,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .mwdma_mask = 0x07, /* mwdma0-2 */
+ .udma_mask = 0x3f, /* udma0-5 */
+ .port_ops = &sil_ops,
+ },
+};
+
+/* per-port register offsets */
+/* TODO: we can probably calculate rather than use a table */
+static const struct {
+ unsigned long tf; /* ATA taskfile register block */
+ unsigned long ctl; /* ATA control/altstatus register block */
+ unsigned long bmdma; /* DMA register block */
+ unsigned long bmdma2; /* DMA register block #2 */
+ unsigned long fifo_cfg; /* FIFO Valid Byte Count and Control */
+ unsigned long scr; /* SATA control register block */
+ unsigned long sien; /* SATA Interrupt Enable register */
+ unsigned long xfer_mode;/* data transfer mode register */
+ unsigned long sfis_cfg; /* SATA FIS reception config register */
+} sil_port[] = {
+ /* port 0 ... */
+ { 0x80, 0x8A, 0x00, 0x10, 0x40, 0x100, 0x148, 0xb4, 0x14c },
+ { 0xC0, 0xCA, 0x08, 0x18, 0x44, 0x180, 0x1c8, 0xf4, 0x1cc },
+ { 0x280, 0x28A, 0x200, 0x210, 0x240, 0x300, 0x348, 0x2b4, 0x34c },
+ { 0x2C0, 0x2CA, 0x208, 0x218, 0x244, 0x380, 0x3c8, 0x2f4, 0x3cc },
+ /* ... port 3 */
+};
+
+MODULE_AUTHOR("Jeff Garzik");
+MODULE_DESCRIPTION("low-level driver for Silicon Image SATA controller");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, sil_pci_tbl);
+MODULE_VERSION(DRV_VERSION);
+
+static int slow_down = 0;
+module_param(slow_down, int, 0444);
+MODULE_PARM_DESC(slow_down, "Sledgehammer used to work around random problems, by limiting commands to 15 sectors (0=off, 1=on)");
+
+
+static unsigned char sil_get_device_cache_line(struct pci_dev *pdev)
+{
+ u8 cache_line = 0;
+ pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &cache_line);
+ return cache_line;
+}
+
+static void sil_post_set_mode (struct ata_port *ap)
+{
+ struct ata_host *host = ap->host;
+ struct ata_device *dev;
+ void __iomem *addr = host->mmio_base + sil_port[ap->port_no].xfer_mode;
+ u32 tmp, dev_mode[2];
+ unsigned int i;
+
+ for (i = 0; i < 2; i++) {
+ dev = &ap->device[i];
+ if (!ata_dev_enabled(dev))
+ dev_mode[i] = 0; /* PIO0/1/2 */
+ else if (dev->flags & ATA_DFLAG_PIO)
+ dev_mode[i] = 1; /* PIO3/4 */
+ else
+ dev_mode[i] = 3; /* UDMA */
+ /* value 2 indicates MDMA */
+ }
+
+ tmp = readl(addr);
+ tmp &= ~((1<<5) | (1<<4) | (1<<1) | (1<<0));
+ tmp |= dev_mode[0];
+ tmp |= (dev_mode[1] << 4);
+ writel(tmp, addr);
+ readl(addr); /* flush */
+}
+
+static inline unsigned long sil_scr_addr(struct ata_port *ap, unsigned int sc_reg)
+{
+ unsigned long offset = ap->ioaddr.scr_addr;
+
+ switch (sc_reg) {
+ case SCR_STATUS:
+ return offset + 4;
+ case SCR_ERROR:
+ return offset + 8;
+ case SCR_CONTROL:
+ return offset;
+ default:
+ /* do nothing */
+ break;
+ }
+
+ return 0;
+}
+
+static u32 sil_scr_read (struct ata_port *ap, unsigned int sc_reg)
+{
+ void __iomem *mmio = (void __iomem *) sil_scr_addr(ap, sc_reg);
+ if (mmio)
+ return readl(mmio);
+ return 0xffffffffU;
+}
+
+static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
+{
+ void *mmio = (void __iomem *) sil_scr_addr(ap, sc_reg);
+ if (mmio)
+ writel(val, mmio);
+}
+
+static void sil_host_intr(struct ata_port *ap, u32 bmdma2)
+{
+ struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag);
+ u8 status;
+
+ if (unlikely(bmdma2 & SIL_DMA_SATA_IRQ)) {
+ u32 serror;
+
+ /* SIEN doesn't mask SATA IRQs on some 3112s. Those
+ * controllers continue to assert IRQ as long as
+ * SError bits are pending. Clear SError immediately.
+ */
+ serror = sil_scr_read(ap, SCR_ERROR);
+ sil_scr_write(ap, SCR_ERROR, serror);
+
+ /* Trigger hotplug and accumulate SError only if the
+ * port isn't already frozen. Otherwise, PHY events
+ * during hardreset makes controllers with broken SIEN
+ * repeat probing needlessly.
+ */
+ if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
+ ata_ehi_hotplugged(&ap->eh_info);
+ ap->eh_info.serror |= serror;
+ }
+
+ goto freeze;
+ }
+
+ if (unlikely(!qc || qc->tf.ctl & ATA_NIEN))
+ goto freeze;
+
+ /* Check whether we are expecting interrupt in this state */
+ switch (ap->hsm_task_state) {
+ case HSM_ST_FIRST:
+ /* Some pre-ATAPI-4 devices assert INTRQ
+ * at this state when ready to receive CDB.
+ */
+
+ /* Check the ATA_DFLAG_CDB_INTR flag is enough here.
+ * The flag was turned on only for atapi devices.
+ * No need to check is_atapi_taskfile(&qc->tf) again.
+ */
+ if (!(qc->dev->flags & ATA_DFLAG_CDB_INTR))
+ goto err_hsm;
+ break;
+ case HSM_ST_LAST:
+ if (qc->tf.protocol == ATA_PROT_DMA ||
+ qc->tf.protocol == ATA_PROT_ATAPI_DMA) {
+ /* clear DMA-Start bit */
+ ap->ops->bmdma_stop(qc);
+
+ if (bmdma2 & SIL_DMA_ERROR) {
+ qc->err_mask |= AC_ERR_HOST_BUS;
+ ap->hsm_task_state = HSM_ST_ERR;
+ }
+ }
+ break;
+ case HSM_ST:
+ break;
+ default:
+ goto err_hsm;
+ }
+
+ /* check main status, clearing INTRQ */
+ status = ata_chk_status(ap);
+ if (unlikely(status & ATA_BUSY))
+ goto err_hsm;
+
+ /* ack bmdma irq events */
+ ata_bmdma_irq_clear(ap);
+
+ /* kick HSM in the ass */
+ ata_hsm_move(ap, qc, status, 0);
+
+ return;
+
+ err_hsm:
+ qc->err_mask |= AC_ERR_HSM;
+ freeze:
+ ata_port_freeze(ap);
+}
+
+static irqreturn_t sil_interrupt(int irq, void *dev_instance,
+ struct pt_regs *regs)
+{
+ struct ata_host *host = dev_instance;
+ void __iomem *mmio_base = host->mmio_base;
+ int handled = 0;
+ int i;
+
+ spin_lock(&host->lock);
+
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap = host->ports[i];
+ u32 bmdma2 = readl(mmio_base + sil_port[ap->port_no].bmdma2);
+
+ if (unlikely(!ap || ap->flags & ATA_FLAG_DISABLED))
+ continue;
+
+ /* turn off SATA_IRQ if not supported */
+ if (ap->flags & SIL_FLAG_NO_SATA_IRQ)
+ bmdma2 &= ~SIL_DMA_SATA_IRQ;
+
+ if (bmdma2 == 0xffffffff ||
+ !(bmdma2 & (SIL_DMA_COMPLETE | SIL_DMA_SATA_IRQ)))
+ continue;
+
+ sil_host_intr(ap, bmdma2);
+ handled = 1;
+ }
+
+ spin_unlock(&host->lock);
+
+ return IRQ_RETVAL(handled);
+}
+
+static void sil_freeze(struct ata_port *ap)
+{
+ void __iomem *mmio_base = ap->host->mmio_base;
+ u32 tmp;
+
+ /* global IRQ mask doesn't block SATA IRQ, turn off explicitly */
+ writel(0, mmio_base + sil_port[ap->port_no].sien);
+
+ /* plug IRQ */
+ tmp = readl(mmio_base + SIL_SYSCFG);
+ tmp |= SIL_MASK_IDE0_INT << ap->port_no;
+ writel(tmp, mmio_base + SIL_SYSCFG);
+ readl(mmio_base + SIL_SYSCFG); /* flush */
+}
+
+static void sil_thaw(struct ata_port *ap)
+{
+ void __iomem *mmio_base = ap->host->mmio_base;
+ u32 tmp;
+
+ /* clear IRQ */
+ ata_chk_status(ap);
+ ata_bmdma_irq_clear(ap);
+
+ /* turn on SATA IRQ if supported */
+ if (!(ap->flags & SIL_FLAG_NO_SATA_IRQ))
+ writel(SIL_SIEN_N, mmio_base + sil_port[ap->port_no].sien);
+
+ /* turn on IRQ */
+ tmp = readl(mmio_base + SIL_SYSCFG);
+ tmp &= ~(SIL_MASK_IDE0_INT << ap->port_no);
+ writel(tmp, mmio_base + SIL_SYSCFG);
+}
+
+/**
+ * sil_dev_config - Apply device/host-specific errata fixups
+ * @ap: Port containing device to be examined
+ * @dev: Device to be examined
+ *
+ * After the IDENTIFY [PACKET] DEVICE step is complete, and a
+ * device is known to be present, this function is called.
+ * We apply two errata fixups which are specific to Silicon Image,
+ * a Seagate and a Maxtor fixup.
+ *
+ * For certain Seagate devices, we must limit the maximum sectors
+ * to under 8K.
+ *
+ * For certain Maxtor devices, we must not program the drive
+ * beyond udma5.
+ *
+ * Both fixups are unfairly pessimistic. As soon as I get more
+ * information on these errata, I will create a more exhaustive
+ * list, and apply the fixups to only the specific
+ * devices/hosts/firmwares that need it.
+ *
+ * 20040111 - Seagate drives affected by the Mod15Write bug are blacklisted
+ * The Maxtor quirk is in the blacklist, but I'm keeping the original
+ * pessimistic fix for the following reasons...
+ * - There seems to be less info on it, only one device gleaned off the
+ * Windows driver, maybe only one is affected. More info would be greatly
+ * appreciated.
+ * - But then again UDMA5 is hardly anything to complain about
+ */
+static void sil_dev_config(struct ata_port *ap, struct ata_device *dev)
+{
+ unsigned int n, quirks = 0;
+ unsigned char model_num[41];
+
+ ata_id_c_string(dev->id, model_num, ATA_ID_PROD_OFS, sizeof(model_num));
+
+ for (n = 0; sil_blacklist[n].product; n++)
+ if (!strcmp(sil_blacklist[n].product, model_num)) {
+ quirks = sil_blacklist[n].quirk;
+ break;
+ }
+
+ /* limit requests to 15 sectors */
+ if (slow_down ||
+ ((ap->flags & SIL_FLAG_MOD15WRITE) &&
+ (quirks & SIL_QUIRK_MOD15WRITE))) {
+ ata_dev_printk(dev, KERN_INFO, "applying Seagate errata fix "
+ "(mod15write workaround)\n");
+ dev->max_sectors = 15;
+ return;
+ }
+
+ /* limit to udma5 */
+ if (quirks & SIL_QUIRK_UDMA5MAX) {
+ ata_dev_printk(dev, KERN_INFO,
+ "applying Maxtor errata fix %s\n", model_num);
+ dev->udma_mask &= ATA_UDMA5;
+ return;
+ }
+}
+
+static void sil_init_controller(struct pci_dev *pdev,
+ int n_ports, unsigned long port_flags,
+ void __iomem *mmio_base)
+{
+ u8 cls;
+ u32 tmp;
+ int i;
+
+ /* Initialize FIFO PCI bus arbitration */
+ cls = sil_get_device_cache_line(pdev);
+ if (cls) {
+ cls >>= 3;
+ cls++; /* cls = (line_size/8)+1 */
+ for (i = 0; i < n_ports; i++)
+ writew(cls << 8 | cls,
+ mmio_base + sil_port[i].fifo_cfg);
+ } else
+ dev_printk(KERN_WARNING, &pdev->dev,
+ "cache line size not set. Driver may not function\n");
+
+ /* Apply R_ERR on DMA activate FIS errata workaround */
+ if (port_flags & SIL_FLAG_RERR_ON_DMA_ACT) {
+ int cnt;
+
+ for (i = 0, cnt = 0; i < n_ports; i++) {
+ tmp = readl(mmio_base + sil_port[i].sfis_cfg);
+ if ((tmp & 0x3) != 0x01)
+ continue;
+ if (!cnt)
+ dev_printk(KERN_INFO, &pdev->dev,
+ "Applying R_ERR on DMA activate "
+ "FIS errata fix\n");
+ writel(tmp & ~0x3, mmio_base + sil_port[i].sfis_cfg);
+ cnt++;
+ }
+ }
+
+ if (n_ports == 4) {
+ /* flip the magic "make 4 ports work" bit */
+ tmp = readl(mmio_base + sil_port[2].bmdma);
+ if ((tmp & SIL_INTR_STEERING) == 0)
+ writel(tmp | SIL_INTR_STEERING,
+ mmio_base + sil_port[2].bmdma);
+ }
+}
+
+static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ static int printed_version;
+ struct ata_probe_ent *probe_ent = NULL;
+ unsigned long base;
+ void __iomem *mmio_base;
+ int rc;
+ unsigned int i;
+ int pci_dev_busy = 0;
+
+ if (!printed_version++)
+ dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
+
+ rc = pci_enable_device(pdev);
+ if (rc)
+ return rc;
+
+ rc = pci_request_regions(pdev, DRV_NAME);
+ if (rc) {
+ pci_dev_busy = 1;
+ goto err_out;
+ }
+
+ rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
+ if (rc)
+ goto err_out_regions;
+ rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
+ if (rc)
+ goto err_out_regions;
+
+ probe_ent = kzalloc(sizeof(*probe_ent), GFP_KERNEL);
+ if (probe_ent == NULL) {
+ rc = -ENOMEM;
+ goto err_out_regions;
+ }
+
+ INIT_LIST_HEAD(&probe_ent->node);
+ probe_ent->dev = pci_dev_to_dev(pdev);
+ probe_ent->port_ops = sil_port_info[ent->driver_data].port_ops;
+ probe_ent->sht = sil_port_info[ent->driver_data].sht;
+ probe_ent->n_ports = (ent->driver_data == sil_3114) ? 4 : 2;
+ probe_ent->pio_mask = sil_port_info[ent->driver_data].pio_mask;
+ probe_ent->mwdma_mask = sil_port_info[ent->driver_data].mwdma_mask;
+ probe_ent->udma_mask = sil_port_info[ent->driver_data].udma_mask;
+ probe_ent->irq = pdev->irq;
+ probe_ent->irq_flags = IRQF_SHARED;
+ probe_ent->port_flags = sil_port_info[ent->driver_data].flags;
+
+ mmio_base = pci_iomap(pdev, 5, 0);
+ if (mmio_base == NULL) {
+ rc = -ENOMEM;
+ goto err_out_free_ent;
+ }
+
+ probe_ent->mmio_base = mmio_base;
+
+ base = (unsigned long) mmio_base;
+
+ for (i = 0; i < probe_ent->n_ports; i++) {
+ probe_ent->port[i].cmd_addr = base + sil_port[i].tf;
+ probe_ent->port[i].altstatus_addr =
+ probe_ent->port[i].ctl_addr = base + sil_port[i].ctl;
+ probe_ent->port[i].bmdma_addr = base + sil_port[i].bmdma;
+ probe_ent->port[i].scr_addr = base + sil_port[i].scr;
+ ata_std_ports(&probe_ent->port[i]);
+ }
+
+ sil_init_controller(pdev, probe_ent->n_ports, probe_ent->port_flags,
+ mmio_base);
+
+ pci_set_master(pdev);
+
+ /* FIXME: check ata_device_add return value */
+ ata_device_add(probe_ent);
+ kfree(probe_ent);
+
+ return 0;
+
+err_out_free_ent:
+ kfree(probe_ent);
+err_out_regions:
+ pci_release_regions(pdev);
+err_out:
+ if (!pci_dev_busy)
+ pci_disable_device(pdev);
+ return rc;
+}
+
+#ifdef CONFIG_PM
+static int sil_pci_device_resume(struct pci_dev *pdev)
+{
+ struct ata_host *host = dev_get_drvdata(&pdev->dev);
+
+ ata_pci_device_do_resume(pdev);
+ sil_init_controller(pdev, host->n_ports, host->ports[0]->flags,
+ host->mmio_base);
+ ata_host_resume(host);
+
+ return 0;
+}
+#endif
+
+static int __init sil_init(void)
+{
+ return pci_register_driver(&sil_pci_driver);
+}
+
+static void __exit sil_exit(void)
+{
+ pci_unregister_driver(&sil_pci_driver);
+}
+
+
+module_init(sil_init);
+module_exit(sil_exit);
diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c
new file mode 100644
index 00000000000..39cb07baeba
--- /dev/null
+++ b/drivers/ata/sata_sil24.c
@@ -0,0 +1,1227 @@
+/*
+ * sata_sil24.c - Driver for Silicon Image 3124/3132 SATA-2 controllers
+ *
+ * Copyright 2005 Tejun Heo
+ *
+ * Based on preview driver from Silicon Image.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/device.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_cmnd.h>
+#include <linux/libata.h>
+#include <asm/io.h>
+
+#define DRV_NAME "sata_sil24"
+#define DRV_VERSION "0.3"
+
+/*
+ * Port request block (PRB) 32 bytes
+ */
+struct sil24_prb {
+ __le16 ctrl;
+ __le16 prot;
+ __le32 rx_cnt;
+ u8 fis[6 * 4];
+};
+
+/*
+ * Scatter gather entry (SGE) 16 bytes
+ */
+struct sil24_sge {
+ __le64 addr;
+ __le32 cnt;
+ __le32 flags;
+};
+
+/*
+ * Port multiplier
+ */
+struct sil24_port_multiplier {
+ __le32 diag;
+ __le32 sactive;
+};
+
+enum {
+ /*
+ * Global controller registers (128 bytes @ BAR0)
+ */
+ /* 32 bit regs */
+ HOST_SLOT_STAT = 0x00, /* 32 bit slot stat * 4 */
+ HOST_CTRL = 0x40,
+ HOST_IRQ_STAT = 0x44,
+ HOST_PHY_CFG = 0x48,
+ HOST_BIST_CTRL = 0x50,
+ HOST_BIST_PTRN = 0x54,
+ HOST_BIST_STAT = 0x58,
+ HOST_MEM_BIST_STAT = 0x5c,
+ HOST_FLASH_CMD = 0x70,
+ /* 8 bit regs */
+ HOST_FLASH_DATA = 0x74,
+ HOST_TRANSITION_DETECT = 0x75,
+ HOST_GPIO_CTRL = 0x76,
+ HOST_I2C_ADDR = 0x78, /* 32 bit */
+ HOST_I2C_DATA = 0x7c,
+ HOST_I2C_XFER_CNT = 0x7e,
+ HOST_I2C_CTRL = 0x7f,
+
+ /* HOST_SLOT_STAT bits */
+ HOST_SSTAT_ATTN = (1 << 31),
+
+ /* HOST_CTRL bits */
+ HOST_CTRL_M66EN = (1 << 16), /* M66EN PCI bus signal */
+ HOST_CTRL_TRDY = (1 << 17), /* latched PCI TRDY */
+ HOST_CTRL_STOP = (1 << 18), /* latched PCI STOP */
+ HOST_CTRL_DEVSEL = (1 << 19), /* latched PCI DEVSEL */
+ HOST_CTRL_REQ64 = (1 << 20), /* latched PCI REQ64 */
+ HOST_CTRL_GLOBAL_RST = (1 << 31), /* global reset */
+
+ /*
+ * Port registers
+ * (8192 bytes @ +0x0000, +0x2000, +0x4000 and +0x6000 @ BAR2)
+ */
+ PORT_REGS_SIZE = 0x2000,
+
+ PORT_LRAM = 0x0000, /* 31 LRAM slots and PM regs */
+ PORT_LRAM_SLOT_SZ = 0x0080, /* 32 bytes PRB + 2 SGE, ACT... */
+
+ PORT_PM = 0x0f80, /* 8 bytes PM * 16 (128 bytes) */
+ /* 32 bit regs */
+ PORT_CTRL_STAT = 0x1000, /* write: ctrl-set, read: stat */
+ PORT_CTRL_CLR = 0x1004, /* write: ctrl-clear */
+ PORT_IRQ_STAT = 0x1008, /* high: status, low: interrupt */
+ PORT_IRQ_ENABLE_SET = 0x1010, /* write: enable-set */
+ PORT_IRQ_ENABLE_CLR = 0x1014, /* write: enable-clear */
+ PORT_ACTIVATE_UPPER_ADDR= 0x101c,
+ PORT_EXEC_FIFO = 0x1020, /* command execution fifo */
+ PORT_CMD_ERR = 0x1024, /* command error number */
+ PORT_FIS_CFG = 0x1028,
+ PORT_FIFO_THRES = 0x102c,
+ /* 16 bit regs */
+ PORT_DECODE_ERR_CNT = 0x1040,
+ PORT_DECODE_ERR_THRESH = 0x1042,
+ PORT_CRC_ERR_CNT = 0x1044,
+ PORT_CRC_ERR_THRESH = 0x1046,
+ PORT_HSHK_ERR_CNT = 0x1048,
+ PORT_HSHK_ERR_THRESH = 0x104a,
+ /* 32 bit regs */
+ PORT_PHY_CFG = 0x1050,
+ PORT_SLOT_STAT = 0x1800,
+ PORT_CMD_ACTIVATE = 0x1c00, /* 64 bit cmd activate * 31 (248 bytes) */
+ PORT_EXEC_DIAG = 0x1e00, /* 32bit exec diag * 16 (64 bytes, 0-10 used on 3124) */
+ PORT_PSD_DIAG = 0x1e40, /* 32bit psd diag * 16 (64 bytes, 0-8 used on 3124) */
+ PORT_SCONTROL = 0x1f00,
+ PORT_SSTATUS = 0x1f04,
+ PORT_SERROR = 0x1f08,
+ PORT_SACTIVE = 0x1f0c,
+
+ /* PORT_CTRL_STAT bits */
+ PORT_CS_PORT_RST = (1 << 0), /* port reset */
+ PORT_CS_DEV_RST = (1 << 1), /* device reset */
+ PORT_CS_INIT = (1 << 2), /* port initialize */
+ PORT_CS_IRQ_WOC = (1 << 3), /* interrupt write one to clear */
+ PORT_CS_CDB16 = (1 << 5), /* 0=12b cdb, 1=16b cdb */
+ PORT_CS_RESUME = (1 << 6), /* port resume */
+ PORT_CS_32BIT_ACTV = (1 << 10), /* 32-bit activation */
+ PORT_CS_PM_EN = (1 << 13), /* port multiplier enable */
+ PORT_CS_RDY = (1 << 31), /* port ready to accept commands */
+
+ /* PORT_IRQ_STAT/ENABLE_SET/CLR */
+ /* bits[11:0] are masked */
+ PORT_IRQ_COMPLETE = (1 << 0), /* command(s) completed */
+ PORT_IRQ_ERROR = (1 << 1), /* command execution error */
+ PORT_IRQ_PORTRDY_CHG = (1 << 2), /* port ready change */
+ PORT_IRQ_PWR_CHG = (1 << 3), /* power management change */
+ PORT_IRQ_PHYRDY_CHG = (1 << 4), /* PHY ready change */
+ PORT_IRQ_COMWAKE = (1 << 5), /* COMWAKE received */
+ PORT_IRQ_UNK_FIS = (1 << 6), /* unknown FIS received */
+ PORT_IRQ_DEV_XCHG = (1 << 7), /* device exchanged */
+ PORT_IRQ_8B10B = (1 << 8), /* 8b/10b decode error threshold */
+ PORT_IRQ_CRC = (1 << 9), /* CRC error threshold */
+ PORT_IRQ_HANDSHAKE = (1 << 10), /* handshake error threshold */
+ PORT_IRQ_SDB_NOTIFY = (1 << 11), /* SDB notify received */
+
+ DEF_PORT_IRQ = PORT_IRQ_COMPLETE | PORT_IRQ_ERROR |
+ PORT_IRQ_PHYRDY_CHG | PORT_IRQ_DEV_XCHG |
+ PORT_IRQ_UNK_FIS,
+
+ /* bits[27:16] are unmasked (raw) */
+ PORT_IRQ_RAW_SHIFT = 16,
+ PORT_IRQ_MASKED_MASK = 0x7ff,
+ PORT_IRQ_RAW_MASK = (0x7ff << PORT_IRQ_RAW_SHIFT),
+
+ /* ENABLE_SET/CLR specific, intr steering - 2 bit field */
+ PORT_IRQ_STEER_SHIFT = 30,
+ PORT_IRQ_STEER_MASK = (3 << PORT_IRQ_STEER_SHIFT),
+
+ /* PORT_CMD_ERR constants */
+ PORT_CERR_DEV = 1, /* Error bit in D2H Register FIS */
+ PORT_CERR_SDB = 2, /* Error bit in SDB FIS */
+ PORT_CERR_DATA = 3, /* Error in data FIS not detected by dev */
+ PORT_CERR_SEND = 4, /* Initial cmd FIS transmission failure */
+ PORT_CERR_INCONSISTENT = 5, /* Protocol mismatch */
+ PORT_CERR_DIRECTION = 6, /* Data direction mismatch */
+ PORT_CERR_UNDERRUN = 7, /* Ran out of SGEs while writing */
+ PORT_CERR_OVERRUN = 8, /* Ran out of SGEs while reading */
+ PORT_CERR_PKT_PROT = 11, /* DIR invalid in 1st PIO setup of ATAPI */
+ PORT_CERR_SGT_BOUNDARY = 16, /* PLD ecode 00 - SGT not on qword boundary */
+ PORT_CERR_SGT_TGTABRT = 17, /* PLD ecode 01 - target abort */
+ PORT_CERR_SGT_MSTABRT = 18, /* PLD ecode 10 - master abort */
+ PORT_CERR_SGT_PCIPERR = 19, /* PLD ecode 11 - PCI parity err while fetching SGT */
+ PORT_CERR_CMD_BOUNDARY = 24, /* ctrl[15:13] 001 - PRB not on qword boundary */
+ PORT_CERR_CMD_TGTABRT = 25, /* ctrl[15:13] 010 - target abort */
+ PORT_CERR_CMD_MSTABRT = 26, /* ctrl[15:13] 100 - master abort */
+ PORT_CERR_CMD_PCIPERR = 27, /* ctrl[15:13] 110 - PCI parity err while fetching PRB */
+ PORT_CERR_XFR_UNDEF = 32, /* PSD ecode 00 - undefined */
+ PORT_CERR_XFR_TGTABRT = 33, /* PSD ecode 01 - target abort */
+ PORT_CERR_XFR_MSTABRT = 34, /* PSD ecode 10 - master abort */
+ PORT_CERR_XFR_PCIPERR = 35, /* PSD ecode 11 - PCI prity err during transfer */
+ PORT_CERR_SENDSERVICE = 36, /* FIS received while sending service */
+
+ /* bits of PRB control field */
+ PRB_CTRL_PROTOCOL = (1 << 0), /* override def. ATA protocol */
+ PRB_CTRL_PACKET_READ = (1 << 4), /* PACKET cmd read */
+ PRB_CTRL_PACKET_WRITE = (1 << 5), /* PACKET cmd write */
+ PRB_CTRL_NIEN = (1 << 6), /* Mask completion irq */
+ PRB_CTRL_SRST = (1 << 7), /* Soft reset request (ign BSY?) */
+
+ /* PRB protocol field */
+ PRB_PROT_PACKET = (1 << 0),
+ PRB_PROT_TCQ = (1 << 1),
+ PRB_PROT_NCQ = (1 << 2),
+ PRB_PROT_READ = (1 << 3),
+ PRB_PROT_WRITE = (1 << 4),
+ PRB_PROT_TRANSPARENT = (1 << 5),
+
+ /*
+ * Other constants
+ */
+ SGE_TRM = (1 << 31), /* Last SGE in chain */
+ SGE_LNK = (1 << 30), /* linked list
+ Points to SGT, not SGE */
+ SGE_DRD = (1 << 29), /* discard data read (/dev/null)
+ data address ignored */
+
+ SIL24_MAX_CMDS = 31,
+
+ /* board id */
+ BID_SIL3124 = 0,
+ BID_SIL3132 = 1,
+ BID_SIL3131 = 2,
+
+ /* host flags */
+ SIL24_COMMON_FLAGS = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+ ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
+ ATA_FLAG_NCQ | ATA_FLAG_SKIP_D2H_BSY,
+ SIL24_FLAG_PCIX_IRQ_WOC = (1 << 24), /* IRQ loss errata on PCI-X */
+
+ IRQ_STAT_4PORTS = 0xf,
+};
+
+struct sil24_ata_block {
+ struct sil24_prb prb;
+ struct sil24_sge sge[LIBATA_MAX_PRD];
+};
+
+struct sil24_atapi_block {
+ struct sil24_prb prb;
+ u8 cdb[16];
+ struct sil24_sge sge[LIBATA_MAX_PRD - 1];
+};
+
+union sil24_cmd_block {
+ struct sil24_ata_block ata;
+ struct sil24_atapi_block atapi;
+};
+
+static struct sil24_cerr_info {
+ unsigned int err_mask, action;
+ const char *desc;
+} sil24_cerr_db[] = {
+ [0] = { AC_ERR_DEV, ATA_EH_REVALIDATE,
+ "device error" },
+ [PORT_CERR_DEV] = { AC_ERR_DEV, ATA_EH_REVALIDATE,
+ "device error via D2H FIS" },
+ [PORT_CERR_SDB] = { AC_ERR_DEV, ATA_EH_REVALIDATE,
+ "device error via SDB FIS" },
+ [PORT_CERR_DATA] = { AC_ERR_ATA_BUS, ATA_EH_SOFTRESET,
+ "error in data FIS" },
+ [PORT_CERR_SEND] = { AC_ERR_ATA_BUS, ATA_EH_SOFTRESET,
+ "failed to transmit command FIS" },
+ [PORT_CERR_INCONSISTENT] = { AC_ERR_HSM, ATA_EH_SOFTRESET,
+ "protocol mismatch" },
+ [PORT_CERR_DIRECTION] = { AC_ERR_HSM, ATA_EH_SOFTRESET,
+ "data directon mismatch" },
+ [PORT_CERR_UNDERRUN] = { AC_ERR_HSM, ATA_EH_SOFTRESET,
+ "ran out of SGEs while writing" },
+ [PORT_CERR_OVERRUN] = { AC_ERR_HSM, ATA_EH_SOFTRESET,
+ "ran out of SGEs while reading" },
+ [PORT_CERR_PKT_PROT] = { AC_ERR_HSM, ATA_EH_SOFTRESET,
+ "invalid data directon for ATAPI CDB" },
+ [PORT_CERR_SGT_BOUNDARY] = { AC_ERR_SYSTEM, ATA_EH_SOFTRESET,
+ "SGT no on qword boundary" },
+ [PORT_CERR_SGT_TGTABRT] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET,
+ "PCI target abort while fetching SGT" },
+ [PORT_CERR_SGT_MSTABRT] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET,
+ "PCI master abort while fetching SGT" },
+ [PORT_CERR_SGT_PCIPERR] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET,
+ "PCI parity error while fetching SGT" },
+ [PORT_CERR_CMD_BOUNDARY] = { AC_ERR_SYSTEM, ATA_EH_SOFTRESET,
+ "PRB not on qword boundary" },
+ [PORT_CERR_CMD_TGTABRT] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET,
+ "PCI target abort while fetching PRB" },
+ [PORT_CERR_CMD_MSTABRT] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET,
+ "PCI master abort while fetching PRB" },
+ [PORT_CERR_CMD_PCIPERR] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET,
+ "PCI parity error while fetching PRB" },
+ [PORT_CERR_XFR_UNDEF] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET,
+ "undefined error while transferring data" },
+ [PORT_CERR_XFR_TGTABRT] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET,
+ "PCI target abort while transferring data" },
+ [PORT_CERR_XFR_MSTABRT] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET,
+ "PCI master abort while transferring data" },
+ [PORT_CERR_XFR_PCIPERR] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET,
+ "PCI parity error while transferring data" },
+ [PORT_CERR_SENDSERVICE] = { AC_ERR_HSM, ATA_EH_SOFTRESET,
+ "FIS received while sending service FIS" },
+};
+
+/*
+ * ap->private_data
+ *
+ * The preview driver always returned 0 for status. We emulate it
+ * here from the previous interrupt.
+ */
+struct sil24_port_priv {
+ union sil24_cmd_block *cmd_block; /* 32 cmd blocks */
+ dma_addr_t cmd_block_dma; /* DMA base addr for them */
+ struct ata_taskfile tf; /* Cached taskfile registers */
+};
+
+/* ap->host->private_data */
+struct sil24_host_priv {
+ void __iomem *host_base; /* global controller control (128 bytes @BAR0) */
+ void __iomem *port_base; /* port registers (4 * 8192 bytes @BAR2) */
+};
+
+static void sil24_dev_config(struct ata_port *ap, struct ata_device *dev);
+static u8 sil24_check_status(struct ata_port *ap);
+static u32 sil24_scr_read(struct ata_port *ap, unsigned sc_reg);
+static void sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val);
+static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf);
+static void sil24_qc_prep(struct ata_queued_cmd *qc);
+static unsigned int sil24_qc_issue(struct ata_queued_cmd *qc);
+static void sil24_irq_clear(struct ata_port *ap);
+static irqreturn_t sil24_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
+static void sil24_freeze(struct ata_port *ap);
+static void sil24_thaw(struct ata_port *ap);
+static void sil24_error_handler(struct ata_port *ap);
+static void sil24_post_internal_cmd(struct ata_queued_cmd *qc);
+static int sil24_port_start(struct ata_port *ap);
+static void sil24_port_stop(struct ata_port *ap);
+static void sil24_host_stop(struct ata_host *host);
+static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
+#ifdef CONFIG_PM
+static int sil24_pci_device_resume(struct pci_dev *pdev);
+#endif
+
+static const struct pci_device_id sil24_pci_tbl[] = {
+ { 0x1095, 0x3124, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3124 },
+ { 0x8086, 0x3124, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3124 },
+ { 0x1095, 0x3132, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3132 },
+ { 0x1095, 0x3131, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3131 },
+ { 0x1095, 0x3531, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3131 },
+ { } /* terminate list */
+};
+
+static struct pci_driver sil24_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = sil24_pci_tbl,
+ .probe = sil24_init_one,
+ .remove = ata_pci_remove_one, /* safe? */
+#ifdef CONFIG_PM
+ .suspend = ata_pci_device_suspend,
+ .resume = sil24_pci_device_resume,
+#endif
+};
+
+static struct scsi_host_template sil24_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .change_queue_depth = ata_scsi_change_queue_depth,
+ .can_queue = SIL24_MAX_CMDS,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .slave_destroy = ata_scsi_slave_destroy,
+ .bios_param = ata_std_bios_param,
+ .suspend = ata_scsi_device_suspend,
+ .resume = ata_scsi_device_resume,
+};
+
+static const struct ata_port_operations sil24_ops = {
+ .port_disable = ata_port_disable,
+
+ .dev_config = sil24_dev_config,
+
+ .check_status = sil24_check_status,
+ .check_altstatus = sil24_check_status,
+ .dev_select = ata_noop_dev_select,
+
+ .tf_read = sil24_tf_read,
+
+ .qc_prep = sil24_qc_prep,
+ .qc_issue = sil24_qc_issue,
+
+ .irq_handler = sil24_interrupt,
+ .irq_clear = sil24_irq_clear,
+
+ .scr_read = sil24_scr_read,
+ .scr_write = sil24_scr_write,
+
+ .freeze = sil24_freeze,
+ .thaw = sil24_thaw,
+ .error_handler = sil24_error_handler,
+ .post_internal_cmd = sil24_post_internal_cmd,
+
+ .port_start = sil24_port_start,
+ .port_stop = sil24_port_stop,
+ .host_stop = sil24_host_stop,
+};
+
+/*
+ * Use bits 30-31 of port_flags to encode available port numbers.
+ * Current maxium is 4.
+ */
+#define SIL24_NPORTS2FLAG(nports) ((((unsigned)(nports) - 1) & 0x3) << 30)
+#define SIL24_FLAG2NPORTS(flag) ((((flag) >> 30) & 0x3) + 1)
+
+static struct ata_port_info sil24_port_info[] = {
+ /* sil_3124 */
+ {
+ .sht = &sil24_sht,
+ .flags = SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(4) |
+ SIL24_FLAG_PCIX_IRQ_WOC,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .mwdma_mask = 0x07, /* mwdma0-2 */
+ .udma_mask = 0x3f, /* udma0-5 */
+ .port_ops = &sil24_ops,
+ },
+ /* sil_3132 */
+ {
+ .sht = &sil24_sht,
+ .flags = SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(2),
+ .pio_mask = 0x1f, /* pio0-4 */
+ .mwdma_mask = 0x07, /* mwdma0-2 */
+ .udma_mask = 0x3f, /* udma0-5 */
+ .port_ops = &sil24_ops,
+ },
+ /* sil_3131/sil_3531 */
+ {
+ .sht = &sil24_sht,
+ .flags = SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(1),
+ .pio_mask = 0x1f, /* pio0-4 */
+ .mwdma_mask = 0x07, /* mwdma0-2 */
+ .udma_mask = 0x3f, /* udma0-5 */
+ .port_ops = &sil24_ops,
+ },
+};
+
+static int sil24_tag(int tag)
+{
+ if (unlikely(ata_tag_internal(tag)))
+ return 0;
+ return tag;
+}
+
+static void sil24_dev_config(struct ata_port *ap, struct ata_device *dev)
+{
+ void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
+
+ if (dev->cdb_len == 16)
+ writel(PORT_CS_CDB16, port + PORT_CTRL_STAT);
+ else
+ writel(PORT_CS_CDB16, port + PORT_CTRL_CLR);
+}
+
+static inline void sil24_update_tf(struct ata_port *ap)
+{
+ struct sil24_port_priv *pp = ap->private_data;
+ void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
+ struct sil24_prb __iomem *prb = port;
+ u8 fis[6 * 4];
+
+ memcpy_fromio(fis, prb->fis, 6 * 4);
+ ata_tf_from_fis(fis, &pp->tf);
+}
+
+static u8 sil24_check_status(struct ata_port *ap)
+{
+ struct sil24_port_priv *pp = ap->private_data;
+ return pp->tf.command;
+}
+
+static int sil24_scr_map[] = {
+ [SCR_CONTROL] = 0,
+ [SCR_STATUS] = 1,
+ [SCR_ERROR] = 2,
+ [SCR_ACTIVE] = 3,
+};
+
+static u32 sil24_scr_read(struct ata_port *ap, unsigned sc_reg)
+{
+ void __iomem *scr_addr = (void __iomem *)ap->ioaddr.scr_addr;
+ if (sc_reg < ARRAY_SIZE(sil24_scr_map)) {
+ void __iomem *addr;
+ addr = scr_addr + sil24_scr_map[sc_reg] * 4;
+ return readl(scr_addr + sil24_scr_map[sc_reg] * 4);
+ }
+ return 0xffffffffU;
+}
+
+static void sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val)
+{
+ void __iomem *scr_addr = (void __iomem *)ap->ioaddr.scr_addr;
+ if (sc_reg < ARRAY_SIZE(sil24_scr_map)) {
+ void __iomem *addr;
+ addr = scr_addr + sil24_scr_map[sc_reg] * 4;
+ writel(val, scr_addr + sil24_scr_map[sc_reg] * 4);
+ }
+}
+
+static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
+{
+ struct sil24_port_priv *pp = ap->private_data;
+ *tf = pp->tf;
+}
+
+static int sil24_init_port(struct ata_port *ap)
+{
+ void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
+ u32 tmp;
+
+ writel(PORT_CS_INIT, port + PORT_CTRL_STAT);
+ ata_wait_register(port + PORT_CTRL_STAT,
+ PORT_CS_INIT, PORT_CS_INIT, 10, 100);
+ tmp = ata_wait_register(port + PORT_CTRL_STAT,
+ PORT_CS_RDY, 0, 10, 100);
+
+ if ((tmp & (PORT_CS_INIT | PORT_CS_RDY)) != PORT_CS_RDY)
+ return -EIO;
+ return 0;
+}
+
+static int sil24_softreset(struct ata_port *ap, unsigned int *class)
+{
+ void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
+ struct sil24_port_priv *pp = ap->private_data;
+ struct sil24_prb *prb = &pp->cmd_block[0].ata.prb;
+ dma_addr_t paddr = pp->cmd_block_dma;
+ u32 mask, irq_stat;
+ const char *reason;
+
+ DPRINTK("ENTER\n");
+
+ if (ata_port_offline(ap)) {
+ DPRINTK("PHY reports no device\n");
+ *class = ATA_DEV_NONE;
+ goto out;
+ }
+
+ /* put the port into known state */
+ if (sil24_init_port(ap)) {
+ reason ="port not ready";
+ goto err;
+ }
+
+ /* do SRST */
+ prb->ctrl = cpu_to_le16(PRB_CTRL_SRST);
+ prb->fis[1] = 0; /* no PM yet */
+
+ writel((u32)paddr, port + PORT_CMD_ACTIVATE);
+ writel((u64)paddr >> 32, port + PORT_CMD_ACTIVATE + 4);
+
+ mask = (PORT_IRQ_COMPLETE | PORT_IRQ_ERROR) << PORT_IRQ_RAW_SHIFT;
+ irq_stat = ata_wait_register(port + PORT_IRQ_STAT, mask, 0x0,
+ 100, ATA_TMOUT_BOOT / HZ * 1000);
+
+ writel(irq_stat, port + PORT_IRQ_STAT); /* clear IRQs */
+ irq_stat >>= PORT_IRQ_RAW_SHIFT;
+
+ if (!(irq_stat & PORT_IRQ_COMPLETE)) {
+ if (irq_stat & PORT_IRQ_ERROR)
+ reason = "SRST command error";
+ else
+ reason = "timeout";
+ goto err;
+ }
+
+ sil24_update_tf(ap);
+ *class = ata_dev_classify(&pp->tf);
+
+ if (*class == ATA_DEV_UNKNOWN)
+ *class = ATA_DEV_NONE;
+
+ out:
+ DPRINTK("EXIT, class=%u\n", *class);
+ return 0;
+
+ err:
+ ata_port_printk(ap, KERN_ERR, "softreset failed (%s)\n", reason);
+ return -EIO;
+}
+
+static int sil24_hardreset(struct ata_port *ap, unsigned int *class)
+{
+ void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
+ const char *reason;
+ int tout_msec, rc;
+ u32 tmp;
+
+ /* sil24 does the right thing(tm) without any protection */
+ sata_set_spd(ap);
+
+ tout_msec = 100;
+ if (ata_port_online(ap))
+ tout_msec = 5000;
+
+ writel(PORT_CS_DEV_RST, port + PORT_CTRL_STAT);
+ tmp = ata_wait_register(port + PORT_CTRL_STAT,
+ PORT_CS_DEV_RST, PORT_CS_DEV_RST, 10, tout_msec);
+
+ /* SStatus oscillates between zero and valid status after
+ * DEV_RST, debounce it.
+ */
+ rc = sata_phy_debounce(ap, sata_deb_timing_long);
+ if (rc) {
+ reason = "PHY debouncing failed";
+ goto err;
+ }
+
+ if (tmp & PORT_CS_DEV_RST) {
+ if (ata_port_offline(ap))
+ return 0;
+ reason = "link not ready";
+ goto err;
+ }
+
+ /* Sil24 doesn't store signature FIS after hardreset, so we
+ * can't wait for BSY to clear. Some devices take a long time
+ * to get ready and those devices will choke if we don't wait
+ * for BSY clearance here. Tell libata to perform follow-up
+ * softreset.
+ */
+ return -EAGAIN;
+
+ err:
+ ata_port_printk(ap, KERN_ERR, "hardreset failed (%s)\n", reason);
+ return -EIO;
+}
+
+static inline void sil24_fill_sg(struct ata_queued_cmd *qc,
+ struct sil24_sge *sge)
+{
+ struct scatterlist *sg;
+ unsigned int idx = 0;
+
+ ata_for_each_sg(sg, qc) {
+ sge->addr = cpu_to_le64(sg_dma_address(sg));
+ sge->cnt = cpu_to_le32(sg_dma_len(sg));
+ if (ata_sg_is_last(sg, qc))
+ sge->flags = cpu_to_le32(SGE_TRM);
+ else
+ sge->flags = 0;
+
+ sge++;
+ idx++;
+ }
+}
+
+static void sil24_qc_prep(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct sil24_port_priv *pp = ap->private_data;
+ union sil24_cmd_block *cb;
+ struct sil24_prb *prb;
+ struct sil24_sge *sge;
+ u16 ctrl = 0;
+
+ cb = &pp->cmd_block[sil24_tag(qc->tag)];
+
+ switch (qc->tf.protocol) {
+ case ATA_PROT_PIO:
+ case ATA_PROT_DMA:
+ case ATA_PROT_NCQ:
+ case ATA_PROT_NODATA:
+ prb = &cb->ata.prb;
+ sge = cb->ata.sge;
+ break;
+
+ case ATA_PROT_ATAPI:
+ case ATA_PROT_ATAPI_DMA:
+ case ATA_PROT_ATAPI_NODATA:
+ prb = &cb->atapi.prb;
+ sge = cb->atapi.sge;
+ memset(cb->atapi.cdb, 0, 32);
+ memcpy(cb->atapi.cdb, qc->cdb, qc->dev->cdb_len);
+
+ if (qc->tf.protocol != ATA_PROT_ATAPI_NODATA) {
+ if (qc->tf.flags & ATA_TFLAG_WRITE)
+ ctrl = PRB_CTRL_PACKET_WRITE;
+ else
+ ctrl = PRB_CTRL_PACKET_READ;
+ }
+ break;
+
+ default:
+ prb = NULL; /* shut up, gcc */
+ sge = NULL;
+ BUG();
+ }
+
+ prb->ctrl = cpu_to_le16(ctrl);
+ ata_tf_to_fis(&qc->tf, prb->fis, 0);
+
+ if (qc->flags & ATA_QCFLAG_DMAMAP)
+ sil24_fill_sg(qc, sge);
+}
+
+static unsigned int sil24_qc_issue(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct sil24_port_priv *pp = ap->private_data;
+ void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
+ unsigned int tag = sil24_tag(qc->tag);
+ dma_addr_t paddr;
+ void __iomem *activate;
+
+ paddr = pp->cmd_block_dma + tag * sizeof(*pp->cmd_block);
+ activate = port + PORT_CMD_ACTIVATE + tag * 8;
+
+ writel((u32)paddr, activate);
+ writel((u64)paddr >> 32, activate + 4);
+
+ return 0;
+}
+
+static void sil24_irq_clear(struct ata_port *ap)
+{
+ /* unused */
+}
+
+static void sil24_freeze(struct ata_port *ap)
+{
+ void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
+
+ /* Port-wide IRQ mask in HOST_CTRL doesn't really work, clear
+ * PORT_IRQ_ENABLE instead.
+ */
+ writel(0xffff, port + PORT_IRQ_ENABLE_CLR);
+}
+
+static void sil24_thaw(struct ata_port *ap)
+{
+ void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
+ u32 tmp;
+
+ /* clear IRQ */
+ tmp = readl(port + PORT_IRQ_STAT);
+ writel(tmp, port + PORT_IRQ_STAT);
+
+ /* turn IRQ back on */
+ writel(DEF_PORT_IRQ, port + PORT_IRQ_ENABLE_SET);
+}
+
+static void sil24_error_intr(struct ata_port *ap)
+{
+ void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
+ struct ata_eh_info *ehi = &ap->eh_info;
+ int freeze = 0;
+ u32 irq_stat;
+
+ /* on error, we need to clear IRQ explicitly */
+ irq_stat = readl(port + PORT_IRQ_STAT);
+ writel(irq_stat, port + PORT_IRQ_STAT);
+
+ /* first, analyze and record host port events */
+ ata_ehi_clear_desc(ehi);
+
+ ata_ehi_push_desc(ehi, "irq_stat 0x%08x", irq_stat);
+
+ if (irq_stat & (PORT_IRQ_PHYRDY_CHG | PORT_IRQ_DEV_XCHG)) {
+ ata_ehi_hotplugged(ehi);
+ ata_ehi_push_desc(ehi, ", %s",
+ irq_stat & PORT_IRQ_PHYRDY_CHG ?
+ "PHY RDY changed" : "device exchanged");
+ freeze = 1;
+ }
+
+ if (irq_stat & PORT_IRQ_UNK_FIS) {
+ ehi->err_mask |= AC_ERR_HSM;
+ ehi->action |= ATA_EH_SOFTRESET;
+ ata_ehi_push_desc(ehi , ", unknown FIS");
+ freeze = 1;
+ }
+
+ /* deal with command error */
+ if (irq_stat & PORT_IRQ_ERROR) {
+ struct sil24_cerr_info *ci = NULL;
+ unsigned int err_mask = 0, action = 0;
+ struct ata_queued_cmd *qc;
+ u32 cerr;
+
+ /* analyze CMD_ERR */
+ cerr = readl(port + PORT_CMD_ERR);
+ if (cerr < ARRAY_SIZE(sil24_cerr_db))
+ ci = &sil24_cerr_db[cerr];
+
+ if (ci && ci->desc) {
+ err_mask |= ci->err_mask;
+ action |= ci->action;
+ ata_ehi_push_desc(ehi, ", %s", ci->desc);
+ } else {
+ err_mask |= AC_ERR_OTHER;
+ action |= ATA_EH_SOFTRESET;
+ ata_ehi_push_desc(ehi, ", unknown command error %d",
+ cerr);
+ }
+
+ /* record error info */
+ qc = ata_qc_from_tag(ap, ap->active_tag);
+ if (qc) {
+ sil24_update_tf(ap);
+ qc->err_mask |= err_mask;
+ } else
+ ehi->err_mask |= err_mask;
+
+ ehi->action |= action;
+ }
+
+ /* freeze or abort */
+ if (freeze)
+ ata_port_freeze(ap);
+ else
+ ata_port_abort(ap);
+}
+
+static void sil24_finish_qc(struct ata_queued_cmd *qc)
+{
+ if (qc->flags & ATA_QCFLAG_RESULT_TF)
+ sil24_update_tf(qc->ap);
+}
+
+static inline void sil24_host_intr(struct ata_port *ap)
+{
+ void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
+ u32 slot_stat, qc_active;
+ int rc;
+
+ slot_stat = readl(port + PORT_SLOT_STAT);
+
+ if (unlikely(slot_stat & HOST_SSTAT_ATTN)) {
+ sil24_error_intr(ap);
+ return;
+ }
+
+ if (ap->flags & SIL24_FLAG_PCIX_IRQ_WOC)
+ writel(PORT_IRQ_COMPLETE, port + PORT_IRQ_STAT);
+
+ qc_active = slot_stat & ~HOST_SSTAT_ATTN;
+ rc = ata_qc_complete_multiple(ap, qc_active, sil24_finish_qc);
+ if (rc > 0)
+ return;
+ if (rc < 0) {
+ struct ata_eh_info *ehi = &ap->eh_info;
+ ehi->err_mask |= AC_ERR_HSM;
+ ehi->action |= ATA_EH_SOFTRESET;
+ ata_port_freeze(ap);
+ return;
+ }
+
+ if (ata_ratelimit())
+ ata_port_printk(ap, KERN_INFO, "spurious interrupt "
+ "(slot_stat 0x%x active_tag %d sactive 0x%x)\n",
+ slot_stat, ap->active_tag, ap->sactive);
+}
+
+static irqreturn_t sil24_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
+{
+ struct ata_host *host = dev_instance;
+ struct sil24_host_priv *hpriv = host->private_data;
+ unsigned handled = 0;
+ u32 status;
+ int i;
+
+ status = readl(hpriv->host_base + HOST_IRQ_STAT);
+
+ if (status == 0xffffffff) {
+ printk(KERN_ERR DRV_NAME ": IRQ status == 0xffffffff, "
+ "PCI fault or device removal?\n");
+ goto out;
+ }
+
+ if (!(status & IRQ_STAT_4PORTS))
+ goto out;
+
+ spin_lock(&host->lock);
+
+ for (i = 0; i < host->n_ports; i++)
+ if (status & (1 << i)) {
+ struct ata_port *ap = host->ports[i];
+ if (ap && !(ap->flags & ATA_FLAG_DISABLED)) {
+ sil24_host_intr(host->ports[i]);
+ handled++;
+ } else
+ printk(KERN_ERR DRV_NAME
+ ": interrupt from disabled port %d\n", i);
+ }
+
+ spin_unlock(&host->lock);
+ out:
+ return IRQ_RETVAL(handled);
+}
+
+static void sil24_error_handler(struct ata_port *ap)
+{
+ struct ata_eh_context *ehc = &ap->eh_context;
+
+ if (sil24_init_port(ap)) {
+ ata_eh_freeze_port(ap);
+ ehc->i.action |= ATA_EH_HARDRESET;
+ }
+
+ /* perform recovery */
+ ata_do_eh(ap, ata_std_prereset, sil24_softreset, sil24_hardreset,
+ ata_std_postreset);
+}
+
+static void sil24_post_internal_cmd(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+
+ if (qc->flags & ATA_QCFLAG_FAILED)
+ qc->err_mask |= AC_ERR_OTHER;
+
+ /* make DMA engine forget about the failed command */
+ if (qc->err_mask)
+ sil24_init_port(ap);
+}
+
+static inline void sil24_cblk_free(struct sil24_port_priv *pp, struct device *dev)
+{
+ const size_t cb_size = sizeof(*pp->cmd_block) * SIL24_MAX_CMDS;
+
+ dma_free_coherent(dev, cb_size, pp->cmd_block, pp->cmd_block_dma);
+}
+
+static int sil24_port_start(struct ata_port *ap)
+{
+ struct device *dev = ap->host->dev;
+ struct sil24_port_priv *pp;
+ union sil24_cmd_block *cb;
+ size_t cb_size = sizeof(*cb) * SIL24_MAX_CMDS;
+ dma_addr_t cb_dma;
+ int rc = -ENOMEM;
+
+ pp = kzalloc(sizeof(*pp), GFP_KERNEL);
+ if (!pp)
+ goto err_out;
+
+ pp->tf.command = ATA_DRDY;
+
+ cb = dma_alloc_coherent(dev, cb_size, &cb_dma, GFP_KERNEL);
+ if (!cb)
+ goto err_out_pp;
+ memset(cb, 0, cb_size);
+
+ rc = ata_pad_alloc(ap, dev);
+ if (rc)
+ goto err_out_pad;
+
+ pp->cmd_block = cb;
+ pp->cmd_block_dma = cb_dma;
+
+ ap->private_data = pp;
+
+ return 0;
+
+err_out_pad:
+ sil24_cblk_free(pp, dev);
+err_out_pp:
+ kfree(pp);
+err_out:
+ return rc;
+}
+
+static void sil24_port_stop(struct ata_port *ap)
+{
+ struct device *dev = ap->host->dev;
+ struct sil24_port_priv *pp = ap->private_data;
+
+ sil24_cblk_free(pp, dev);
+ ata_pad_free(ap, dev);
+ kfree(pp);
+}
+
+static void sil24_host_stop(struct ata_host *host)
+{
+ struct sil24_host_priv *hpriv = host->private_data;
+ struct pci_dev *pdev = to_pci_dev(host->dev);
+
+ pci_iounmap(pdev, hpriv->host_base);
+ pci_iounmap(pdev, hpriv->port_base);
+ kfree(hpriv);
+}
+
+static void sil24_init_controller(struct pci_dev *pdev, int n_ports,
+ unsigned long port_flags,
+ void __iomem *host_base,
+ void __iomem *port_base)
+{
+ u32 tmp;
+ int i;
+
+ /* GPIO off */
+ writel(0, host_base + HOST_FLASH_CMD);
+
+ /* clear global reset & mask interrupts during initialization */
+ writel(0, host_base + HOST_CTRL);
+
+ /* init ports */
+ for (i = 0; i < n_ports; i++) {
+ void __iomem *port = port_base + i * PORT_REGS_SIZE;
+
+ /* Initial PHY setting */
+ writel(0x20c, port + PORT_PHY_CFG);
+
+ /* Clear port RST */
+ tmp = readl(port + PORT_CTRL_STAT);
+ if (tmp & PORT_CS_PORT_RST) {
+ writel(PORT_CS_PORT_RST, port + PORT_CTRL_CLR);
+ tmp = ata_wait_register(port + PORT_CTRL_STAT,
+ PORT_CS_PORT_RST,
+ PORT_CS_PORT_RST, 10, 100);
+ if (tmp & PORT_CS_PORT_RST)
+ dev_printk(KERN_ERR, &pdev->dev,
+ "failed to clear port RST\n");
+ }
+
+ /* Configure IRQ WoC */
+ if (port_flags & SIL24_FLAG_PCIX_IRQ_WOC)
+ writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_STAT);
+ else
+ writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_CLR);
+
+ /* Zero error counters. */
+ writel(0x8000, port + PORT_DECODE_ERR_THRESH);
+ writel(0x8000, port + PORT_CRC_ERR_THRESH);
+ writel(0x8000, port + PORT_HSHK_ERR_THRESH);
+ writel(0x0000, port + PORT_DECODE_ERR_CNT);
+ writel(0x0000, port + PORT_CRC_ERR_CNT);
+ writel(0x0000, port + PORT_HSHK_ERR_CNT);
+
+ /* Always use 64bit activation */
+ writel(PORT_CS_32BIT_ACTV, port + PORT_CTRL_CLR);
+
+ /* Clear port multiplier enable and resume bits */
+ writel(PORT_CS_PM_EN | PORT_CS_RESUME, port + PORT_CTRL_CLR);
+ }
+
+ /* Turn on interrupts */
+ writel(IRQ_STAT_4PORTS, host_base + HOST_CTRL);
+}
+
+static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ static int printed_version = 0;
+ unsigned int board_id = (unsigned int)ent->driver_data;
+ struct ata_port_info *pinfo = &sil24_port_info[board_id];
+ struct ata_probe_ent *probe_ent = NULL;
+ struct sil24_host_priv *hpriv = NULL;
+ void __iomem *host_base = NULL;
+ void __iomem *port_base = NULL;
+ int i, rc;
+ u32 tmp;
+
+ if (!printed_version++)
+ dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
+
+ rc = pci_enable_device(pdev);
+ if (rc)
+ return rc;
+
+ rc = pci_request_regions(pdev, DRV_NAME);
+ if (rc)
+ goto out_disable;
+
+ rc = -ENOMEM;
+ /* map mmio registers */
+ host_base = pci_iomap(pdev, 0, 0);
+ if (!host_base)
+ goto out_free;
+ port_base = pci_iomap(pdev, 2, 0);
+ if (!port_base)
+ goto out_free;
+
+ /* allocate & init probe_ent and hpriv */
+ probe_ent = kzalloc(sizeof(*probe_ent), GFP_KERNEL);
+ if (!probe_ent)
+ goto out_free;
+
+ hpriv = kzalloc(sizeof(*hpriv), GFP_KERNEL);
+ if (!hpriv)
+ goto out_free;
+
+ probe_ent->dev = pci_dev_to_dev(pdev);
+ INIT_LIST_HEAD(&probe_ent->node);
+
+ probe_ent->sht = pinfo->sht;
+ probe_ent->port_flags = pinfo->flags;
+ probe_ent->pio_mask = pinfo->pio_mask;
+ probe_ent->mwdma_mask = pinfo->mwdma_mask;
+ probe_ent->udma_mask = pinfo->udma_mask;
+ probe_ent->port_ops = pinfo->port_ops;
+ probe_ent->n_ports = SIL24_FLAG2NPORTS(pinfo->flags);
+
+ probe_ent->irq = pdev->irq;
+ probe_ent->irq_flags = IRQF_SHARED;
+ probe_ent->private_data = hpriv;
+
+ hpriv->host_base = host_base;
+ hpriv->port_base = port_base;
+
+ /*
+ * Configure the device
+ */
+ if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
+ rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
+ if (rc) {
+ rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+ if (rc) {
+ dev_printk(KERN_ERR, &pdev->dev,
+ "64-bit DMA enable failed\n");
+ goto out_free;
+ }
+ }
+ } else {
+ rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+ if (rc) {
+ dev_printk(KERN_ERR, &pdev->dev,
+ "32-bit DMA enable failed\n");
+ goto out_free;
+ }
+ rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+ if (rc) {
+ dev_printk(KERN_ERR, &pdev->dev,
+ "32-bit consistent DMA enable failed\n");
+ goto out_free;
+ }
+ }
+
+ /* Apply workaround for completion IRQ loss on PCI-X errata */
+ if (probe_ent->port_flags & SIL24_FLAG_PCIX_IRQ_WOC) {
+ tmp = readl(host_base + HOST_CTRL);
+ if (tmp & (HOST_CTRL_TRDY | HOST_CTRL_STOP | HOST_CTRL_DEVSEL))
+ dev_printk(KERN_INFO, &pdev->dev,
+ "Applying completion IRQ loss on PCI-X "
+ "errata fix\n");
+ else
+ probe_ent->port_flags &= ~SIL24_FLAG_PCIX_IRQ_WOC;
+ }
+
+ for (i = 0; i < probe_ent->n_ports; i++) {
+ unsigned long portu =
+ (unsigned long)port_base + i * PORT_REGS_SIZE;
+
+ probe_ent->port[i].cmd_addr = portu;
+ probe_ent->port[i].scr_addr = portu + PORT_SCONTROL;
+
+ ata_std_ports(&probe_ent->port[i]);
+ }
+
+ sil24_init_controller(pdev, probe_ent->n_ports, probe_ent->port_flags,
+ host_base, port_base);
+
+ pci_set_master(pdev);
+
+ /* FIXME: check ata_device_add return value */
+ ata_device_add(probe_ent);
+
+ kfree(probe_ent);
+ return 0;
+
+ out_free:
+ if (host_base)
+ pci_iounmap(pdev, host_base);
+ if (port_base)
+ pci_iounmap(pdev, port_base);
+ kfree(probe_ent);
+ kfree(hpriv);
+ pci_release_regions(pdev);
+ out_disable:
+ pci_disable_device(pdev);
+ return rc;
+}
+
+#ifdef CONFIG_PM
+static int sil24_pci_device_resume(struct pci_dev *pdev)
+{
+ struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct sil24_host_priv *hpriv = host->private_data;
+
+ ata_pci_device_do_resume(pdev);
+
+ if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND)
+ writel(HOST_CTRL_GLOBAL_RST, hpriv->host_base + HOST_CTRL);
+
+ sil24_init_controller(pdev, host->n_ports, host->ports[0]->flags,
+ hpriv->host_base, hpriv->port_base);
+
+ ata_host_resume(host);
+
+ return 0;
+}
+#endif
+
+static int __init sil24_init(void)
+{
+ return pci_register_driver(&sil24_pci_driver);
+}
+
+static void __exit sil24_exit(void)
+{
+ pci_unregister_driver(&sil24_pci_driver);
+}
+
+MODULE_AUTHOR("Tejun Heo");
+MODULE_DESCRIPTION("Silicon Image 3124/3132 SATA low-level driver");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, sil24_pci_tbl);
+
+module_init(sil24_init);
+module_exit(sil24_exit);
diff --git a/drivers/ata/sata_sis.c b/drivers/ata/sata_sis.c
new file mode 100644
index 00000000000..18d49fff8dc
--- /dev/null
+++ b/drivers/ata/sata_sis.c
@@ -0,0 +1,347 @@
+/*
+ * sata_sis.c - Silicon Integrated Systems SATA
+ *
+ * Maintained by: Uwe Koziolek
+ * Please ALWAYS copy linux-ide@vger.kernel.org
+ * on emails.
+ *
+ * Copyright 2004 Uwe Koziolek
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * libata documentation is available via 'make {ps|pdf}docs',
+ * as Documentation/DocBook/libata.*
+ *
+ * Hardware documentation available under NDA.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+
+#define DRV_NAME "sata_sis"
+#define DRV_VERSION "0.6"
+
+enum {
+ sis_180 = 0,
+ SIS_SCR_PCI_BAR = 5,
+
+ /* PCI configuration registers */
+ SIS_GENCTL = 0x54, /* IDE General Control register */
+ SIS_SCR_BASE = 0xc0, /* sata0 phy SCR registers */
+ SIS180_SATA1_OFS = 0x10, /* offset from sata0->sata1 phy regs */
+ SIS182_SATA1_OFS = 0x20, /* offset from sata0->sata1 phy regs */
+ SIS_PMR = 0x90, /* port mapping register */
+ SIS_PMR_COMBINED = 0x30,
+
+ /* random bits */
+ SIS_FLAG_CFGSCR = (1 << 30), /* host flag: SCRs via PCI cfg */
+
+ GENCTL_IOMAPPED_SCR = (1 << 26), /* if set, SCRs are in IO space */
+};
+
+static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
+static u32 sis_scr_read (struct ata_port *ap, unsigned int sc_reg);
+static void sis_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+
+static const struct pci_device_id sis_pci_tbl[] = {
+ { PCI_VENDOR_ID_SI, 0x180, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sis_180 },
+ { PCI_VENDOR_ID_SI, 0x181, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sis_180 },
+ { PCI_VENDOR_ID_SI, 0x182, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sis_180 },
+ { } /* terminate list */
+};
+
+
+static struct pci_driver sis_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = sis_pci_tbl,
+ .probe = sis_init_one,
+ .remove = ata_pci_remove_one,
+};
+
+static struct scsi_host_template sis_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = ATA_MAX_PRD,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .slave_destroy = ata_scsi_slave_destroy,
+ .bios_param = ata_std_bios_param,
+};
+
+static const struct ata_port_operations sis_ops = {
+ .port_disable = ata_port_disable,
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+ .data_xfer = ata_pio_data_xfer,
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = ata_bmdma_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+ .scr_read = sis_scr_read,
+ .scr_write = sis_scr_write,
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop,
+};
+
+static struct ata_port_info sis_port_info = {
+ .sht = &sis_sht,
+ .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x7,
+ .udma_mask = 0x7f,
+ .port_ops = &sis_ops,
+};
+
+
+MODULE_AUTHOR("Uwe Koziolek");
+MODULE_DESCRIPTION("low-level driver for Silicon Integratad Systems SATA controller");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, sis_pci_tbl);
+MODULE_VERSION(DRV_VERSION);
+
+static unsigned int get_scr_cfg_addr(unsigned int port_no, unsigned int sc_reg, int device)
+{
+ unsigned int addr = SIS_SCR_BASE + (4 * sc_reg);
+
+ if (port_no) {
+ if (device == 0x182)
+ addr += SIS182_SATA1_OFS;
+ else
+ addr += SIS180_SATA1_OFS;
+ }
+
+ return addr;
+}
+
+static u32 sis_scr_cfg_read (struct ata_port *ap, unsigned int sc_reg)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ unsigned int cfg_addr = get_scr_cfg_addr(ap->port_no, sc_reg, pdev->device);
+ u32 val, val2 = 0;
+ u8 pmr;
+
+ if (sc_reg == SCR_ERROR) /* doesn't exist in PCI cfg space */
+ return 0xffffffff;
+
+ pci_read_config_byte(pdev, SIS_PMR, &pmr);
+
+ pci_read_config_dword(pdev, cfg_addr, &val);
+
+ if ((pdev->device == 0x182) || (pmr & SIS_PMR_COMBINED))
+ pci_read_config_dword(pdev, cfg_addr+0x10, &val2);
+
+ return val|val2;
+}
+
+static void sis_scr_cfg_write (struct ata_port *ap, unsigned int scr, u32 val)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ unsigned int cfg_addr = get_scr_cfg_addr(ap->port_no, scr, pdev->device);
+ u8 pmr;
+
+ if (scr == SCR_ERROR) /* doesn't exist in PCI cfg space */
+ return;
+
+ pci_read_config_byte(pdev, SIS_PMR, &pmr);
+
+ pci_write_config_dword(pdev, cfg_addr, val);
+
+ if ((pdev->device == 0x182) || (pmr & SIS_PMR_COMBINED))
+ pci_write_config_dword(pdev, cfg_addr+0x10, val);
+}
+
+static u32 sis_scr_read (struct ata_port *ap, unsigned int sc_reg)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u32 val, val2 = 0;
+ u8 pmr;
+
+ if (sc_reg > SCR_CONTROL)
+ return 0xffffffffU;
+
+ if (ap->flags & SIS_FLAG_CFGSCR)
+ return sis_scr_cfg_read(ap, sc_reg);
+
+ pci_read_config_byte(pdev, SIS_PMR, &pmr);
+
+ val = inl(ap->ioaddr.scr_addr + (sc_reg * 4));
+
+ if ((pdev->device == 0x182) || (pmr & SIS_PMR_COMBINED))
+ val2 = inl(ap->ioaddr.scr_addr + (sc_reg * 4) + 0x10);
+
+ return val | val2;
+}
+
+static void sis_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u8 pmr;
+
+ if (sc_reg > SCR_CONTROL)
+ return;
+
+ pci_read_config_byte(pdev, SIS_PMR, &pmr);
+
+ if (ap->flags & SIS_FLAG_CFGSCR)
+ sis_scr_cfg_write(ap, sc_reg, val);
+ else {
+ outl(val, ap->ioaddr.scr_addr + (sc_reg * 4));
+ if ((pdev->device == 0x182) || (pmr & SIS_PMR_COMBINED))
+ outl(val, ap->ioaddr.scr_addr + (sc_reg * 4)+0x10);
+ }
+}
+
+static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ static int printed_version;
+ struct ata_probe_ent *probe_ent = NULL;
+ int rc;
+ u32 genctl;
+ struct ata_port_info *ppi[2];
+ int pci_dev_busy = 0;
+ u8 pmr;
+ u8 port2_start;
+
+ if (!printed_version++)
+ dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n");
+
+ rc = pci_enable_device(pdev);
+ if (rc)
+ return rc;
+
+ rc = pci_request_regions(pdev, DRV_NAME);
+ if (rc) {
+ pci_dev_busy = 1;
+ goto err_out;
+ }
+
+ rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
+ if (rc)
+ goto err_out_regions;
+ rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
+ if (rc)
+ goto err_out_regions;
+
+ ppi[0] = ppi[1] = &sis_port_info;
+ probe_ent = ata_pci_init_native_mode(pdev, ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY);
+ if (!probe_ent) {
+ rc = -ENOMEM;
+ goto err_out_regions;
+ }
+
+ /* check and see if the SCRs are in IO space or PCI cfg space */
+ pci_read_config_dword(pdev, SIS_GENCTL, &genctl);
+ if ((genctl & GENCTL_IOMAPPED_SCR) == 0)
+ probe_ent->port_flags |= SIS_FLAG_CFGSCR;
+
+ /* if hardware thinks SCRs are in IO space, but there are
+ * no IO resources assigned, change to PCI cfg space.
+ */
+ if ((!(probe_ent->port_flags & SIS_FLAG_CFGSCR)) &&
+ ((pci_resource_start(pdev, SIS_SCR_PCI_BAR) == 0) ||
+ (pci_resource_len(pdev, SIS_SCR_PCI_BAR) < 128))) {
+ genctl &= ~GENCTL_IOMAPPED_SCR;
+ pci_write_config_dword(pdev, SIS_GENCTL, genctl);
+ probe_ent->port_flags |= SIS_FLAG_CFGSCR;
+ }
+
+ pci_read_config_byte(pdev, SIS_PMR, &pmr);
+ if (ent->device != 0x182) {
+ if ((pmr & SIS_PMR_COMBINED) == 0) {
+ dev_printk(KERN_INFO, &pdev->dev,
+ "Detected SiS 180/181 chipset in SATA mode\n");
+ port2_start = 64;
+ }
+ else {
+ dev_printk(KERN_INFO, &pdev->dev,
+ "Detected SiS 180/181 chipset in combined mode\n");
+ port2_start=0;
+ }
+ }
+ else {
+ dev_printk(KERN_INFO, &pdev->dev, "Detected SiS 182 chipset\n");
+ port2_start = 0x20;
+ }
+
+ if (!(probe_ent->port_flags & SIS_FLAG_CFGSCR)) {
+ probe_ent->port[0].scr_addr =
+ pci_resource_start(pdev, SIS_SCR_PCI_BAR);
+ probe_ent->port[1].scr_addr =
+ pci_resource_start(pdev, SIS_SCR_PCI_BAR) + port2_start;
+ }
+
+ pci_set_master(pdev);
+ pci_intx(pdev, 1);
+
+ /* FIXME: check ata_device_add return value */
+ ata_device_add(probe_ent);
+ kfree(probe_ent);
+
+ return 0;
+
+err_out_regions:
+ pci_release_regions(pdev);
+
+err_out:
+ if (!pci_dev_busy)
+ pci_disable_device(pdev);
+ return rc;
+
+}
+
+static int __init sis_init(void)
+{
+ return pci_register_driver(&sis_pci_driver);
+}
+
+static void __exit sis_exit(void)
+{
+ pci_unregister_driver(&sis_pci_driver);
+}
+
+module_init(sis_init);
+module_exit(sis_exit);
+
diff --git a/drivers/ata/sata_svw.c b/drivers/ata/sata_svw.c
new file mode 100644
index 00000000000..d6d6658d832
--- /dev/null
+++ b/drivers/ata/sata_svw.c
@@ -0,0 +1,508 @@
+/*
+ * sata_svw.c - ServerWorks / Apple K2 SATA
+ *
+ * Maintained by: Benjamin Herrenschmidt <benh@kernel.crashing.org> and
+ * Jeff Garzik <jgarzik@pobox.com>
+ * Please ALWAYS copy linux-ide@vger.kernel.org
+ * on emails.
+ *
+ * Copyright 2003 Benjamin Herrenschmidt <benh@kernel.crashing.org>
+ *
+ * Bits from Jeff Garzik, Copyright RedHat, Inc.
+ *
+ * This driver probably works with non-Apple versions of the
+ * Broadcom chipset...
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * libata documentation is available via 'make {ps|pdf}docs',
+ * as Documentation/DocBook/libata.*
+ *
+ * Hardware documentation available under NDA.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+
+#ifdef CONFIG_PPC_OF
+#include <asm/prom.h>
+#include <asm/pci-bridge.h>
+#endif /* CONFIG_PPC_OF */
+
+#define DRV_NAME "sata_svw"
+#define DRV_VERSION "2.0"
+
+enum {
+ /* Taskfile registers offsets */
+ K2_SATA_TF_CMD_OFFSET = 0x00,
+ K2_SATA_TF_DATA_OFFSET = 0x00,
+ K2_SATA_TF_ERROR_OFFSET = 0x04,
+ K2_SATA_TF_NSECT_OFFSET = 0x08,
+ K2_SATA_TF_LBAL_OFFSET = 0x0c,
+ K2_SATA_TF_LBAM_OFFSET = 0x10,
+ K2_SATA_TF_LBAH_OFFSET = 0x14,
+ K2_SATA_TF_DEVICE_OFFSET = 0x18,
+ K2_SATA_TF_CMDSTAT_OFFSET = 0x1c,
+ K2_SATA_TF_CTL_OFFSET = 0x20,
+
+ /* DMA base */
+ K2_SATA_DMA_CMD_OFFSET = 0x30,
+
+ /* SCRs base */
+ K2_SATA_SCR_STATUS_OFFSET = 0x40,
+ K2_SATA_SCR_ERROR_OFFSET = 0x44,
+ K2_SATA_SCR_CONTROL_OFFSET = 0x48,
+
+ /* Others */
+ K2_SATA_SICR1_OFFSET = 0x80,
+ K2_SATA_SICR2_OFFSET = 0x84,
+ K2_SATA_SIM_OFFSET = 0x88,
+
+ /* Port stride */
+ K2_SATA_PORT_OFFSET = 0x100,
+};
+
+static u8 k2_stat_check_status(struct ata_port *ap);
+
+
+static u32 k2_sata_scr_read (struct ata_port *ap, unsigned int sc_reg)
+{
+ if (sc_reg > SCR_CONTROL)
+ return 0xffffffffU;
+ return readl((void *) ap->ioaddr.scr_addr + (sc_reg * 4));
+}
+
+
+static void k2_sata_scr_write (struct ata_port *ap, unsigned int sc_reg,
+ u32 val)
+{
+ if (sc_reg > SCR_CONTROL)
+ return;
+ writel(val, (void *) ap->ioaddr.scr_addr + (sc_reg * 4));
+}
+
+
+static void k2_sata_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) {
+ writeb(tf->ctl, ioaddr->ctl_addr);
+ ap->last_ctl = tf->ctl;
+ ata_wait_idle(ap);
+ }
+ if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
+ writew(tf->feature | (((u16)tf->hob_feature) << 8), ioaddr->feature_addr);
+ writew(tf->nsect | (((u16)tf->hob_nsect) << 8), ioaddr->nsect_addr);
+ writew(tf->lbal | (((u16)tf->hob_lbal) << 8), ioaddr->lbal_addr);
+ writew(tf->lbam | (((u16)tf->hob_lbam) << 8), ioaddr->lbam_addr);
+ writew(tf->lbah | (((u16)tf->hob_lbah) << 8), ioaddr->lbah_addr);
+ } else if (is_addr) {
+ writew(tf->feature, ioaddr->feature_addr);
+ writew(tf->nsect, ioaddr->nsect_addr);
+ writew(tf->lbal, ioaddr->lbal_addr);
+ writew(tf->lbam, ioaddr->lbam_addr);
+ writew(tf->lbah, ioaddr->lbah_addr);
+ }
+
+ if (tf->flags & ATA_TFLAG_DEVICE)
+ writeb(tf->device, ioaddr->device_addr);
+
+ ata_wait_idle(ap);
+}
+
+
+static void k2_sata_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
+{
+ struct ata_ioports *ioaddr = &ap->ioaddr;
+ u16 nsect, lbal, lbam, lbah, feature;
+
+ tf->command = k2_stat_check_status(ap);
+ tf->device = readw(ioaddr->device_addr);
+ feature = readw(ioaddr->error_addr);
+ nsect = readw(ioaddr->nsect_addr);
+ lbal = readw(ioaddr->lbal_addr);
+ lbam = readw(ioaddr->lbam_addr);
+ lbah = readw(ioaddr->lbah_addr);
+
+ tf->feature = feature;
+ tf->nsect = nsect;
+ tf->lbal = lbal;
+ tf->lbam = lbam;
+ tf->lbah = lbah;
+
+ if (tf->flags & ATA_TFLAG_LBA48) {
+ tf->hob_feature = feature >> 8;
+ tf->hob_nsect = nsect >> 8;
+ tf->hob_lbal = lbal >> 8;
+ tf->hob_lbam = lbam >> 8;
+ tf->hob_lbah = lbah >> 8;
+ }
+}
+
+/**
+ * k2_bmdma_setup_mmio - Set up PCI IDE BMDMA transaction (MMIO)
+ * @qc: Info associated with this ATA transaction.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ */
+
+static void k2_bmdma_setup_mmio (struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE);
+ u8 dmactl;
+ void *mmio = (void *) ap->ioaddr.bmdma_addr;
+ /* load PRD table addr. */
+ mb(); /* make sure PRD table writes are visible to controller */
+ writel(ap->prd_dma, mmio + ATA_DMA_TABLE_OFS);
+
+ /* specify data direction, triple-check start bit is clear */
+ dmactl = readb(mmio + ATA_DMA_CMD);
+ dmactl &= ~(ATA_DMA_WR | ATA_DMA_START);
+ if (!rw)
+ dmactl |= ATA_DMA_WR;
+ writeb(dmactl, mmio + ATA_DMA_CMD);
+
+ /* issue r/w command if this is not a ATA DMA command*/
+ if (qc->tf.protocol != ATA_PROT_DMA)
+ ap->ops->exec_command(ap, &qc->tf);
+}
+
+/**
+ * k2_bmdma_start_mmio - Start a PCI IDE BMDMA transaction (MMIO)
+ * @qc: Info associated with this ATA transaction.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ */
+
+static void k2_bmdma_start_mmio (struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ void *mmio = (void *) ap->ioaddr.bmdma_addr;
+ u8 dmactl;
+
+ /* start host DMA transaction */
+ dmactl = readb(mmio + ATA_DMA_CMD);
+ writeb(dmactl | ATA_DMA_START, mmio + ATA_DMA_CMD);
+ /* There is a race condition in certain SATA controllers that can
+ be seen when the r/w command is given to the controller before the
+ host DMA is started. On a Read command, the controller would initiate
+ the command to the drive even before it sees the DMA start. When there
+ are very fast drives connected to the controller, or when the data request
+ hits in the drive cache, there is the possibility that the drive returns a part
+ or all of the requested data to the controller before the DMA start is issued.
+ In this case, the controller would become confused as to what to do with the data.
+ In the worst case when all the data is returned back to the controller, the
+ controller could hang. In other cases it could return partial data returning
+ in data corruption. This problem has been seen in PPC systems and can also appear
+ on an system with very fast disks, where the SATA controller is sitting behind a
+ number of bridges, and hence there is significant latency between the r/w command
+ and the start command. */
+ /* issue r/w command if the access is to ATA*/
+ if (qc->tf.protocol == ATA_PROT_DMA)
+ ap->ops->exec_command(ap, &qc->tf);
+}
+
+
+static u8 k2_stat_check_status(struct ata_port *ap)
+{
+ return readl((void *) ap->ioaddr.status_addr);
+}
+
+#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)
+{
+ struct ata_port *ap;
+ struct device_node *np;
+ int len, index;
+
+ /* Find the ata_port */
+ ap = ata_shost_to_port(shost);
+ if (ap == NULL)
+ return 0;
+
+ /* Find the OF node for the PCI device proper */
+ np = pci_device_to_OF_node(to_pci_dev(ap->host->dev));
+ if (np == NULL)
+ return 0;
+
+ /* Match it to a port node */
+ index = (ap == ap->host->ports[0]) ? 0 : 1;
+ for (np = np->child; np != NULL; np = np->sibling) {
+ const u32 *reg = get_property(np, "reg", NULL);
+ if (!reg)
+ continue;
+ if (index == *reg)
+ break;
+ }
+ if (np == NULL)
+ return 0;
+
+ len = sprintf(page, "devspec: %s\n", np->full_name);
+
+ return len;
+}
+#endif /* CONFIG_PPC_OF */
+
+
+static struct scsi_host_template k2_sata_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .slave_destroy = ata_scsi_slave_destroy,
+#ifdef CONFIG_PPC_OF
+ .proc_info = k2_sata_proc_info,
+#endif
+ .bios_param = ata_std_bios_param,
+};
+
+
+static const struct ata_port_operations k2_sata_ops = {
+ .port_disable = ata_port_disable,
+ .tf_load = k2_sata_tf_load,
+ .tf_read = k2_sata_tf_read,
+ .check_status = k2_stat_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+ .bmdma_setup = k2_bmdma_setup_mmio,
+ .bmdma_start = k2_bmdma_start_mmio,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+ .data_xfer = ata_mmio_data_xfer,
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = ata_bmdma_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+ .scr_read = k2_sata_scr_read,
+ .scr_write = k2_sata_scr_write,
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_pci_host_stop,
+};
+
+static void k2_sata_setup_port(struct ata_ioports *port, unsigned long base)
+{
+ port->cmd_addr = base + K2_SATA_TF_CMD_OFFSET;
+ port->data_addr = base + K2_SATA_TF_DATA_OFFSET;
+ port->feature_addr =
+ port->error_addr = base + K2_SATA_TF_ERROR_OFFSET;
+ port->nsect_addr = base + K2_SATA_TF_NSECT_OFFSET;
+ port->lbal_addr = base + K2_SATA_TF_LBAL_OFFSET;
+ port->lbam_addr = base + K2_SATA_TF_LBAM_OFFSET;
+ port->lbah_addr = base + K2_SATA_TF_LBAH_OFFSET;
+ port->device_addr = base + K2_SATA_TF_DEVICE_OFFSET;
+ port->command_addr =
+ port->status_addr = base + K2_SATA_TF_CMDSTAT_OFFSET;
+ port->altstatus_addr =
+ port->ctl_addr = base + K2_SATA_TF_CTL_OFFSET;
+ port->bmdma_addr = base + K2_SATA_DMA_CMD_OFFSET;
+ port->scr_addr = base + K2_SATA_SCR_STATUS_OFFSET;
+}
+
+
+static int k2_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ static int printed_version;
+ struct ata_probe_ent *probe_ent = NULL;
+ unsigned long base;
+ void __iomem *mmio_base;
+ int pci_dev_busy = 0;
+ int rc;
+ int i;
+
+ if (!printed_version++)
+ dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
+
+ /*
+ * If this driver happens to only be useful on Apple's K2, then
+ * we should check that here as it has a normal Serverworks ID
+ */
+ rc = pci_enable_device(pdev);
+ if (rc)
+ return rc;
+ /*
+ * Check if we have resources mapped at all (second function may
+ * have been disabled by firmware)
+ */
+ if (pci_resource_len(pdev, 5) == 0)
+ return -ENODEV;
+
+ /* Request PCI regions */
+ rc = pci_request_regions(pdev, DRV_NAME);
+ if (rc) {
+ pci_dev_busy = 1;
+ goto err_out;
+ }
+
+ rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
+ if (rc)
+ goto err_out_regions;
+ rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
+ if (rc)
+ goto err_out_regions;
+
+ probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
+ if (probe_ent == NULL) {
+ rc = -ENOMEM;
+ goto err_out_regions;
+ }
+
+ memset(probe_ent, 0, sizeof(*probe_ent));
+ probe_ent->dev = pci_dev_to_dev(pdev);
+ INIT_LIST_HEAD(&probe_ent->node);
+
+ mmio_base = pci_iomap(pdev, 5, 0);
+ if (mmio_base == NULL) {
+ rc = -ENOMEM;
+ goto err_out_free_ent;
+ }
+ base = (unsigned long) mmio_base;
+
+ /* Clear a magic bit in SCR1 according to Darwin, those help
+ * some funky seagate drives (though so far, those were already
+ * set by the firmware on the machines I had access to)
+ */
+ writel(readl(mmio_base + K2_SATA_SICR1_OFFSET) & ~0x00040000,
+ mmio_base + K2_SATA_SICR1_OFFSET);
+
+ /* Clear SATA error & interrupts we don't use */
+ writel(0xffffffff, mmio_base + K2_SATA_SCR_ERROR_OFFSET);
+ writel(0x0, mmio_base + K2_SATA_SIM_OFFSET);
+
+ probe_ent->sht = &k2_sata_sht;
+ probe_ent->port_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+ ATA_FLAG_MMIO;
+ probe_ent->port_ops = &k2_sata_ops;
+ probe_ent->n_ports = 4;
+ probe_ent->irq = pdev->irq;
+ probe_ent->irq_flags = IRQF_SHARED;
+ probe_ent->mmio_base = mmio_base;
+
+ /* We don't care much about the PIO/UDMA masks, but the core won't like us
+ * if we don't fill these
+ */
+ probe_ent->pio_mask = 0x1f;
+ probe_ent->mwdma_mask = 0x7;
+ probe_ent->udma_mask = 0x7f;
+
+ /* different controllers have different number of ports - currently 4 or 8 */
+ /* All ports are on the same function. Multi-function device is no
+ * longer available. This should not be seen in any system. */
+ for (i = 0; i < ent->driver_data; i++)
+ k2_sata_setup_port(&probe_ent->port[i], base + i * K2_SATA_PORT_OFFSET);
+
+ pci_set_master(pdev);
+
+ /* FIXME: check ata_device_add return value */
+ ata_device_add(probe_ent);
+ kfree(probe_ent);
+
+ return 0;
+
+err_out_free_ent:
+ kfree(probe_ent);
+err_out_regions:
+ pci_release_regions(pdev);
+err_out:
+ if (!pci_dev_busy)
+ pci_disable_device(pdev);
+ return rc;
+}
+
+/* 0x240 is device ID for Apple K2 device
+ * 0x241 is device ID for Serverworks Frodo4
+ * 0x242 is device ID for Serverworks Frodo8
+ * 0x24a is device ID for BCM5785 (aka HT1000) HT southbridge integrated SATA
+ * controller
+ * */
+static const struct pci_device_id k2_sata_pci_tbl[] = {
+ { 0x1166, 0x0240, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 },
+ { 0x1166, 0x0241, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 },
+ { 0x1166, 0x0242, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 },
+ { 0x1166, 0x024a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 },
+ { 0x1166, 0x024b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 },
+ { }
+};
+
+
+static struct pci_driver k2_sata_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = k2_sata_pci_tbl,
+ .probe = k2_sata_init_one,
+ .remove = ata_pci_remove_one,
+};
+
+
+static int __init k2_sata_init(void)
+{
+ return pci_register_driver(&k2_sata_pci_driver);
+}
+
+
+static void __exit k2_sata_exit(void)
+{
+ pci_unregister_driver(&k2_sata_pci_driver);
+}
+
+
+MODULE_AUTHOR("Benjamin Herrenschmidt");
+MODULE_DESCRIPTION("low-level driver for K2 SATA controller");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, k2_sata_pci_tbl);
+MODULE_VERSION(DRV_VERSION);
+
+module_init(k2_sata_init);
+module_exit(k2_sata_exit);
diff --git a/drivers/ata/sata_sx4.c b/drivers/ata/sata_sx4.c
new file mode 100644
index 00000000000..091867e10ea
--- /dev/null
+++ b/drivers/ata/sata_sx4.c
@@ -0,0 +1,1502 @@
+/*
+ * sata_sx4.c - Promise SATA
+ *
+ * Maintained by: Jeff Garzik <jgarzik@pobox.com>
+ * Please ALWAYS copy linux-ide@vger.kernel.org
+ * on emails.
+ *
+ * Copyright 2003-2004 Red Hat, Inc.
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * libata documentation is available via 'make {ps|pdf}docs',
+ * as Documentation/DocBook/libata.*
+ *
+ * Hardware documentation available under NDA.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/device.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_cmnd.h>
+#include <linux/libata.h>
+#include <asm/io.h>
+#include "sata_promise.h"
+
+#define DRV_NAME "sata_sx4"
+#define DRV_VERSION "0.9"
+
+
+enum {
+ PDC_PRD_TBL = 0x44, /* Direct command DMA table addr */
+
+ PDC_PKT_SUBMIT = 0x40, /* Command packet pointer addr */
+ PDC_HDMA_PKT_SUBMIT = 0x100, /* Host DMA packet pointer addr */
+ PDC_INT_SEQMASK = 0x40, /* Mask of asserted SEQ INTs */
+ PDC_HDMA_CTLSTAT = 0x12C, /* Host DMA control / status */
+
+ PDC_20621_SEQCTL = 0x400,
+ PDC_20621_SEQMASK = 0x480,
+ PDC_20621_GENERAL_CTL = 0x484,
+ PDC_20621_PAGE_SIZE = (32 * 1024),
+
+ /* chosen, not constant, values; we design our own DIMM mem map */
+ PDC_20621_DIMM_WINDOW = 0x0C, /* page# for 32K DIMM window */
+ PDC_20621_DIMM_BASE = 0x00200000,
+ PDC_20621_DIMM_DATA = (64 * 1024),
+ PDC_DIMM_DATA_STEP = (256 * 1024),
+ PDC_DIMM_WINDOW_STEP = (8 * 1024),
+ PDC_DIMM_HOST_PRD = (6 * 1024),
+ PDC_DIMM_HOST_PKT = (128 * 0),
+ PDC_DIMM_HPKT_PRD = (128 * 1),
+ PDC_DIMM_ATA_PKT = (128 * 2),
+ PDC_DIMM_APKT_PRD = (128 * 3),
+ PDC_DIMM_HEADER_SZ = PDC_DIMM_APKT_PRD + 128,
+ PDC_PAGE_WINDOW = 0x40,
+ PDC_PAGE_DATA = PDC_PAGE_WINDOW +
+ (PDC_20621_DIMM_DATA / PDC_20621_PAGE_SIZE),
+ PDC_PAGE_SET = PDC_DIMM_DATA_STEP / PDC_20621_PAGE_SIZE,
+
+ PDC_CHIP0_OFS = 0xC0000, /* offset of chip #0 */
+
+ PDC_20621_ERR_MASK = (1<<19) | (1<<20) | (1<<21) | (1<<22) |
+ (1<<23),
+
+ board_20621 = 0, /* FastTrak S150 SX4 */
+
+ PDC_RESET = (1 << 11), /* HDMA reset */
+
+ PDC_MAX_HDMA = 32,
+ PDC_HDMA_Q_MASK = (PDC_MAX_HDMA - 1),
+
+ PDC_DIMM0_SPD_DEV_ADDRESS = 0x50,
+ PDC_DIMM1_SPD_DEV_ADDRESS = 0x51,
+ PDC_MAX_DIMM_MODULE = 0x02,
+ PDC_I2C_CONTROL_OFFSET = 0x48,
+ PDC_I2C_ADDR_DATA_OFFSET = 0x4C,
+ PDC_DIMM0_CONTROL_OFFSET = 0x80,
+ PDC_DIMM1_CONTROL_OFFSET = 0x84,
+ PDC_SDRAM_CONTROL_OFFSET = 0x88,
+ PDC_I2C_WRITE = 0x00000000,
+ PDC_I2C_READ = 0x00000040,
+ PDC_I2C_START = 0x00000080,
+ PDC_I2C_MASK_INT = 0x00000020,
+ PDC_I2C_COMPLETE = 0x00010000,
+ PDC_I2C_NO_ACK = 0x00100000,
+ PDC_DIMM_SPD_SUBADDRESS_START = 0x00,
+ PDC_DIMM_SPD_SUBADDRESS_END = 0x7F,
+ PDC_DIMM_SPD_ROW_NUM = 3,
+ PDC_DIMM_SPD_COLUMN_NUM = 4,
+ PDC_DIMM_SPD_MODULE_ROW = 5,
+ PDC_DIMM_SPD_TYPE = 11,
+ PDC_DIMM_SPD_FRESH_RATE = 12,
+ PDC_DIMM_SPD_BANK_NUM = 17,
+ PDC_DIMM_SPD_CAS_LATENCY = 18,
+ PDC_DIMM_SPD_ATTRIBUTE = 21,
+ PDC_DIMM_SPD_ROW_PRE_CHARGE = 27,
+ PDC_DIMM_SPD_ROW_ACTIVE_DELAY = 28,
+ PDC_DIMM_SPD_RAS_CAS_DELAY = 29,
+ PDC_DIMM_SPD_ACTIVE_PRECHARGE = 30,
+ PDC_DIMM_SPD_SYSTEM_FREQ = 126,
+ PDC_CTL_STATUS = 0x08,
+ PDC_DIMM_WINDOW_CTLR = 0x0C,
+ PDC_TIME_CONTROL = 0x3C,
+ PDC_TIME_PERIOD = 0x40,
+ PDC_TIME_COUNTER = 0x44,
+ PDC_GENERAL_CTLR = 0x484,
+ PCI_PLL_INIT = 0x8A531824,
+ PCI_X_TCOUNT = 0xEE1E5CFF
+};
+
+
+struct pdc_port_priv {
+ u8 dimm_buf[(ATA_PRD_SZ * ATA_MAX_PRD) + 512];
+ u8 *pkt;
+ dma_addr_t pkt_dma;
+};
+
+struct pdc_host_priv {
+ void __iomem *dimm_mmio;
+
+ unsigned int doing_hdma;
+ unsigned int hdma_prod;
+ unsigned int hdma_cons;
+ struct {
+ struct ata_queued_cmd *qc;
+ unsigned int seq;
+ unsigned long pkt_ofs;
+ } hdma[32];
+};
+
+
+static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
+static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance, struct pt_regs *regs);
+static void pdc_eng_timeout(struct ata_port *ap);
+static void pdc_20621_phy_reset (struct ata_port *ap);
+static int pdc_port_start(struct ata_port *ap);
+static void pdc_port_stop(struct ata_port *ap);
+static void pdc20621_qc_prep(struct ata_queued_cmd *qc);
+static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf);
+static void pdc_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf);
+static void pdc20621_host_stop(struct ata_host *host);
+static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe);
+static int pdc20621_detect_dimm(struct ata_probe_ent *pe);
+static unsigned int pdc20621_i2c_read(struct ata_probe_ent *pe,
+ u32 device, u32 subaddr, u32 *pdata);
+static int pdc20621_prog_dimm0(struct ata_probe_ent *pe);
+static unsigned int pdc20621_prog_dimm_global(struct ata_probe_ent *pe);
+#ifdef ATA_VERBOSE_DEBUG
+static void pdc20621_get_from_dimm(struct ata_probe_ent *pe,
+ void *psource, u32 offset, u32 size);
+#endif
+static void pdc20621_put_to_dimm(struct ata_probe_ent *pe,
+ void *psource, u32 offset, u32 size);
+static void pdc20621_irq_clear(struct ata_port *ap);
+static unsigned int pdc20621_qc_issue_prot(struct ata_queued_cmd *qc);
+
+
+static struct scsi_host_template pdc_sata_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .slave_destroy = ata_scsi_slave_destroy,
+ .bios_param = ata_std_bios_param,
+};
+
+static const struct ata_port_operations pdc_20621_ops = {
+ .port_disable = ata_port_disable,
+ .tf_load = pdc_tf_load_mmio,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = pdc_exec_command_mmio,
+ .dev_select = ata_std_dev_select,
+ .phy_reset = pdc_20621_phy_reset,
+ .qc_prep = pdc20621_qc_prep,
+ .qc_issue = pdc20621_qc_issue_prot,
+ .data_xfer = ata_mmio_data_xfer,
+ .eng_timeout = pdc_eng_timeout,
+ .irq_handler = pdc20621_interrupt,
+ .irq_clear = pdc20621_irq_clear,
+ .port_start = pdc_port_start,
+ .port_stop = pdc_port_stop,
+ .host_stop = pdc20621_host_stop,
+};
+
+static const struct ata_port_info pdc_port_info[] = {
+ /* board_20621 */
+ {
+ .sht = &pdc_sata_sht,
+ .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+ ATA_FLAG_SRST | ATA_FLAG_MMIO |
+ ATA_FLAG_NO_ATAPI | ATA_FLAG_PIO_POLLING,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .mwdma_mask = 0x07, /* mwdma0-2 */
+ .udma_mask = 0x7f, /* udma0-6 ; FIXME */
+ .port_ops = &pdc_20621_ops,
+ },
+
+};
+
+static const struct pci_device_id pdc_sata_pci_tbl[] = {
+ { PCI_VENDOR_ID_PROMISE, 0x6622, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ board_20621 },
+ { } /* terminate list */
+};
+
+
+static struct pci_driver pdc_sata_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = pdc_sata_pci_tbl,
+ .probe = pdc_sata_init_one,
+ .remove = ata_pci_remove_one,
+};
+
+
+static void pdc20621_host_stop(struct ata_host *host)
+{
+ struct pci_dev *pdev = to_pci_dev(host->dev);
+ struct pdc_host_priv *hpriv = host->private_data;
+ void __iomem *dimm_mmio = hpriv->dimm_mmio;
+
+ pci_iounmap(pdev, dimm_mmio);
+ kfree(hpriv);
+
+ pci_iounmap(pdev, host->mmio_base);
+}
+
+static int pdc_port_start(struct ata_port *ap)
+{
+ struct device *dev = ap->host->dev;
+ struct pdc_port_priv *pp;
+ int rc;
+
+ rc = ata_port_start(ap);
+ if (rc)
+ return rc;
+
+ pp = kmalloc(sizeof(*pp), GFP_KERNEL);
+ if (!pp) {
+ rc = -ENOMEM;
+ goto err_out;
+ }
+ memset(pp, 0, sizeof(*pp));
+
+ pp->pkt = dma_alloc_coherent(dev, 128, &pp->pkt_dma, GFP_KERNEL);
+ if (!pp->pkt) {
+ rc = -ENOMEM;
+ goto err_out_kfree;
+ }
+
+ ap->private_data = pp;
+
+ return 0;
+
+err_out_kfree:
+ kfree(pp);
+err_out:
+ ata_port_stop(ap);
+ return rc;
+}
+
+
+static void pdc_port_stop(struct ata_port *ap)
+{
+ struct device *dev = ap->host->dev;
+ struct pdc_port_priv *pp = ap->private_data;
+
+ ap->private_data = NULL;
+ dma_free_coherent(dev, 128, pp->pkt, pp->pkt_dma);
+ kfree(pp);
+ ata_port_stop(ap);
+}
+
+
+static void pdc_20621_phy_reset (struct ata_port *ap)
+{
+ VPRINTK("ENTER\n");
+ ap->cbl = ATA_CBL_SATA;
+ ata_port_probe(ap);
+ ata_bus_reset(ap);
+}
+
+static inline void pdc20621_ata_sg(struct ata_taskfile *tf, u8 *buf,
+ unsigned int portno,
+ unsigned int total_len)
+{
+ u32 addr;
+ unsigned int dw = PDC_DIMM_APKT_PRD >> 2;
+ u32 *buf32 = (u32 *) buf;
+
+ /* output ATA packet S/G table */
+ addr = PDC_20621_DIMM_BASE + PDC_20621_DIMM_DATA +
+ (PDC_DIMM_DATA_STEP * portno);
+ VPRINTK("ATA sg addr 0x%x, %d\n", addr, addr);
+ buf32[dw] = cpu_to_le32(addr);
+ buf32[dw + 1] = cpu_to_le32(total_len | ATA_PRD_EOT);
+
+ VPRINTK("ATA PSG @ %x == (0x%x, 0x%x)\n",
+ PDC_20621_DIMM_BASE +
+ (PDC_DIMM_WINDOW_STEP * portno) +
+ PDC_DIMM_APKT_PRD,
+ buf32[dw], buf32[dw + 1]);
+}
+
+static inline void pdc20621_host_sg(struct ata_taskfile *tf, u8 *buf,
+ unsigned int portno,
+ unsigned int total_len)
+{
+ u32 addr;
+ unsigned int dw = PDC_DIMM_HPKT_PRD >> 2;
+ u32 *buf32 = (u32 *) buf;
+
+ /* output Host DMA packet S/G table */
+ addr = PDC_20621_DIMM_BASE + PDC_20621_DIMM_DATA +
+ (PDC_DIMM_DATA_STEP * portno);
+
+ buf32[dw] = cpu_to_le32(addr);
+ buf32[dw + 1] = cpu_to_le32(total_len | ATA_PRD_EOT);
+
+ VPRINTK("HOST PSG @ %x == (0x%x, 0x%x)\n",
+ PDC_20621_DIMM_BASE +
+ (PDC_DIMM_WINDOW_STEP * portno) +
+ PDC_DIMM_HPKT_PRD,
+ buf32[dw], buf32[dw + 1]);
+}
+
+static inline unsigned int pdc20621_ata_pkt(struct ata_taskfile *tf,
+ unsigned int devno, u8 *buf,
+ unsigned int portno)
+{
+ unsigned int i, dw;
+ u32 *buf32 = (u32 *) buf;
+ u8 dev_reg;
+
+ unsigned int dimm_sg = PDC_20621_DIMM_BASE +
+ (PDC_DIMM_WINDOW_STEP * portno) +
+ PDC_DIMM_APKT_PRD;
+ VPRINTK("ENTER, dimm_sg == 0x%x, %d\n", dimm_sg, dimm_sg);
+
+ i = PDC_DIMM_ATA_PKT;
+
+ /*
+ * Set up ATA packet
+ */
+ if ((tf->protocol == ATA_PROT_DMA) && (!(tf->flags & ATA_TFLAG_WRITE)))
+ buf[i++] = PDC_PKT_READ;
+ else if (tf->protocol == ATA_PROT_NODATA)
+ buf[i++] = PDC_PKT_NODATA;
+ else
+ buf[i++] = 0;
+ buf[i++] = 0; /* reserved */
+ buf[i++] = portno + 1; /* seq. id */
+ buf[i++] = 0xff; /* delay seq. id */
+
+ /* dimm dma S/G, and next-pkt */
+ dw = i >> 2;
+ if (tf->protocol == ATA_PROT_NODATA)
+ buf32[dw] = 0;
+ else
+ buf32[dw] = cpu_to_le32(dimm_sg);
+ buf32[dw + 1] = 0;
+ i += 8;
+
+ if (devno == 0)
+ dev_reg = ATA_DEVICE_OBS;
+ else
+ dev_reg = ATA_DEVICE_OBS | ATA_DEV1;
+
+ /* select device */
+ buf[i++] = (1 << 5) | PDC_PKT_CLEAR_BSY | ATA_REG_DEVICE;
+ buf[i++] = dev_reg;
+
+ /* device control register */
+ buf[i++] = (1 << 5) | PDC_REG_DEVCTL;
+ buf[i++] = tf->ctl;
+
+ return i;
+}
+
+static inline void pdc20621_host_pkt(struct ata_taskfile *tf, u8 *buf,
+ unsigned int portno)
+{
+ unsigned int dw;
+ u32 tmp, *buf32 = (u32 *) buf;
+
+ unsigned int host_sg = PDC_20621_DIMM_BASE +
+ (PDC_DIMM_WINDOW_STEP * portno) +
+ PDC_DIMM_HOST_PRD;
+ unsigned int dimm_sg = PDC_20621_DIMM_BASE +
+ (PDC_DIMM_WINDOW_STEP * portno) +
+ PDC_DIMM_HPKT_PRD;
+ VPRINTK("ENTER, dimm_sg == 0x%x, %d\n", dimm_sg, dimm_sg);
+ VPRINTK("host_sg == 0x%x, %d\n", host_sg, host_sg);
+
+ dw = PDC_DIMM_HOST_PKT >> 2;
+
+ /*
+ * Set up Host DMA packet
+ */
+ if ((tf->protocol == ATA_PROT_DMA) && (!(tf->flags & ATA_TFLAG_WRITE)))
+ tmp = PDC_PKT_READ;
+ else
+ tmp = 0;
+ tmp |= ((portno + 1 + 4) << 16); /* seq. id */
+ tmp |= (0xff << 24); /* delay seq. id */
+ buf32[dw + 0] = cpu_to_le32(tmp);
+ buf32[dw + 1] = cpu_to_le32(host_sg);
+ buf32[dw + 2] = cpu_to_le32(dimm_sg);
+ buf32[dw + 3] = 0;
+
+ VPRINTK("HOST PKT @ %x == (0x%x 0x%x 0x%x 0x%x)\n",
+ PDC_20621_DIMM_BASE + (PDC_DIMM_WINDOW_STEP * portno) +
+ PDC_DIMM_HOST_PKT,
+ buf32[dw + 0],
+ buf32[dw + 1],
+ buf32[dw + 2],
+ buf32[dw + 3]);
+}
+
+static void pdc20621_dma_prep(struct ata_queued_cmd *qc)
+{
+ struct scatterlist *sg;
+ struct ata_port *ap = qc->ap;
+ struct pdc_port_priv *pp = ap->private_data;
+ void __iomem *mmio = ap->host->mmio_base;
+ struct pdc_host_priv *hpriv = ap->host->private_data;
+ void __iomem *dimm_mmio = hpriv->dimm_mmio;
+ unsigned int portno = ap->port_no;
+ unsigned int i, idx, total_len = 0, sgt_len;
+ u32 *buf = (u32 *) &pp->dimm_buf[PDC_DIMM_HEADER_SZ];
+
+ WARN_ON(!(qc->flags & ATA_QCFLAG_DMAMAP));
+
+ VPRINTK("ata%u: ENTER\n", ap->id);
+
+ /* hard-code chip #0 */
+ mmio += PDC_CHIP0_OFS;
+
+ /*
+ * Build S/G table
+ */
+ idx = 0;
+ ata_for_each_sg(sg, qc) {
+ buf[idx++] = cpu_to_le32(sg_dma_address(sg));
+ buf[idx++] = cpu_to_le32(sg_dma_len(sg));
+ total_len += sg_dma_len(sg);
+ }
+ buf[idx - 1] |= cpu_to_le32(ATA_PRD_EOT);
+ sgt_len = idx * 4;
+
+ /*
+ * Build ATA, host DMA packets
+ */
+ pdc20621_host_sg(&qc->tf, &pp->dimm_buf[0], portno, total_len);
+ pdc20621_host_pkt(&qc->tf, &pp->dimm_buf[0], portno);
+
+ pdc20621_ata_sg(&qc->tf, &pp->dimm_buf[0], portno, total_len);
+ i = pdc20621_ata_pkt(&qc->tf, qc->dev->devno, &pp->dimm_buf[0], portno);
+
+ if (qc->tf.flags & ATA_TFLAG_LBA48)
+ i = pdc_prep_lba48(&qc->tf, &pp->dimm_buf[0], i);
+ else
+ i = pdc_prep_lba28(&qc->tf, &pp->dimm_buf[0], i);
+
+ pdc_pkt_footer(&qc->tf, &pp->dimm_buf[0], i);
+
+ /* copy three S/G tables and two packets to DIMM MMIO window */
+ memcpy_toio(dimm_mmio + (portno * PDC_DIMM_WINDOW_STEP),
+ &pp->dimm_buf, PDC_DIMM_HEADER_SZ);
+ memcpy_toio(dimm_mmio + (portno * PDC_DIMM_WINDOW_STEP) +
+ PDC_DIMM_HOST_PRD,
+ &pp->dimm_buf[PDC_DIMM_HEADER_SZ], sgt_len);
+
+ /* force host FIFO dump */
+ writel(0x00000001, mmio + PDC_20621_GENERAL_CTL);
+
+ readl(dimm_mmio); /* MMIO PCI posting flush */
+
+ VPRINTK("ata pkt buf ofs %u, prd size %u, mmio copied\n", i, sgt_len);
+}
+
+static void pdc20621_nodata_prep(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct pdc_port_priv *pp = ap->private_data;
+ void __iomem *mmio = ap->host->mmio_base;
+ struct pdc_host_priv *hpriv = ap->host->private_data;
+ void __iomem *dimm_mmio = hpriv->dimm_mmio;
+ unsigned int portno = ap->port_no;
+ unsigned int i;
+
+ VPRINTK("ata%u: ENTER\n", ap->id);
+
+ /* hard-code chip #0 */
+ mmio += PDC_CHIP0_OFS;
+
+ i = pdc20621_ata_pkt(&qc->tf, qc->dev->devno, &pp->dimm_buf[0], portno);
+
+ if (qc->tf.flags & ATA_TFLAG_LBA48)
+ i = pdc_prep_lba48(&qc->tf, &pp->dimm_buf[0], i);
+ else
+ i = pdc_prep_lba28(&qc->tf, &pp->dimm_buf[0], i);
+
+ pdc_pkt_footer(&qc->tf, &pp->dimm_buf[0], i);
+
+ /* copy three S/G tables and two packets to DIMM MMIO window */
+ memcpy_toio(dimm_mmio + (portno * PDC_DIMM_WINDOW_STEP),
+ &pp->dimm_buf, PDC_DIMM_HEADER_SZ);
+
+ /* force host FIFO dump */
+ writel(0x00000001, mmio + PDC_20621_GENERAL_CTL);
+
+ readl(dimm_mmio); /* MMIO PCI posting flush */
+
+ VPRINTK("ata pkt buf ofs %u, mmio copied\n", i);
+}
+
+static void pdc20621_qc_prep(struct ata_queued_cmd *qc)
+{
+ switch (qc->tf.protocol) {
+ case ATA_PROT_DMA:
+ pdc20621_dma_prep(qc);
+ break;
+ case ATA_PROT_NODATA:
+ pdc20621_nodata_prep(qc);
+ break;
+ default:
+ break;
+ }
+}
+
+static void __pdc20621_push_hdma(struct ata_queued_cmd *qc,
+ unsigned int seq,
+ u32 pkt_ofs)
+{
+ struct ata_port *ap = qc->ap;
+ struct ata_host *host = ap->host;
+ void __iomem *mmio = host->mmio_base;
+
+ /* hard-code chip #0 */
+ mmio += PDC_CHIP0_OFS;
+
+ writel(0x00000001, mmio + PDC_20621_SEQCTL + (seq * 4));
+ readl(mmio + PDC_20621_SEQCTL + (seq * 4)); /* flush */
+
+ writel(pkt_ofs, mmio + PDC_HDMA_PKT_SUBMIT);
+ readl(mmio + PDC_HDMA_PKT_SUBMIT); /* flush */
+}
+
+static void pdc20621_push_hdma(struct ata_queued_cmd *qc,
+ unsigned int seq,
+ u32 pkt_ofs)
+{
+ struct ata_port *ap = qc->ap;
+ struct pdc_host_priv *pp = ap->host->private_data;
+ unsigned int idx = pp->hdma_prod & PDC_HDMA_Q_MASK;
+
+ if (!pp->doing_hdma) {
+ __pdc20621_push_hdma(qc, seq, pkt_ofs);
+ pp->doing_hdma = 1;
+ return;
+ }
+
+ pp->hdma[idx].qc = qc;
+ pp->hdma[idx].seq = seq;
+ pp->hdma[idx].pkt_ofs = pkt_ofs;
+ pp->hdma_prod++;
+}
+
+static void pdc20621_pop_hdma(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct pdc_host_priv *pp = ap->host->private_data;
+ unsigned int idx = pp->hdma_cons & PDC_HDMA_Q_MASK;
+
+ /* if nothing on queue, we're done */
+ if (pp->hdma_prod == pp->hdma_cons) {
+ pp->doing_hdma = 0;
+ return;
+ }
+
+ __pdc20621_push_hdma(pp->hdma[idx].qc, pp->hdma[idx].seq,
+ pp->hdma[idx].pkt_ofs);
+ pp->hdma_cons++;
+}
+
+#ifdef ATA_VERBOSE_DEBUG
+static void pdc20621_dump_hdma(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ unsigned int port_no = ap->port_no;
+ struct pdc_host_priv *hpriv = ap->host->private_data;
+ void *dimm_mmio = hpriv->dimm_mmio;
+
+ dimm_mmio += (port_no * PDC_DIMM_WINDOW_STEP);
+ dimm_mmio += PDC_DIMM_HOST_PKT;
+
+ printk(KERN_ERR "HDMA[0] == 0x%08X\n", readl(dimm_mmio));
+ printk(KERN_ERR "HDMA[1] == 0x%08X\n", readl(dimm_mmio + 4));
+ printk(KERN_ERR "HDMA[2] == 0x%08X\n", readl(dimm_mmio + 8));
+ printk(KERN_ERR "HDMA[3] == 0x%08X\n", readl(dimm_mmio + 12));
+}
+#else
+static inline void pdc20621_dump_hdma(struct ata_queued_cmd *qc) { }
+#endif /* ATA_VERBOSE_DEBUG */
+
+static void pdc20621_packet_start(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct ata_host *host = ap->host;
+ unsigned int port_no = ap->port_no;
+ void __iomem *mmio = host->mmio_base;
+ unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE);
+ u8 seq = (u8) (port_no + 1);
+ unsigned int port_ofs;
+
+ /* hard-code chip #0 */
+ mmio += PDC_CHIP0_OFS;
+
+ VPRINTK("ata%u: ENTER\n", ap->id);
+
+ wmb(); /* flush PRD, pkt writes */
+
+ port_ofs = PDC_20621_DIMM_BASE + (PDC_DIMM_WINDOW_STEP * port_no);
+
+ /* if writing, we (1) DMA to DIMM, then (2) do ATA command */
+ if (rw && qc->tf.protocol == ATA_PROT_DMA) {
+ seq += 4;
+
+ pdc20621_dump_hdma(qc);
+ pdc20621_push_hdma(qc, seq, port_ofs + PDC_DIMM_HOST_PKT);
+ VPRINTK("queued ofs 0x%x (%u), seq %u\n",
+ port_ofs + PDC_DIMM_HOST_PKT,
+ port_ofs + PDC_DIMM_HOST_PKT,
+ seq);
+ } else {
+ writel(0x00000001, mmio + PDC_20621_SEQCTL + (seq * 4));
+ readl(mmio + PDC_20621_SEQCTL + (seq * 4)); /* flush */
+
+ writel(port_ofs + PDC_DIMM_ATA_PKT,
+ (void __iomem *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
+ readl((void __iomem *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
+ VPRINTK("submitted ofs 0x%x (%u), seq %u\n",
+ port_ofs + PDC_DIMM_ATA_PKT,
+ port_ofs + PDC_DIMM_ATA_PKT,
+ seq);
+ }
+}
+
+static unsigned int pdc20621_qc_issue_prot(struct ata_queued_cmd *qc)
+{
+ switch (qc->tf.protocol) {
+ case ATA_PROT_DMA:
+ case ATA_PROT_NODATA:
+ pdc20621_packet_start(qc);
+ return 0;
+
+ case ATA_PROT_ATAPI_DMA:
+ BUG();
+ break;
+
+ default:
+ break;
+ }
+
+ return ata_qc_issue_prot(qc);
+}
+
+static inline unsigned int pdc20621_host_intr( struct ata_port *ap,
+ struct ata_queued_cmd *qc,
+ unsigned int doing_hdma,
+ void __iomem *mmio)
+{
+ unsigned int port_no = ap->port_no;
+ unsigned int port_ofs =
+ PDC_20621_DIMM_BASE + (PDC_DIMM_WINDOW_STEP * port_no);
+ u8 status;
+ unsigned int handled = 0;
+
+ VPRINTK("ENTER\n");
+
+ if ((qc->tf.protocol == ATA_PROT_DMA) && /* read */
+ (!(qc->tf.flags & ATA_TFLAG_WRITE))) {
+
+ /* step two - DMA from DIMM to host */
+ if (doing_hdma) {
+ VPRINTK("ata%u: read hdma, 0x%x 0x%x\n", ap->id,
+ readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT));
+ /* get drive status; clear intr; complete txn */
+ qc->err_mask |= ac_err_mask(ata_wait_idle(ap));
+ ata_qc_complete(qc);
+ pdc20621_pop_hdma(qc);
+ }
+
+ /* step one - exec ATA command */
+ else {
+ u8 seq = (u8) (port_no + 1 + 4);
+ VPRINTK("ata%u: read ata, 0x%x 0x%x\n", ap->id,
+ readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT));
+
+ /* submit hdma pkt */
+ pdc20621_dump_hdma(qc);
+ pdc20621_push_hdma(qc, seq,
+ port_ofs + PDC_DIMM_HOST_PKT);
+ }
+ handled = 1;
+
+ } else if (qc->tf.protocol == ATA_PROT_DMA) { /* write */
+
+ /* step one - DMA from host to DIMM */
+ if (doing_hdma) {
+ u8 seq = (u8) (port_no + 1);
+ VPRINTK("ata%u: write hdma, 0x%x 0x%x\n", ap->id,
+ readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT));
+
+ /* submit ata pkt */
+ writel(0x00000001, mmio + PDC_20621_SEQCTL + (seq * 4));
+ readl(mmio + PDC_20621_SEQCTL + (seq * 4));
+ writel(port_ofs + PDC_DIMM_ATA_PKT,
+ (void __iomem *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
+ readl((void __iomem *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
+ }
+
+ /* step two - execute ATA command */
+ else {
+ VPRINTK("ata%u: write ata, 0x%x 0x%x\n", ap->id,
+ readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT));
+ /* get drive status; clear intr; complete txn */
+ qc->err_mask |= ac_err_mask(ata_wait_idle(ap));
+ ata_qc_complete(qc);
+ pdc20621_pop_hdma(qc);
+ }
+ handled = 1;
+
+ /* command completion, but no data xfer */
+ } else if (qc->tf.protocol == ATA_PROT_NODATA) {
+
+ status = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000);
+ DPRINTK("BUS_NODATA (drv_stat 0x%X)\n", status);
+ qc->err_mask |= ac_err_mask(status);
+ ata_qc_complete(qc);
+ handled = 1;
+
+ } else {
+ ap->stats.idle_irq++;
+ }
+
+ return handled;
+}
+
+static void pdc20621_irq_clear(struct ata_port *ap)
+{
+ struct ata_host *host = ap->host;
+ void __iomem *mmio = host->mmio_base;
+
+ mmio += PDC_CHIP0_OFS;
+
+ readl(mmio + PDC_20621_SEQMASK);
+}
+
+static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance, struct pt_regs *regs)
+{
+ struct ata_host *host = dev_instance;
+ struct ata_port *ap;
+ u32 mask = 0;
+ unsigned int i, tmp, port_no;
+ unsigned int handled = 0;
+ void __iomem *mmio_base;
+
+ VPRINTK("ENTER\n");
+
+ if (!host || !host->mmio_base) {
+ VPRINTK("QUICK EXIT\n");
+ return IRQ_NONE;
+ }
+
+ mmio_base = host->mmio_base;
+
+ /* reading should also clear interrupts */
+ mmio_base += PDC_CHIP0_OFS;
+ mask = readl(mmio_base + PDC_20621_SEQMASK);
+ VPRINTK("mask == 0x%x\n", mask);
+
+ if (mask == 0xffffffff) {
+ VPRINTK("QUICK EXIT 2\n");
+ return IRQ_NONE;
+ }
+ mask &= 0xffff; /* only 16 tags possible */
+ if (!mask) {
+ VPRINTK("QUICK EXIT 3\n");
+ return IRQ_NONE;
+ }
+
+ spin_lock(&host->lock);
+
+ for (i = 1; i < 9; i++) {
+ port_no = i - 1;
+ if (port_no > 3)
+ port_no -= 4;
+ if (port_no >= host->n_ports)
+ ap = NULL;
+ else
+ ap = host->ports[port_no];
+ tmp = mask & (1 << i);
+ VPRINTK("seq %u, port_no %u, ap %p, tmp %x\n", i, port_no, ap, tmp);
+ if (tmp && ap &&
+ !(ap->flags & ATA_FLAG_DISABLED)) {
+ struct ata_queued_cmd *qc;
+
+ qc = ata_qc_from_tag(ap, ap->active_tag);
+ if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)))
+ handled += pdc20621_host_intr(ap, qc, (i > 4),
+ mmio_base);
+ }
+ }
+
+ spin_unlock(&host->lock);
+
+ VPRINTK("mask == 0x%x\n", mask);
+
+ VPRINTK("EXIT\n");
+
+ return IRQ_RETVAL(handled);
+}
+
+static void pdc_eng_timeout(struct ata_port *ap)
+{
+ u8 drv_stat;
+ struct ata_host *host = ap->host;
+ struct ata_queued_cmd *qc;
+ unsigned long flags;
+
+ DPRINTK("ENTER\n");
+
+ spin_lock_irqsave(&host->lock, flags);
+
+ qc = ata_qc_from_tag(ap, ap->active_tag);
+
+ switch (qc->tf.protocol) {
+ case ATA_PROT_DMA:
+ case ATA_PROT_NODATA:
+ ata_port_printk(ap, KERN_ERR, "command timeout\n");
+ qc->err_mask |= __ac_err_mask(ata_wait_idle(ap));
+ break;
+
+ default:
+ drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000);
+
+ ata_port_printk(ap, KERN_ERR,
+ "unknown timeout, cmd 0x%x stat 0x%x\n",
+ qc->tf.command, drv_stat);
+
+ qc->err_mask |= ac_err_mask(drv_stat);
+ break;
+ }
+
+ spin_unlock_irqrestore(&host->lock, flags);
+ ata_eh_qc_complete(qc);
+ DPRINTK("EXIT\n");
+}
+
+static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf)
+{
+ WARN_ON (tf->protocol == ATA_PROT_DMA ||
+ tf->protocol == ATA_PROT_NODATA);
+ ata_tf_load(ap, tf);
+}
+
+
+static void pdc_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf)
+{
+ WARN_ON (tf->protocol == ATA_PROT_DMA ||
+ tf->protocol == ATA_PROT_NODATA);
+ ata_exec_command(ap, tf);
+}
+
+
+static void pdc_sata_setup_port(struct ata_ioports *port, unsigned long base)
+{
+ port->cmd_addr = base;
+ port->data_addr = base;
+ port->feature_addr =
+ port->error_addr = base + 0x4;
+ port->nsect_addr = base + 0x8;
+ port->lbal_addr = base + 0xc;
+ port->lbam_addr = base + 0x10;
+ port->lbah_addr = base + 0x14;
+ port->device_addr = base + 0x18;
+ port->command_addr =
+ port->status_addr = base + 0x1c;
+ port->altstatus_addr =
+ port->ctl_addr = base + 0x38;
+}
+
+
+#ifdef ATA_VERBOSE_DEBUG
+static void pdc20621_get_from_dimm(struct ata_probe_ent *pe, void *psource,
+ u32 offset, u32 size)
+{
+ u32 window_size;
+ u16 idx;
+ u8 page_mask;
+ long dist;
+ void __iomem *mmio = pe->mmio_base;
+ struct pdc_host_priv *hpriv = pe->private_data;
+ void __iomem *dimm_mmio = hpriv->dimm_mmio;
+
+ /* hard-code chip #0 */
+ mmio += PDC_CHIP0_OFS;
+
+ page_mask = 0x00;
+ window_size = 0x2000 * 4; /* 32K byte uchar size */
+ idx = (u16) (offset / window_size);
+
+ writel(0x01, mmio + PDC_GENERAL_CTLR);
+ readl(mmio + PDC_GENERAL_CTLR);
+ writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
+ readl(mmio + PDC_DIMM_WINDOW_CTLR);
+
+ offset -= (idx * window_size);
+ idx++;
+ dist = ((long) (window_size - (offset + size))) >= 0 ? size :
+ (long) (window_size - offset);
+ memcpy_fromio((char *) psource, (char *) (dimm_mmio + offset / 4),
+ dist);
+
+ psource += dist;
+ size -= dist;
+ for (; (long) size >= (long) window_size ;) {
+ writel(0x01, mmio + PDC_GENERAL_CTLR);
+ readl(mmio + PDC_GENERAL_CTLR);
+ writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
+ readl(mmio + PDC_DIMM_WINDOW_CTLR);
+ memcpy_fromio((char *) psource, (char *) (dimm_mmio),
+ window_size / 4);
+ psource += window_size;
+ size -= window_size;
+ idx ++;
+ }
+
+ if (size) {
+ writel(0x01, mmio + PDC_GENERAL_CTLR);
+ readl(mmio + PDC_GENERAL_CTLR);
+ writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
+ readl(mmio + PDC_DIMM_WINDOW_CTLR);
+ memcpy_fromio((char *) psource, (char *) (dimm_mmio),
+ size / 4);
+ }
+}
+#endif
+
+
+static void pdc20621_put_to_dimm(struct ata_probe_ent *pe, void *psource,
+ u32 offset, u32 size)
+{
+ u32 window_size;
+ u16 idx;
+ u8 page_mask;
+ long dist;
+ void __iomem *mmio = pe->mmio_base;
+ struct pdc_host_priv *hpriv = pe->private_data;
+ void __iomem *dimm_mmio = hpriv->dimm_mmio;
+
+ /* hard-code chip #0 */
+ mmio += PDC_CHIP0_OFS;
+
+ page_mask = 0x00;
+ window_size = 0x2000 * 4; /* 32K byte uchar size */
+ idx = (u16) (offset / window_size);
+
+ writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
+ readl(mmio + PDC_DIMM_WINDOW_CTLR);
+ offset -= (idx * window_size);
+ idx++;
+ dist = ((long)(s32)(window_size - (offset + size))) >= 0 ? size :
+ (long) (window_size - offset);
+ memcpy_toio(dimm_mmio + offset / 4, psource, dist);
+ writel(0x01, mmio + PDC_GENERAL_CTLR);
+ readl(mmio + PDC_GENERAL_CTLR);
+
+ psource += dist;
+ size -= dist;
+ for (; (long) size >= (long) window_size ;) {
+ writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
+ readl(mmio + PDC_DIMM_WINDOW_CTLR);
+ memcpy_toio(dimm_mmio, psource, window_size / 4);
+ writel(0x01, mmio + PDC_GENERAL_CTLR);
+ readl(mmio + PDC_GENERAL_CTLR);
+ psource += window_size;
+ size -= window_size;
+ idx ++;
+ }
+
+ if (size) {
+ writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
+ readl(mmio + PDC_DIMM_WINDOW_CTLR);
+ memcpy_toio(dimm_mmio, psource, size / 4);
+ writel(0x01, mmio + PDC_GENERAL_CTLR);
+ readl(mmio + PDC_GENERAL_CTLR);
+ }
+}
+
+
+static unsigned int pdc20621_i2c_read(struct ata_probe_ent *pe, u32 device,
+ u32 subaddr, u32 *pdata)
+{
+ void __iomem *mmio = pe->mmio_base;
+ u32 i2creg = 0;
+ u32 status;
+ u32 count =0;
+
+ /* hard-code chip #0 */
+ mmio += PDC_CHIP0_OFS;
+
+ i2creg |= device << 24;
+ i2creg |= subaddr << 16;
+
+ /* Set the device and subaddress */
+ writel(i2creg, mmio + PDC_I2C_ADDR_DATA_OFFSET);
+ readl(mmio + PDC_I2C_ADDR_DATA_OFFSET);
+
+ /* Write Control to perform read operation, mask int */
+ writel(PDC_I2C_READ | PDC_I2C_START | PDC_I2C_MASK_INT,
+ mmio + PDC_I2C_CONTROL_OFFSET);
+
+ for (count = 0; count <= 1000; count ++) {
+ status = readl(mmio + PDC_I2C_CONTROL_OFFSET);
+ if (status & PDC_I2C_COMPLETE) {
+ status = readl(mmio + PDC_I2C_ADDR_DATA_OFFSET);
+ break;
+ } else if (count == 1000)
+ return 0;
+ }
+
+ *pdata = (status >> 8) & 0x000000ff;
+ return 1;
+}
+
+
+static int pdc20621_detect_dimm(struct ata_probe_ent *pe)
+{
+ u32 data=0 ;
+ if (pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS,
+ PDC_DIMM_SPD_SYSTEM_FREQ, &data)) {
+ if (data == 100)
+ return 100;
+ } else
+ return 0;
+
+ if (pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS, 9, &data)) {
+ if(data <= 0x75)
+ return 133;
+ } else
+ return 0;
+
+ return 0;
+}
+
+
+static int pdc20621_prog_dimm0(struct ata_probe_ent *pe)
+{
+ u32 spd0[50];
+ u32 data = 0;
+ int size, i;
+ u8 bdimmsize;
+ void __iomem *mmio = pe->mmio_base;
+ static const struct {
+ unsigned int reg;
+ unsigned int ofs;
+ } pdc_i2c_read_data [] = {
+ { PDC_DIMM_SPD_TYPE, 11 },
+ { PDC_DIMM_SPD_FRESH_RATE, 12 },
+ { PDC_DIMM_SPD_COLUMN_NUM, 4 },
+ { PDC_DIMM_SPD_ATTRIBUTE, 21 },
+ { PDC_DIMM_SPD_ROW_NUM, 3 },
+ { PDC_DIMM_SPD_BANK_NUM, 17 },
+ { PDC_DIMM_SPD_MODULE_ROW, 5 },
+ { PDC_DIMM_SPD_ROW_PRE_CHARGE, 27 },
+ { PDC_DIMM_SPD_ROW_ACTIVE_DELAY, 28 },
+ { PDC_DIMM_SPD_RAS_CAS_DELAY, 29 },
+ { PDC_DIMM_SPD_ACTIVE_PRECHARGE, 30 },
+ { PDC_DIMM_SPD_CAS_LATENCY, 18 },
+ };
+
+ /* hard-code chip #0 */
+ mmio += PDC_CHIP0_OFS;
+
+ for(i=0; i<ARRAY_SIZE(pdc_i2c_read_data); i++)
+ pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS,
+ pdc_i2c_read_data[i].reg,
+ &spd0[pdc_i2c_read_data[i].ofs]);
+
+ data |= (spd0[4] - 8) | ((spd0[21] != 0) << 3) | ((spd0[3]-11) << 4);
+ data |= ((spd0[17] / 4) << 6) | ((spd0[5] / 2) << 7) |
+ ((((spd0[27] + 9) / 10) - 1) << 8) ;
+ data |= (((((spd0[29] > spd0[28])
+ ? spd0[29] : spd0[28]) + 9) / 10) - 1) << 10;
+ data |= ((spd0[30] - spd0[29] + 9) / 10 - 2) << 12;
+
+ if (spd0[18] & 0x08)
+ data |= ((0x03) << 14);
+ else if (spd0[18] & 0x04)
+ data |= ((0x02) << 14);
+ else if (spd0[18] & 0x01)
+ data |= ((0x01) << 14);
+ else
+ data |= (0 << 14);
+
+ /*
+ Calculate the size of bDIMMSize (power of 2) and
+ merge the DIMM size by program start/end address.
+ */
+
+ bdimmsize = spd0[4] + (spd0[5] / 2) + spd0[3] + (spd0[17] / 2) + 3;
+ size = (1 << bdimmsize) >> 20; /* size = xxx(MB) */
+ data |= (((size / 16) - 1) << 16);
+ data |= (0 << 23);
+ data |= 8;
+ writel(data, mmio + PDC_DIMM0_CONTROL_OFFSET);
+ readl(mmio + PDC_DIMM0_CONTROL_OFFSET);
+ return size;
+}
+
+
+static unsigned int pdc20621_prog_dimm_global(struct ata_probe_ent *pe)
+{
+ u32 data, spd0;
+ int error, i;
+ void __iomem *mmio = pe->mmio_base;
+
+ /* hard-code chip #0 */
+ mmio += PDC_CHIP0_OFS;
+
+ /*
+ Set To Default : DIMM Module Global Control Register (0x022259F1)
+ DIMM Arbitration Disable (bit 20)
+ DIMM Data/Control Output Driving Selection (bit12 - bit15)
+ Refresh Enable (bit 17)
+ */
+
+ data = 0x022259F1;
+ writel(data, mmio + PDC_SDRAM_CONTROL_OFFSET);
+ readl(mmio + PDC_SDRAM_CONTROL_OFFSET);
+
+ /* Turn on for ECC */
+ pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS,
+ PDC_DIMM_SPD_TYPE, &spd0);
+ if (spd0 == 0x02) {
+ data |= (0x01 << 16);
+ writel(data, mmio + PDC_SDRAM_CONTROL_OFFSET);
+ readl(mmio + PDC_SDRAM_CONTROL_OFFSET);
+ printk(KERN_ERR "Local DIMM ECC Enabled\n");
+ }
+
+ /* DIMM Initialization Select/Enable (bit 18/19) */
+ data &= (~(1<<18));
+ data |= (1<<19);
+ writel(data, mmio + PDC_SDRAM_CONTROL_OFFSET);
+
+ error = 1;
+ for (i = 1; i <= 10; i++) { /* polling ~5 secs */
+ data = readl(mmio + PDC_SDRAM_CONTROL_OFFSET);
+ if (!(data & (1<<19))) {
+ error = 0;
+ break;
+ }
+ msleep(i*100);
+ }
+ return error;
+}
+
+
+static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe)
+{
+ int speed, size, length;
+ u32 addr,spd0,pci_status;
+ u32 tmp=0;
+ u32 time_period=0;
+ u32 tcount=0;
+ u32 ticks=0;
+ u32 clock=0;
+ u32 fparam=0;
+ void __iomem *mmio = pe->mmio_base;
+
+ /* hard-code chip #0 */
+ mmio += PDC_CHIP0_OFS;
+
+ /* Initialize PLL based upon PCI Bus Frequency */
+
+ /* Initialize Time Period Register */
+ writel(0xffffffff, mmio + PDC_TIME_PERIOD);
+ time_period = readl(mmio + PDC_TIME_PERIOD);
+ VPRINTK("Time Period Register (0x40): 0x%x\n", time_period);
+
+ /* Enable timer */
+ writel(0x00001a0, mmio + PDC_TIME_CONTROL);
+ readl(mmio + PDC_TIME_CONTROL);
+
+ /* Wait 3 seconds */
+ msleep(3000);
+
+ /*
+ When timer is enabled, counter is decreased every internal
+ clock cycle.
+ */
+
+ tcount = readl(mmio + PDC_TIME_COUNTER);
+ VPRINTK("Time Counter Register (0x44): 0x%x\n", tcount);
+
+ /*
+ If SX4 is on PCI-X bus, after 3 seconds, the timer counter
+ register should be >= (0xffffffff - 3x10^8).
+ */
+ if(tcount >= PCI_X_TCOUNT) {
+ ticks = (time_period - tcount);
+ VPRINTK("Num counters 0x%x (%d)\n", ticks, ticks);
+
+ clock = (ticks / 300000);
+ VPRINTK("10 * Internal clk = 0x%x (%d)\n", clock, clock);
+
+ clock = (clock * 33);
+ VPRINTK("10 * Internal clk * 33 = 0x%x (%d)\n", clock, clock);
+
+ /* PLL F Param (bit 22:16) */
+ fparam = (1400000 / clock) - 2;
+ VPRINTK("PLL F Param: 0x%x (%d)\n", fparam, fparam);
+
+ /* OD param = 0x2 (bit 31:30), R param = 0x5 (bit 29:25) */
+ pci_status = (0x8a001824 | (fparam << 16));
+ } else
+ pci_status = PCI_PLL_INIT;
+
+ /* Initialize PLL. */
+ VPRINTK("pci_status: 0x%x\n", pci_status);
+ writel(pci_status, mmio + PDC_CTL_STATUS);
+ readl(mmio + PDC_CTL_STATUS);
+
+ /*
+ Read SPD of DIMM by I2C interface,
+ and program the DIMM Module Controller.
+ */
+ if (!(speed = pdc20621_detect_dimm(pe))) {
+ printk(KERN_ERR "Detect Local DIMM Fail\n");
+ return 1; /* DIMM error */
+ }
+ VPRINTK("Local DIMM Speed = %d\n", speed);
+
+ /* Programming DIMM0 Module Control Register (index_CID0:80h) */
+ size = pdc20621_prog_dimm0(pe);
+ VPRINTK("Local DIMM Size = %dMB\n",size);
+
+ /* Programming DIMM Module Global Control Register (index_CID0:88h) */
+ if (pdc20621_prog_dimm_global(pe)) {
+ printk(KERN_ERR "Programming DIMM Module Global Control Register Fail\n");
+ return 1;
+ }
+
+#ifdef ATA_VERBOSE_DEBUG
+ {
+ u8 test_parttern1[40] = {0x55,0xAA,'P','r','o','m','i','s','e',' ',
+ 'N','o','t',' ','Y','e','t',' ','D','e','f','i','n','e','d',' ',
+ '1','.','1','0',
+ '9','8','0','3','1','6','1','2',0,0};
+ u8 test_parttern2[40] = {0};
+
+ pdc20621_put_to_dimm(pe, (void *) test_parttern2, 0x10040, 40);
+ pdc20621_put_to_dimm(pe, (void *) test_parttern2, 0x40, 40);
+
+ pdc20621_put_to_dimm(pe, (void *) test_parttern1, 0x10040, 40);
+ pdc20621_get_from_dimm(pe, (void *) test_parttern2, 0x40, 40);
+ printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0],
+ test_parttern2[1], &(test_parttern2[2]));
+ pdc20621_get_from_dimm(pe, (void *) test_parttern2, 0x10040,
+ 40);
+ printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0],
+ test_parttern2[1], &(test_parttern2[2]));
+
+ pdc20621_put_to_dimm(pe, (void *) test_parttern1, 0x40, 40);
+ pdc20621_get_from_dimm(pe, (void *) test_parttern2, 0x40, 40);
+ printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0],
+ test_parttern2[1], &(test_parttern2[2]));
+ }
+#endif
+
+ /* ECC initiliazation. */
+
+ pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS,
+ PDC_DIMM_SPD_TYPE, &spd0);
+ if (spd0 == 0x02) {
+ VPRINTK("Start ECC initialization\n");
+ addr = 0;
+ length = size * 1024 * 1024;
+ while (addr < length) {
+ pdc20621_put_to_dimm(pe, (void *) &tmp, addr,
+ sizeof(u32));
+ addr += sizeof(u32);
+ }
+ VPRINTK("Finish ECC initialization\n");
+ }
+ return 0;
+}
+
+
+static void pdc_20621_init(struct ata_probe_ent *pe)
+{
+ u32 tmp;
+ void __iomem *mmio = pe->mmio_base;
+
+ /* hard-code chip #0 */
+ mmio += PDC_CHIP0_OFS;
+
+ /*
+ * Select page 0x40 for our 32k DIMM window
+ */
+ tmp = readl(mmio + PDC_20621_DIMM_WINDOW) & 0xffff0000;
+ tmp |= PDC_PAGE_WINDOW; /* page 40h; arbitrarily selected */
+ writel(tmp, mmio + PDC_20621_DIMM_WINDOW);
+
+ /*
+ * Reset Host DMA
+ */
+ tmp = readl(mmio + PDC_HDMA_CTLSTAT);
+ tmp |= PDC_RESET;
+ writel(tmp, mmio + PDC_HDMA_CTLSTAT);
+ readl(mmio + PDC_HDMA_CTLSTAT); /* flush */
+
+ udelay(10);
+
+ tmp = readl(mmio + PDC_HDMA_CTLSTAT);
+ tmp &= ~PDC_RESET;
+ writel(tmp, mmio + PDC_HDMA_CTLSTAT);
+ readl(mmio + PDC_HDMA_CTLSTAT); /* flush */
+}
+
+static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ static int printed_version;
+ struct ata_probe_ent *probe_ent = NULL;
+ unsigned long base;
+ void __iomem *mmio_base;
+ void __iomem *dimm_mmio = NULL;
+ struct pdc_host_priv *hpriv = NULL;
+ unsigned int board_idx = (unsigned int) ent->driver_data;
+ int pci_dev_busy = 0;
+ int rc;
+
+ if (!printed_version++)
+ dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
+
+ rc = pci_enable_device(pdev);
+ if (rc)
+ return rc;
+
+ rc = pci_request_regions(pdev, DRV_NAME);
+ if (rc) {
+ pci_dev_busy = 1;
+ goto err_out;
+ }
+
+ rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
+ if (rc)
+ goto err_out_regions;
+ rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
+ if (rc)
+ goto err_out_regions;
+
+ probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
+ if (probe_ent == NULL) {
+ rc = -ENOMEM;
+ goto err_out_regions;
+ }
+
+ memset(probe_ent, 0, sizeof(*probe_ent));
+ probe_ent->dev = pci_dev_to_dev(pdev);
+ INIT_LIST_HEAD(&probe_ent->node);
+
+ mmio_base = pci_iomap(pdev, 3, 0);
+ if (mmio_base == NULL) {
+ rc = -ENOMEM;
+ goto err_out_free_ent;
+ }
+ base = (unsigned long) mmio_base;
+
+ hpriv = kmalloc(sizeof(*hpriv), GFP_KERNEL);
+ if (!hpriv) {
+ rc = -ENOMEM;
+ goto err_out_iounmap;
+ }
+ memset(hpriv, 0, sizeof(*hpriv));
+
+ dimm_mmio = pci_iomap(pdev, 4, 0);
+ if (!dimm_mmio) {
+ kfree(hpriv);
+ rc = -ENOMEM;
+ goto err_out_iounmap;
+ }
+
+ hpriv->dimm_mmio = dimm_mmio;
+
+ probe_ent->sht = pdc_port_info[board_idx].sht;
+ probe_ent->port_flags = pdc_port_info[board_idx].flags;
+ probe_ent->pio_mask = pdc_port_info[board_idx].pio_mask;
+ probe_ent->mwdma_mask = pdc_port_info[board_idx].mwdma_mask;
+ probe_ent->udma_mask = pdc_port_info[board_idx].udma_mask;
+ probe_ent->port_ops = pdc_port_info[board_idx].port_ops;
+
+ probe_ent->irq = pdev->irq;
+ probe_ent->irq_flags = IRQF_SHARED;
+ probe_ent->mmio_base = mmio_base;
+
+ probe_ent->private_data = hpriv;
+ base += PDC_CHIP0_OFS;
+
+ probe_ent->n_ports = 4;
+ pdc_sata_setup_port(&probe_ent->port[0], base + 0x200);
+ pdc_sata_setup_port(&probe_ent->port[1], base + 0x280);
+ pdc_sata_setup_port(&probe_ent->port[2], base + 0x300);
+ pdc_sata_setup_port(&probe_ent->port[3], base + 0x380);
+
+ pci_set_master(pdev);
+
+ /* initialize adapter */
+ /* initialize local dimm */
+ if (pdc20621_dimm_init(probe_ent)) {
+ rc = -ENOMEM;
+ goto err_out_iounmap_dimm;
+ }
+ pdc_20621_init(probe_ent);
+
+ /* FIXME: check ata_device_add return value */
+ ata_device_add(probe_ent);
+ kfree(probe_ent);
+
+ return 0;
+
+err_out_iounmap_dimm: /* only get to this label if 20621 */
+ kfree(hpriv);
+ pci_iounmap(pdev, dimm_mmio);
+err_out_iounmap:
+ pci_iounmap(pdev, mmio_base);
+err_out_free_ent:
+ kfree(probe_ent);
+err_out_regions:
+ pci_release_regions(pdev);
+err_out:
+ if (!pci_dev_busy)
+ pci_disable_device(pdev);
+ return rc;
+}
+
+
+static int __init pdc_sata_init(void)
+{
+ return pci_register_driver(&pdc_sata_pci_driver);
+}
+
+
+static void __exit pdc_sata_exit(void)
+{
+ pci_unregister_driver(&pdc_sata_pci_driver);
+}
+
+
+MODULE_AUTHOR("Jeff Garzik");
+MODULE_DESCRIPTION("Promise SATA low-level driver");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, pdc_sata_pci_tbl);
+MODULE_VERSION(DRV_VERSION);
+
+module_init(pdc_sata_init);
+module_exit(pdc_sata_exit);
diff --git a/drivers/ata/sata_uli.c b/drivers/ata/sata_uli.c
new file mode 100644
index 00000000000..dd76f37be18
--- /dev/null
+++ b/drivers/ata/sata_uli.c
@@ -0,0 +1,300 @@
+/*
+ * sata_uli.c - ULi Electronics SATA
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * libata documentation is available via 'make {ps|pdf}docs',
+ * as Documentation/DocBook/libata.*
+ *
+ * Hardware documentation available under NDA.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+
+#define DRV_NAME "sata_uli"
+#define DRV_VERSION "1.0"
+
+enum {
+ uli_5289 = 0,
+ uli_5287 = 1,
+ uli_5281 = 2,
+
+ uli_max_ports = 4,
+
+ /* PCI configuration registers */
+ ULI5287_BASE = 0x90, /* sata0 phy SCR registers */
+ ULI5287_OFFS = 0x10, /* offset from sata0->sata1 phy regs */
+ ULI5281_BASE = 0x60, /* sata0 phy SCR registers */
+ ULI5281_OFFS = 0x60, /* offset from sata0->sata1 phy regs */
+};
+
+struct uli_priv {
+ unsigned int scr_cfg_addr[uli_max_ports];
+};
+
+static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
+static u32 uli_scr_read (struct ata_port *ap, unsigned int sc_reg);
+static void uli_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+
+static const struct pci_device_id uli_pci_tbl[] = {
+ { PCI_VENDOR_ID_AL, 0x5289, PCI_ANY_ID, PCI_ANY_ID, 0, 0, uli_5289 },
+ { PCI_VENDOR_ID_AL, 0x5287, PCI_ANY_ID, PCI_ANY_ID, 0, 0, uli_5287 },
+ { PCI_VENDOR_ID_AL, 0x5281, PCI_ANY_ID, PCI_ANY_ID, 0, 0, uli_5281 },
+ { } /* terminate list */
+};
+
+
+static struct pci_driver uli_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = uli_pci_tbl,
+ .probe = uli_init_one,
+ .remove = ata_pci_remove_one,
+};
+
+static struct scsi_host_template uli_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .slave_destroy = ata_scsi_slave_destroy,
+ .bios_param = ata_std_bios_param,
+};
+
+static const struct ata_port_operations uli_ops = {
+ .port_disable = ata_port_disable,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+ .data_xfer = ata_pio_data_xfer,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = ata_bmdma_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .scr_read = uli_scr_read,
+ .scr_write = uli_scr_write,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop,
+};
+
+static struct ata_port_info uli_port_info = {
+ .sht = &uli_sht,
+ .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .udma_mask = 0x7f, /* udma0-6 */
+ .port_ops = &uli_ops,
+};
+
+
+MODULE_AUTHOR("Peer Chen");
+MODULE_DESCRIPTION("low-level driver for ULi Electronics SATA controller");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, uli_pci_tbl);
+MODULE_VERSION(DRV_VERSION);
+
+static unsigned int get_scr_cfg_addr(struct ata_port *ap, unsigned int sc_reg)
+{
+ struct uli_priv *hpriv = ap->host->private_data;
+ return hpriv->scr_cfg_addr[ap->port_no] + (4 * sc_reg);
+}
+
+static u32 uli_scr_cfg_read (struct ata_port *ap, unsigned int sc_reg)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ unsigned int cfg_addr = get_scr_cfg_addr(ap, sc_reg);
+ u32 val;
+
+ pci_read_config_dword(pdev, cfg_addr, &val);
+ return val;
+}
+
+static void uli_scr_cfg_write (struct ata_port *ap, unsigned int scr, u32 val)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ unsigned int cfg_addr = get_scr_cfg_addr(ap, scr);
+
+ pci_write_config_dword(pdev, cfg_addr, val);
+}
+
+static u32 uli_scr_read (struct ata_port *ap, unsigned int sc_reg)
+{
+ if (sc_reg > SCR_CONTROL)
+ return 0xffffffffU;
+
+ return uli_scr_cfg_read(ap, sc_reg);
+}
+
+static void uli_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
+{
+ if (sc_reg > SCR_CONTROL) //SCR_CONTROL=2, SCR_ERROR=1, SCR_STATUS=0
+ return;
+
+ uli_scr_cfg_write(ap, sc_reg, val);
+}
+
+static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ static int printed_version;
+ struct ata_probe_ent *probe_ent;
+ struct ata_port_info *ppi[2];
+ int rc;
+ unsigned int board_idx = (unsigned int) ent->driver_data;
+ int pci_dev_busy = 0;
+ struct uli_priv *hpriv;
+
+ if (!printed_version++)
+ dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n");
+
+ rc = pci_enable_device(pdev);
+ if (rc)
+ return rc;
+
+ rc = pci_request_regions(pdev, DRV_NAME);
+ if (rc) {
+ pci_dev_busy = 1;
+ goto err_out;
+ }
+
+ rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
+ if (rc)
+ goto err_out_regions;
+ rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
+ if (rc)
+ goto err_out_regions;
+
+ ppi[0] = ppi[1] = &uli_port_info;
+ probe_ent = ata_pci_init_native_mode(pdev, ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY);
+ if (!probe_ent) {
+ rc = -ENOMEM;
+ goto err_out_regions;
+ }
+
+ hpriv = kzalloc(sizeof(*hpriv), GFP_KERNEL);
+ if (!hpriv) {
+ rc = -ENOMEM;
+ goto err_out_probe_ent;
+ }
+
+ probe_ent->private_data = hpriv;
+
+ switch (board_idx) {
+ case uli_5287:
+ hpriv->scr_cfg_addr[0] = ULI5287_BASE;
+ hpriv->scr_cfg_addr[1] = ULI5287_BASE + ULI5287_OFFS;
+ probe_ent->n_ports = 4;
+
+ probe_ent->port[2].cmd_addr = pci_resource_start(pdev, 0) + 8;
+ probe_ent->port[2].altstatus_addr =
+ probe_ent->port[2].ctl_addr =
+ (pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS) + 4;
+ probe_ent->port[2].bmdma_addr = pci_resource_start(pdev, 4) + 16;
+ hpriv->scr_cfg_addr[2] = ULI5287_BASE + ULI5287_OFFS*4;
+
+ probe_ent->port[3].cmd_addr = pci_resource_start(pdev, 2) + 8;
+ probe_ent->port[3].altstatus_addr =
+ probe_ent->port[3].ctl_addr =
+ (pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS) + 4;
+ probe_ent->port[3].bmdma_addr = pci_resource_start(pdev, 4) + 24;
+ hpriv->scr_cfg_addr[3] = ULI5287_BASE + ULI5287_OFFS*5;
+
+ ata_std_ports(&probe_ent->port[2]);
+ ata_std_ports(&probe_ent->port[3]);
+ break;
+
+ case uli_5289:
+ hpriv->scr_cfg_addr[0] = ULI5287_BASE;
+ hpriv->scr_cfg_addr[1] = ULI5287_BASE + ULI5287_OFFS;
+ break;
+
+ case uli_5281:
+ hpriv->scr_cfg_addr[0] = ULI5281_BASE;
+ hpriv->scr_cfg_addr[1] = ULI5281_BASE + ULI5281_OFFS;
+ break;
+
+ default:
+ BUG();
+ break;
+ }
+
+ pci_set_master(pdev);
+ pci_intx(pdev, 1);
+
+ /* FIXME: check ata_device_add return value */
+ ata_device_add(probe_ent);
+ kfree(probe_ent);
+
+ return 0;
+
+err_out_probe_ent:
+ kfree(probe_ent);
+err_out_regions:
+ pci_release_regions(pdev);
+err_out:
+ if (!pci_dev_busy)
+ pci_disable_device(pdev);
+ return rc;
+
+}
+
+static int __init uli_init(void)
+{
+ return pci_register_driver(&uli_pci_driver);
+}
+
+static void __exit uli_exit(void)
+{
+ pci_unregister_driver(&uli_pci_driver);
+}
+
+
+module_init(uli_init);
+module_exit(uli_exit);
diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c
new file mode 100644
index 00000000000..a72a2389a11
--- /dev/null
+++ b/drivers/ata/sata_via.c
@@ -0,0 +1,503 @@
+/*
+ * sata_via.c - VIA Serial ATA controllers
+ *
+ * Maintained by: Jeff Garzik <jgarzik@pobox.com>
+ * Please ALWAYS copy linux-ide@vger.kernel.org
+ on emails.
+ *
+ * Copyright 2003-2004 Red Hat, Inc. All rights reserved.
+ * Copyright 2003-2004 Jeff Garzik
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * libata documentation is available via 'make {ps|pdf}docs',
+ * as Documentation/DocBook/libata.*
+ *
+ * Hardware documentation available under NDA.
+ *
+ *
+ * To-do list:
+ * - VT6421 PATA support
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+#include <asm/io.h>
+
+#define DRV_NAME "sata_via"
+#define DRV_VERSION "2.0"
+
+enum board_ids_enum {
+ vt6420,
+ vt6421,
+};
+
+enum {
+ SATA_CHAN_ENAB = 0x40, /* SATA channel enable */
+ SATA_INT_GATE = 0x41, /* SATA interrupt gating */
+ SATA_NATIVE_MODE = 0x42, /* Native mode enable */
+ SATA_PATA_SHARING = 0x49, /* PATA/SATA sharing func ctrl */
+
+ PORT0 = (1 << 1),
+ PORT1 = (1 << 0),
+ ALL_PORTS = PORT0 | PORT1,
+ N_PORTS = 2,
+
+ NATIVE_MODE_ALL = (1 << 7) | (1 << 6) | (1 << 5) | (1 << 4),
+
+ SATA_EXT_PHY = (1 << 6), /* 0==use PATA, 1==ext phy */
+ SATA_2DEV = (1 << 5), /* SATA is master/slave */
+};
+
+static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
+static u32 svia_scr_read (struct ata_port *ap, unsigned int sc_reg);
+static void svia_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+static void vt6420_error_handler(struct ata_port *ap);
+
+static const struct pci_device_id svia_pci_tbl[] = {
+ { 0x1106, 0x0591, PCI_ANY_ID, PCI_ANY_ID, 0, 0, vt6420 },
+ { 0x1106, 0x3149, PCI_ANY_ID, PCI_ANY_ID, 0, 0, vt6420 },
+ { 0x1106, 0x3249, PCI_ANY_ID, PCI_ANY_ID, 0, 0, vt6421 },
+
+ { } /* terminate list */
+};
+
+static struct pci_driver svia_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = svia_pci_tbl,
+ .probe = svia_init_one,
+ .remove = ata_pci_remove_one,
+};
+
+static struct scsi_host_template svia_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .slave_destroy = ata_scsi_slave_destroy,
+ .bios_param = ata_std_bios_param,
+};
+
+static const struct ata_port_operations vt6420_sata_ops = {
+ .port_disable = ata_port_disable,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+ .data_xfer = ata_pio_data_xfer,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = vt6420_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop,
+};
+
+static const struct ata_port_operations vt6421_sata_ops = {
+ .port_disable = ata_port_disable,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+ .data_xfer = ata_pio_data_xfer,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = ata_bmdma_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .scr_read = svia_scr_read,
+ .scr_write = svia_scr_write,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop,
+};
+
+static struct ata_port_info vt6420_port_info = {
+ .sht = &svia_sht,
+ .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x7f,
+ .port_ops = &vt6420_sata_ops,
+};
+
+MODULE_AUTHOR("Jeff Garzik");
+MODULE_DESCRIPTION("SCSI low-level driver for VIA SATA controllers");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, svia_pci_tbl);
+MODULE_VERSION(DRV_VERSION);
+
+static u32 svia_scr_read (struct ata_port *ap, unsigned int sc_reg)
+{
+ if (sc_reg > SCR_CONTROL)
+ return 0xffffffffU;
+ return inl(ap->ioaddr.scr_addr + (4 * sc_reg));
+}
+
+static void svia_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
+{
+ if (sc_reg > SCR_CONTROL)
+ return;
+ outl(val, ap->ioaddr.scr_addr + (4 * sc_reg));
+}
+
+/**
+ * vt6420_prereset - prereset for vt6420
+ * @ap: target ATA port
+ *
+ * SCR registers on vt6420 are pieces of shit and may hang the
+ * whole machine completely if accessed with the wrong timing.
+ * To avoid such catastrophe, vt6420 doesn't provide generic SCR
+ * access operations, but uses SStatus and SControl only during
+ * boot probing in controlled way.
+ *
+ * As the old (pre EH update) probing code is proven to work, we
+ * strictly follow the access pattern.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep)
+ *
+ * RETURNS:
+ * 0 on success, -errno otherwise.
+ */
+static int vt6420_prereset(struct ata_port *ap)
+{
+ struct ata_eh_context *ehc = &ap->eh_context;
+ unsigned long timeout = jiffies + (HZ * 5);
+ u32 sstatus, scontrol;
+ int online;
+
+ /* don't do any SCR stuff if we're not loading */
+ if (!ATA_PFLAG_LOADING)
+ goto skip_scr;
+
+ /* Resume phy. This is the old resume sequence from
+ * __sata_phy_reset().
+ */
+ svia_scr_write(ap, SCR_CONTROL, 0x300);
+ svia_scr_read(ap, SCR_CONTROL); /* flush */
+
+ /* wait for phy to become ready, if necessary */
+ do {
+ msleep(200);
+ if ((svia_scr_read(ap, SCR_STATUS) & 0xf) != 1)
+ break;
+ } while (time_before(jiffies, timeout));
+
+ /* open code sata_print_link_status() */
+ sstatus = svia_scr_read(ap, SCR_STATUS);
+ scontrol = svia_scr_read(ap, SCR_CONTROL);
+
+ online = (sstatus & 0xf) == 0x3;
+
+ ata_port_printk(ap, KERN_INFO,
+ "SATA link %s 1.5 Gbps (SStatus %X SControl %X)\n",
+ online ? "up" : "down", sstatus, scontrol);
+
+ /* SStatus is read one more time */
+ svia_scr_read(ap, SCR_STATUS);
+
+ if (!online) {
+ /* tell EH to bail */
+ ehc->i.action &= ~ATA_EH_RESET_MASK;
+ return 0;
+ }
+
+ skip_scr:
+ /* wait for !BSY */
+ ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
+
+ return 0;
+}
+
+static void vt6420_error_handler(struct ata_port *ap)
+{
+ return ata_bmdma_drive_eh(ap, vt6420_prereset, ata_std_softreset,
+ NULL, ata_std_postreset);
+}
+
+static const unsigned int svia_bar_sizes[] = {
+ 8, 4, 8, 4, 16, 256
+};
+
+static const unsigned int vt6421_bar_sizes[] = {
+ 16, 16, 16, 16, 32, 128
+};
+
+static unsigned long svia_scr_addr(unsigned long addr, unsigned int port)
+{
+ return addr + (port * 128);
+}
+
+static unsigned long vt6421_scr_addr(unsigned long addr, unsigned int port)
+{
+ return addr + (port * 64);
+}
+
+static void vt6421_init_addrs(struct ata_probe_ent *probe_ent,
+ struct pci_dev *pdev,
+ unsigned int port)
+{
+ unsigned long reg_addr = pci_resource_start(pdev, port);
+ unsigned long bmdma_addr = pci_resource_start(pdev, 4) + (port * 8);
+ unsigned long scr_addr;
+
+ probe_ent->port[port].cmd_addr = reg_addr;
+ probe_ent->port[port].altstatus_addr =
+ probe_ent->port[port].ctl_addr = (reg_addr + 8) | ATA_PCI_CTL_OFS;
+ probe_ent->port[port].bmdma_addr = bmdma_addr;
+
+ scr_addr = vt6421_scr_addr(pci_resource_start(pdev, 5), port);
+ probe_ent->port[port].scr_addr = scr_addr;
+
+ ata_std_ports(&probe_ent->port[port]);
+}
+
+static struct ata_probe_ent *vt6420_init_probe_ent(struct pci_dev *pdev)
+{
+ struct ata_probe_ent *probe_ent;
+ struct ata_port_info *ppi[2];
+
+ ppi[0] = ppi[1] = &vt6420_port_info;
+ probe_ent = ata_pci_init_native_mode(pdev, ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY);
+ if (!probe_ent)
+ return NULL;
+
+ probe_ent->port[0].scr_addr =
+ svia_scr_addr(pci_resource_start(pdev, 5), 0);
+ probe_ent->port[1].scr_addr =
+ svia_scr_addr(pci_resource_start(pdev, 5), 1);
+
+ return probe_ent;
+}
+
+static struct ata_probe_ent *vt6421_init_probe_ent(struct pci_dev *pdev)
+{
+ struct ata_probe_ent *probe_ent;
+ unsigned int i;
+
+ probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
+ if (!probe_ent)
+ return NULL;
+
+ memset(probe_ent, 0, sizeof(*probe_ent));
+ probe_ent->dev = pci_dev_to_dev(pdev);
+ INIT_LIST_HEAD(&probe_ent->node);
+
+ probe_ent->sht = &svia_sht;
+ probe_ent->port_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY;
+ probe_ent->port_ops = &vt6421_sata_ops;
+ probe_ent->n_ports = N_PORTS;
+ probe_ent->irq = pdev->irq;
+ probe_ent->irq_flags = IRQF_SHARED;
+ probe_ent->pio_mask = 0x1f;
+ probe_ent->mwdma_mask = 0x07;
+ probe_ent->udma_mask = 0x7f;
+
+ for (i = 0; i < N_PORTS; i++)
+ vt6421_init_addrs(probe_ent, pdev, i);
+
+ return probe_ent;
+}
+
+static void svia_configure(struct pci_dev *pdev)
+{
+ u8 tmp8;
+
+ pci_read_config_byte(pdev, PCI_INTERRUPT_LINE, &tmp8);
+ dev_printk(KERN_INFO, &pdev->dev, "routed to hard irq line %d\n",
+ (int) (tmp8 & 0xf0) == 0xf0 ? 0 : tmp8 & 0x0f);
+
+ /* make sure SATA channels are enabled */
+ pci_read_config_byte(pdev, SATA_CHAN_ENAB, &tmp8);
+ if ((tmp8 & ALL_PORTS) != ALL_PORTS) {
+ dev_printk(KERN_DEBUG, &pdev->dev,
+ "enabling SATA channels (0x%x)\n",
+ (int) tmp8);
+ tmp8 |= ALL_PORTS;
+ pci_write_config_byte(pdev, SATA_CHAN_ENAB, tmp8);
+ }
+
+ /* make sure interrupts for each channel sent to us */
+ pci_read_config_byte(pdev, SATA_INT_GATE, &tmp8);
+ if ((tmp8 & ALL_PORTS) != ALL_PORTS) {
+ dev_printk(KERN_DEBUG, &pdev->dev,
+ "enabling SATA channel interrupts (0x%x)\n",
+ (int) tmp8);
+ tmp8 |= ALL_PORTS;
+ pci_write_config_byte(pdev, SATA_INT_GATE, tmp8);
+ }
+
+ /* make sure native mode is enabled */
+ pci_read_config_byte(pdev, SATA_NATIVE_MODE, &tmp8);
+ if ((tmp8 & NATIVE_MODE_ALL) != NATIVE_MODE_ALL) {
+ dev_printk(KERN_DEBUG, &pdev->dev,
+ "enabling SATA channel native mode (0x%x)\n",
+ (int) tmp8);
+ tmp8 |= NATIVE_MODE_ALL;
+ pci_write_config_byte(pdev, SATA_NATIVE_MODE, tmp8);
+ }
+}
+
+static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ static int printed_version;
+ unsigned int i;
+ int rc;
+ struct ata_probe_ent *probe_ent;
+ int board_id = (int) ent->driver_data;
+ const int *bar_sizes;
+ int pci_dev_busy = 0;
+ u8 tmp8;
+
+ if (!printed_version++)
+ dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
+
+ rc = pci_enable_device(pdev);
+ if (rc)
+ return rc;
+
+ rc = pci_request_regions(pdev, DRV_NAME);
+ if (rc) {
+ pci_dev_busy = 1;
+ goto err_out;
+ }
+
+ if (board_id == vt6420) {
+ pci_read_config_byte(pdev, SATA_PATA_SHARING, &tmp8);
+ if (tmp8 & SATA_2DEV) {
+ dev_printk(KERN_ERR, &pdev->dev,
+ "SATA master/slave not supported (0x%x)\n",
+ (int) tmp8);
+ rc = -EIO;
+ goto err_out_regions;
+ }
+
+ bar_sizes = &svia_bar_sizes[0];
+ } else {
+ bar_sizes = &vt6421_bar_sizes[0];
+ }
+
+ for (i = 0; i < ARRAY_SIZE(svia_bar_sizes); i++)
+ if ((pci_resource_start(pdev, i) == 0) ||
+ (pci_resource_len(pdev, i) < bar_sizes[i])) {
+ dev_printk(KERN_ERR, &pdev->dev,
+ "invalid PCI BAR %u (sz 0x%llx, val 0x%llx)\n",
+ i,
+ (unsigned long long)pci_resource_start(pdev, i),
+ (unsigned long long)pci_resource_len(pdev, i));
+ rc = -ENODEV;
+ goto err_out_regions;
+ }
+
+ rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
+ if (rc)
+ goto err_out_regions;
+ rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
+ if (rc)
+ goto err_out_regions;
+
+ if (board_id == vt6420)
+ probe_ent = vt6420_init_probe_ent(pdev);
+ else
+ probe_ent = vt6421_init_probe_ent(pdev);
+
+ if (!probe_ent) {
+ dev_printk(KERN_ERR, &pdev->dev, "out of memory\n");
+ rc = -ENOMEM;
+ goto err_out_regions;
+ }
+
+ svia_configure(pdev);
+
+ pci_set_master(pdev);
+
+ /* FIXME: check ata_device_add return value */
+ ata_device_add(probe_ent);
+ kfree(probe_ent);
+
+ return 0;
+
+err_out_regions:
+ pci_release_regions(pdev);
+err_out:
+ if (!pci_dev_busy)
+ pci_disable_device(pdev);
+ return rc;
+}
+
+static int __init svia_init(void)
+{
+ return pci_register_driver(&svia_pci_driver);
+}
+
+static void __exit svia_exit(void)
+{
+ pci_unregister_driver(&svia_pci_driver);
+}
+
+module_init(svia_init);
+module_exit(svia_exit);
+
diff --git a/drivers/ata/sata_vsc.c b/drivers/ata/sata_vsc.c
new file mode 100644
index 00000000000..d0d92f33de5
--- /dev/null
+++ b/drivers/ata/sata_vsc.c
@@ -0,0 +1,482 @@
+/*
+ * sata_vsc.c - Vitesse VSC7174 4 port DPA SATA
+ *
+ * Maintained by: Jeremy Higdon @ SGI
+ * Please ALWAYS copy linux-ide@vger.kernel.org
+ * on emails.
+ *
+ * Copyright 2004 SGI
+ *
+ * Bits from Jeff Garzik, Copyright RedHat, Inc.
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * libata documentation is available via 'make {ps|pdf}docs',
+ * as Documentation/DocBook/libata.*
+ *
+ * Vitesse hardware documentation presumably available under NDA.
+ * Intel 31244 (same hardware interface) documentation presumably
+ * available from http://developer.intel.com/
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/device.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+
+#define DRV_NAME "sata_vsc"
+#define DRV_VERSION "2.0"
+
+enum {
+ /* Interrupt register offsets (from chip base address) */
+ VSC_SATA_INT_STAT_OFFSET = 0x00,
+ VSC_SATA_INT_MASK_OFFSET = 0x04,
+
+ /* Taskfile registers offsets */
+ VSC_SATA_TF_CMD_OFFSET = 0x00,
+ VSC_SATA_TF_DATA_OFFSET = 0x00,
+ VSC_SATA_TF_ERROR_OFFSET = 0x04,
+ VSC_SATA_TF_FEATURE_OFFSET = 0x06,
+ VSC_SATA_TF_NSECT_OFFSET = 0x08,
+ VSC_SATA_TF_LBAL_OFFSET = 0x0c,
+ VSC_SATA_TF_LBAM_OFFSET = 0x10,
+ VSC_SATA_TF_LBAH_OFFSET = 0x14,
+ VSC_SATA_TF_DEVICE_OFFSET = 0x18,
+ VSC_SATA_TF_STATUS_OFFSET = 0x1c,
+ VSC_SATA_TF_COMMAND_OFFSET = 0x1d,
+ VSC_SATA_TF_ALTSTATUS_OFFSET = 0x28,
+ VSC_SATA_TF_CTL_OFFSET = 0x29,
+
+ /* DMA base */
+ VSC_SATA_UP_DESCRIPTOR_OFFSET = 0x64,
+ VSC_SATA_UP_DATA_BUFFER_OFFSET = 0x6C,
+ VSC_SATA_DMA_CMD_OFFSET = 0x70,
+
+ /* SCRs base */
+ VSC_SATA_SCR_STATUS_OFFSET = 0x100,
+ VSC_SATA_SCR_ERROR_OFFSET = 0x104,
+ VSC_SATA_SCR_CONTROL_OFFSET = 0x108,
+
+ /* Port stride */
+ VSC_SATA_PORT_OFFSET = 0x200,
+
+ /* Error interrupt status bit offsets */
+ VSC_SATA_INT_ERROR_CRC = 0x40,
+ VSC_SATA_INT_ERROR_T = 0x20,
+ VSC_SATA_INT_ERROR_P = 0x10,
+ VSC_SATA_INT_ERROR_R = 0x8,
+ VSC_SATA_INT_ERROR_E = 0x4,
+ VSC_SATA_INT_ERROR_M = 0x2,
+ VSC_SATA_INT_PHY_CHANGE = 0x1,
+ VSC_SATA_INT_ERROR = (VSC_SATA_INT_ERROR_CRC | VSC_SATA_INT_ERROR_T | \
+ VSC_SATA_INT_ERROR_P | VSC_SATA_INT_ERROR_R | \
+ VSC_SATA_INT_ERROR_E | VSC_SATA_INT_ERROR_M | \
+ VSC_SATA_INT_PHY_CHANGE),
+};
+
+
+#define is_vsc_sata_int_err(port_idx, int_status) \
+ (int_status & (VSC_SATA_INT_ERROR << (8 * port_idx)))
+
+
+static u32 vsc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg)
+{
+ if (sc_reg > SCR_CONTROL)
+ return 0xffffffffU;
+ return readl((void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4));
+}
+
+
+static void vsc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg,
+ u32 val)
+{
+ if (sc_reg > SCR_CONTROL)
+ return;
+ writel(val, (void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4));
+}
+
+
+static void vsc_intr_mask_update(struct ata_port *ap, u8 ctl)
+{
+ void __iomem *mask_addr;
+ u8 mask;
+
+ mask_addr = ap->host->mmio_base +
+ VSC_SATA_INT_MASK_OFFSET + ap->port_no;
+ mask = readb(mask_addr);
+ if (ctl & ATA_NIEN)
+ mask |= 0x80;
+ else
+ mask &= 0x7F;
+ writeb(mask, mask_addr);
+}
+
+
+static void vsc_sata_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;
+
+ /*
+ * The only thing the ctl register is used for is SRST.
+ * That is not enabled or disabled via tf_load.
+ * However, if ATA_NIEN is changed, then we need to change the interrupt register.
+ */
+ if ((tf->ctl & ATA_NIEN) != (ap->last_ctl & ATA_NIEN)) {
+ ap->last_ctl = tf->ctl;
+ vsc_intr_mask_update(ap, tf->ctl & ATA_NIEN);
+ }
+ if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
+ writew(tf->feature | (((u16)tf->hob_feature) << 8), ioaddr->feature_addr);
+ writew(tf->nsect | (((u16)tf->hob_nsect) << 8), ioaddr->nsect_addr);
+ writew(tf->lbal | (((u16)tf->hob_lbal) << 8), ioaddr->lbal_addr);
+ writew(tf->lbam | (((u16)tf->hob_lbam) << 8), ioaddr->lbam_addr);
+ writew(tf->lbah | (((u16)tf->hob_lbah) << 8), ioaddr->lbah_addr);
+ } else if (is_addr) {
+ writew(tf->feature, ioaddr->feature_addr);
+ writew(tf->nsect, ioaddr->nsect_addr);
+ writew(tf->lbal, ioaddr->lbal_addr);
+ writew(tf->lbam, ioaddr->lbam_addr);
+ writew(tf->lbah, ioaddr->lbah_addr);
+ }
+
+ if (tf->flags & ATA_TFLAG_DEVICE)
+ writeb(tf->device, ioaddr->device_addr);
+
+ ata_wait_idle(ap);
+}
+
+
+static void vsc_sata_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
+{
+ struct ata_ioports *ioaddr = &ap->ioaddr;
+ u16 nsect, lbal, lbam, lbah, feature;
+
+ tf->command = ata_check_status(ap);
+ tf->device = readw(ioaddr->device_addr);
+ feature = readw(ioaddr->error_addr);
+ nsect = readw(ioaddr->nsect_addr);
+ lbal = readw(ioaddr->lbal_addr);
+ lbam = readw(ioaddr->lbam_addr);
+ lbah = readw(ioaddr->lbah_addr);
+
+ tf->feature = feature;
+ tf->nsect = nsect;
+ tf->lbal = lbal;
+ tf->lbam = lbam;
+ tf->lbah = lbah;
+
+ if (tf->flags & ATA_TFLAG_LBA48) {
+ tf->hob_feature = feature >> 8;
+ tf->hob_nsect = nsect >> 8;
+ tf->hob_lbal = lbal >> 8;
+ tf->hob_lbam = lbam >> 8;
+ tf->hob_lbah = lbah >> 8;
+ }
+}
+
+
+/*
+ * vsc_sata_interrupt
+ *
+ * Read the interrupt register and process for the devices that have them pending.
+ */
+static irqreturn_t vsc_sata_interrupt (int irq, void *dev_instance,
+ struct pt_regs *regs)
+{
+ struct ata_host *host = dev_instance;
+ unsigned int i;
+ unsigned int handled = 0;
+ u32 int_status;
+
+ spin_lock(&host->lock);
+
+ int_status = readl(host->mmio_base + VSC_SATA_INT_STAT_OFFSET);
+
+ for (i = 0; i < host->n_ports; i++) {
+ if (int_status & ((u32) 0xFF << (8 * i))) {
+ struct ata_port *ap;
+
+ ap = host->ports[i];
+
+ if (is_vsc_sata_int_err(i, int_status)) {
+ u32 err_status;
+ printk(KERN_DEBUG "%s: ignoring interrupt(s)\n", __FUNCTION__);
+ err_status = ap ? vsc_sata_scr_read(ap, SCR_ERROR) : 0;
+ vsc_sata_scr_write(ap, SCR_ERROR, err_status);
+ handled++;
+ }
+
+ if (ap && !(ap->flags & ATA_FLAG_DISABLED)) {
+ struct ata_queued_cmd *qc;
+
+ qc = ata_qc_from_tag(ap, ap->active_tag);
+ if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)))
+ handled += ata_host_intr(ap, qc);
+ else if (is_vsc_sata_int_err(i, int_status)) {
+ /*
+ * On some chips (i.e. Intel 31244), an error
+ * interrupt will sneak in at initialization
+ * time (phy state changes). Clearing the SCR
+ * error register is not required, but it prevents
+ * the phy state change interrupts from recurring
+ * later.
+ */
+ u32 err_status;
+ err_status = vsc_sata_scr_read(ap, SCR_ERROR);
+ printk(KERN_DEBUG "%s: clearing interrupt, "
+ "status %x; sata err status %x\n",
+ __FUNCTION__,
+ int_status, err_status);
+ vsc_sata_scr_write(ap, SCR_ERROR, err_status);
+ /* Clear interrupt status */
+ ata_chk_status(ap);
+ handled++;
+ }
+ }
+ }
+ }
+
+ spin_unlock(&host->lock);
+
+ return IRQ_RETVAL(handled);
+}
+
+
+static struct scsi_host_template vsc_sata_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .slave_destroy = ata_scsi_slave_destroy,
+ .bios_param = ata_std_bios_param,
+};
+
+
+static const struct ata_port_operations vsc_sata_ops = {
+ .port_disable = ata_port_disable,
+ .tf_load = vsc_sata_tf_load,
+ .tf_read = vsc_sata_tf_read,
+ .exec_command = ata_exec_command,
+ .check_status = ata_check_status,
+ .dev_select = ata_std_dev_select,
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+ .data_xfer = ata_mmio_data_xfer,
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = ata_bmdma_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .irq_handler = vsc_sata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+ .scr_read = vsc_sata_scr_read,
+ .scr_write = vsc_sata_scr_write,
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_pci_host_stop,
+};
+
+static void __devinit vsc_sata_setup_port(struct ata_ioports *port, unsigned long base)
+{
+ port->cmd_addr = base + VSC_SATA_TF_CMD_OFFSET;
+ port->data_addr = base + VSC_SATA_TF_DATA_OFFSET;
+ port->error_addr = base + VSC_SATA_TF_ERROR_OFFSET;
+ port->feature_addr = base + VSC_SATA_TF_FEATURE_OFFSET;
+ port->nsect_addr = base + VSC_SATA_TF_NSECT_OFFSET;
+ port->lbal_addr = base + VSC_SATA_TF_LBAL_OFFSET;
+ port->lbam_addr = base + VSC_SATA_TF_LBAM_OFFSET;
+ port->lbah_addr = base + VSC_SATA_TF_LBAH_OFFSET;
+ port->device_addr = base + VSC_SATA_TF_DEVICE_OFFSET;
+ port->status_addr = base + VSC_SATA_TF_STATUS_OFFSET;
+ port->command_addr = base + VSC_SATA_TF_COMMAND_OFFSET;
+ port->altstatus_addr = base + VSC_SATA_TF_ALTSTATUS_OFFSET;
+ port->ctl_addr = base + VSC_SATA_TF_CTL_OFFSET;
+ port->bmdma_addr = base + VSC_SATA_DMA_CMD_OFFSET;
+ port->scr_addr = base + VSC_SATA_SCR_STATUS_OFFSET;
+ writel(0, base + VSC_SATA_UP_DESCRIPTOR_OFFSET);
+ writel(0, base + VSC_SATA_UP_DATA_BUFFER_OFFSET);
+}
+
+
+static int __devinit vsc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ static int printed_version;
+ struct ata_probe_ent *probe_ent = NULL;
+ unsigned long base;
+ int pci_dev_busy = 0;
+ void __iomem *mmio_base;
+ int rc;
+
+ if (!printed_version++)
+ dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
+
+ rc = pci_enable_device(pdev);
+ if (rc)
+ return rc;
+
+ /*
+ * Check if we have needed resource mapped.
+ */
+ if (pci_resource_len(pdev, 0) == 0) {
+ rc = -ENODEV;
+ goto err_out;
+ }
+
+ rc = pci_request_regions(pdev, DRV_NAME);
+ if (rc) {
+ pci_dev_busy = 1;
+ goto err_out;
+ }
+
+ /*
+ * Use 32 bit DMA mask, because 64 bit address support is poor.
+ */
+ rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+ if (rc)
+ goto err_out_regions;
+ rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+ if (rc)
+ goto err_out_regions;
+
+ probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
+ if (probe_ent == NULL) {
+ rc = -ENOMEM;
+ goto err_out_regions;
+ }
+ memset(probe_ent, 0, sizeof(*probe_ent));
+ probe_ent->dev = pci_dev_to_dev(pdev);
+ INIT_LIST_HEAD(&probe_ent->node);
+
+ mmio_base = pci_iomap(pdev, 0, 0);
+ if (mmio_base == NULL) {
+ rc = -ENOMEM;
+ goto err_out_free_ent;
+ }
+ base = (unsigned long) mmio_base;
+
+ /*
+ * Due to a bug in the chip, the default cache line size can't be used
+ */
+ pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 0x80);
+
+ probe_ent->sht = &vsc_sata_sht;
+ probe_ent->port_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+ ATA_FLAG_MMIO;
+ probe_ent->port_ops = &vsc_sata_ops;
+ probe_ent->n_ports = 4;
+ probe_ent->irq = pdev->irq;
+ probe_ent->irq_flags = IRQF_SHARED;
+ probe_ent->mmio_base = mmio_base;
+
+ /* We don't care much about the PIO/UDMA masks, but the core won't like us
+ * if we don't fill these
+ */
+ probe_ent->pio_mask = 0x1f;
+ probe_ent->mwdma_mask = 0x07;
+ probe_ent->udma_mask = 0x7f;
+
+ /* We have 4 ports per PCI function */
+ vsc_sata_setup_port(&probe_ent->port[0], base + 1 * VSC_SATA_PORT_OFFSET);
+ vsc_sata_setup_port(&probe_ent->port[1], base + 2 * VSC_SATA_PORT_OFFSET);
+ vsc_sata_setup_port(&probe_ent->port[2], base + 3 * VSC_SATA_PORT_OFFSET);
+ vsc_sata_setup_port(&probe_ent->port[3], base + 4 * VSC_SATA_PORT_OFFSET);
+
+ pci_set_master(pdev);
+
+ /*
+ * Config offset 0x98 is "Extended Control and Status Register 0"
+ * Default value is (1 << 28). All bits except bit 28 are reserved in
+ * DPA mode. If bit 28 is set, LED 0 reflects all ports' activity.
+ * If bit 28 is clear, each port has its own LED.
+ */
+ pci_write_config_dword(pdev, 0x98, 0);
+
+ /* FIXME: check ata_device_add return value */
+ ata_device_add(probe_ent);
+ kfree(probe_ent);
+
+ return 0;
+
+err_out_free_ent:
+ kfree(probe_ent);
+err_out_regions:
+ pci_release_regions(pdev);
+err_out:
+ if (!pci_dev_busy)
+ pci_disable_device(pdev);
+ return rc;
+}
+
+
+static const struct pci_device_id vsc_sata_pci_tbl[] = {
+ { PCI_VENDOR_ID_VITESSE, 0x7174,
+ PCI_ANY_ID, PCI_ANY_ID, 0x10600, 0xFFFFFF, 0 },
+ { PCI_VENDOR_ID_INTEL, 0x3200,
+ PCI_ANY_ID, PCI_ANY_ID, 0x10600, 0xFFFFFF, 0 },
+ { } /* terminate list */
+};
+
+
+static struct pci_driver vsc_sata_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = vsc_sata_pci_tbl,
+ .probe = vsc_sata_init_one,
+ .remove = ata_pci_remove_one,
+};
+
+
+static int __init vsc_sata_init(void)
+{
+ return pci_register_driver(&vsc_sata_pci_driver);
+}
+
+
+static void __exit vsc_sata_exit(void)
+{
+ pci_unregister_driver(&vsc_sata_pci_driver);
+}
+
+
+MODULE_AUTHOR("Jeremy Higdon");
+MODULE_DESCRIPTION("low-level driver for Vitesse VSC7174 SATA controller");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, vsc_sata_pci_tbl);
+MODULE_VERSION(DRV_VERSION);
+
+module_init(vsc_sata_init);
+module_exit(vsc_sata_exit);