Creation of Cybook 2416 (actually Gen4) repository
This commit is contained in:
576
drivers/ata/Kconfig
Normal file
576
drivers/ata/Kconfig
Normal file
@@ -0,0 +1,576 @@
|
||||
#
|
||||
# SATA/PATA driver configuration
|
||||
#
|
||||
|
||||
menu "Serial ATA (prod) and Parallel ATA (experimental) drivers"
|
||||
|
||||
config ATA
|
||||
tristate "ATA device support"
|
||||
depends on BLOCK
|
||||
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 ATA_NONSTANDARD
|
||||
bool
|
||||
default n
|
||||
|
||||
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 ESB, ICH, PIIX3, PIIX4 PATA/SATA support"
|
||||
depends on PCI
|
||||
help
|
||||
This option enables support for ICH5/6/7/8 Serial ATA
|
||||
and support for PATA on the Intel ESB/ICH/PIIX3/PIIX4 series
|
||||
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/965/966/180 SATA support"
|
||||
depends on PCI
|
||||
select PATA_SIS
|
||||
help
|
||||
This option enables support for SiS Serial ATA on
|
||||
SiS 964/965/966/180 and Parallel ATA on SiS 180.
|
||||
The PATA support for SiS 180 requires additionally to
|
||||
enable the PATA_SIS driver in the config.
|
||||
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_INIC162X
|
||||
tristate "Initio 162x SATA support (HIGHLY EXPERIMENTAL)"
|
||||
depends on PCI && EXPERIMENTAL
|
||||
help
|
||||
This option enables support for Initio 162x Serial ATA.
|
||||
|
||||
config SATA_INTEL_COMBINED
|
||||
bool
|
||||
depends on IDE=y && !BLK_DEV_IDE_SATA && (SATA_AHCI || ATA_PIIX)
|
||||
default y
|
||||
|
||||
config SATA_ACPI
|
||||
bool
|
||||
depends on ACPI && PCI
|
||||
default y
|
||||
help
|
||||
This option adds support for SATA-related ACPI objects.
|
||||
These ACPI objects add the ability to retrieve taskfiles
|
||||
from the ACPI BIOS and write them to the disk controller.
|
||||
These objects may be related to performance, security,
|
||||
power management, or other areas.
|
||||
You can disable this at kernel boot time by using the
|
||||
option libata.noacpi=1
|
||||
|
||||
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 "IT8211/2 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_IT8213
|
||||
tristate "IT8213 PATA support (Experimental)"
|
||||
depends on PCI && EXPERIMENTAL
|
||||
help
|
||||
This option enables support for the ITE 821 PATA
|
||||
controllers via the new ATA layer.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config PATA_JMICRON
|
||||
tristate "JMicron PATA support"
|
||||
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_MARVELL
|
||||
tristate "Marvell PATA support via legacy mode"
|
||||
depends on PCI
|
||||
help
|
||||
This option enables limited support for the Marvell 88SE6145 ATA
|
||||
controller.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config PATA_MPC52xx
|
||||
tristate "Freescale MPC52xx SoC internal IDE"
|
||||
depends on PPC_MPC52xx
|
||||
help
|
||||
This option enables support for integrated IDE controller
|
||||
of the Freescale MPC52xx SoC.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config PATA_MPIIX
|
||||
tristate "Intel PATA MPIIX support"
|
||||
depends on PCI
|
||||
help
|
||||
This option enables support for MPIIX PATA support.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config PATA_OLDPIIX
|
||||
tristate "Intel PATA old PIIX support (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 (Very 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.
|
||||
|
||||
config PATA_WINBOND_VLB
|
||||
tristate "Winbond W83759A VLB PATA support (Experimental)"
|
||||
depends on ISA && EXPERIMENTAL
|
||||
help
|
||||
Support for the Winbond W83759A controller on Vesa Local Bus
|
||||
systems.
|
||||
|
||||
config PATA_PLATFORM
|
||||
tristate "Generic platform device PATA support"
|
||||
depends on EMBEDDED
|
||||
help
|
||||
This option enables support for generic directly connected ATA
|
||||
devices commonly found on embedded systems.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config PATA_IXP4XX_CF
|
||||
tristate "IXP4XX Compact Flash support"
|
||||
depends on ARCH_IXP4XX
|
||||
help
|
||||
This option enables support for a Compact Flash connected on
|
||||
the ixp4xx expansion bus. This driver had been written for
|
||||
Loft/Avila boards in mind but can work with others.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config PATA_SCC
|
||||
tristate "Toshiba's Cell Reference Set IDE support"
|
||||
depends on PCI && PPC_CELLEB
|
||||
help
|
||||
This option enables support for the built-in IDE controller on
|
||||
Toshiba Cell Reference Board.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
endif
|
||||
endmenu
|
||||
|
||||
70
drivers/ata/Makefile
Normal file
70
drivers/ata/Makefile
Normal file
@@ -0,0 +1,70 @@
|
||||
|
||||
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_SATA_INIC162X) += sata_inic162x.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_IT8213) += pata_it8213.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_MPC52xx) += pata_mpc52xx.o
|
||||
obj-$(CONFIG_PATA_MARVELL) += pata_marvell.o
|
||||
obj-$(CONFIG_PATA_MPIIX) += pata_mpiix.o
|
||||
obj-$(CONFIG_PATA_OLDPIIX) += pata_oldpiix.o
|
||||
obj-$(CONFIG_PATA_PCMCIA) += pata_pcmcia.o
|
||||
obj-$(CONFIG_PATA_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_WINBOND_VLB) += pata_winbond.o
|
||||
obj-$(CONFIG_PATA_SIS) += pata_sis.o
|
||||
obj-$(CONFIG_PATA_TRIFLEX) += pata_triflex.o
|
||||
obj-$(CONFIG_PATA_IXP4XX_CF) += pata_ixp4xx_cf.o
|
||||
obj-$(CONFIG_PATA_SCC) += pata_scc.o
|
||||
obj-$(CONFIG_PATA_PLATFORM) += pata_platform.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
|
||||
libata-$(CONFIG_SATA_ACPI) += libata-acpi.o
|
||||
1785
drivers/ata/ahci.c
Normal file
1785
drivers/ata/ahci.c
Normal file
File diff suppressed because it is too large
Load Diff
262
drivers/ata/ata_generic.c
Normal file
262
drivers/ata/ata_generic.c
Normal file
@@ -0,0 +1,262 @@
|
||||
/*
|
||||
* 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.11"
|
||||
|
||||
/*
|
||||
* 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
|
||||
* @unused: returned device on error
|
||||
*
|
||||
* 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 int generic_set_mode(struct ata_port *ap, struct ata_device **unused)
|
||||
{
|
||||
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 = ioread8(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_ready(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))) {
|
||||
ata_id_to_dma_mode(dev, XFER_MW_DMA_0);
|
||||
dev->flags &= ~ATA_DFLAG_PIO;
|
||||
} else {
|
||||
ata_dev_printk(dev, KERN_INFO, "configured for PIO\n");
|
||||
dev->xfer_mode = XFER_PIO_0;
|
||||
dev->xfer_shift = ATA_SHIFT_PIO;
|
||||
dev->flags |= ATA_DFLAG_PIO;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
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,
|
||||
.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,
|
||||
#ifdef CONFIG_PM
|
||||
.resume = ata_scsi_device_resume,
|
||||
.suspend = ata_scsi_device_suspend,
|
||||
#endif
|
||||
};
|
||||
|
||||
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_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,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
|
||||
.port_start = ata_port_start,
|
||||
};
|
||||
|
||||
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,
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = ata_pci_device_suspend,
|
||||
.resume = ata_pci_device_resume,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int __init ata_generic_init(void)
|
||||
{
|
||||
return pci_register_driver(&ata_generic_pci_driver);
|
||||
}
|
||||
|
||||
|
||||
static void __exit ata_generic_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&ata_generic_pci_driver);
|
||||
}
|
||||
|
||||
|
||||
MODULE_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);
|
||||
1154
drivers/ata/ata_piix.c
Normal file
1154
drivers/ata/ata_piix.c
Normal file
File diff suppressed because it is too large
Load Diff
709
drivers/ata/libata-acpi.c
Normal file
709
drivers/ata/libata-acpi.c
Normal file
@@ -0,0 +1,709 @@
|
||||
/*
|
||||
* libata-acpi.c
|
||||
* Provides ACPI support for PATA/SATA.
|
||||
*
|
||||
* Copyright (C) 2006 Intel Corp.
|
||||
* Copyright (C) 2006 Randy Dunlap
|
||||
*/
|
||||
|
||||
#include <linux/ata.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/libata.h>
|
||||
#include <linux/pci.h>
|
||||
#include "libata.h"
|
||||
|
||||
#include <acpi/acpi_bus.h>
|
||||
#include <acpi/acnames.h>
|
||||
#include <acpi/acnamesp.h>
|
||||
#include <acpi/acparser.h>
|
||||
#include <acpi/acexcep.h>
|
||||
#include <acpi/acmacros.h>
|
||||
#include <acpi/actypes.h>
|
||||
|
||||
#define SATA_ROOT_PORT(x) (((x) >> 16) & 0xffff)
|
||||
#define SATA_PORT_NUMBER(x) ((x) & 0xffff) /* or NO_PORT_MULT */
|
||||
#define NO_PORT_MULT 0xffff
|
||||
#define SATA_ADR_RSVD 0xffffffff
|
||||
|
||||
#define REGS_PER_GTF 7
|
||||
struct taskfile_array {
|
||||
u8 tfa[REGS_PER_GTF]; /* regs. 0x1f1 - 0x1f7 */
|
||||
};
|
||||
|
||||
/*
|
||||
* Helper - belongs in the PCI layer somewhere eventually
|
||||
*/
|
||||
static int is_pci_dev(struct device *dev)
|
||||
{
|
||||
return (dev->bus == &pci_bus_type);
|
||||
}
|
||||
|
||||
/**
|
||||
* sata_get_dev_handle - finds acpi_handle and PCI device.function
|
||||
* @dev: device to locate
|
||||
* @handle: returned acpi_handle for @dev
|
||||
* @pcidevfn: return PCI device.func for @dev
|
||||
*
|
||||
* This function is somewhat SATA-specific. Or at least the
|
||||
* PATA & SATA versions of this function are different,
|
||||
* so it's not entirely generic code.
|
||||
*
|
||||
* Returns 0 on success, <0 on error.
|
||||
*/
|
||||
static int sata_get_dev_handle(struct device *dev, acpi_handle *handle,
|
||||
acpi_integer *pcidevfn)
|
||||
{
|
||||
struct pci_dev *pci_dev;
|
||||
acpi_integer addr;
|
||||
|
||||
if (!is_pci_dev(dev))
|
||||
return -ENODEV;
|
||||
|
||||
pci_dev = to_pci_dev(dev); /* NOTE: PCI-specific */
|
||||
/* Please refer to the ACPI spec for the syntax of _ADR. */
|
||||
addr = (PCI_SLOT(pci_dev->devfn) << 16) | PCI_FUNC(pci_dev->devfn);
|
||||
*pcidevfn = addr;
|
||||
*handle = acpi_get_child(DEVICE_ACPI_HANDLE(dev->parent), addr);
|
||||
if (!*handle)
|
||||
return -ENODEV;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* pata_get_dev_handle - finds acpi_handle and PCI device.function
|
||||
* @dev: device to locate
|
||||
* @handle: returned acpi_handle for @dev
|
||||
* @pcidevfn: return PCI device.func for @dev
|
||||
*
|
||||
* The PATA and SATA versions of this function are different.
|
||||
*
|
||||
* Returns 0 on success, <0 on error.
|
||||
*/
|
||||
static int pata_get_dev_handle(struct device *dev, acpi_handle *handle,
|
||||
acpi_integer *pcidevfn)
|
||||
{
|
||||
unsigned int bus, devnum, func;
|
||||
acpi_integer addr;
|
||||
acpi_handle dev_handle, parent_handle;
|
||||
struct acpi_buffer buffer = {.length = ACPI_ALLOCATE_BUFFER,
|
||||
.pointer = NULL};
|
||||
acpi_status status;
|
||||
struct acpi_device_info *dinfo = NULL;
|
||||
int ret = -ENODEV;
|
||||
struct pci_dev *pdev;
|
||||
|
||||
if (!is_pci_dev(dev))
|
||||
return -ENODEV;
|
||||
|
||||
pdev = to_pci_dev(dev);
|
||||
|
||||
bus = pdev->bus->number;
|
||||
devnum = PCI_SLOT(pdev->devfn);
|
||||
func = PCI_FUNC(pdev->devfn);
|
||||
|
||||
dev_handle = DEVICE_ACPI_HANDLE(dev);
|
||||
parent_handle = DEVICE_ACPI_HANDLE(dev->parent);
|
||||
|
||||
status = acpi_get_object_info(parent_handle, &buffer);
|
||||
if (ACPI_FAILURE(status))
|
||||
goto err;
|
||||
|
||||
dinfo = buffer.pointer;
|
||||
if (dinfo && (dinfo->valid & ACPI_VALID_ADR) &&
|
||||
dinfo->address == bus) {
|
||||
/* ACPI spec for _ADR for PCI bus: */
|
||||
addr = (acpi_integer)(devnum << 16 | func);
|
||||
*pcidevfn = addr;
|
||||
*handle = dev_handle;
|
||||
} else {
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!*handle)
|
||||
goto err;
|
||||
ret = 0;
|
||||
err:
|
||||
kfree(dinfo);
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct walk_info { /* can be trimmed some */
|
||||
struct device *dev;
|
||||
struct acpi_device *adev;
|
||||
acpi_handle handle;
|
||||
acpi_integer pcidevfn;
|
||||
unsigned int drivenum;
|
||||
acpi_handle obj_handle;
|
||||
struct ata_port *ataport;
|
||||
struct ata_device *atadev;
|
||||
u32 sata_adr;
|
||||
int status;
|
||||
char basepath[ACPI_PATHNAME_MAX];
|
||||
int basepath_len;
|
||||
};
|
||||
|
||||
static acpi_status get_devices(acpi_handle handle,
|
||||
u32 level, void *context, void **return_value)
|
||||
{
|
||||
acpi_status status;
|
||||
struct walk_info *winfo = context;
|
||||
struct acpi_buffer namebuf = {ACPI_ALLOCATE_BUFFER, NULL};
|
||||
char *pathname;
|
||||
struct acpi_buffer buffer;
|
||||
struct acpi_device_info *dinfo;
|
||||
|
||||
status = acpi_get_name(handle, ACPI_FULL_PATHNAME, &namebuf);
|
||||
if (status)
|
||||
goto ret;
|
||||
pathname = namebuf.pointer;
|
||||
|
||||
buffer.length = ACPI_ALLOCATE_BUFFER;
|
||||
buffer.pointer = NULL;
|
||||
status = acpi_get_object_info(handle, &buffer);
|
||||
if (ACPI_FAILURE(status))
|
||||
goto out2;
|
||||
|
||||
dinfo = buffer.pointer;
|
||||
|
||||
/* find full device path name for pcidevfn */
|
||||
if (dinfo && (dinfo->valid & ACPI_VALID_ADR) &&
|
||||
dinfo->address == winfo->pcidevfn) {
|
||||
if (ata_msg_probe(winfo->ataport))
|
||||
ata_dev_printk(winfo->atadev, KERN_DEBUG,
|
||||
":%s: matches pcidevfn (0x%llx)\n",
|
||||
pathname, winfo->pcidevfn);
|
||||
strlcpy(winfo->basepath, pathname,
|
||||
sizeof(winfo->basepath));
|
||||
winfo->basepath_len = strlen(pathname);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* if basepath is not yet known, ignore this object */
|
||||
if (!winfo->basepath_len)
|
||||
goto out;
|
||||
|
||||
/* if this object is in scope of basepath, maybe use it */
|
||||
if (strncmp(pathname, winfo->basepath,
|
||||
winfo->basepath_len) == 0) {
|
||||
if (!(dinfo->valid & ACPI_VALID_ADR))
|
||||
goto out;
|
||||
if (ata_msg_probe(winfo->ataport))
|
||||
ata_dev_printk(winfo->atadev, KERN_DEBUG,
|
||||
"GOT ONE: (%s) root_port = 0x%llx,"
|
||||
" port_num = 0x%llx\n", pathname,
|
||||
SATA_ROOT_PORT(dinfo->address),
|
||||
SATA_PORT_NUMBER(dinfo->address));
|
||||
/* heuristics: */
|
||||
if (SATA_PORT_NUMBER(dinfo->address) != NO_PORT_MULT)
|
||||
if (ata_msg_probe(winfo->ataport))
|
||||
ata_dev_printk(winfo->atadev,
|
||||
KERN_DEBUG, "warning: don't"
|
||||
" know how to handle SATA port"
|
||||
" multiplier\n");
|
||||
if (SATA_ROOT_PORT(dinfo->address) ==
|
||||
winfo->ataport->port_no &&
|
||||
SATA_PORT_NUMBER(dinfo->address) == NO_PORT_MULT) {
|
||||
if (ata_msg_probe(winfo->ataport))
|
||||
ata_dev_printk(winfo->atadev,
|
||||
KERN_DEBUG,
|
||||
"THIS ^^^^^ is the requested"
|
||||
" SATA drive (handle = 0x%p)\n",
|
||||
handle);
|
||||
winfo->sata_adr = dinfo->address;
|
||||
winfo->obj_handle = handle;
|
||||
}
|
||||
}
|
||||
out:
|
||||
kfree(dinfo);
|
||||
out2:
|
||||
kfree(pathname);
|
||||
|
||||
ret:
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Get the SATA drive _ADR object. */
|
||||
static int get_sata_adr(struct device *dev, acpi_handle handle,
|
||||
acpi_integer pcidevfn, unsigned int drive,
|
||||
struct ata_port *ap,
|
||||
struct ata_device *atadev, u32 *dev_adr)
|
||||
{
|
||||
acpi_status status;
|
||||
struct walk_info *winfo;
|
||||
int err = -ENOMEM;
|
||||
|
||||
winfo = kzalloc(sizeof(struct walk_info), GFP_KERNEL);
|
||||
if (!winfo)
|
||||
goto out;
|
||||
|
||||
winfo->dev = dev;
|
||||
winfo->atadev = atadev;
|
||||
winfo->ataport = ap;
|
||||
if (acpi_bus_get_device(handle, &winfo->adev) < 0)
|
||||
if (ata_msg_probe(ap))
|
||||
ata_dev_printk(winfo->atadev, KERN_DEBUG,
|
||||
"acpi_bus_get_device failed\n");
|
||||
winfo->handle = handle;
|
||||
winfo->pcidevfn = pcidevfn;
|
||||
winfo->drivenum = drive;
|
||||
|
||||
status = acpi_get_devices(NULL, get_devices, winfo, NULL);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
if (ata_msg_probe(ap))
|
||||
ata_dev_printk(winfo->atadev, KERN_DEBUG,
|
||||
"%s: acpi_get_devices failed\n",
|
||||
__FUNCTION__);
|
||||
err = -ENODEV;
|
||||
} else {
|
||||
*dev_adr = winfo->sata_adr;
|
||||
atadev->obj_handle = winfo->obj_handle;
|
||||
err = 0;
|
||||
}
|
||||
kfree(winfo);
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* do_drive_get_GTF - get the drive bootup default taskfile settings
|
||||
* @ap: the ata_port for the drive
|
||||
* @ix: target ata_device (drive) index
|
||||
* @gtf_length: number of bytes of _GTF data returned at @gtf_address
|
||||
* @gtf_address: buffer containing _GTF taskfile arrays
|
||||
*
|
||||
* This applies to both PATA and SATA drives.
|
||||
*
|
||||
* The _GTF method has no input parameters.
|
||||
* It returns a variable number of register set values (registers
|
||||
* hex 1F1..1F7, taskfiles).
|
||||
* The <variable number> is not known in advance, so have ACPI-CA
|
||||
* allocate the buffer as needed and return it, then free it later.
|
||||
*
|
||||
* The returned @gtf_length and @gtf_address are only valid if the
|
||||
* function return value is 0.
|
||||
*/
|
||||
static int do_drive_get_GTF(struct ata_port *ap, int ix,
|
||||
unsigned int *gtf_length, unsigned long *gtf_address,
|
||||
unsigned long *obj_loc)
|
||||
{
|
||||
acpi_status status;
|
||||
acpi_handle dev_handle = NULL;
|
||||
acpi_handle chan_handle, drive_handle;
|
||||
acpi_integer pcidevfn = 0;
|
||||
u32 dev_adr;
|
||||
struct acpi_buffer output;
|
||||
union acpi_object *out_obj;
|
||||
struct device *dev = ap->host->dev;
|
||||
struct ata_device *atadev = &ap->device[ix];
|
||||
int err = -ENODEV;
|
||||
|
||||
*gtf_length = 0;
|
||||
*gtf_address = 0UL;
|
||||
*obj_loc = 0UL;
|
||||
|
||||
if (libata_noacpi)
|
||||
return 0;
|
||||
|
||||
if (ata_msg_probe(ap))
|
||||
ata_dev_printk(atadev, KERN_DEBUG, "%s: ENTER: port#: %d\n",
|
||||
__FUNCTION__, ap->port_no);
|
||||
|
||||
if (!ata_dev_enabled(atadev) || (ap->flags & ATA_FLAG_DISABLED)) {
|
||||
if (ata_msg_probe(ap))
|
||||
ata_dev_printk(atadev, KERN_DEBUG, "%s: ERR: "
|
||||
"ata_dev_present: %d, PORT_DISABLED: %lu\n",
|
||||
__FUNCTION__, ata_dev_enabled(atadev),
|
||||
ap->flags & ATA_FLAG_DISABLED);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Don't continue if device has no _ADR method.
|
||||
* _GTF is intended for known motherboard devices. */
|
||||
if (!(ap->cbl == ATA_CBL_SATA)) {
|
||||
err = pata_get_dev_handle(dev, &dev_handle, &pcidevfn);
|
||||
if (err < 0) {
|
||||
if (ata_msg_probe(ap))
|
||||
ata_dev_printk(atadev, KERN_DEBUG,
|
||||
"%s: pata_get_dev_handle failed (%d)\n",
|
||||
__FUNCTION__, err);
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
err = sata_get_dev_handle(dev, &dev_handle, &pcidevfn);
|
||||
if (err < 0) {
|
||||
if (ata_msg_probe(ap))
|
||||
ata_dev_printk(atadev, KERN_DEBUG,
|
||||
"%s: sata_get_dev_handle failed (%d\n",
|
||||
__FUNCTION__, err);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/* Get this drive's _ADR info. if not already known. */
|
||||
if (!atadev->obj_handle) {
|
||||
if (!(ap->cbl == ATA_CBL_SATA)) {
|
||||
/* get child objects of dev_handle == channel objects,
|
||||
* + _their_ children == drive objects */
|
||||
/* channel is ap->port_no */
|
||||
chan_handle = acpi_get_child(dev_handle,
|
||||
ap->port_no);
|
||||
if (ata_msg_probe(ap))
|
||||
ata_dev_printk(atadev, KERN_DEBUG,
|
||||
"%s: chan adr=%d: chan_handle=0x%p\n",
|
||||
__FUNCTION__, ap->port_no,
|
||||
chan_handle);
|
||||
if (!chan_handle) {
|
||||
err = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
/* TBD: could also check ACPI object VALID bits */
|
||||
drive_handle = acpi_get_child(chan_handle, ix);
|
||||
if (!drive_handle) {
|
||||
err = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
dev_adr = ix;
|
||||
atadev->obj_handle = drive_handle;
|
||||
} else { /* for SATA mode */
|
||||
dev_adr = SATA_ADR_RSVD;
|
||||
err = get_sata_adr(dev, dev_handle, pcidevfn, 0,
|
||||
ap, atadev, &dev_adr);
|
||||
}
|
||||
if (err < 0 || dev_adr == SATA_ADR_RSVD ||
|
||||
!atadev->obj_handle) {
|
||||
if (ata_msg_probe(ap))
|
||||
ata_dev_printk(atadev, KERN_DEBUG,
|
||||
"%s: get_sata/pata_adr failed: "
|
||||
"err=%d, dev_adr=%u, obj_handle=0x%p\n",
|
||||
__FUNCTION__, err, dev_adr,
|
||||
atadev->obj_handle);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/* Setting up output buffer */
|
||||
output.length = ACPI_ALLOCATE_BUFFER;
|
||||
output.pointer = NULL; /* ACPI-CA sets this; save/free it later */
|
||||
|
||||
/* _GTF has no input parameters */
|
||||
err = -EIO;
|
||||
status = acpi_evaluate_object(atadev->obj_handle, "_GTF",
|
||||
NULL, &output);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
if (ata_msg_probe(ap))
|
||||
ata_dev_printk(atadev, KERN_DEBUG,
|
||||
"%s: Run _GTF error: status = 0x%x\n",
|
||||
__FUNCTION__, status);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!output.length || !output.pointer) {
|
||||
if (ata_msg_probe(ap))
|
||||
ata_dev_printk(atadev, KERN_DEBUG, "%s: Run _GTF: "
|
||||
"length or ptr is NULL (0x%llx, 0x%p)\n",
|
||||
__FUNCTION__,
|
||||
(unsigned long long)output.length,
|
||||
output.pointer);
|
||||
kfree(output.pointer);
|
||||
goto out;
|
||||
}
|
||||
|
||||
out_obj = output.pointer;
|
||||
if (out_obj->type != ACPI_TYPE_BUFFER) {
|
||||
kfree(output.pointer);
|
||||
if (ata_msg_probe(ap))
|
||||
ata_dev_printk(atadev, KERN_DEBUG, "%s: Run _GTF: "
|
||||
"error: expected object type of "
|
||||
" ACPI_TYPE_BUFFER, got 0x%x\n",
|
||||
__FUNCTION__, out_obj->type);
|
||||
err = -ENOENT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!out_obj->buffer.length || !out_obj->buffer.pointer ||
|
||||
out_obj->buffer.length % REGS_PER_GTF) {
|
||||
if (ata_msg_drv(ap))
|
||||
ata_dev_printk(atadev, KERN_ERR,
|
||||
"%s: unexpected GTF length (%d) or addr (0x%p)\n",
|
||||
__FUNCTION__, out_obj->buffer.length,
|
||||
out_obj->buffer.pointer);
|
||||
err = -ENOENT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
*gtf_length = out_obj->buffer.length;
|
||||
*gtf_address = (unsigned long)out_obj->buffer.pointer;
|
||||
*obj_loc = (unsigned long)out_obj;
|
||||
if (ata_msg_probe(ap))
|
||||
ata_dev_printk(atadev, KERN_DEBUG, "%s: returning "
|
||||
"gtf_length=%d, gtf_address=0x%lx, obj_loc=0x%lx\n",
|
||||
__FUNCTION__, *gtf_length, *gtf_address, *obj_loc);
|
||||
err = 0;
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* taskfile_load_raw - send taskfile registers to host controller
|
||||
* @ap: Port to which output is sent
|
||||
* @gtf: raw ATA taskfile register set (0x1f1 - 0x1f7)
|
||||
*
|
||||
* Outputs ATA taskfile to standard ATA host controller using MMIO
|
||||
* or PIO as indicated by the ATA_FLAG_MMIO flag.
|
||||
* 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.
|
||||
*
|
||||
* LOCKING: TBD:
|
||||
* Inherited from caller.
|
||||
*/
|
||||
static void taskfile_load_raw(struct ata_port *ap,
|
||||
struct ata_device *atadev,
|
||||
const struct taskfile_array *gtf)
|
||||
{
|
||||
struct ata_taskfile tf;
|
||||
unsigned int err;
|
||||
|
||||
if (ata_msg_probe(ap))
|
||||
ata_dev_printk(atadev, KERN_DEBUG, "%s: (0x1f1-1f7): hex: "
|
||||
"%02x %02x %02x %02x %02x %02x %02x\n",
|
||||
__FUNCTION__,
|
||||
gtf->tfa[0], gtf->tfa[1], gtf->tfa[2],
|
||||
gtf->tfa[3], gtf->tfa[4], gtf->tfa[5], gtf->tfa[6]);
|
||||
|
||||
if ((gtf->tfa[0] == 0) && (gtf->tfa[1] == 0) && (gtf->tfa[2] == 0)
|
||||
&& (gtf->tfa[3] == 0) && (gtf->tfa[4] == 0) && (gtf->tfa[5] == 0)
|
||||
&& (gtf->tfa[6] == 0))
|
||||
return;
|
||||
|
||||
ata_tf_init(atadev, &tf);
|
||||
|
||||
/* convert gtf to tf */
|
||||
tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; /* TBD */
|
||||
tf.protocol = atadev->class == ATA_DEV_ATAPI ?
|
||||
ATA_PROT_ATAPI_NODATA : ATA_PROT_NODATA;
|
||||
tf.feature = gtf->tfa[0]; /* 0x1f1 */
|
||||
tf.nsect = gtf->tfa[1]; /* 0x1f2 */
|
||||
tf.lbal = gtf->tfa[2]; /* 0x1f3 */
|
||||
tf.lbam = gtf->tfa[3]; /* 0x1f4 */
|
||||
tf.lbah = gtf->tfa[4]; /* 0x1f5 */
|
||||
tf.device = gtf->tfa[5]; /* 0x1f6 */
|
||||
tf.command = gtf->tfa[6]; /* 0x1f7 */
|
||||
|
||||
err = ata_exec_internal(atadev, &tf, NULL, DMA_NONE, NULL, 0);
|
||||
if (err && ata_msg_probe(ap))
|
||||
ata_dev_printk(atadev, KERN_ERR,
|
||||
"%s: ata_exec_internal failed: %u\n",
|
||||
__FUNCTION__, err);
|
||||
}
|
||||
|
||||
/**
|
||||
* do_drive_set_taskfiles - write the drive taskfile settings from _GTF
|
||||
* @ap: the ata_port for the drive
|
||||
* @atadev: target ata_device
|
||||
* @gtf_length: total number of bytes of _GTF taskfiles
|
||||
* @gtf_address: location of _GTF taskfile arrays
|
||||
*
|
||||
* This applies to both PATA and SATA drives.
|
||||
*
|
||||
* Write {gtf_address, length gtf_length} in groups of
|
||||
* REGS_PER_GTF bytes.
|
||||
*/
|
||||
static int do_drive_set_taskfiles(struct ata_port *ap,
|
||||
struct ata_device *atadev, unsigned int gtf_length,
|
||||
unsigned long gtf_address)
|
||||
{
|
||||
int err = -ENODEV;
|
||||
int gtf_count = gtf_length / REGS_PER_GTF;
|
||||
int ix;
|
||||
struct taskfile_array *gtf;
|
||||
|
||||
if (ata_msg_probe(ap))
|
||||
ata_dev_printk(atadev, KERN_DEBUG, "%s: ENTER: port#: %d\n",
|
||||
__FUNCTION__, ap->port_no);
|
||||
|
||||
if (libata_noacpi || !(ap->cbl == ATA_CBL_SATA))
|
||||
return 0;
|
||||
|
||||
if (!ata_dev_enabled(atadev) || (ap->flags & ATA_FLAG_DISABLED))
|
||||
goto out;
|
||||
if (!gtf_count) /* shouldn't be here */
|
||||
goto out;
|
||||
|
||||
if (gtf_length % REGS_PER_GTF) {
|
||||
if (ata_msg_drv(ap))
|
||||
ata_dev_printk(atadev, KERN_ERR,
|
||||
"%s: unexpected GTF length (%d)\n",
|
||||
__FUNCTION__, gtf_length);
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (ix = 0; ix < gtf_count; ix++) {
|
||||
gtf = (struct taskfile_array *)
|
||||
(gtf_address + ix * REGS_PER_GTF);
|
||||
|
||||
/* send all TaskFile registers (0x1f1-0x1f7) *in*that*order* */
|
||||
taskfile_load_raw(ap, atadev, gtf);
|
||||
}
|
||||
|
||||
err = 0;
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* ata_acpi_exec_tfs - get then write drive taskfile settings
|
||||
* @ap: the ata_port for the drive
|
||||
*
|
||||
* This applies to both PATA and SATA drives.
|
||||
*/
|
||||
int ata_acpi_exec_tfs(struct ata_port *ap)
|
||||
{
|
||||
int ix;
|
||||
int ret =0;
|
||||
unsigned int gtf_length;
|
||||
unsigned long gtf_address;
|
||||
unsigned long obj_loc;
|
||||
|
||||
if (libata_noacpi)
|
||||
return 0;
|
||||
/*
|
||||
* TBD - implement PATA support. For now,
|
||||
* we should not run GTF on PATA devices since some
|
||||
* PATA require execution of GTM/STM before GTF.
|
||||
*/
|
||||
if (!(ap->cbl == ATA_CBL_SATA))
|
||||
return 0;
|
||||
|
||||
for (ix = 0; ix < ATA_MAX_DEVICES; ix++) {
|
||||
if (!ata_dev_enabled(&ap->device[ix]))
|
||||
continue;
|
||||
|
||||
ret = do_drive_get_GTF(ap, ix,
|
||||
>f_length, >f_address, &obj_loc);
|
||||
if (ret < 0) {
|
||||
if (ata_msg_probe(ap))
|
||||
ata_port_printk(ap, KERN_DEBUG,
|
||||
"%s: get_GTF error (%d)\n",
|
||||
__FUNCTION__, ret);
|
||||
break;
|
||||
}
|
||||
|
||||
ret = do_drive_set_taskfiles(ap, &ap->device[ix],
|
||||
gtf_length, gtf_address);
|
||||
kfree((void *)obj_loc);
|
||||
if (ret < 0) {
|
||||
if (ata_msg_probe(ap))
|
||||
ata_port_printk(ap, KERN_DEBUG,
|
||||
"%s: set_taskfiles error (%d)\n",
|
||||
__FUNCTION__, ret);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* ata_acpi_push_id - send Identify data to drive
|
||||
* @ap: the ata_port for the drive
|
||||
* @ix: drive index
|
||||
*
|
||||
* _SDD ACPI object: for SATA mode only
|
||||
* Must be after Identify (Packet) Device -- uses its data
|
||||
* ATM this function never returns a failure. It is an optional
|
||||
* method and if it fails for whatever reason, we should still
|
||||
* just keep going.
|
||||
*/
|
||||
int ata_acpi_push_id(struct ata_port *ap, unsigned int ix)
|
||||
{
|
||||
acpi_handle handle;
|
||||
acpi_integer pcidevfn;
|
||||
int err;
|
||||
struct device *dev = ap->host->dev;
|
||||
struct ata_device *atadev = &ap->device[ix];
|
||||
u32 dev_adr;
|
||||
acpi_status status;
|
||||
struct acpi_object_list input;
|
||||
union acpi_object in_params[1];
|
||||
|
||||
if (libata_noacpi)
|
||||
return 0;
|
||||
|
||||
if (ata_msg_probe(ap))
|
||||
ata_dev_printk(atadev, KERN_DEBUG, "%s: ix = %d, port#: %d\n",
|
||||
__FUNCTION__, ix, ap->port_no);
|
||||
|
||||
/* Don't continue if not a SATA device. */
|
||||
if (!(ap->cbl == ATA_CBL_SATA)) {
|
||||
if (ata_msg_probe(ap))
|
||||
ata_dev_printk(atadev, KERN_DEBUG,
|
||||
"%s: Not a SATA device\n", __FUNCTION__);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Don't continue if device has no _ADR method.
|
||||
* _SDD is intended for known motherboard devices. */
|
||||
err = sata_get_dev_handle(dev, &handle, &pcidevfn);
|
||||
if (err < 0) {
|
||||
if (ata_msg_probe(ap))
|
||||
ata_dev_printk(atadev, KERN_DEBUG,
|
||||
"%s: sata_get_dev_handle failed (%d\n",
|
||||
__FUNCTION__, err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Get this drive's _ADR info, if not already known */
|
||||
if (!atadev->obj_handle) {
|
||||
dev_adr = SATA_ADR_RSVD;
|
||||
err = get_sata_adr(dev, handle, pcidevfn, ix, ap, atadev,
|
||||
&dev_adr);
|
||||
if (err < 0 || dev_adr == SATA_ADR_RSVD ||
|
||||
!atadev->obj_handle) {
|
||||
if (ata_msg_probe(ap))
|
||||
ata_dev_printk(atadev, KERN_DEBUG,
|
||||
"%s: get_sata_adr failed: "
|
||||
"err=%d, dev_adr=%u, obj_handle=0x%p\n",
|
||||
__FUNCTION__, err, dev_adr,
|
||||
atadev->obj_handle);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/* Give the drive Identify data to the drive via the _SDD method */
|
||||
/* _SDD: set up input parameters */
|
||||
input.count = 1;
|
||||
input.pointer = in_params;
|
||||
in_params[0].type = ACPI_TYPE_BUFFER;
|
||||
in_params[0].buffer.length = sizeof(atadev->id[0]) * ATA_ID_WORDS;
|
||||
in_params[0].buffer.pointer = (u8 *)atadev->id;
|
||||
/* Output buffer: _SDD has no output */
|
||||
|
||||
/* It's OK for _SDD to be missing too. */
|
||||
swap_buf_le16(atadev->id, ATA_ID_WORDS);
|
||||
status = acpi_evaluate_object(atadev->obj_handle, "_SDD", &input, NULL);
|
||||
swap_buf_le16(atadev->id, ATA_ID_WORDS);
|
||||
|
||||
err = ACPI_FAILURE(status) ? -EIO : 0;
|
||||
if (err < 0) {
|
||||
if (ata_msg_probe(ap))
|
||||
ata_dev_printk(atadev, KERN_DEBUG,
|
||||
"%s _SDD error: status = 0x%x\n",
|
||||
__FUNCTION__, status);
|
||||
}
|
||||
|
||||
/* always return success */
|
||||
out:
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
6463
drivers/ata/libata-core.c
Normal file
6463
drivers/ata/libata-core.c
Normal file
File diff suppressed because it is too large
Load Diff
2419
drivers/ata/libata-eh.c
Normal file
2419
drivers/ata/libata-eh.c
Normal file
File diff suppressed because it is too large
Load Diff
3361
drivers/ata/libata-scsi.c
Normal file
3361
drivers/ata/libata-scsi.c
Normal file
File diff suppressed because it is too large
Load Diff
918
drivers/ata/libata-sff.c
Normal file
918
drivers/ata/libata-sff.c
Normal file
@@ -0,0 +1,918 @@
|
||||
/*
|
||||
* 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_irq_on - Enable interrupts on a port.
|
||||
* @ap: Port on which interrupts are enabled.
|
||||
*
|
||||
* Enable interrupts on a legacy IDE device using MMIO or PIO,
|
||||
* wait for idle, clear any pending interrupts.
|
||||
*
|
||||
* LOCKING:
|
||||
* Inherited from caller.
|
||||
*/
|
||||
u8 ata_irq_on(struct ata_port *ap)
|
||||
{
|
||||
struct ata_ioports *ioaddr = &ap->ioaddr;
|
||||
u8 tmp;
|
||||
|
||||
ap->ctl &= ~ATA_NIEN;
|
||||
ap->last_ctl = ap->ctl;
|
||||
|
||||
iowrite8(ap->ctl, ioaddr->ctl_addr);
|
||||
tmp = ata_wait_idle(ap);
|
||||
|
||||
ap->ops->irq_clear(ap);
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
u8 ata_dummy_irq_on (struct ata_port *ap) { return 0; }
|
||||
|
||||
/**
|
||||
* ata_irq_ack - Acknowledge a device interrupt.
|
||||
* @ap: Port on which interrupts are enabled.
|
||||
*
|
||||
* Wait up to 10 ms for legacy IDE device to become idle (BUSY
|
||||
* or BUSY+DRQ clear). Obtain dma status and port status from
|
||||
* device. Clear the interrupt. Return port status.
|
||||
*
|
||||
* LOCKING:
|
||||
*/
|
||||
|
||||
u8 ata_irq_ack(struct ata_port *ap, unsigned int chk_drq)
|
||||
{
|
||||
unsigned int bits = chk_drq ? ATA_BUSY | ATA_DRQ : ATA_BUSY;
|
||||
u8 host_stat, post_stat, status;
|
||||
|
||||
status = ata_busy_wait(ap, bits, 1000);
|
||||
if (status & bits)
|
||||
if (ata_msg_err(ap))
|
||||
printk(KERN_ERR "abnormal status 0x%X\n", status);
|
||||
|
||||
/* get controller status; clear intr, err bits */
|
||||
host_stat = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
|
||||
iowrite8(host_stat | ATA_DMA_INTR | ATA_DMA_ERR,
|
||||
ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
|
||||
|
||||
post_stat = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
|
||||
|
||||
if (ata_msg_intr(ap))
|
||||
printk(KERN_INFO "%s: irq ack: host_stat 0x%X, new host_stat 0x%X, drv_stat 0x%X\n",
|
||||
__FUNCTION__,
|
||||
host_stat, post_stat, status);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
u8 ata_dummy_irq_ack(struct ata_port *ap, unsigned int chk_drq) { return 0; }
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* LOCKING:
|
||||
* Inherited from caller.
|
||||
*/
|
||||
|
||||
void ata_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) {
|
||||
iowrite8(tf->ctl, ioaddr->ctl_addr);
|
||||
ap->last_ctl = tf->ctl;
|
||||
ata_wait_idle(ap);
|
||||
}
|
||||
|
||||
if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
|
||||
iowrite8(tf->hob_feature, ioaddr->feature_addr);
|
||||
iowrite8(tf->hob_nsect, ioaddr->nsect_addr);
|
||||
iowrite8(tf->hob_lbal, ioaddr->lbal_addr);
|
||||
iowrite8(tf->hob_lbam, ioaddr->lbam_addr);
|
||||
iowrite8(tf->hob_lbah, ioaddr->lbah_addr);
|
||||
VPRINTK("hob: feat 0x%X nsect 0x%X, lba 0x%X 0x%X 0x%X\n",
|
||||
tf->hob_feature,
|
||||
tf->hob_nsect,
|
||||
tf->hob_lbal,
|
||||
tf->hob_lbam,
|
||||
tf->hob_lbah);
|
||||
}
|
||||
|
||||
if (is_addr) {
|
||||
iowrite8(tf->feature, ioaddr->feature_addr);
|
||||
iowrite8(tf->nsect, ioaddr->nsect_addr);
|
||||
iowrite8(tf->lbal, ioaddr->lbal_addr);
|
||||
iowrite8(tf->lbam, ioaddr->lbam_addr);
|
||||
iowrite8(tf->lbah, ioaddr->lbah_addr);
|
||||
VPRINTK("feat 0x%X nsect 0x%X lba 0x%X 0x%X 0x%X\n",
|
||||
tf->feature,
|
||||
tf->nsect,
|
||||
tf->lbal,
|
||||
tf->lbam,
|
||||
tf->lbah);
|
||||
}
|
||||
|
||||
if (tf->flags & ATA_TFLAG_DEVICE) {
|
||||
iowrite8(tf->device, ioaddr->device_addr);
|
||||
VPRINTK("device 0x%X\n", tf->device);
|
||||
}
|
||||
|
||||
ata_wait_idle(ap);
|
||||
}
|
||||
|
||||
/**
|
||||
* ata_exec_command - issue ATA command to host controller
|
||||
* @ap: port to which command is being issued
|
||||
* @tf: ATA taskfile register set
|
||||
*
|
||||
* Issues ATA command, with proper synchronization with interrupt
|
||||
* handler / other threads.
|
||||
*
|
||||
* LOCKING:
|
||||
* spin_lock_irqsave(host lock)
|
||||
*/
|
||||
void ata_exec_command(struct ata_port *ap, const struct ata_taskfile *tf)
|
||||
{
|
||||
DPRINTK("ata%u: cmd 0x%X\n", ap->print_id, tf->command);
|
||||
|
||||
iowrite8(tf->command, ap->ioaddr.command_addr);
|
||||
ata_pause(ap);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* LOCKING:
|
||||
* Inherited from caller.
|
||||
*/
|
||||
void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
|
||||
{
|
||||
struct ata_ioports *ioaddr = &ap->ioaddr;
|
||||
|
||||
tf->command = ata_check_status(ap);
|
||||
tf->feature = ioread8(ioaddr->error_addr);
|
||||
tf->nsect = ioread8(ioaddr->nsect_addr);
|
||||
tf->lbal = ioread8(ioaddr->lbal_addr);
|
||||
tf->lbam = ioread8(ioaddr->lbam_addr);
|
||||
tf->lbah = ioread8(ioaddr->lbah_addr);
|
||||
tf->device = ioread8(ioaddr->device_addr);
|
||||
|
||||
if (tf->flags & ATA_TFLAG_LBA48) {
|
||||
iowrite8(tf->ctl | ATA_HOB, ioaddr->ctl_addr);
|
||||
tf->hob_feature = ioread8(ioaddr->error_addr);
|
||||
tf->hob_nsect = ioread8(ioaddr->nsect_addr);
|
||||
tf->hob_lbal = ioread8(ioaddr->lbal_addr);
|
||||
tf->hob_lbam = ioread8(ioaddr->lbam_addr);
|
||||
tf->hob_lbah = ioread8(ioaddr->lbah_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
|
||||
*
|
||||
* LOCKING:
|
||||
* Inherited from caller.
|
||||
*/
|
||||
u8 ata_check_status(struct ata_port *ap)
|
||||
{
|
||||
return ioread8(ap->ioaddr.status_addr);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
return ioread8(ap->ioaddr.altstatus_addr);
|
||||
}
|
||||
|
||||
/**
|
||||
* ata_bmdma_setup - Set up PCI IDE BMDMA transaction
|
||||
* @qc: Info associated with this ATA transaction.
|
||||
*
|
||||
* LOCKING:
|
||||
* spin_lock_irqsave(host lock)
|
||||
*/
|
||||
void ata_bmdma_setup(struct ata_queued_cmd *qc)
|
||||
{
|
||||
struct ata_port *ap = qc->ap;
|
||||
unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE);
|
||||
u8 dmactl;
|
||||
|
||||
/* load PRD table addr. */
|
||||
mb(); /* make sure PRD table writes are visible to controller */
|
||||
iowrite32(ap->prd_dma, ap->ioaddr.bmdma_addr + ATA_DMA_TABLE_OFS);
|
||||
|
||||
/* specify data direction, triple-check start bit is clear */
|
||||
dmactl = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
|
||||
dmactl &= ~(ATA_DMA_WR | ATA_DMA_START);
|
||||
if (!rw)
|
||||
dmactl |= ATA_DMA_WR;
|
||||
iowrite8(dmactl, ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
|
||||
|
||||
/* issue r/w command */
|
||||
ap->ops->exec_command(ap, &qc->tf);
|
||||
}
|
||||
|
||||
/**
|
||||
* ata_bmdma_start - Start a PCI IDE BMDMA transaction
|
||||
* @qc: Info associated with this ATA transaction.
|
||||
*
|
||||
* LOCKING:
|
||||
* spin_lock_irqsave(host lock)
|
||||
*/
|
||||
void ata_bmdma_start (struct ata_queued_cmd *qc)
|
||||
{
|
||||
struct ata_port *ap = qc->ap;
|
||||
u8 dmactl;
|
||||
|
||||
/* start host DMA transaction */
|
||||
dmactl = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
|
||||
iowrite8(dmactl | ATA_DMA_START, ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
|
||||
|
||||
/* Strictly, one may wish to issue 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_irq_clear - Clear PCI IDE BMDMA interrupt.
|
||||
* @ap: Port associated with this ATA transaction.
|
||||
*
|
||||
* Clear interrupt and error flags in DMA status register.
|
||||
*
|
||||
* May be used as the irq_clear() entry in ata_port_operations.
|
||||
*
|
||||
* LOCKING:
|
||||
* spin_lock_irqsave(host lock)
|
||||
*/
|
||||
void ata_bmdma_irq_clear(struct ata_port *ap)
|
||||
{
|
||||
void __iomem *mmio = ap->ioaddr.bmdma_addr;
|
||||
|
||||
if (!mmio)
|
||||
return;
|
||||
|
||||
iowrite8(ioread8(mmio + ATA_DMA_STATUS), mmio + ATA_DMA_STATUS);
|
||||
}
|
||||
|
||||
/**
|
||||
* ata_bmdma_status - Read PCI IDE BMDMA status
|
||||
* @ap: Port associated with this ATA transaction.
|
||||
*
|
||||
* Read and return BMDMA status register.
|
||||
*
|
||||
* May be used as the bmdma_status() entry in ata_port_operations.
|
||||
*
|
||||
* LOCKING:
|
||||
* spin_lock_irqsave(host lock)
|
||||
*/
|
||||
u8 ata_bmdma_status(struct ata_port *ap)
|
||||
{
|
||||
return ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
|
||||
}
|
||||
|
||||
/**
|
||||
* ata_bmdma_stop - Stop PCI IDE BMDMA transfer
|
||||
* @qc: Command we are ending DMA for
|
||||
*
|
||||
* Clears the ATA_DMA_START flag in the dma control register
|
||||
*
|
||||
* May be used as the bmdma_stop() entry in ata_port_operations.
|
||||
*
|
||||
* LOCKING:
|
||||
* spin_lock_irqsave(host lock)
|
||||
*/
|
||||
void ata_bmdma_stop(struct ata_queued_cmd *qc)
|
||||
{
|
||||
struct ata_port *ap = qc->ap;
|
||||
void __iomem *mmio = ap->ioaddr.bmdma_addr;
|
||||
|
||||
/* clear start/stop bit */
|
||||
iowrite8(ioread8(mmio + ATA_DMA_CMD) & ~ATA_DMA_START,
|
||||
mmio + ATA_DMA_CMD);
|
||||
|
||||
/* one-PIO-cycle guaranteed wait, per spec, for HDMA1:0 transition */
|
||||
ata_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;
|
||||
|
||||
iowrite8(ap->ctl, ioaddr->ctl_addr);
|
||||
|
||||
/* Under certain circumstances, some controllers raise IRQ on
|
||||
* ATA_NIEN manipulation. Also, many controllers fail to mask
|
||||
* previously pending IRQ on ATA_NIEN assertion. Clear it.
|
||||
*/
|
||||
ata_chk_status(ap);
|
||||
|
||||
ap->ops->irq_clear(ap);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
ap->ops->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_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 = ap->ops->bmdma_status(ap);
|
||||
|
||||
/* BMDMA controllers indicate host bus error by
|
||||
* setting DMA_ERR bit and timing out. As it wasn't
|
||||
* really a timeout event, adjust error mask and
|
||||
* cancel frozen state.
|
||||
*/
|
||||
if (qc->err_mask == AC_ERR_TIMEOUT && (host_stat & ATA_DMA_ERR)) {
|
||||
qc->err_mask = AC_ERR_HOST_BUS;
|
||||
thaw = 1;
|
||||
}
|
||||
|
||||
ap->ops->bmdma_stop(qc);
|
||||
}
|
||||
|
||||
ata_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)
|
||||
{
|
||||
if (qc->ap->ioaddr.bmdma_addr)
|
||||
ata_bmdma_stop(qc);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PCI
|
||||
|
||||
static int ata_resources_present(struct pci_dev *pdev, int port)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Check the PCI resources for this channel are enabled */
|
||||
port = port * 2;
|
||||
for (i = 0; i < 2; i ++) {
|
||||
if (pci_resource_start(pdev, port + i) == 0 ||
|
||||
pci_resource_len(pdev, port + i) == 0)
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
int i, p = 0;
|
||||
void __iomem * const *iomap;
|
||||
|
||||
/* Discard disabled ports. Some controllers show their
|
||||
unused channels this way */
|
||||
if (ata_resources_present(pdev, 0) == 0)
|
||||
ports &= ~ATA_PORT_PRIMARY;
|
||||
if (ata_resources_present(pdev, 1) == 0)
|
||||
ports &= ~ATA_PORT_SECONDARY;
|
||||
|
||||
/* iomap BARs */
|
||||
if (ports & ATA_PORT_PRIMARY) {
|
||||
for (i = 0; i <= 1; i++) {
|
||||
if (pcim_iomap(pdev, i, 0) == NULL) {
|
||||
dev_printk(KERN_ERR, &pdev->dev,
|
||||
"failed to iomap PCI BAR %d\n", i);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ports & ATA_PORT_SECONDARY) {
|
||||
for (i = 2; i <= 3; i++) {
|
||||
if (pcim_iomap(pdev, i, 0) == NULL) {
|
||||
dev_printk(KERN_ERR, &pdev->dev,
|
||||
"failed to iomap PCI BAR %d\n", i);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pcim_iomap(pdev, 4, 0); /* may fail */
|
||||
iomap = pcim_iomap_table(pdev);
|
||||
|
||||
/* alloc and init probe_ent */
|
||||
probe_ent = ata_probe_ent_alloc(pci_dev_to_dev(pdev), port[0]);
|
||||
if (!probe_ent)
|
||||
return NULL;
|
||||
|
||||
probe_ent->irq = pdev->irq;
|
||||
probe_ent->irq_flags = IRQF_SHARED;
|
||||
|
||||
if (ports & ATA_PORT_PRIMARY) {
|
||||
probe_ent->port[p].cmd_addr = iomap[0];
|
||||
probe_ent->port[p].altstatus_addr =
|
||||
probe_ent->port[p].ctl_addr = (void __iomem *)
|
||||
((unsigned long)iomap[1] | ATA_PCI_CTL_OFS);
|
||||
if (iomap[4]) {
|
||||
if ((!(port[p]->flags & ATA_FLAG_IGN_SIMPLEX)) &&
|
||||
(ioread8(iomap[4] + 2) & 0x80))
|
||||
probe_ent->_host_flags |= ATA_HOST_SIMPLEX;
|
||||
probe_ent->port[p].bmdma_addr = iomap[4];
|
||||
}
|
||||
ata_std_ports(&probe_ent->port[p]);
|
||||
p++;
|
||||
}
|
||||
|
||||
if (ports & ATA_PORT_SECONDARY) {
|
||||
probe_ent->port[p].cmd_addr = iomap[2];
|
||||
probe_ent->port[p].altstatus_addr =
|
||||
probe_ent->port[p].ctl_addr = (void __iomem *)
|
||||
((unsigned long)iomap[3] | ATA_PCI_CTL_OFS);
|
||||
if (iomap[4]) {
|
||||
if ((!(port[p]->flags & ATA_FLAG_IGN_SIMPLEX)) &&
|
||||
(ioread8(iomap[4] + 10) & 0x80))
|
||||
probe_ent->_host_flags |= ATA_HOST_SIMPLEX;
|
||||
probe_ent->port[p].bmdma_addr = iomap[4] + 8;
|
||||
}
|
||||
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;
|
||||
void __iomem *iomap[5] = { }, *bmdma;
|
||||
|
||||
if (port_mask & ATA_PORT_PRIMARY) {
|
||||
iomap[0] = devm_ioport_map(&pdev->dev, ATA_PRIMARY_CMD, 8);
|
||||
iomap[1] = devm_ioport_map(&pdev->dev, ATA_PRIMARY_CTL, 1);
|
||||
if (!iomap[0] || !iomap[1])
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (port_mask & ATA_PORT_SECONDARY) {
|
||||
iomap[2] = devm_ioport_map(&pdev->dev, ATA_SECONDARY_CMD, 8);
|
||||
iomap[3] = devm_ioport_map(&pdev->dev, ATA_SECONDARY_CTL, 1);
|
||||
if (!iomap[2] || !iomap[3])
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bmdma = pcim_iomap(pdev, 4, 16); /* may fail */
|
||||
|
||||
/* alloc and init probe_ent */
|
||||
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->irq_flags = IRQF_SHARED;
|
||||
|
||||
if (port_mask & ATA_PORT_PRIMARY) {
|
||||
probe_ent->irq = ATA_PRIMARY_IRQ(pdev);
|
||||
probe_ent->port[0].cmd_addr = iomap[0];
|
||||
probe_ent->port[0].altstatus_addr =
|
||||
probe_ent->port[0].ctl_addr = iomap[1];
|
||||
if (bmdma) {
|
||||
probe_ent->port[0].bmdma_addr = bmdma;
|
||||
if ((!(port[0]->flags & ATA_FLAG_IGN_SIMPLEX)) &&
|
||||
(ioread8(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(pdev);
|
||||
else
|
||||
probe_ent->irq = ATA_SECONDARY_IRQ(pdev);
|
||||
probe_ent->port[1].cmd_addr = iomap[2];
|
||||
probe_ent->port[1].altstatus_addr =
|
||||
probe_ent->port[1].ctl_addr = iomap[3];
|
||||
if (bmdma) {
|
||||
probe_ent->port[1].bmdma_addr = bmdma + 8;
|
||||
if ((!(port[1]->flags & ATA_FLAG_IGN_SIMPLEX)) &&
|
||||
(ioread8(bmdma + 10) & 0x80))
|
||||
probe_ent->_host_flags |= ATA_HOST_SIMPLEX;
|
||||
}
|
||||
ata_std_ports(&probe_ent->port[1]);
|
||||
|
||||
/* FIXME: could be pointing to stack area; must copy */
|
||||
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 device *dev = &pdev->dev;
|
||||
struct ata_probe_ent *probe_ent = NULL;
|
||||
struct ata_port_info *port[2];
|
||||
u8 mask;
|
||||
unsigned int legacy_mode = 0;
|
||||
int rc;
|
||||
|
||||
DPRINTK("ENTER\n");
|
||||
|
||||
if (!devres_open_group(dev, NULL, GFP_KERNEL))
|
||||
return -ENOMEM;
|
||||
|
||||
BUG_ON(n_ports < 1 || n_ports > 2);
|
||||
|
||||
port[0] = port_info[0];
|
||||
if (n_ports > 1)
|
||||
port[1] = port_info[1];
|
||||
else
|
||||
port[1] = port[0];
|
||||
|
||||
/* 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 = pcim_enable_device(pdev);
|
||||
if (rc)
|
||||
goto err_out;
|
||||
|
||||
if ((pdev->class >> 8) == PCI_CLASS_STORAGE_IDE) {
|
||||
u8 tmp8;
|
||||
|
||||
/* 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);
|
||||
#if defined(CONFIG_NO_ATA_LEGACY)
|
||||
/* Some platforms with PCI limits cannot address compat
|
||||
port space. In that case we punt if their firmware has
|
||||
left a device in compatibility mode */
|
||||
if (legacy_mode) {
|
||||
printk(KERN_ERR "ata: Compatibility mode ATA is not supported on this platform, skipping.\n");
|
||||
rc = -EOPNOTSUPP;
|
||||
goto err_out;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!legacy_mode) {
|
||||
rc = pci_request_regions(pdev, DRV_NAME);
|
||||
if (rc) {
|
||||
pcim_pin_device(pdev);
|
||||
goto err_out;
|
||||
}
|
||||
} else {
|
||||
/* Deal with combined mode hack. This side of the logic all
|
||||
goes away once the combined mode hack is killed in 2.6.21 */
|
||||
if (!devm_request_region(dev, 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 {
|
||||
pcim_pin_device(pdev);
|
||||
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 (!devm_request_region(dev, 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 {
|
||||
pcim_pin_device(pdev);
|
||||
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;
|
||||
|
||||
if (legacy_mode & ATA_PORT_PRIMARY)
|
||||
pci_request_region(pdev, 1, DRV_NAME);
|
||||
if (legacy_mode & ATA_PORT_SECONDARY)
|
||||
pci_request_region(pdev, 3, DRV_NAME);
|
||||
/* If there is a DMA resource, allocate it */
|
||||
pci_request_region(pdev, 4, DRV_NAME);
|
||||
}
|
||||
|
||||
/* we have legacy mode, but all ports are unavailable */
|
||||
if (legacy_mode == (1 << 3)) {
|
||||
rc = -EBUSY;
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
/* TODO: 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;
|
||||
rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
|
||||
if (rc)
|
||||
goto err_out;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
pci_set_master(pdev);
|
||||
|
||||
if (!ata_device_add(probe_ent)) {
|
||||
rc = -ENODEV;
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
devm_kfree(dev, probe_ent);
|
||||
devres_remove_group(dev, NULL);
|
||||
return 0;
|
||||
|
||||
err_out:
|
||||
devres_release_group(dev, NULL);
|
||||
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 */
|
||||
|
||||
163
drivers/ata/libata.h
Normal file
163
drivers/ata/libata.h
Normal file
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
* 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"
|
||||
|
||||
struct ata_scsi_args {
|
||||
struct ata_device *dev;
|
||||
u16 *id;
|
||||
struct scsi_cmnd *cmd;
|
||||
void (*done)(struct scsi_cmnd *);
|
||||
};
|
||||
|
||||
/* libata-core.c */
|
||||
enum {
|
||||
/* flags for ata_dev_read_id() */
|
||||
ATA_READID_POSTRESET = (1 << 0), /* reading ID after reset */
|
||||
|
||||
/* selector for ata_down_xfermask_limit() */
|
||||
ATA_DNXFER_PIO = 0, /* speed down PIO */
|
||||
ATA_DNXFER_DMA = 1, /* speed down DMA */
|
||||
ATA_DNXFER_40C = 2, /* apply 40c cable limit */
|
||||
ATA_DNXFER_FORCE_PIO = 3, /* force PIO */
|
||||
ATA_DNXFER_FORCE_PIO0 = 4, /* force PIO0 */
|
||||
|
||||
ATA_DNXFER_QUIET = (1 << 31),
|
||||
};
|
||||
|
||||
extern struct workqueue_struct *ata_aux_wq;
|
||||
extern int atapi_enabled;
|
||||
extern int atapi_dmadir;
|
||||
extern int libata_fua;
|
||||
extern int libata_noacpi;
|
||||
extern struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev);
|
||||
extern int ata_build_rw_tf(struct ata_taskfile *tf, struct ata_device *dev,
|
||||
u64 block, u32 n_block, unsigned int tf_flags,
|
||||
unsigned int tag);
|
||||
extern u64 ata_tf_read_block(struct ata_taskfile *tf, struct ata_device *dev);
|
||||
extern void ata_dev_disable(struct ata_device *dev);
|
||||
extern void ata_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 ata_exec_internal_sg(struct ata_device *dev,
|
||||
struct ata_taskfile *tf, const u8 *cdb,
|
||||
int dma_dir, struct scatterlist *sg,
|
||||
unsigned int n_elem);
|
||||
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,
|
||||
unsigned int flags, u16 *id);
|
||||
extern int ata_dev_revalidate(struct ata_device *dev, unsigned int flags);
|
||||
extern int ata_dev_configure(struct ata_device *dev);
|
||||
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, unsigned int sel);
|
||||
extern int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev);
|
||||
extern void ata_sg_clean(struct ata_queued_cmd *qc);
|
||||
extern void ata_qc_free(struct ata_queued_cmd *qc);
|
||||
extern void ata_qc_issue(struct ata_queued_cmd *qc);
|
||||
extern void __ata_qc_complete(struct ata_queued_cmd *qc);
|
||||
extern int ata_check_atapi_dma(struct ata_queued_cmd *qc);
|
||||
extern 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-acpi.c */
|
||||
#ifdef CONFIG_SATA_ACPI
|
||||
extern int ata_acpi_exec_tfs(struct ata_port *ap);
|
||||
extern int ata_acpi_push_id(struct ata_port *ap, unsigned int ix);
|
||||
#else
|
||||
static inline int ata_acpi_exec_tfs(struct ata_port *ap)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline int ata_acpi_push_id(struct ata_port *ap, unsigned int ix)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* 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(struct work_struct *work);
|
||||
extern unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf,
|
||||
unsigned int buflen);
|
||||
|
||||
extern unsigned int ata_scsiop_inq_00(struct ata_scsi_args *args, u8 *rbuf,
|
||||
unsigned int buflen);
|
||||
|
||||
extern unsigned int ata_scsiop_inq_80(struct ata_scsi_args *args, u8 *rbuf,
|
||||
unsigned int buflen);
|
||||
extern unsigned int ata_scsiop_inq_83(struct ata_scsi_args *args, u8 *rbuf,
|
||||
unsigned int buflen);
|
||||
extern unsigned int ata_scsiop_noop(struct ata_scsi_args *args, u8 *rbuf,
|
||||
unsigned int buflen);
|
||||
extern unsigned int ata_scsiop_sync_cache(struct ata_scsi_args *args, u8 *rbuf,
|
||||
unsigned int buflen);
|
||||
extern unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf,
|
||||
unsigned int buflen);
|
||||
extern unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf,
|
||||
unsigned int buflen);
|
||||
extern unsigned int ata_scsiop_report_luns(struct ata_scsi_args *args, u8 *rbuf,
|
||||
unsigned int buflen);
|
||||
extern void ata_scsi_badcmd(struct scsi_cmnd *cmd,
|
||||
void (*done)(struct scsi_cmnd *),
|
||||
u8 asc, u8 ascq);
|
||||
extern void ata_scsi_set_sense(struct scsi_cmnd *cmd,
|
||||
u8 sk, u8 asc, u8 ascq);
|
||||
extern void ata_scsi_rbuf_fill(struct ata_scsi_args *args,
|
||||
unsigned int (*actor) (struct ata_scsi_args *args,
|
||||
u8 *rbuf, unsigned int buflen));
|
||||
extern void ata_schedule_scsi_eh(struct Scsi_Host *shost);
|
||||
extern void ata_scsi_dev_rescan(struct work_struct *work);
|
||||
extern int ata_bus_probe(struct ata_port *ap);
|
||||
|
||||
/* 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);
|
||||
|
||||
/* libata-sff.c */
|
||||
extern u8 ata_irq_on(struct ata_port *ap);
|
||||
|
||||
|
||||
#endif /* __LIBATA_H__ */
|
||||
717
drivers/ata/pata_ali.c
Normal file
717
drivers/ata/pata_ali.c
Normal file
@@ -0,0 +1,717 @@
|
||||
/*
|
||||
* 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.7.3"
|
||||
|
||||
/*
|
||||
* 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_PATA40_SHORT;
|
||||
|
||||
/* 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[ATA_ID_PROD_LEN + 1];
|
||||
/* No DMA on anything but a disk for now */
|
||||
if (adev->class != ATA_DEV_ATA)
|
||||
mask &= ~(ATA_MASK_MWDMA | ATA_MASK_UDMA);
|
||||
ata_id_c_string(adev->id, model_num, ATA_ID_PROD, sizeof(model_num));
|
||||
if (strstr(model_num, "WDC"))
|
||||
return mask &= ~ATA_MASK_UDMA;
|
||||
return ata_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, ®4b);
|
||||
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,
|
||||
.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,
|
||||
#ifdef CONFIG_PM
|
||||
.resume = ata_scsi_device_resume,
|
||||
.suspend = ata_scsi_device_suspend,
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
* 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_data_xfer,
|
||||
|
||||
.irq_handler = ata_interrupt,
|
||||
.irq_clear = ata_bmdma_irq_clear,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
|
||||
.port_start = ata_port_start,
|
||||
};
|
||||
|
||||
/*
|
||||
* 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_data_xfer,
|
||||
|
||||
.irq_handler = ata_interrupt,
|
||||
.irq_clear = ata_bmdma_irq_clear,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
|
||||
.port_start = ata_port_start,
|
||||
};
|
||||
|
||||
/*
|
||||
* 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_data_xfer,
|
||||
|
||||
.irq_handler = ata_interrupt,
|
||||
.irq_clear = ata_bmdma_irq_clear,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
|
||||
.port_start = ata_port_start,
|
||||
};
|
||||
|
||||
/*
|
||||
* 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_data_xfer,
|
||||
|
||||
.irq_handler = ata_interrupt,
|
||||
.irq_clear = ata_bmdma_irq_clear,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
|
||||
.port_start = ata_port_start,
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* ali_init_chipset - chip setup function
|
||||
* @pdev: PCI device of ATA controller
|
||||
*
|
||||
* Perform the setup on the device that must be done both at boot
|
||||
* and at resume time.
|
||||
*/
|
||||
|
||||
static void ali_init_chipset(struct pci_dev *pdev)
|
||||
{
|
||||
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 && 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);
|
||||
} else 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_bus_and_slot(0, PCI_DEVFN(0,0));
|
||||
isa_bridge = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL);
|
||||
|
||||
if (north && north->vendor == PCI_VENDOR_ID_AL && isa_bridge) {
|
||||
/* Configure the ALi bridge logic. For non ALi rely on BIOS.
|
||||
Set the south bridge enable bit */
|
||||
pci_read_config_byte(isa_bridge, 0x79, &tmp);
|
||||
if (rev == 0xC2)
|
||||
pci_write_config_byte(isa_bridge, 0x79, tmp | 0x04);
|
||||
else if (rev > 0xC2 && rev < 0xC5)
|
||||
pci_write_config_byte(isa_bridge, 0x79, tmp | 0x02);
|
||||
}
|
||||
if (rev >= 0x20) {
|
||||
/*
|
||||
* CD_ROM DMA on (0x53 bit 0). Enable this even if we want
|
||||
* to use PIO. 0x53 bit 1 (rev 20 only) - enable FIFO control
|
||||
* via 0x54/55.
|
||||
*/
|
||||
pci_read_config_byte(pdev, 0x53, &tmp);
|
||||
if (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);
|
||||
}
|
||||
/**
|
||||
* 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 *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) {
|
||||
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;
|
||||
|
||||
ali_init_chipset(pdev);
|
||||
|
||||
isa_bridge = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL);
|
||||
if (isa_bridge && rev >= 0x20 && 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;
|
||||
pci_dev_put(isa_bridge);
|
||||
}
|
||||
return ata_pci_init_one(pdev, port_info, 2);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int ali_reinit_one(struct pci_dev *pdev)
|
||||
{
|
||||
ali_init_chipset(pdev);
|
||||
return ata_pci_device_resume(pdev);
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct pci_device_id ali[] = {
|
||||
{ PCI_VDEVICE(AL, PCI_DEVICE_ID_AL_M5228), },
|
||||
{ PCI_VDEVICE(AL, PCI_DEVICE_ID_AL_M5229), },
|
||||
|
||||
{ },
|
||||
};
|
||||
|
||||
static struct pci_driver ali_pci_driver = {
|
||||
.name = DRV_NAME,
|
||||
.id_table = ali,
|
||||
.probe = ali_init_one,
|
||||
.remove = ata_pci_remove_one,
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = ata_pci_device_suspend,
|
||||
.resume = ali_reinit_one,
|
||||
#endif
|
||||
};
|
||||
|
||||
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);
|
||||
738
drivers/ata/pata_amd.c
Normal file
738
drivers/ata/pata_amd.c
Normal file
@@ -0,0 +1,738 @@
|
||||
/*
|
||||
* 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.8"
|
||||
|
||||
/**
|
||||
* 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, 0x0C};
|
||||
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, 0x0C};
|
||||
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,
|
||||
.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,
|
||||
#ifdef CONFIG_PM
|
||||
.resume = ata_scsi_device_resume,
|
||||
.suspend = ata_scsi_device_suspend,
|
||||
#endif
|
||||
};
|
||||
|
||||
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_data_xfer,
|
||||
|
||||
.irq_handler = ata_interrupt,
|
||||
.irq_clear = ata_bmdma_irq_clear,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
|
||||
.port_start = ata_port_start,
|
||||
};
|
||||
|
||||
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_data_xfer,
|
||||
|
||||
.irq_handler = ata_interrupt,
|
||||
.irq_clear = ata_bmdma_irq_clear,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
|
||||
.port_start = ata_port_start,
|
||||
};
|
||||
|
||||
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_data_xfer,
|
||||
|
||||
.irq_handler = ata_interrupt,
|
||||
.irq_clear = ata_bmdma_irq_clear,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
|
||||
.port_start = ata_port_start,
|
||||
};
|
||||
|
||||
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_data_xfer,
|
||||
|
||||
.irq_handler = ata_interrupt,
|
||||
.irq_clear = ata_bmdma_irq_clear,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
|
||||
.port_start = ata_port_start,
|
||||
};
|
||||
|
||||
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_data_xfer,
|
||||
|
||||
.irq_handler = ata_interrupt,
|
||||
.irq_clear = ata_bmdma_irq_clear,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
|
||||
.port_start = ata_port_start,
|
||||
};
|
||||
|
||||
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_data_xfer,
|
||||
|
||||
.irq_handler = ata_interrupt,
|
||||
.irq_clear = ata_bmdma_irq_clear,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
|
||||
.port_start = ata_port_start,
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int amd_reinit_one(struct pci_dev *pdev)
|
||||
{
|
||||
if (pdev->vendor == PCI_VENDOR_ID_AMD) {
|
||||
u8 fifo;
|
||||
pci_read_config_byte(pdev, 0x41, &fifo);
|
||||
if (pdev->device == PCI_DEVICE_ID_AMD_VIPER_7411)
|
||||
/* FIFO is broken */
|
||||
pci_write_config_byte(pdev, 0x41, fifo & 0x0F);
|
||||
else
|
||||
pci_write_config_byte(pdev, 0x41, fifo | 0xF0);
|
||||
if (pdev->device == PCI_DEVICE_ID_AMD_VIPER_7409 ||
|
||||
pdev->device == PCI_DEVICE_ID_AMD_COBRA_7401)
|
||||
ata_pci_clear_simplex(pdev);
|
||||
}
|
||||
return ata_pci_device_resume(pdev);
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct pci_device_id amd[] = {
|
||||
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_COBRA_7401), 0 },
|
||||
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_VIPER_7409), 1 },
|
||||
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_VIPER_7411), 3 },
|
||||
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_OPUS_7441), 4 },
|
||||
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_8111_IDE), 5 },
|
||||
{ PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_IDE), 7 },
|
||||
{ PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2_IDE), 8 },
|
||||
{ PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_IDE), 8 },
|
||||
{ PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3_IDE), 8 },
|
||||
{ PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_IDE), 8 },
|
||||
{ PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_IDE), 8 },
|
||||
{ PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE), 8 },
|
||||
{ PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_IDE), 8 },
|
||||
{ PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_IDE), 8 },
|
||||
{ PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_IDE), 8 },
|
||||
{ PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP65_IDE), 8 },
|
||||
{ PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP67_IDE), 8 },
|
||||
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_CS5536_IDE), 9 },
|
||||
|
||||
{ },
|
||||
};
|
||||
|
||||
static struct pci_driver amd_pci_driver = {
|
||||
.name = DRV_NAME,
|
||||
.id_table = amd,
|
||||
.probe = amd_init_one,
|
||||
.remove = ata_pci_remove_one,
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = ata_pci_device_suspend,
|
||||
.resume = amd_reinit_one,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int __init amd_init(void)
|
||||
{
|
||||
return pci_register_driver(&amd_pci_driver);
|
||||
}
|
||||
|
||||
static void __exit amd_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&amd_pci_driver);
|
||||
}
|
||||
|
||||
MODULE_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);
|
||||
515
drivers/ata/pata_artop.c
Normal file
515
drivers/ata/pata_artop.c
Normal file
@@ -0,0 +1,515 @@
|
||||
/*
|
||||
* 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,
|
||||
.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 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_data_xfer,
|
||||
|
||||
.irq_handler = ata_interrupt,
|
||||
.irq_clear = ata_bmdma_irq_clear,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
|
||||
.port_start = ata_port_start,
|
||||
};
|
||||
|
||||
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_data_xfer,
|
||||
|
||||
.irq_handler = ata_interrupt,
|
||||
.irq_clear = ata_bmdma_irq_clear,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
|
||||
.port_start = ata_port_start,
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* 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 = NULL;
|
||||
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, ®);
|
||||
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, ®);
|
||||
if (reg <= 0x80)
|
||||
pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x90);
|
||||
|
||||
/* Enable IRQ output and burst mode */
|
||||
pci_read_config_byte(pdev, 0x4a, ®);
|
||||
pci_write_config_byte(pdev, 0x4a, (reg & ~0x01) | 0x80);
|
||||
|
||||
}
|
||||
|
||||
BUG_ON(info == NULL);
|
||||
|
||||
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[] = {
|
||||
{ PCI_VDEVICE(ARTOP, 0x0005), 0 },
|
||||
{ PCI_VDEVICE(ARTOP, 0x0006), 1 },
|
||||
{ PCI_VDEVICE(ARTOP, 0x0007), 1 },
|
||||
{ PCI_VDEVICE(ARTOP, 0x0008), 2 },
|
||||
{ PCI_VDEVICE(ARTOP, 0x0009), 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);
|
||||
|
||||
319
drivers/ata/pata_atiixp.c
Normal file
319
drivers/ata/pata_atiixp.c
Normal file
@@ -0,0 +1,319 @@
|
||||
/*
|
||||
* 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.4"
|
||||
|
||||
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 const struct pci_bits atiixp_enable_bits[] = {
|
||||
{ 0x48, 1, 0x01, 0x00 },
|
||||
{ 0x48, 1, 0x08, 0x00 }
|
||||
};
|
||||
u8 udma;
|
||||
|
||||
if (!pci_test_config_bits(pdev, &atiixp_enable_bits[ap->port_no]))
|
||||
return -ENOENT;
|
||||
|
||||
/* Hack from drivers/ide/pci. Really we want to know how to do the
|
||||
raw detection not play follow the bios mode guess */
|
||||
pci_read_config_byte(pdev, ATIIXP_IDE_UDMA_MODE + ap->port_no, &udma);
|
||||
if ((udma & 0x07) >= 0x04 || (udma & 0x70) >= 0x40)
|
||||
ap->cbl = ATA_CBL_PATA80;
|
||||
else
|
||||
ap->cbl = ATA_CBL_PATA40;
|
||||
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,
|
||||
.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,
|
||||
#ifdef CONFIG_PM
|
||||
.resume = ata_scsi_device_resume,
|
||||
.suspend = ata_scsi_device_suspend,
|
||||
#endif
|
||||
};
|
||||
|
||||
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_data_xfer,
|
||||
|
||||
.irq_handler = ata_interrupt,
|
||||
.irq_clear = ata_bmdma_irq_clear,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
|
||||
.port_start = ata_port_start,
|
||||
};
|
||||
|
||||
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 const struct pci_device_id atiixp[] = {
|
||||
{ PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP200_IDE), },
|
||||
{ PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP300_IDE), },
|
||||
{ PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP400_IDE), },
|
||||
{ PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP600_IDE), },
|
||||
|
||||
{ },
|
||||
};
|
||||
|
||||
static struct pci_driver atiixp_pci_driver = {
|
||||
.name = DRV_NAME,
|
||||
.id_table = atiixp,
|
||||
.probe = atiixp_init_one,
|
||||
.remove = ata_pci_remove_one,
|
||||
#ifdef CONFIG_PM
|
||||
.resume = ata_pci_device_resume,
|
||||
.suspend = ata_pci_device_suspend,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int __init atiixp_init(void)
|
||||
{
|
||||
return pci_register_driver(&atiixp_pci_driver);
|
||||
}
|
||||
|
||||
|
||||
static void __exit atiixp_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&atiixp_pci_driver);
|
||||
}
|
||||
|
||||
MODULE_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);
|
||||
537
drivers/ata/pata_cmd64x.c
Normal file
537
drivers/ata/pata_cmd64x.c
Normal file
@@ -0,0 +1,537 @@
|
||||
/*
|
||||
* pata_cmd64x.c - CMD64x 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.2"
|
||||
|
||||
/*
|
||||
* 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 &= 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[] = {
|
||||
0x30, 0x20, 0x10, 0x20, 0x10, 0x00
|
||||
};
|
||||
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, ®D);
|
||||
pci_read_config_byte(pdev, pciU, ®U);
|
||||
|
||||
/* DMA bits off */
|
||||
regD &= ~(0x20 << adev->devno);
|
||||
/* DMA control bits */
|
||||
regU &= ~(0x30 << shift);
|
||||
/* DMA timing bits */
|
||||
regU &= ~(0x05 << adev->devno);
|
||||
|
||||
if (adev->dma_mode >= XFER_UDMA_0) {
|
||||
/* Merge thge timing value */
|
||||
regU |= udma_data[adev->dma_mode - XFER_UDMA_0] << shift;
|
||||
/* Merge the control bits */
|
||||
regU |= 1 << adev->devno; /* UDMA on */
|
||||
if (adev->dma_mode > 2) /* 15nS timing */
|
||||
regU |= 4 << adev->devno;
|
||||
} 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_mask = ap->port_no ? ARTTIM23_INTR_CH1 : CFR_INTR_CH0;
|
||||
int dma_reg = 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,
|
||||
.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,
|
||||
#ifdef CONFIG_PM
|
||||
.resume = ata_scsi_device_resume,
|
||||
.suspend = ata_scsi_device_suspend,
|
||||
#endif
|
||||
};
|
||||
|
||||
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_data_xfer,
|
||||
|
||||
.irq_handler = ata_interrupt,
|
||||
.irq_clear = ata_bmdma_irq_clear,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
|
||||
.port_start = ata_port_start,
|
||||
};
|
||||
|
||||
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_data_xfer,
|
||||
|
||||
.irq_handler = ata_interrupt,
|
||||
.irq_clear = ata_bmdma_irq_clear,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
|
||||
.port_start = ata_port_start,
|
||||
};
|
||||
|
||||
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_data_xfer,
|
||||
|
||||
.irq_handler = ata_interrupt,
|
||||
.irq_clear = ata_bmdma_irq_clear,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
|
||||
.port_start = ata_port_start,
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int cmd64x_reinit_one(struct pci_dev *pdev)
|
||||
{
|
||||
u8 mrdmode;
|
||||
pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 64);
|
||||
pci_read_config_byte(pdev, MRDMODE, &mrdmode);
|
||||
mrdmode &= ~ 0x30; /* IRQ set up */
|
||||
mrdmode |= 0x02; /* Memory read line enable */
|
||||
pci_write_config_byte(pdev, MRDMODE, mrdmode);
|
||||
#ifdef CONFIG_PPC
|
||||
pci_write_config_byte(pdev, UDIDETCR0, 0xF0);
|
||||
#endif
|
||||
return ata_pci_device_resume(pdev);
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct pci_device_id cmd64x[] = {
|
||||
{ PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_643), 0 },
|
||||
{ PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_646), 1 },
|
||||
{ PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_648), 4 },
|
||||
{ PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_649), 5 },
|
||||
|
||||
{ },
|
||||
};
|
||||
|
||||
static struct pci_driver cmd64x_pci_driver = {
|
||||
.name = DRV_NAME,
|
||||
.id_table = cmd64x,
|
||||
.probe = cmd64x_init_one,
|
||||
.remove = ata_pci_remove_one,
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = ata_pci_device_suspend,
|
||||
.resume = cmd64x_reinit_one,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int __init cmd64x_init(void)
|
||||
{
|
||||
return pci_register_driver(&cmd64x_pci_driver);
|
||||
}
|
||||
|
||||
static void __exit cmd64x_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&cmd64x_pci_driver);
|
||||
}
|
||||
|
||||
MODULE_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);
|
||||
394
drivers/ata/pata_cs5520.c
Normal file
394
drivers/ata/pata_cs5520.c
Normal file
@@ -0,0 +1,394 @@
|
||||
/*
|
||||
* 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.4"
|
||||
|
||||
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 = ioread8(ap->ioaddr.bmdma_addr + 0x02);
|
||||
reg |= 1<<(adev->devno + 5);
|
||||
iowrite8(reg, ap->ioaddr.bmdma_addr + 0x02);
|
||||
}
|
||||
|
||||
/**
|
||||
* cs5520_set_dmamode - program DMA timings
|
||||
* @ap: ATA port
|
||||
* @adev: ATA device
|
||||
*
|
||||
* Program the DMA mode timings for the controller according to the pio
|
||||
* clocking table. Note that this device sets the DMA timings to PIO
|
||||
* mode values. This may seem bizarre but the 5520 architecture talks
|
||||
* PIO mode to the disk and DMA mode to the controller so the underlying
|
||||
* transfers are PIO timed.
|
||||
*/
|
||||
|
||||
static void cs5520_set_dmamode(struct ata_port *ap, struct ata_device *adev)
|
||||
{
|
||||
static const int dma_xlate[3] = { XFER_PIO_0, XFER_PIO_3, XFER_PIO_4 };
|
||||
cs5520_set_timings(ap, adev, dma_xlate[adev->dma_mode]);
|
||||
cs5520_enable_dma(ap, adev);
|
||||
}
|
||||
|
||||
/**
|
||||
* cs5520_set_piomode - program PIO timings
|
||||
* @ap: ATA port
|
||||
* @adev: ATA device
|
||||
*
|
||||
* Program the PIO mode timings for the controller according to the pio
|
||||
* clocking table. We know pio_mode will equal dma_mode because of the
|
||||
* CS5520 architecture. At least once we turned DMA on and wrote a
|
||||
* mode setter.
|
||||
*/
|
||||
|
||||
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,
|
||||
.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,
|
||||
#ifdef CONFIG_PM
|
||||
.resume = ata_scsi_device_resume,
|
||||
.suspend = ata_scsi_device_suspend,
|
||||
#endif
|
||||
};
|
||||
|
||||
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_data_xfer,
|
||||
|
||||
.irq_handler = ata_interrupt,
|
||||
.irq_clear = ata_bmdma_irq_clear,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
|
||||
.port_start = ata_port_start,
|
||||
};
|
||||
|
||||
static int __devinit cs5520_init_one(struct pci_dev *dev, const struct pci_device_id *id)
|
||||
{
|
||||
u8 pcicfg;
|
||||
void __iomem *iomap[5];
|
||||
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;
|
||||
}
|
||||
|
||||
/* Map IO ports */
|
||||
iomap[0] = devm_ioport_map(&dev->dev, 0x1F0, 8);
|
||||
iomap[1] = devm_ioport_map(&dev->dev, 0x3F6, 1);
|
||||
iomap[2] = devm_ioport_map(&dev->dev, 0x170, 8);
|
||||
iomap[3] = devm_ioport_map(&dev->dev, 0x376, 1);
|
||||
iomap[4] = pcim_iomap(dev, 2, 0);
|
||||
|
||||
if (!iomap[0] || !iomap[1] || !iomap[2] || !iomap[3] || !iomap[4])
|
||||
return -ENOMEM;
|
||||
|
||||
/* 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 = iomap[0];
|
||||
probe[0].port[0].ctl_addr = iomap[1];
|
||||
probe[0].port[0].altstatus_addr = iomap[1];
|
||||
probe[0].port[0].bmdma_addr = iomap[4];
|
||||
|
||||
/* 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 = iomap[2];
|
||||
probe[1].port[0].ctl_addr = iomap[3];
|
||||
probe[1].port[0].altstatus_addr = iomap[3];
|
||||
probe[1].port[0].bmdma_addr = iomap[4] + 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_detach(host);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
/**
|
||||
* cs5520_reinit_one - device resume
|
||||
* @pdev: PCI device
|
||||
*
|
||||
* Do any reconfiguration work needed by a resume from RAM. We need
|
||||
* to restore DMA mode support on BIOSen which disabled it
|
||||
*/
|
||||
|
||||
static int cs5520_reinit_one(struct pci_dev *pdev)
|
||||
{
|
||||
u8 pcicfg;
|
||||
pci_read_config_byte(pdev, 0x60, &pcicfg);
|
||||
if ((pcicfg & 0x40) == 0)
|
||||
pci_write_config_byte(pdev, 0x60, pcicfg | 0x40);
|
||||
return ata_pci_device_resume(pdev);
|
||||
}
|
||||
|
||||
/**
|
||||
* cs5520_pci_device_suspend - device suspend
|
||||
* @pdev: PCI device
|
||||
*
|
||||
* We have to cut and waste bits from the standard method because
|
||||
* the 5520 is a bit odd and not just a pure ATA device. As a result
|
||||
* we must not disable it. The needed code is short and this avoids
|
||||
* chip specific mess in the core code.
|
||||
*/
|
||||
|
||||
static int cs5520_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;
|
||||
|
||||
pci_save_state(pdev);
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
/* For now keep DMA off. We can set it for all but A rev CS5510 once the
|
||||
core ATA code can handle it */
|
||||
|
||||
static const struct pci_device_id pata_cs5520[] = {
|
||||
{ PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5510), },
|
||||
{ PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5520), },
|
||||
|
||||
{ },
|
||||
};
|
||||
|
||||
static struct pci_driver cs5520_pci_driver = {
|
||||
.name = DRV_NAME,
|
||||
.id_table = pata_cs5520,
|
||||
.probe = cs5520_init_one,
|
||||
.remove = cs5520_remove_one,
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = cs5520_pci_device_suspend,
|
||||
.resume = cs5520_reinit_one,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int __init cs5520_init(void)
|
||||
{
|
||||
return pci_register_driver(&cs5520_pci_driver);
|
||||
}
|
||||
|
||||
static void __exit cs5520_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&cs5520_pci_driver);
|
||||
}
|
||||
|
||||
MODULE_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);
|
||||
|
||||
425
drivers/ata/pata_cs5530.c
Normal file
425
drivers/ata/pata_cs5530.c
Normal file
@@ -0,0 +1,425 @@
|
||||
/*
|
||||
* 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.7.2"
|
||||
|
||||
static void __iomem *cs5530_port_base(struct ata_port *ap)
|
||||
{
|
||||
unsigned long bmdma = (unsigned long)ap->ioaddr.bmdma_addr;
|
||||
|
||||
return (void __iomem *)((bmdma & ~0x0F) + 0x20 + 0x10 * ap->port_no);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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}
|
||||
};
|
||||
void __iomem *base = cs5530_port_base(ap);
|
||||
u32 tuning;
|
||||
int format;
|
||||
|
||||
/* Find out which table to use */
|
||||
tuning = ioread32(base + 0x04);
|
||||
format = (tuning & 0x80000000UL) ? 1 : 0;
|
||||
|
||||
/* Now load the right timing register */
|
||||
if (adev->devno)
|
||||
base += 0x08;
|
||||
|
||||
iowrite32(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)
|
||||
{
|
||||
void __iomem *base = cs5530_port_base(ap);
|
||||
u32 tuning, timing = 0;
|
||||
u8 reg;
|
||||
|
||||
/* Find out which table to use */
|
||||
tuning = ioread32(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 */
|
||||
iowrite32(timing, base + 0x04);
|
||||
else {
|
||||
if (timing & 0x00100000)
|
||||
tuning |= 0x00100000; /* UDMA for both */
|
||||
else
|
||||
tuning &= ~0x00100000; /* MWDMA for both */
|
||||
iowrite32(tuning, base + 0x04);
|
||||
iowrite32(timing, base + 0x0C);
|
||||
}
|
||||
|
||||
/* Set the DMA capable bit in the BMDMA area */
|
||||
reg = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
|
||||
reg |= (1 << (5 + adev->devno));
|
||||
iowrite8(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,
|
||||
.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,
|
||||
#ifdef CONFIG_PM
|
||||
.resume = ata_scsi_device_resume,
|
||||
.suspend = ata_scsi_device_suspend,
|
||||
#endif
|
||||
};
|
||||
|
||||
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_data_xfer,
|
||||
|
||||
.irq_handler = ata_interrupt,
|
||||
.irq_clear = ata_bmdma_irq_clear,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
|
||||
.port_start = ata_port_start,
|
||||
};
|
||||
|
||||
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_chip - Chipset init
|
||||
*
|
||||
* Perform the chip initialisation work that is shared between both
|
||||
* setup and resume paths
|
||||
*/
|
||||
|
||||
static int cs5530_init_chip(void)
|
||||
{
|
||||
struct pci_dev *master_0 = NULL, *cs5530_0 = NULL, *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);
|
||||
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);
|
||||
return 0;
|
||||
fail_put:
|
||||
if (master_0)
|
||||
pci_dev_put(master_0);
|
||||
if (cs5530_0)
|
||||
pci_dev_put(cs5530_0);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 *pdev, const struct pci_device_id *id)
|
||||
{
|
||||
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 };
|
||||
|
||||
/* Chip initialisation */
|
||||
if (cs5530_init_chip())
|
||||
return -ENODEV;
|
||||
|
||||
if (cs5530_is_palmax())
|
||||
port_info[1] = &info_palmax_secondary;
|
||||
|
||||
/* Now kick off ATA set up */
|
||||
return ata_pci_init_one(pdev, port_info, 2);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int cs5530_reinit_one(struct pci_dev *pdev)
|
||||
{
|
||||
/* If we fail on resume we are doomed */
|
||||
if (cs5530_init_chip())
|
||||
BUG();
|
||||
return ata_pci_device_resume(pdev);
|
||||
}
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
static const struct pci_device_id cs5530[] = {
|
||||
{ PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5530_IDE), },
|
||||
|
||||
{ },
|
||||
};
|
||||
|
||||
static struct pci_driver cs5530_pci_driver = {
|
||||
.name = DRV_NAME,
|
||||
.id_table = cs5530,
|
||||
.probe = cs5530_init_one,
|
||||
.remove = ata_pci_remove_one,
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = ata_pci_device_suspend,
|
||||
.resume = cs5530_reinit_one,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int __init cs5530_init(void)
|
||||
{
|
||||
return pci_register_driver(&cs5530_pci_driver);
|
||||
}
|
||||
|
||||
static void __exit cs5530_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&cs5530_pci_driver);
|
||||
}
|
||||
|
||||
MODULE_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);
|
||||
298
drivers/ata/pata_cs5535.c
Normal file
298
drivers/ata/pata_cs5535.c
Normal file
@@ -0,0 +1,298 @@
|
||||
/*
|
||||
* 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.11"
|
||||
|
||||
/*
|
||||
* 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,
|
||||
.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,
|
||||
#ifdef CONFIG_PM
|
||||
.resume = ata_scsi_device_resume,
|
||||
.suspend = ata_scsi_device_suspend,
|
||||
#endif
|
||||
};
|
||||
|
||||
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_data_xfer,
|
||||
|
||||
.irq_handler = ata_interrupt,
|
||||
.irq_clear = ata_bmdma_irq_clear,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
|
||||
.port_start = ata_port_start,
|
||||
};
|
||||
|
||||
/**
|
||||
* 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 const struct pci_device_id cs5535[] = {
|
||||
{ PCI_VDEVICE(NS, 0x002D), },
|
||||
|
||||
{ },
|
||||
};
|
||||
|
||||
static struct pci_driver cs5535_pci_driver = {
|
||||
.name = DRV_NAME,
|
||||
.id_table = cs5535,
|
||||
.probe = cs5535_init_one,
|
||||
.remove = ata_pci_remove_one,
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = ata_pci_device_suspend,
|
||||
.resume = ata_pci_device_resume,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int __init cs5535_init(void)
|
||||
{
|
||||
return pci_register_driver(&cs5535_pci_driver);
|
||||
}
|
||||
|
||||
static void __exit cs5535_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&cs5535_pci_driver);
|
||||
}
|
||||
|
||||
MODULE_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);
|
||||
236
drivers/ata/pata_cypress.c
Normal file
236
drivers/ata/pata_cypress.c
Normal file
@@ -0,0 +1,236 @@
|
||||
/*
|
||||
* 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.4"
|
||||
|
||||
/* 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,
|
||||
.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,
|
||||
#ifdef CONFIG_PM
|
||||
.resume = ata_scsi_device_resume,
|
||||
.suspend = ata_scsi_device_suspend,
|
||||
#endif
|
||||
};
|
||||
|
||||
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_data_xfer,
|
||||
|
||||
.irq_handler = ata_interrupt,
|
||||
.irq_clear = ata_bmdma_irq_clear,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
|
||||
.port_start = ata_port_start,
|
||||
};
|
||||
|
||||
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 const struct pci_device_id cy82c693[] = {
|
||||
{ PCI_VDEVICE(CONTAQ, PCI_DEVICE_ID_CONTAQ_82C693), },
|
||||
|
||||
{ },
|
||||
};
|
||||
|
||||
static struct pci_driver cy82c693_pci_driver = {
|
||||
.name = DRV_NAME,
|
||||
.id_table = cy82c693,
|
||||
.probe = cy82c693_init_one,
|
||||
.remove = ata_pci_remove_one,
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = ata_pci_device_suspend,
|
||||
.resume = ata_pci_device_resume,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int __init cy82c693_init(void)
|
||||
{
|
||||
return pci_register_driver(&cy82c693_pci_driver);
|
||||
}
|
||||
|
||||
|
||||
static void __exit cy82c693_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&cy82c693_pci_driver);
|
||||
}
|
||||
|
||||
|
||||
MODULE_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);
|
||||
346
drivers/ata/pata_efar.c
Normal file
346
drivers/ata/pata_efar.c
Normal file
@@ -0,0 +1,346 @@
|
||||
/*
|
||||
* 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.3"
|
||||
|
||||
/**
|
||||
* 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,
|
||||
.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,
|
||||
#ifdef CONFIG_PM
|
||||
.resume = ata_scsi_device_resume,
|
||||
.suspend = ata_scsi_device_suspend,
|
||||
#endif
|
||||
};
|
||||
|
||||
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_data_xfer,
|
||||
|
||||
.irq_handler = ata_interrupt,
|
||||
.irq_clear = ata_bmdma_irq_clear,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
|
||||
.port_start = ata_port_start,
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* 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[] = {
|
||||
{ PCI_VDEVICE(EFAR, 0x9130), },
|
||||
|
||||
{ } /* 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,
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = ata_pci_device_suspend,
|
||||
.resume = ata_pci_device_resume,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int __init efar_init(void)
|
||||
{
|
||||
return pci_register_driver(&efar_pci_driver);
|
||||
}
|
||||
|
||||
static void __exit efar_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&efar_pci_driver);
|
||||
}
|
||||
|
||||
module_init(efar_init);
|
||||
module_exit(efar_exit);
|
||||
|
||||
MODULE_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);
|
||||
|
||||
503
drivers/ata/pata_hpt366.c
Normal file
503
drivers/ata/pata_hpt366.c
Normal file
@@ -0,0 +1,503 @@
|
||||
/*
|
||||
* 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.6.0"
|
||||
|
||||
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[ATA_ID_PROD_LEN + 1];
|
||||
int i = 0;
|
||||
|
||||
ata_id_c_string(dev->id, model_num, ATA_ID_PROD, sizeof(model_num));
|
||||
|
||||
while (list[i] != NULL) {
|
||||
if (!strcmp(list[i], model_num)) {
|
||||
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)
|
||||
{
|
||||
static const struct pci_bits hpt36x_enable_bits[] = {
|
||||
{ 0x50, 1, 0x04, 0x04 },
|
||||
{ 0x54, 1, 0x04, 0x04 }
|
||||
};
|
||||
|
||||
u8 ata66;
|
||||
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
|
||||
|
||||
if (!pci_test_config_bits(pdev, &hpt36x_enable_bits[ap->port_no]))
|
||||
return -ENOENT;
|
||||
|
||||
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, ®);
|
||||
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, ®);
|
||||
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,
|
||||
.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,
|
||||
#ifdef CONFIG_PM
|
||||
.resume = ata_scsi_device_resume,
|
||||
.suspend = ata_scsi_device_suspend,
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
* 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_data_xfer,
|
||||
|
||||
.irq_handler = ata_interrupt,
|
||||
.irq_clear = ata_bmdma_irq_clear,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
|
||||
.port_start = ata_port_start,
|
||||
};
|
||||
|
||||
/**
|
||||
* hpt36x_init_chipset - common chip setup
|
||||
* @dev: PCI device
|
||||
*
|
||||
* Perform the chip setup work that must be done at both init and
|
||||
* resume time
|
||||
*/
|
||||
|
||||
static void hpt36x_init_chipset(struct pci_dev *dev)
|
||||
{
|
||||
u8 drive_fast;
|
||||
pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, (L1_CACHE_BYTES / 4));
|
||||
pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x78);
|
||||
pci_write_config_byte(dev, PCI_MIN_GNT, 0x08);
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
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;
|
||||
|
||||
hpt36x_init_chipset(dev);
|
||||
|
||||
pci_read_config_dword(dev, 0x40, ®1);
|
||||
|
||||
/* PCI clocking determines the ATA timing values to use */
|
||||
/* info_hpt366 is safe against re-entry so we can scribble on it */
|
||||
switch((reg1 & 0x700) >> 8) {
|
||||
case 5:
|
||||
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);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int hpt36x_reinit_one(struct pci_dev *dev)
|
||||
{
|
||||
hpt36x_init_chipset(dev);
|
||||
return ata_pci_device_resume(dev);
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct pci_device_id hpt36x[] = {
|
||||
{ PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT366), },
|
||||
{ },
|
||||
};
|
||||
|
||||
static struct pci_driver hpt36x_pci_driver = {
|
||||
.name = DRV_NAME,
|
||||
.id_table = hpt36x,
|
||||
.probe = hpt36x_init_one,
|
||||
.remove = ata_pci_remove_one,
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = ata_pci_device_suspend,
|
||||
.resume = hpt36x_reinit_one,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int __init hpt36x_init(void)
|
||||
{
|
||||
return pci_register_driver(&hpt36x_pci_driver);
|
||||
}
|
||||
|
||||
static void __exit hpt36x_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&hpt36x_pci_driver);
|
||||
}
|
||||
|
||||
MODULE_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);
|
||||
1258
drivers/ata/pata_hpt37x.c
Normal file
1258
drivers/ata/pata_hpt37x.c
Normal file
File diff suppressed because it is too large
Load Diff
596
drivers/ata/pata_hpt3x2n.c
Normal file
596
drivers/ata/pata_hpt3x2n.c
Normal file
@@ -0,0 +1,596 @@
|
||||
/*
|
||||
* 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.2"
|
||||
|
||||
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, ®);
|
||||
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, ®);
|
||||
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)
|
||||
{
|
||||
void __iomem *bmdma = ap->ioaddr.bmdma_addr;
|
||||
|
||||
/* Tristate the bus */
|
||||
iowrite8(0x80, bmdma+0x73);
|
||||
iowrite8(0x80, bmdma+0x77);
|
||||
|
||||
/* Switch clock and reset channels */
|
||||
iowrite8(source, bmdma+0x7B);
|
||||
iowrite8(0xC0, bmdma+0x79);
|
||||
|
||||
/* Reset state machines */
|
||||
iowrite8(0x37, bmdma+0x70);
|
||||
iowrite8(0x37, bmdma+0x74);
|
||||
|
||||
/* Complete reset */
|
||||
iowrite8(0x00, bmdma+0x79);
|
||||
|
||||
/* Reconnect channels to bus */
|
||||
iowrite8(0x00, bmdma+0x73);
|
||||
iowrite8(0x00, bmdma+0x77);
|
||||
}
|
||||
|
||||
/* Check if our partner interface is busy */
|
||||
|
||||
static int hpt3x2n_pair_idle(struct ata_port *ap)
|
||||
{
|
||||
struct ata_host *host = ap->host;
|
||||
struct ata_port *pair = host->ports[ap->port_no ^ 1];
|
||||
|
||||
if (pair->hsm_task_state == HSM_ST_IDLE)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hpt3x2n_use_dpll(struct ata_port *ap, int writing)
|
||||
{
|
||||
long flags = (long)ap->host->private_data;
|
||||
/* See if we should use the DPLL */
|
||||
if (writing)
|
||||
return USE_DPLL; /* Needed for write */
|
||||
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,
|
||||
.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,
|
||||
};
|
||||
|
||||
/*
|
||||
* 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_data_xfer,
|
||||
|
||||
.irq_handler = ata_interrupt,
|
||||
.irq_clear = ata_bmdma_irq_clear,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
|
||||
.port_start = ata_port_start,
|
||||
};
|
||||
|
||||
/**
|
||||
* 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, ®5b);
|
||||
if (reg5b & 0x80) {
|
||||
/* See if it stays set */
|
||||
for(tries = 0; tries < 0x1000; tries ++) {
|
||||
pci_read_config_byte(dev, 0x5b, ®5b);
|
||||
/* Failed ? */
|
||||
if ((reg5b & 0x80) == 0)
|
||||
return 0;
|
||||
}
|
||||
/* Turn off tuning, we have the DPLL set */
|
||||
pci_read_config_dword(dev, 0x5c, ®5c);
|
||||
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 const struct pci_device_id hpt3x2n[] = {
|
||||
{ PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT366), },
|
||||
{ PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT372), },
|
||||
{ PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT302), },
|
||||
{ PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT372N), },
|
||||
|
||||
{ },
|
||||
};
|
||||
|
||||
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);
|
||||
255
drivers/ata/pata_hpt3x3.c
Normal file
255
drivers/ata/pata_hpt3x3.c
Normal file
@@ -0,0 +1,255 @@
|
||||
/*
|
||||
* 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.2"
|
||||
|
||||
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,
|
||||
.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,
|
||||
#ifdef CONFIG_PM
|
||||
.resume = ata_scsi_device_resume,
|
||||
.suspend = ata_scsi_device_suspend,
|
||||
#endif
|
||||
};
|
||||
|
||||
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_data_xfer,
|
||||
|
||||
.irq_handler = ata_interrupt,
|
||||
.irq_clear = ata_bmdma_irq_clear,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
|
||||
.port_start = ata_port_start,
|
||||
};
|
||||
|
||||
/**
|
||||
* hpt3x3_init_chipset - chip setup
|
||||
* @dev: PCI device
|
||||
*
|
||||
* Perform the setup required at boot and on resume.
|
||||
*/
|
||||
|
||||
static void hpt3x3_init_chipset(struct pci_dev *dev)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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 };
|
||||
|
||||
hpt3x3_init_chipset(dev);
|
||||
/* Now kick off ATA set up */
|
||||
return ata_pci_init_one(dev, port_info, 2);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int hpt3x3_reinit_one(struct pci_dev *dev)
|
||||
{
|
||||
hpt3x3_init_chipset(dev);
|
||||
return ata_pci_device_resume(dev);
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct pci_device_id hpt3x3[] = {
|
||||
{ PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT343), },
|
||||
|
||||
{ },
|
||||
};
|
||||
|
||||
static struct pci_driver hpt3x3_pci_driver = {
|
||||
.name = DRV_NAME,
|
||||
.id_table = hpt3x3,
|
||||
.probe = hpt3x3_init_one,
|
||||
.remove = ata_pci_remove_one,
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = ata_pci_device_suspend,
|
||||
.resume = hpt3x3_reinit_one,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int __init hpt3x3_init(void)
|
||||
{
|
||||
return pci_register_driver(&hpt3x3_pci_driver);
|
||||
}
|
||||
|
||||
|
||||
static void __exit hpt3x3_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&hpt3x3_pci_driver);
|
||||
}
|
||||
|
||||
|
||||
MODULE_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);
|
||||
162
drivers/ata/pata_isapnp.c
Normal file
162
drivers/ata/pata_isapnp.c
Normal file
@@ -0,0 +1,162 @@
|
||||
|
||||
/*
|
||||
* 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.2.0"
|
||||
|
||||
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,
|
||||
.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 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_data_xfer,
|
||||
|
||||
.irq_handler = ata_interrupt,
|
||||
.irq_clear = ata_bmdma_irq_clear,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
|
||||
.port_start = ata_port_start,
|
||||
};
|
||||
|
||||
/**
|
||||
* 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;
|
||||
void __iomem *cmd_addr, *ctl_addr;
|
||||
|
||||
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;
|
||||
|
||||
cmd_addr = devm_ioport_map(&idev->dev, pnp_port_start(idev, 0), 8);
|
||||
if (!cmd_addr)
|
||||
return -ENOMEM;
|
||||
|
||||
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 = cmd_addr;
|
||||
|
||||
if (pnp_port_valid(idev, 1) == 0) {
|
||||
ctl_addr = devm_ioport_map(&idev->dev,
|
||||
pnp_port_start(idev, 1), 1);
|
||||
ae.port[0].altstatus_addr = ctl_addr;
|
||||
ae.port[0].ctl_addr = ctl_addr;
|
||||
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_detach(host);
|
||||
}
|
||||
|
||||
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);
|
||||
358
drivers/ata/pata_it8213.c
Normal file
358
drivers/ata/pata_it8213.c
Normal file
@@ -0,0 +1,358 @@
|
||||
/*
|
||||
* pata_it8213.c - iTE Tech. Inc. IT8213 PATA driver
|
||||
*
|
||||
* The IT8213 is a very Intel ICH like device for timing purposes, having
|
||||
* a similar register layout and the same split clock arrangement. Cable
|
||||
* detection is different, and it does not have slave channels or all the
|
||||
* clutter of later ICH/SATA setups.
|
||||
*/
|
||||
|
||||
#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_it8213"
|
||||
#define DRV_VERSION "0.0.2"
|
||||
|
||||
/**
|
||||
* it8213_pre_reset - check for 40/80 pin
|
||||
* @ap: Port
|
||||
*
|
||||
* Perform cable detection for the 8213 ATA interface. This is
|
||||
* different to the PIIX arrangement
|
||||
*/
|
||||
|
||||
static int it8213_pre_reset(struct ata_port *ap)
|
||||
{
|
||||
static const struct pci_bits it8213_enable_bits[] = {
|
||||
{ 0x41U, 1U, 0x80UL, 0x80UL }, /* port 0 */
|
||||
};
|
||||
|
||||
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
|
||||
u8 tmp;
|
||||
|
||||
if (!pci_test_config_bits(pdev, &it8213_enable_bits[ap->port_no]))
|
||||
return -ENOENT;
|
||||
|
||||
pci_read_config_byte(pdev, 0x42, &tmp);
|
||||
if (tmp & 2) /* The initial docs are incorrect */
|
||||
ap->cbl = ATA_CBL_PATA40;
|
||||
else
|
||||
ap->cbl = ATA_CBL_PATA80;
|
||||
return ata_std_prereset(ap);
|
||||
}
|
||||
|
||||
/**
|
||||
* it8213_probe_reset - Probe specified port on PATA host controller
|
||||
* @ap: Port to probe
|
||||
*
|
||||
* LOCKING:
|
||||
* None (inherited from caller).
|
||||
*/
|
||||
|
||||
static void it8213_error_handler(struct ata_port *ap)
|
||||
{
|
||||
ata_bmdma_drive_eh(ap, it8213_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
|
||||
}
|
||||
|
||||
/**
|
||||
* it8213_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 it8213_set_piomode (struct ata_port *ap, struct ata_device *adev)
|
||||
{
|
||||
unsigned int pio = adev->pio_mode - XFER_PIO_0;
|
||||
struct pci_dev *dev = to_pci_dev(ap->host->dev);
|
||||
unsigned int idetm_port= ap->port_no ? 0x42 : 0x40;
|
||||
u16 idetm_data;
|
||||
int control = 0;
|
||||
|
||||
/*
|
||||
* See Intel Document 298600-004 for the timing programing rules
|
||||
* for PIIX/ICH. The 8213 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; /* IORDY enable */
|
||||
/* Bit 2 is set for ATAPI on the IT8213 - reverse of ICH/PIIX */
|
||||
if (adev->class != ATA_DEV_ATA)
|
||||
control |= 4;
|
||||
|
||||
pci_read_config_word(dev, idetm_port, &idetm_data);
|
||||
|
||||
/* 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 {
|
||||
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 &= 0xF0;
|
||||
slave_data |= ((timings[pio][0] << 2) | timings[pio][1]) << 4;
|
||||
pci_write_config_byte(dev, 0x44, slave_data);
|
||||
}
|
||||
|
||||
idetm_data |= 0x4000; /* Ensure SITRE is enabled */
|
||||
pci_write_config_word(dev, idetm_port, idetm_data);
|
||||
}
|
||||
|
||||
/**
|
||||
* it8213_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.
|
||||
* This device is basically an ICH alike.
|
||||
*
|
||||
* LOCKING:
|
||||
* None (inherited from caller).
|
||||
*/
|
||||
|
||||
static void it8213_set_dmamode (struct ata_port *ap, struct ata_device *adev)
|
||||
{
|
||||
struct pci_dev *dev = to_pci_dev(ap->host->dev);
|
||||
u16 master_data;
|
||||
u8 speed = adev->dma_mode;
|
||||
int devid = adev->devno;
|
||||
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, 0x40, &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;
|
||||
|
||||
/* Clocks follow the PIIX style */
|
||||
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 UDMA mode number */
|
||||
pci_read_config_word(dev, 0x4A, &udma_timing);
|
||||
udma_timing &= ~(3 << (4 * devid));
|
||||
udma_timing |= (udma & 3) << (4 * devid);
|
||||
pci_write_config_word(dev, 0x4A, udma_timing);
|
||||
|
||||
/* Load the clock selection */
|
||||
pci_read_config_word(dev, 0x54, &ideconf);
|
||||
ideconf &= ~(0x1001 << devid);
|
||||
ideconf |= u_clock << devid;
|
||||
pci_write_config_word(dev, 0x54, ideconf);
|
||||
} else {
|
||||
/*
|
||||
* MWDMA is driven by the PIO timings. We must also enable
|
||||
* IORDY unconditionally along with TIME1. PPE has already
|
||||
* been set when the PIO timing was set.
|
||||
*/
|
||||
unsigned int mwdma = adev->dma_mode - XFER_MW_DMA_0;
|
||||
unsigned int control;
|
||||
u8 slave_data;
|
||||
static 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 (devid) { /* 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, 0x40, master_data);
|
||||
}
|
||||
pci_write_config_byte(dev, 0x48, udma_enable);
|
||||
}
|
||||
|
||||
static struct scsi_host_template it8213_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,
|
||||
#ifdef CONFIG_PM
|
||||
.resume = ata_scsi_device_resume,
|
||||
.suspend = ata_scsi_device_suspend,
|
||||
#endif
|
||||
};
|
||||
|
||||
static const struct ata_port_operations it8213_ops = {
|
||||
.port_disable = ata_port_disable,
|
||||
.set_piomode = it8213_set_piomode,
|
||||
.set_dmamode = it8213_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 = it8213_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_data_xfer,
|
||||
|
||||
.irq_handler = ata_interrupt,
|
||||
.irq_clear = ata_bmdma_irq_clear,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
|
||||
.port_start = ata_port_start,
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* it8213_init_one - Register 8213 ATA PCI device with kernel services
|
||||
* @pdev: PCI device to register
|
||||
* @ent: Entry in it8213_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 it8213_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
{
|
||||
static int printed_version;
|
||||
static struct ata_port_info info = {
|
||||
.sht = &it8213_sht,
|
||||
.flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
|
||||
.pio_mask = 0x1f, /* pio0-4 */
|
||||
.mwdma_mask = 0x07, /* mwdma0-2 */
|
||||
.udma_mask = 0x1f, /* UDMA 100 */
|
||||
.port_ops = &it8213_ops,
|
||||
};
|
||||
static struct ata_port_info *port_info[2] = { &info, &info };
|
||||
|
||||
if (!printed_version++)
|
||||
dev_printk(KERN_DEBUG, &pdev->dev,
|
||||
"version " DRV_VERSION "\n");
|
||||
|
||||
/* Current IT8213 stuff is single port */
|
||||
return ata_pci_init_one(pdev, port_info, 1);
|
||||
}
|
||||
|
||||
static const struct pci_device_id it8213_pci_tbl[] = {
|
||||
{ PCI_VDEVICE(ITE, PCI_DEVICE_ID_ITE_8213), },
|
||||
|
||||
{ } /* terminate list */
|
||||
};
|
||||
|
||||
static struct pci_driver it8213_pci_driver = {
|
||||
.name = DRV_NAME,
|
||||
.id_table = it8213_pci_tbl,
|
||||
.probe = it8213_init_one,
|
||||
.remove = ata_pci_remove_one,
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = ata_pci_device_suspend,
|
||||
.resume = ata_pci_device_resume,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int __init it8213_init(void)
|
||||
{
|
||||
return pci_register_driver(&it8213_pci_driver);
|
||||
}
|
||||
|
||||
static void __exit it8213_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&it8213_pci_driver);
|
||||
}
|
||||
|
||||
module_init(it8213_init);
|
||||
module_exit(it8213_exit);
|
||||
|
||||
MODULE_AUTHOR("Alan Cox");
|
||||
MODULE_DESCRIPTION("SCSI low-level driver for the ITE 8213");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DEVICE_TABLE(pci, it8213_pci_tbl);
|
||||
MODULE_VERSION(DRV_VERSION);
|
||||
834
drivers/ata/pata_it821x.c
Normal file
834
drivers/ata/pata_it821x.c
Normal file
@@ -0,0 +1,834 @@
|
||||
/*
|
||||
* 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.4"
|
||||
|
||||
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
|
||||
* @unused: device that failed (error only)
|
||||
*
|
||||
* 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 int it821x_smart_set_mode(struct ata_port *ap, struct ata_device **unused)
|
||||
{
|
||||
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 = ioread8(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))) {
|
||||
ata_dev_printk(dev, KERN_INFO, "configured for DMA\n");
|
||||
dev->xfer_mode = XFER_MW_DMA_0;
|
||||
dev->xfer_shift = ATA_SHIFT_MWDMA;
|
||||
dev->flags &= ~ATA_DFLAG_PIO;
|
||||
} else {
|
||||
ata_dev_printk(dev, KERN_INFO, "configured for PIO\n");
|
||||
dev->xfer_mode = XFER_PIO_0;
|
||||
dev->xfer_shift = ATA_SHIFT_PIO;
|
||||
dev->flags |= ATA_DFLAG_PIO;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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[ATA_ID_PROD_LEN + 1];
|
||||
|
||||
ata_id_c_string(adev->id, model_num, ATA_ID_PROD, sizeof(model_num));
|
||||
|
||||
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;
|
||||
|
||||
itdev = devm_kzalloc(&pdev->dev, sizeof(struct it821x_dev), GFP_KERNEL);
|
||||
if (itdev == NULL)
|
||||
return -ENOMEM;
|
||||
ap->private_data = itdev;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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,
|
||||
.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,
|
||||
#ifdef CONFIG_PM
|
||||
.resume = ata_scsi_device_resume,
|
||||
.suspend = ata_scsi_device_suspend,
|
||||
#endif
|
||||
};
|
||||
|
||||
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_data_xfer,
|
||||
|
||||
.irq_handler = ata_interrupt,
|
||||
.irq_clear = ata_bmdma_irq_clear,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
|
||||
.port_start = it821x_port_start,
|
||||
};
|
||||
|
||||
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_data_xfer,
|
||||
|
||||
.irq_clear = ata_bmdma_irq_clear,
|
||||
.irq_handler = ata_interrupt,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
|
||||
.port_start = it821x_port_start,
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int it821x_reinit_one(struct pci_dev *pdev)
|
||||
{
|
||||
/* Resume - turn raid back off if need be */
|
||||
if (it8212_noraid)
|
||||
it821x_disable_raid(pdev);
|
||||
return ata_pci_device_resume(pdev);
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct pci_device_id it821x[] = {
|
||||
{ PCI_VDEVICE(ITE, PCI_DEVICE_ID_ITE_8211), },
|
||||
{ PCI_VDEVICE(ITE, PCI_DEVICE_ID_ITE_8212), },
|
||||
|
||||
{ },
|
||||
};
|
||||
|
||||
static struct pci_driver it821x_pci_driver = {
|
||||
.name = DRV_NAME,
|
||||
.id_table = it821x,
|
||||
.probe = it821x_init_one,
|
||||
.remove = ata_pci_remove_one,
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = ata_pci_device_suspend,
|
||||
.resume = it821x_reinit_one,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int __init it821x_init(void)
|
||||
{
|
||||
return pci_register_driver(&it821x_pci_driver);
|
||||
}
|
||||
|
||||
static void __exit it821x_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&it821x_pci_driver);
|
||||
}
|
||||
|
||||
MODULE_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);
|
||||
264
drivers/ata/pata_ixp4xx_cf.c
Normal file
264
drivers/ata/pata_ixp4xx_cf.c
Normal file
@@ -0,0 +1,264 @@
|
||||
/*
|
||||
* ixp4xx PATA/Compact Flash driver
|
||||
* Copyright (c) 2006 Tower Technologies
|
||||
* Author: Alessandro Zummo <a.zummo@towertech.it>
|
||||
*
|
||||
* An ATA driver to handle a Compact Flash connected
|
||||
* to the ixp4xx expansion bus in TrueIDE mode. The CF
|
||||
* must have it chip selects connected to two CS lines
|
||||
* on the ixp4xx. The interrupt line is optional, if not
|
||||
* specified the driver will run in polling mode.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/libata.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <scsi/scsi_host.h>
|
||||
|
||||
#define DRV_NAME "pata_ixp4xx_cf"
|
||||
#define DRV_VERSION "0.1.2"
|
||||
|
||||
static int ixp4xx_set_mode(struct ata_port *ap, struct ata_device **error)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ATA_MAX_DEVICES; i++) {
|
||||
struct ata_device *dev = &ap->device[i];
|
||||
if (ata_dev_ready(dev)) {
|
||||
ata_dev_printk(dev, KERN_INFO, "configured for PIO0\n");
|
||||
dev->pio_mode = XFER_PIO_0;
|
||||
dev->xfer_mode = XFER_PIO_0;
|
||||
dev->xfer_shift = ATA_SHIFT_PIO;
|
||||
dev->flags |= ATA_DFLAG_PIO;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ixp4xx_phy_reset(struct ata_port *ap)
|
||||
{
|
||||
ap->cbl = ATA_CBL_PATA40;
|
||||
ata_port_probe(ap);
|
||||
ata_bus_reset(ap);
|
||||
}
|
||||
|
||||
static void ixp4xx_mmio_data_xfer(struct ata_device *adev, unsigned char *buf,
|
||||
unsigned int buflen, int write_data)
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned int words = buflen >> 1;
|
||||
u16 *buf16 = (u16 *) buf;
|
||||
struct ata_port *ap = adev->ap;
|
||||
void __iomem *mmio = (void __iomem *)ap->ioaddr.data_addr;
|
||||
struct ixp4xx_pata_data *data = ap->host->dev->platform_data;
|
||||
|
||||
/* set the expansion bus in 16bit mode and restore
|
||||
* 8 bit mode after the transaction.
|
||||
*/
|
||||
*data->cs0_cfg &= ~(0x01);
|
||||
udelay(100);
|
||||
|
||||
/* Transfer multiple of 2 bytes */
|
||||
if (write_data) {
|
||||
for (i = 0; i < words; i++)
|
||||
writew(buf16[i], mmio);
|
||||
} else {
|
||||
for (i = 0; i < words; i++)
|
||||
buf16[i] = 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(align_buf[0], mmio);
|
||||
} else {
|
||||
align_buf[0] = readw(mmio);
|
||||
memcpy(trailing_buf, align_buf, 1);
|
||||
}
|
||||
}
|
||||
|
||||
udelay(100);
|
||||
*data->cs0_cfg |= 0x01;
|
||||
}
|
||||
|
||||
static void ixp4xx_irq_clear(struct ata_port *ap)
|
||||
{
|
||||
}
|
||||
|
||||
static struct scsi_host_template ixp4xx_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 struct ata_port_operations ixp4xx_port_ops = {
|
||||
.set_mode = ixp4xx_set_mode,
|
||||
.mode_filter = ata_pci_default_filter,
|
||||
|
||||
.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,
|
||||
|
||||
.qc_prep = ata_qc_prep,
|
||||
.qc_issue = ata_qc_issue_prot,
|
||||
.eng_timeout = ata_eng_timeout,
|
||||
.data_xfer = ixp4xx_mmio_data_xfer,
|
||||
|
||||
.irq_handler = ata_interrupt,
|
||||
.irq_clear = ixp4xx_irq_clear,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
|
||||
.port_start = ata_port_start,
|
||||
|
||||
.phy_reset = ixp4xx_phy_reset,
|
||||
};
|
||||
|
||||
static void ixp4xx_setup_port(struct ata_ioports *ioaddr,
|
||||
struct ixp4xx_pata_data *data)
|
||||
{
|
||||
ioaddr->cmd_addr = data->cs0;
|
||||
ioaddr->altstatus_addr = data->cs1 + 0x06;
|
||||
ioaddr->ctl_addr = data->cs1 + 0x06;
|
||||
|
||||
ata_std_ports(ioaddr);
|
||||
|
||||
#ifndef __ARMEB__
|
||||
|
||||
/* adjust the addresses to handle the address swizzling of the
|
||||
* ixp4xx in little endian mode.
|
||||
*/
|
||||
|
||||
*(unsigned long *)&ioaddr->data_addr ^= 0x02;
|
||||
*(unsigned long *)&ioaddr->cmd_addr ^= 0x03;
|
||||
*(unsigned long *)&ioaddr->altstatus_addr ^= 0x03;
|
||||
*(unsigned long *)&ioaddr->ctl_addr ^= 0x03;
|
||||
*(unsigned long *)&ioaddr->error_addr ^= 0x03;
|
||||
*(unsigned long *)&ioaddr->feature_addr ^= 0x03;
|
||||
*(unsigned long *)&ioaddr->nsect_addr ^= 0x03;
|
||||
*(unsigned long *)&ioaddr->lbal_addr ^= 0x03;
|
||||
*(unsigned long *)&ioaddr->lbam_addr ^= 0x03;
|
||||
*(unsigned long *)&ioaddr->lbah_addr ^= 0x03;
|
||||
*(unsigned long *)&ioaddr->device_addr ^= 0x03;
|
||||
*(unsigned long *)&ioaddr->status_addr ^= 0x03;
|
||||
*(unsigned long *)&ioaddr->command_addr ^= 0x03;
|
||||
#endif
|
||||
}
|
||||
|
||||
static __devinit int ixp4xx_pata_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
unsigned int irq;
|
||||
struct resource *cs0, *cs1;
|
||||
struct ata_probe_ent ae;
|
||||
|
||||
struct ixp4xx_pata_data *data = pdev->dev.platform_data;
|
||||
|
||||
cs0 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
cs1 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
|
||||
|
||||
if (!cs0 || !cs1)
|
||||
return -EINVAL;
|
||||
|
||||
pdev->dev.coherent_dma_mask = DMA_32BIT_MASK;
|
||||
|
||||
data->cs0 = devm_ioremap(&pdev->dev, cs0->start, 0x1000);
|
||||
data->cs1 = devm_ioremap(&pdev->dev, cs1->start, 0x1000);
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq)
|
||||
set_irq_type(irq, IRQT_RISING);
|
||||
|
||||
/* Setup expansion bus chip selects */
|
||||
*data->cs0_cfg = data->cs0_bits;
|
||||
*data->cs1_cfg = data->cs1_bits;
|
||||
|
||||
memset(&ae, 0, sizeof(struct ata_probe_ent));
|
||||
INIT_LIST_HEAD(&ae.node);
|
||||
|
||||
ae.dev = &pdev->dev;
|
||||
ae.port_ops = &ixp4xx_port_ops;
|
||||
ae.sht = &ixp4xx_sht;
|
||||
ae.n_ports = 1;
|
||||
ae.pio_mask = 0x1f; /* PIO4 */
|
||||
ae.irq = irq;
|
||||
ae.irq_flags = 0;
|
||||
ae.port_flags = ATA_FLAG_MMIO | ATA_FLAG_NO_LEGACY
|
||||
| ATA_FLAG_NO_ATAPI | ATA_FLAG_SRST;
|
||||
|
||||
/* run in polling mode if no irq has been assigned */
|
||||
if (!irq)
|
||||
ae.port_flags |= ATA_FLAG_PIO_POLLING;
|
||||
|
||||
ixp4xx_setup_port(&ae.port[0], data);
|
||||
|
||||
dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n");
|
||||
|
||||
ret = ata_device_add(&ae);
|
||||
if (ret == 0)
|
||||
return -ENODEV;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static __devexit int ixp4xx_pata_remove(struct platform_device *dev)
|
||||
{
|
||||
struct ata_host *host = platform_get_drvdata(dev);
|
||||
|
||||
ata_host_detach(host);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver ixp4xx_pata_platform_driver = {
|
||||
.driver = {
|
||||
.name = DRV_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = ixp4xx_pata_probe,
|
||||
.remove = __devexit_p(ixp4xx_pata_remove),
|
||||
};
|
||||
|
||||
static int __init ixp4xx_pata_init(void)
|
||||
{
|
||||
return platform_driver_register(&ixp4xx_pata_platform_driver);
|
||||
}
|
||||
|
||||
static void __exit ixp4xx_pata_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&ixp4xx_pata_platform_driver);
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
|
||||
MODULE_DESCRIPTION("low-level driver for ixp4xx Compact Flash PATA");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_VERSION(DRV_VERSION);
|
||||
|
||||
module_init(ixp4xx_pata_init);
|
||||
module_exit(ixp4xx_pata_exit);
|
||||
256
drivers/ata/pata_jmicron.c
Normal file
256
drivers/ata/pata_jmicron.c
Normal file
@@ -0,0 +1,256 @@
|
||||
/*
|
||||
* 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.4"
|
||||
|
||||
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,
|
||||
.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,
|
||||
/* Use standard CHS mapping rules */
|
||||
.bios_param = ata_std_bios_param,
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = ata_scsi_device_suspend,
|
||||
.resume = ata_scsi_device_resume,
|
||||
#endif
|
||||
};
|
||||
|
||||
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_data_xfer,
|
||||
|
||||
/* IRQ-related hooks */
|
||||
.irq_handler = ata_interrupt,
|
||||
.irq_clear = ata_bmdma_irq_clear,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
|
||||
/* Generic PATA PCI ATA helpers */
|
||||
.port_start = ata_port_start,
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* 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 };
|
||||
|
||||
return ata_pci_init_one(pdev, port_info, 2);
|
||||
}
|
||||
|
||||
static const struct pci_device_id jmicron_pci_tbl[] = {
|
||||
{ PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB361,
|
||||
PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xffff00, 361 },
|
||||
{ PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB363,
|
||||
PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xffff00, 363 },
|
||||
{ PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB365,
|
||||
PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xffff00, 365 },
|
||||
{ PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB366,
|
||||
PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xffff00, 366 },
|
||||
{ PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB368,
|
||||
PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xffff00, 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,
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = ata_pci_device_suspend,
|
||||
.resume = ata_pci_device_resume,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int __init jmicron_init(void)
|
||||
{
|
||||
return pci_register_driver(&jmicron_pci_driver);
|
||||
}
|
||||
|
||||
static void __exit jmicron_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&jmicron_pci_driver);
|
||||
}
|
||||
|
||||
module_init(jmicron_init);
|
||||
module_exit(jmicron_exit);
|
||||
|
||||
MODULE_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);
|
||||
|
||||
976
drivers/ata/pata_legacy.c
Normal file
976
drivers/ata/pata_legacy.c
Normal file
@@ -0,0 +1,976 @@
|
||||
/*
|
||||
* 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.4"
|
||||
|
||||
#define NR_HOST 6
|
||||
|
||||
static int legacy_port[NR_HOST] = { 0x1f0, 0x170, 0x1e8, 0x168, 0x1e0, 0x160 };
|
||||
static int legacy_irq[NR_HOST] = { 14, 15, 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 */
|
||||
static int iordy_mask = 0xFFFFFFFF; /* Use iordy if available */
|
||||
|
||||
/**
|
||||
* legacy_set_mode - mode setting
|
||||
* @ap: IDE interface
|
||||
* @unused: Device that failed when error is returned
|
||||
*
|
||||
* 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 int legacy_set_mode(struct ata_port *ap, struct ata_device **unused)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ATA_MAX_DEVICES; i++) {
|
||||
struct ata_device *dev = &ap->device[i];
|
||||
if (ata_dev_enabled(dev)) {
|
||||
ata_dev_printk(dev, KERN_INFO, "configured for PIO\n");
|
||||
dev->pio_mode = XFER_PIO_0;
|
||||
dev->xfer_mode = XFER_PIO_0;
|
||||
dev->xfer_shift = ATA_SHIFT_PIO;
|
||||
dev->flags |= ATA_DFLAG_PIO;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
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,
|
||||
.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,
|
||||
};
|
||||
|
||||
/*
|
||||
* 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_data_xfer_noirq,
|
||||
|
||||
.irq_handler = ata_interrupt,
|
||||
.irq_clear = ata_bmdma_irq_clear,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
|
||||
.port_start = ata_port_start,
|
||||
};
|
||||
|
||||
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,
|
||||
|
||||
.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_data_xfer_noirq,
|
||||
|
||||
.irq_handler = ata_interrupt,
|
||||
.irq_clear = ata_bmdma_irq_clear,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
|
||||
.port_start = ata_port_start,
|
||||
};
|
||||
|
||||
/*
|
||||
* 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 */
|
||||
ioread8(ap->ioaddr.nsect_addr);
|
||||
ioread8(ap->ioaddr.nsect_addr);
|
||||
ioread8(ap->ioaddr.nsect_addr);
|
||||
|
||||
/* Now the data */
|
||||
|
||||
if (write_data)
|
||||
iowrite32_rep(ap->ioaddr.data_addr, buf, buflen >> 2);
|
||||
else
|
||||
ioread32_rep(ap->ioaddr.data_addr, buf, buflen >> 2);
|
||||
|
||||
if (unlikely(slop)) {
|
||||
u32 pad;
|
||||
if (write_data) {
|
||||
memcpy(&pad, buf + buflen - slop, slop);
|
||||
pad = le32_to_cpu(pad);
|
||||
iowrite32(pad, ap->ioaddr.data_addr);
|
||||
} else {
|
||||
pad = ioread32(ap->ioaddr.data_addr);
|
||||
pad = cpu_to_le16(pad);
|
||||
memcpy(buf + buflen - slop, &pad, slop);
|
||||
}
|
||||
}
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
else
|
||||
ata_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,
|
||||
|
||||
.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 = pdc_data_xfer_vlb,
|
||||
|
||||
.irq_handler = ata_interrupt,
|
||||
.irq_clear = ata_bmdma_irq_clear,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
|
||||
.port_start = ata_port_start,
|
||||
};
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
iowrite8(recover << 4 | active, ap->ioaddr.device_addr);
|
||||
ioread8(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,
|
||||
|
||||
.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_data_xfer, /* Check vlb/noirq */
|
||||
|
||||
.irq_handler = ata_interrupt,
|
||||
.irq_clear = ata_bmdma_irq_clear,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
|
||||
.port_start = ata_port_start,
|
||||
};
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
iowrite8(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);
|
||||
}
|
||||
}
|
||||
ioread8(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,
|
||||
|
||||
.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_data_xfer, /* FIXME: Check 32bit and noirq */
|
||||
|
||||
.irq_handler = ata_interrupt,
|
||||
.irq_clear = ata_bmdma_irq_clear,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
|
||||
.port_start = ata_port_start,
|
||||
};
|
||||
|
||||
/*
|
||||
* 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 */
|
||||
ioread16(ap->ioaddr.error_addr);
|
||||
ioread16(ap->ioaddr.error_addr);
|
||||
iowrite8(3, ap->ioaddr.nsect_addr);
|
||||
|
||||
/* Read VLB clock strapping */
|
||||
clock = 1000000000 / khz[ioread8(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 = ioread8(ap->ioaddr.lbal_addr);
|
||||
rc &= 0x7F;
|
||||
rc |= (adev->devno << 7);
|
||||
iowrite8(rc, ap->ioaddr.lbal_addr);
|
||||
|
||||
/* Write the timings */
|
||||
iowrite8(active << 4 | recover, ap->ioaddr.error_addr);
|
||||
|
||||
/* Select the right bank for read timings, also
|
||||
load the shared timings for address */
|
||||
rc = ioread8(ap->ioaddr.device_addr);
|
||||
rc &= 0xC0;
|
||||
rc |= adev->devno; /* Index select */
|
||||
rc |= (setup << 4) | 0x04;
|
||||
iowrite8(rc, ap->ioaddr.device_addr);
|
||||
|
||||
/* Load the read timings */
|
||||
iowrite8(active << 4 | recover, ap->ioaddr.data_addr);
|
||||
|
||||
/* Ensure the timing register mode is right */
|
||||
rc = ioread8(ap->ioaddr.lbal_addr);
|
||||
rc &= 0x73;
|
||||
rc |= 0x84;
|
||||
iowrite8(rc, ap->ioaddr.lbal_addr);
|
||||
|
||||
/* Exit command mode */
|
||||
iowrite8(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,
|
||||
|
||||
.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_data_xfer,
|
||||
|
||||
.irq_handler = ata_interrupt,
|
||||
.irq_clear = ata_bmdma_irq_clear,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
|
||||
.port_start = ata_port_start,
|
||||
};
|
||||
|
||||
/*
|
||||
* 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 */
|
||||
ioread16(ap->ioaddr.error_addr);
|
||||
ioread16(ap->ioaddr.error_addr);
|
||||
iowrite8(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 = ioread8(ap->ioaddr.lbal_addr);
|
||||
rc &= 0x7F;
|
||||
rc |= (adev->devno << 7);
|
||||
iowrite8(rc, ap->ioaddr.lbal_addr);
|
||||
|
||||
/* Write the timings */
|
||||
iowrite8(active << 4 | recover, ap->ioaddr.error_addr);
|
||||
|
||||
/* Select the right bank for read timings, also
|
||||
load the shared timings for address */
|
||||
rc = ioread8(ap->ioaddr.device_addr);
|
||||
rc &= 0xC0;
|
||||
rc |= adev->devno; /* Index select */
|
||||
rc |= (setup << 4) | 0x04;
|
||||
iowrite8(rc, ap->ioaddr.device_addr);
|
||||
|
||||
/* Load the read timings */
|
||||
iowrite8(active << 4 | recover, ap->ioaddr.data_addr);
|
||||
|
||||
/* Ensure the timing register mode is right */
|
||||
rc = ioread8(ap->ioaddr.lbal_addr);
|
||||
rc &= 0x73;
|
||||
rc |= 0x84;
|
||||
iowrite8(rc, ap->ioaddr.lbal_addr);
|
||||
|
||||
/* Exit command mode */
|
||||
iowrite8(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,
|
||||
|
||||
.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 = opti82c46x_qc_issue_prot,
|
||||
|
||||
.data_xfer = ata_data_xfer,
|
||||
|
||||
.irq_handler = ata_interrupt,
|
||||
.irq_clear = ata_bmdma_irq_clear,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
|
||||
.port_start = ata_port_start,
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* 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;
|
||||
struct ata_port_operations *ops = &legacy_port_ops;
|
||||
void __iomem *io_addr, *ctrl_addr;
|
||||
int pio_modes = pio_mask;
|
||||
u32 mask = (1 << port);
|
||||
u32 iordy = (iordy_mask & mask) ? 0: ATA_FLAG_NO_IORDY;
|
||||
int ret;
|
||||
|
||||
pdev = platform_device_register_simple(DRV_NAME, nr_legacy_host, NULL, 0);
|
||||
if (IS_ERR(pdev))
|
||||
return PTR_ERR(pdev);
|
||||
|
||||
ret = -EBUSY;
|
||||
if (devm_request_region(&pdev->dev, io, 8, "pata_legacy") == NULL ||
|
||||
devm_request_region(&pdev->dev, ctrl, 1, "pata_legacy") == NULL)
|
||||
goto fail;
|
||||
|
||||
ret = -ENOMEM;
|
||||
io_addr = devm_ioport_map(&pdev->dev, io, 8);
|
||||
ctrl_addr = devm_ioport_map(&pdev->dev, ctrl, 1);
|
||||
if (!io_addr || !ctrl_addr)
|
||||
goto fail;
|
||||
|
||||
if (ht6560a & mask) {
|
||||
ops = &ht6560a_port_ops;
|
||||
pio_modes = 0x07;
|
||||
iordy = ATA_FLAG_NO_IORDY;
|
||||
}
|
||||
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;
|
||||
iordy = ATA_FLAG_NO_IORDY;
|
||||
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|iordy;
|
||||
ae.port[0].cmd_addr = io_addr;
|
||||
ae.port[0].altstatus_addr = ctrl_addr;
|
||||
ae.port[0].ctl_addr = ctrl_addr;
|
||||
ata_std_ports(&ae.port[0]);
|
||||
ae.private_data = ld;
|
||||
|
||||
ret = -ENODEV;
|
||||
if (!ata_device_add(&ae))
|
||||
goto fail;
|
||||
|
||||
legacy_host[nr_legacy_host++] = dev_get_drvdata(&pdev->dev);
|
||||
ld->platform_dev = pdev;
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
platform_device_unregister(pdev);
|
||||
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];
|
||||
|
||||
ata_host_detach(legacy_host[i]);
|
||||
platform_device_unregister(ld->platform_dev);
|
||||
if (ld->timing)
|
||||
release_region(ld->timing, 2);
|
||||
}
|
||||
}
|
||||
|
||||
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_param(iordy_mask, int, 0);
|
||||
|
||||
module_init(legacy_init);
|
||||
module_exit(legacy_exit);
|
||||
|
||||
228
drivers/ata/pata_marvell.c
Normal file
228
drivers/ata/pata_marvell.c
Normal file
@@ -0,0 +1,228 @@
|
||||
/*
|
||||
* Marvell PATA driver.
|
||||
*
|
||||
* For the moment we drive the PATA port in legacy mode. That
|
||||
* isn't making full use of the device functionality but it is
|
||||
* easy to get working.
|
||||
*
|
||||
* (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_marvell"
|
||||
#define DRV_VERSION "0.1.1"
|
||||
|
||||
/**
|
||||
* marvell_pre_reset - check for 40/80 pin
|
||||
* @ap: Port
|
||||
*
|
||||
* Perform the PATA port setup we need.
|
||||
*/
|
||||
|
||||
static int marvell_pre_reset(struct ata_port *ap)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
|
||||
u32 devices;
|
||||
void __iomem *barp;
|
||||
int i;
|
||||
|
||||
/* Check if our port is enabled */
|
||||
|
||||
barp = pci_iomap(pdev, 5, 0x10);
|
||||
if (barp == NULL)
|
||||
return -ENOMEM;
|
||||
printk("BAR5:");
|
||||
for(i = 0; i <= 0x0F; i++)
|
||||
printk("%02X:%02X ", i, readb(barp + i));
|
||||
printk("\n");
|
||||
|
||||
devices = readl(barp + 0x0C);
|
||||
pci_iounmap(pdev, barp);
|
||||
|
||||
if ((pdev->device == 0x6145) && (ap->port_no == 0) &&
|
||||
(!(devices & 0x10))) /* PATA enable ? */
|
||||
return -ENOENT;
|
||||
|
||||
/* Cable type */
|
||||
switch(ap->port_no)
|
||||
{
|
||||
case 0:
|
||||
if (ioread8(ap->ioaddr.bmdma_addr + 1) & 1)
|
||||
ap->cbl = ATA_CBL_PATA40;
|
||||
else
|
||||
ap->cbl = ATA_CBL_PATA80;
|
||||
break;
|
||||
|
||||
case 1: /* Legacy SATA port */
|
||||
ap->cbl = ATA_CBL_SATA;
|
||||
break;
|
||||
}
|
||||
return ata_std_prereset(ap);
|
||||
}
|
||||
|
||||
/**
|
||||
* marvell_error_handler - Setup and error handler
|
||||
* @ap: Port to handle
|
||||
*
|
||||
* LOCKING:
|
||||
* None (inherited from caller).
|
||||
*/
|
||||
|
||||
static void marvell_error_handler(struct ata_port *ap)
|
||||
{
|
||||
return ata_bmdma_drive_eh(ap, marvell_pre_reset, ata_std_softreset,
|
||||
NULL, ata_std_postreset);
|
||||
}
|
||||
|
||||
/* No PIO or DMA methods needed for this device */
|
||||
|
||||
static struct scsi_host_template marvell_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,
|
||||
/* Use standard CHS mapping rules */
|
||||
.bios_param = ata_std_bios_param,
|
||||
#ifdef CONFIG_PM
|
||||
.resume = ata_scsi_device_resume,
|
||||
.suspend = ata_scsi_device_suspend,
|
||||
#endif
|
||||
};
|
||||
|
||||
static const struct ata_port_operations marvell_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 = marvell_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_data_xfer,
|
||||
|
||||
/* Timeout handling */
|
||||
.irq_handler = ata_interrupt,
|
||||
.irq_clear = ata_bmdma_irq_clear,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
|
||||
/* Generic PATA PCI ATA helpers */
|
||||
.port_start = ata_port_start,
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* marvell_init_one - Register Marvell ATA PCI device with kernel services
|
||||
* @pdev: PCI device to register
|
||||
* @ent: Entry in marvell_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 marvell_init_one (struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
{
|
||||
static struct ata_port_info info = {
|
||||
.sht = &marvell_sht,
|
||||
.flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
|
||||
|
||||
.pio_mask = 0x1f,
|
||||
.mwdma_mask = 0x07,
|
||||
.udma_mask = 0x3f,
|
||||
|
||||
.port_ops = &marvell_ops,
|
||||
};
|
||||
static struct ata_port_info info_sata = {
|
||||
.sht = &marvell_sht,
|
||||
/* Slave possible as its magically mapped not real */
|
||||
.flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
|
||||
|
||||
.pio_mask = 0x1f,
|
||||
.mwdma_mask = 0x07,
|
||||
.udma_mask = 0x7f,
|
||||
|
||||
.port_ops = &marvell_ops,
|
||||
};
|
||||
struct ata_port_info *port_info[2] = { &info, &info_sata };
|
||||
int n_port = 2;
|
||||
|
||||
if (pdev->device == 0x6101)
|
||||
n_port = 1;
|
||||
|
||||
return ata_pci_init_one(pdev, port_info, n_port);
|
||||
}
|
||||
|
||||
static const struct pci_device_id marvell_pci_tbl[] = {
|
||||
{ PCI_DEVICE(0x11AB, 0x6101), },
|
||||
{ PCI_DEVICE(0x11AB, 0x6145), },
|
||||
{ } /* terminate list */
|
||||
};
|
||||
|
||||
static struct pci_driver marvell_pci_driver = {
|
||||
.name = DRV_NAME,
|
||||
.id_table = marvell_pci_tbl,
|
||||
.probe = marvell_init_one,
|
||||
.remove = ata_pci_remove_one,
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = ata_pci_device_suspend,
|
||||
.resume = ata_pci_device_resume,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int __init marvell_init(void)
|
||||
{
|
||||
return pci_register_driver(&marvell_pci_driver);
|
||||
}
|
||||
|
||||
static void __exit marvell_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&marvell_pci_driver);
|
||||
}
|
||||
|
||||
module_init(marvell_init);
|
||||
module_exit(marvell_exit);
|
||||
|
||||
MODULE_AUTHOR("Alan Cox");
|
||||
MODULE_DESCRIPTION("SCSI low-level driver for Marvell ATA in legacy mode");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DEVICE_TABLE(pci, marvell_pci_tbl);
|
||||
MODULE_VERSION(DRV_VERSION);
|
||||
|
||||
540
drivers/ata/pata_mpc52xx.c
Normal file
540
drivers/ata/pata_mpc52xx.c
Normal file
@@ -0,0 +1,540 @@
|
||||
/*
|
||||
* drivers/ata/pata_mpc52xx.c
|
||||
*
|
||||
* libata driver for the Freescale MPC52xx on-chip IDE interface
|
||||
*
|
||||
* Copyright (C) 2006 Sylvain Munaut <tnt@246tNt.com>
|
||||
* Copyright (C) 2003 Mipsys - Benjamin Herrenschmidt
|
||||
*
|
||||
* This file is licensed under the terms of the GNU General Public License
|
||||
* version 2. This program is licensed "as is" without any warranty of any
|
||||
* kind, whether express or implied.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/libata.h>
|
||||
|
||||
#include <asm/types.h>
|
||||
#include <asm/prom.h>
|
||||
#include <asm/of_platform.h>
|
||||
#include <asm/mpc52xx.h>
|
||||
|
||||
|
||||
#define DRV_NAME "mpc52xx_ata"
|
||||
#define DRV_VERSION "0.1.0"
|
||||
|
||||
|
||||
/* Private structures used by the driver */
|
||||
struct mpc52xx_ata_timings {
|
||||
u32 pio1;
|
||||
u32 pio2;
|
||||
};
|
||||
|
||||
struct mpc52xx_ata_priv {
|
||||
unsigned int ipb_period;
|
||||
struct mpc52xx_ata __iomem * ata_regs;
|
||||
int ata_irq;
|
||||
struct mpc52xx_ata_timings timings[2];
|
||||
int csel;
|
||||
};
|
||||
|
||||
|
||||
/* ATAPI-4 PIO specs (in ns) */
|
||||
static const int ataspec_t0[5] = {600, 383, 240, 180, 120};
|
||||
static const int ataspec_t1[5] = { 70, 50, 30, 30, 25};
|
||||
static const int ataspec_t2_8[5] = {290, 290, 290, 80, 70};
|
||||
static const int ataspec_t2_16[5] = {165, 125, 100, 80, 70};
|
||||
static const int ataspec_t2i[5] = { 0, 0, 0, 70, 25};
|
||||
static const int ataspec_t4[5] = { 30, 20, 15, 10, 10};
|
||||
static const int ataspec_ta[5] = { 35, 35, 35, 35, 35};
|
||||
|
||||
#define CALC_CLKCYC(c,v) ((((v)+(c)-1)/(c)))
|
||||
|
||||
|
||||
/* Bit definitions inside the registers */
|
||||
#define MPC52xx_ATA_HOSTCONF_SMR 0x80000000UL /* State machine reset */
|
||||
#define MPC52xx_ATA_HOSTCONF_FR 0x40000000UL /* FIFO Reset */
|
||||
#define MPC52xx_ATA_HOSTCONF_IE 0x02000000UL /* Enable interrupt in PIO */
|
||||
#define MPC52xx_ATA_HOSTCONF_IORDY 0x01000000UL /* Drive supports IORDY protocol */
|
||||
|
||||
#define MPC52xx_ATA_HOSTSTAT_TIP 0x80000000UL /* Transaction in progress */
|
||||
#define MPC52xx_ATA_HOSTSTAT_UREP 0x40000000UL /* UDMA Read Extended Pause */
|
||||
#define MPC52xx_ATA_HOSTSTAT_RERR 0x02000000UL /* Read Error */
|
||||
#define MPC52xx_ATA_HOSTSTAT_WERR 0x01000000UL /* Write Error */
|
||||
|
||||
#define MPC52xx_ATA_FIFOSTAT_EMPTY 0x01 /* FIFO Empty */
|
||||
|
||||
#define MPC52xx_ATA_DMAMODE_WRITE 0x01 /* Write DMA */
|
||||
#define MPC52xx_ATA_DMAMODE_READ 0x02 /* Read DMA */
|
||||
#define MPC52xx_ATA_DMAMODE_UDMA 0x04 /* UDMA enabled */
|
||||
#define MPC52xx_ATA_DMAMODE_IE 0x08 /* Enable drive interrupt to CPU in DMA mode */
|
||||
#define MPC52xx_ATA_DMAMODE_FE 0x10 /* FIFO Flush enable in Rx mode */
|
||||
#define MPC52xx_ATA_DMAMODE_FR 0x20 /* FIFO Reset */
|
||||
#define MPC52xx_ATA_DMAMODE_HUT 0x40 /* Host UDMA burst terminate */
|
||||
|
||||
|
||||
/* Structure of the hardware registers */
|
||||
struct mpc52xx_ata {
|
||||
|
||||
/* Host interface registers */
|
||||
u32 config; /* ATA + 0x00 Host configuration */
|
||||
u32 host_status; /* ATA + 0x04 Host controller status */
|
||||
u32 pio1; /* ATA + 0x08 PIO Timing 1 */
|
||||
u32 pio2; /* ATA + 0x0c PIO Timing 2 */
|
||||
u32 mdma1; /* ATA + 0x10 MDMA Timing 1 */
|
||||
u32 mdma2; /* ATA + 0x14 MDMA Timing 2 */
|
||||
u32 udma1; /* ATA + 0x18 UDMA Timing 1 */
|
||||
u32 udma2; /* ATA + 0x1c UDMA Timing 2 */
|
||||
u32 udma3; /* ATA + 0x20 UDMA Timing 3 */
|
||||
u32 udma4; /* ATA + 0x24 UDMA Timing 4 */
|
||||
u32 udma5; /* ATA + 0x28 UDMA Timing 5 */
|
||||
u32 share_cnt; /* ATA + 0x2c ATA share counter */
|
||||
u32 reserved0[3];
|
||||
|
||||
/* FIFO registers */
|
||||
u32 fifo_data; /* ATA + 0x3c */
|
||||
u8 fifo_status_frame; /* ATA + 0x40 */
|
||||
u8 fifo_status; /* ATA + 0x41 */
|
||||
u16 reserved7[1];
|
||||
u8 fifo_control; /* ATA + 0x44 */
|
||||
u8 reserved8[5];
|
||||
u16 fifo_alarm; /* ATA + 0x4a */
|
||||
u16 reserved9;
|
||||
u16 fifo_rdp; /* ATA + 0x4e */
|
||||
u16 reserved10;
|
||||
u16 fifo_wrp; /* ATA + 0x52 */
|
||||
u16 reserved11;
|
||||
u16 fifo_lfrdp; /* ATA + 0x56 */
|
||||
u16 reserved12;
|
||||
u16 fifo_lfwrp; /* ATA + 0x5a */
|
||||
|
||||
/* Drive TaskFile registers */
|
||||
u8 tf_control; /* ATA + 0x5c TASKFILE Control/Alt Status */
|
||||
u8 reserved13[3];
|
||||
u16 tf_data; /* ATA + 0x60 TASKFILE Data */
|
||||
u16 reserved14;
|
||||
u8 tf_features; /* ATA + 0x64 TASKFILE Features/Error */
|
||||
u8 reserved15[3];
|
||||
u8 tf_sec_count; /* ATA + 0x68 TASKFILE Sector Count */
|
||||
u8 reserved16[3];
|
||||
u8 tf_sec_num; /* ATA + 0x6c TASKFILE Sector Number */
|
||||
u8 reserved17[3];
|
||||
u8 tf_cyl_low; /* ATA + 0x70 TASKFILE Cylinder Low */
|
||||
u8 reserved18[3];
|
||||
u8 tf_cyl_high; /* ATA + 0x74 TASKFILE Cylinder High */
|
||||
u8 reserved19[3];
|
||||
u8 tf_dev_head; /* ATA + 0x78 TASKFILE Device/Head */
|
||||
u8 reserved20[3];
|
||||
u8 tf_command; /* ATA + 0x7c TASKFILE Command/Status */
|
||||
u8 dma_mode; /* ATA + 0x7d ATA Host DMA Mode configuration */
|
||||
u8 reserved21[2];
|
||||
};
|
||||
|
||||
|
||||
/* ======================================================================== */
|
||||
/* Aux fns */
|
||||
/* ======================================================================== */
|
||||
|
||||
|
||||
/* MPC52xx low level hw control */
|
||||
|
||||
static int
|
||||
mpc52xx_ata_compute_pio_timings(struct mpc52xx_ata_priv *priv, int dev, int pio)
|
||||
{
|
||||
struct mpc52xx_ata_timings *timing = &priv->timings[dev];
|
||||
unsigned int ipb_period = priv->ipb_period;
|
||||
unsigned int t0, t1, t2_8, t2_16, t2i, t4, ta;
|
||||
|
||||
if ((pio<0) || (pio>4))
|
||||
return -EINVAL;
|
||||
|
||||
t0 = CALC_CLKCYC(ipb_period, 1000 * ataspec_t0[pio]);
|
||||
t1 = CALC_CLKCYC(ipb_period, 1000 * ataspec_t1[pio]);
|
||||
t2_8 = CALC_CLKCYC(ipb_period, 1000 * ataspec_t2_8[pio]);
|
||||
t2_16 = CALC_CLKCYC(ipb_period, 1000 * ataspec_t2_16[pio]);
|
||||
t2i = CALC_CLKCYC(ipb_period, 1000 * ataspec_t2i[pio]);
|
||||
t4 = CALC_CLKCYC(ipb_period, 1000 * ataspec_t4[pio]);
|
||||
ta = CALC_CLKCYC(ipb_period, 1000 * ataspec_ta[pio]);
|
||||
|
||||
timing->pio1 = (t0 << 24) | (t2_8 << 16) | (t2_16 << 8) | (t2i);
|
||||
timing->pio2 = (t4 << 24) | (t1 << 16) | (ta << 8);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
mpc52xx_ata_apply_timings(struct mpc52xx_ata_priv *priv, int device)
|
||||
{
|
||||
struct mpc52xx_ata __iomem *regs = priv->ata_regs;
|
||||
struct mpc52xx_ata_timings *timing = &priv->timings[device];
|
||||
|
||||
out_be32(®s->pio1, timing->pio1);
|
||||
out_be32(®s->pio2, timing->pio2);
|
||||
out_be32(®s->mdma1, 0);
|
||||
out_be32(®s->mdma2, 0);
|
||||
out_be32(®s->udma1, 0);
|
||||
out_be32(®s->udma2, 0);
|
||||
out_be32(®s->udma3, 0);
|
||||
out_be32(®s->udma4, 0);
|
||||
out_be32(®s->udma5, 0);
|
||||
|
||||
priv->csel = device;
|
||||
}
|
||||
|
||||
static int
|
||||
mpc52xx_ata_hw_init(struct mpc52xx_ata_priv *priv)
|
||||
{
|
||||
struct mpc52xx_ata __iomem *regs = priv->ata_regs;
|
||||
int tslot;
|
||||
|
||||
/* Clear share_cnt (all sample code do this ...) */
|
||||
out_be32(®s->share_cnt, 0);
|
||||
|
||||
/* Configure and reset host */
|
||||
out_be32(®s->config,
|
||||
MPC52xx_ATA_HOSTCONF_IE |
|
||||
MPC52xx_ATA_HOSTCONF_IORDY |
|
||||
MPC52xx_ATA_HOSTCONF_SMR |
|
||||
MPC52xx_ATA_HOSTCONF_FR);
|
||||
|
||||
udelay(10);
|
||||
|
||||
out_be32(®s->config,
|
||||
MPC52xx_ATA_HOSTCONF_IE |
|
||||
MPC52xx_ATA_HOSTCONF_IORDY);
|
||||
|
||||
/* Set the time slot to 1us */
|
||||
tslot = CALC_CLKCYC(priv->ipb_period, 1000000);
|
||||
out_be32(®s->share_cnt, tslot << 16 );
|
||||
|
||||
/* Init timings to PIO0 */
|
||||
memset(priv->timings, 0x00, 2*sizeof(struct mpc52xx_ata_timings));
|
||||
|
||||
mpc52xx_ata_compute_pio_timings(priv, 0, 0);
|
||||
mpc52xx_ata_compute_pio_timings(priv, 1, 0);
|
||||
|
||||
mpc52xx_ata_apply_timings(priv, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* ======================================================================== */
|
||||
/* libata driver */
|
||||
/* ======================================================================== */
|
||||
|
||||
static void
|
||||
mpc52xx_ata_set_piomode(struct ata_port *ap, struct ata_device *adev)
|
||||
{
|
||||
struct mpc52xx_ata_priv *priv = ap->host->private_data;
|
||||
int pio, rv;
|
||||
|
||||
pio = adev->pio_mode - XFER_PIO_0;
|
||||
|
||||
rv = mpc52xx_ata_compute_pio_timings(priv, adev->devno, pio);
|
||||
|
||||
if (rv) {
|
||||
printk(KERN_ERR DRV_NAME
|
||||
": Trying to select invalid PIO mode %d\n", pio);
|
||||
return;
|
||||
}
|
||||
|
||||
mpc52xx_ata_apply_timings(priv, adev->devno);
|
||||
}
|
||||
static void
|
||||
mpc52xx_ata_dev_select(struct ata_port *ap, unsigned int device)
|
||||
{
|
||||
struct mpc52xx_ata_priv *priv = ap->host->private_data;
|
||||
|
||||
if (device != priv->csel)
|
||||
mpc52xx_ata_apply_timings(priv, device);
|
||||
|
||||
ata_std_dev_select(ap,device);
|
||||
}
|
||||
|
||||
static void
|
||||
mpc52xx_ata_error_handler(struct ata_port *ap)
|
||||
{
|
||||
ata_bmdma_drive_eh(ap, ata_std_prereset, ata_std_softreset, NULL,
|
||||
ata_std_postreset);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static struct scsi_host_template mpc52xx_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,
|
||||
.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,
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = ata_scsi_device_suspend,
|
||||
.resume = ata_scsi_device_resume,
|
||||
#endif
|
||||
};
|
||||
|
||||
static struct ata_port_operations mpc52xx_ata_port_ops = {
|
||||
.port_disable = ata_port_disable,
|
||||
.set_piomode = mpc52xx_ata_set_piomode,
|
||||
.dev_select = mpc52xx_ata_dev_select,
|
||||
.tf_load = ata_tf_load,
|
||||
.tf_read = ata_tf_read,
|
||||
.check_status = ata_check_status,
|
||||
.exec_command = ata_exec_command,
|
||||
.freeze = ata_bmdma_freeze,
|
||||
.thaw = ata_bmdma_thaw,
|
||||
.error_handler = mpc52xx_ata_error_handler,
|
||||
.qc_prep = ata_qc_prep,
|
||||
.qc_issue = ata_qc_issue_prot,
|
||||
.data_xfer = ata_data_xfer,
|
||||
.irq_handler = ata_interrupt,
|
||||
.irq_clear = ata_bmdma_irq_clear,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
.port_start = ata_port_start,
|
||||
};
|
||||
|
||||
static struct ata_probe_ent mpc52xx_ata_probe_ent = {
|
||||
.port_ops = &mpc52xx_ata_port_ops,
|
||||
.sht = &mpc52xx_ata_sht,
|
||||
.n_ports = 1,
|
||||
.pio_mask = 0x1f, /* Up to PIO4 */
|
||||
.mwdma_mask = 0x00, /* No MWDMA */
|
||||
.udma_mask = 0x00, /* No UDMA */
|
||||
.port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
|
||||
.irq_flags = 0,
|
||||
};
|
||||
|
||||
static int __devinit
|
||||
mpc52xx_ata_init_one(struct device *dev, struct mpc52xx_ata_priv *priv)
|
||||
{
|
||||
struct ata_probe_ent *ae = &mpc52xx_ata_probe_ent;
|
||||
struct ata_ioports *aio = &ae->port[0];
|
||||
int rv;
|
||||
|
||||
INIT_LIST_HEAD(&ae->node);
|
||||
ae->dev = dev;
|
||||
ae->irq = priv->ata_irq;
|
||||
|
||||
aio->cmd_addr = NULL; /* Don't have a classic reg block */
|
||||
aio->altstatus_addr = &priv->ata_regs->tf_control;
|
||||
aio->ctl_addr = &priv->ata_regs->tf_control;
|
||||
aio->data_addr = &priv->ata_regs->tf_data;
|
||||
aio->error_addr = &priv->ata_regs->tf_features;
|
||||
aio->feature_addr = &priv->ata_regs->tf_features;
|
||||
aio->nsect_addr = &priv->ata_regs->tf_sec_count;
|
||||
aio->lbal_addr = &priv->ata_regs->tf_sec_num;
|
||||
aio->lbam_addr = &priv->ata_regs->tf_cyl_low;
|
||||
aio->lbah_addr = &priv->ata_regs->tf_cyl_high;
|
||||
aio->device_addr = &priv->ata_regs->tf_dev_head;
|
||||
aio->status_addr = &priv->ata_regs->tf_command;
|
||||
aio->command_addr = &priv->ata_regs->tf_command;
|
||||
|
||||
ae->private_data = priv;
|
||||
|
||||
rv = ata_device_add(ae);
|
||||
|
||||
return rv ? 0 : -EINVAL;
|
||||
}
|
||||
|
||||
static struct mpc52xx_ata_priv *
|
||||
mpc52xx_ata_remove_one(struct device *dev)
|
||||
{
|
||||
struct ata_host *host = dev_get_drvdata(dev);
|
||||
struct mpc52xx_ata_priv *priv = host->private_data;
|
||||
|
||||
ata_host_detach(host);
|
||||
|
||||
return priv;
|
||||
}
|
||||
|
||||
|
||||
/* ======================================================================== */
|
||||
/* OF Platform driver */
|
||||
/* ======================================================================== */
|
||||
|
||||
static int __devinit
|
||||
mpc52xx_ata_probe(struct of_device *op, const struct of_device_id *match)
|
||||
{
|
||||
unsigned int ipb_freq;
|
||||
struct resource res_mem;
|
||||
int ata_irq = NO_IRQ;
|
||||
struct mpc52xx_ata __iomem *ata_regs;
|
||||
struct mpc52xx_ata_priv *priv;
|
||||
int rv;
|
||||
|
||||
/* Get ipb frequency */
|
||||
ipb_freq = mpc52xx_find_ipb_freq(op->node);
|
||||
if (!ipb_freq) {
|
||||
printk(KERN_ERR DRV_NAME ": "
|
||||
"Unable to find IPB Bus frequency\n" );
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* Get IRQ and register */
|
||||
rv = of_address_to_resource(op->node, 0, &res_mem);
|
||||
if (rv) {
|
||||
printk(KERN_ERR DRV_NAME ": "
|
||||
"Error while parsing device node resource\n" );
|
||||
return rv;
|
||||
}
|
||||
|
||||
ata_irq = irq_of_parse_and_map(op->node, 0);
|
||||
if (ata_irq == NO_IRQ) {
|
||||
printk(KERN_ERR DRV_NAME ": "
|
||||
"Error while mapping the irq\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Request mem region */
|
||||
if (!devm_request_mem_region(&op->dev, res_mem.start,
|
||||
sizeof(struct mpc52xx_ata), DRV_NAME)) {
|
||||
printk(KERN_ERR DRV_NAME ": "
|
||||
"Error while requesting mem region\n");
|
||||
rv = -EBUSY;
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Remap registers */
|
||||
ata_regs = devm_ioremap(&op->dev, res_mem.start,
|
||||
sizeof(struct mpc52xx_ata));
|
||||
if (!ata_regs) {
|
||||
printk(KERN_ERR DRV_NAME ": "
|
||||
"Error while mapping register set\n");
|
||||
rv = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Prepare our private structure */
|
||||
priv = devm_kzalloc(&op->dev, sizeof(struct mpc52xx_ata_priv),
|
||||
GFP_ATOMIC);
|
||||
if (!priv) {
|
||||
printk(KERN_ERR DRV_NAME ": "
|
||||
"Error while allocating private structure\n");
|
||||
rv = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
priv->ipb_period = 1000000000 / (ipb_freq / 1000);
|
||||
priv->ata_regs = ata_regs;
|
||||
priv->ata_irq = ata_irq;
|
||||
priv->csel = -1;
|
||||
|
||||
/* Init the hw */
|
||||
rv = mpc52xx_ata_hw_init(priv);
|
||||
if (rv) {
|
||||
printk(KERN_ERR DRV_NAME ": Error during HW init\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Register ourselves to libata */
|
||||
rv = mpc52xx_ata_init_one(&op->dev, priv);
|
||||
if (rv) {
|
||||
printk(KERN_ERR DRV_NAME ": "
|
||||
"Error while registering to ATA layer\n");
|
||||
return rv;
|
||||
}
|
||||
|
||||
/* Done */
|
||||
return 0;
|
||||
|
||||
/* Error path */
|
||||
err:
|
||||
irq_dispose_mapping(ata_irq);
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int
|
||||
mpc52xx_ata_remove(struct of_device *op)
|
||||
{
|
||||
struct mpc52xx_ata_priv *priv;
|
||||
|
||||
priv = mpc52xx_ata_remove_one(&op->dev);
|
||||
irq_dispose_mapping(priv->ata_irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
|
||||
static int
|
||||
mpc52xx_ata_suspend(struct of_device *op, pm_message_t state)
|
||||
{
|
||||
return 0; /* FIXME : What to do here ? */
|
||||
}
|
||||
|
||||
static int
|
||||
mpc52xx_ata_resume(struct of_device *op)
|
||||
{
|
||||
return 0; /* FIXME : What to do here ? */
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
static struct of_device_id mpc52xx_ata_of_match[] = {
|
||||
{
|
||||
.type = "ata",
|
||||
.compatible = "mpc5200-ata",
|
||||
},
|
||||
{},
|
||||
};
|
||||
|
||||
|
||||
static struct of_platform_driver mpc52xx_ata_of_platform_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = DRV_NAME,
|
||||
.match_table = mpc52xx_ata_of_match,
|
||||
.probe = mpc52xx_ata_probe,
|
||||
.remove = mpc52xx_ata_remove,
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = mpc52xx_ata_suspend,
|
||||
.resume = mpc52xx_ata_resume,
|
||||
#endif
|
||||
.driver = {
|
||||
.name = DRV_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
/* ======================================================================== */
|
||||
/* Module */
|
||||
/* ======================================================================== */
|
||||
|
||||
static int __init
|
||||
mpc52xx_ata_init(void)
|
||||
{
|
||||
printk(KERN_INFO "ata: MPC52xx IDE/ATA libata driver\n");
|
||||
return of_register_platform_driver(&mpc52xx_ata_of_platform_driver);
|
||||
}
|
||||
|
||||
static void __exit
|
||||
mpc52xx_ata_exit(void)
|
||||
{
|
||||
of_unregister_platform_driver(&mpc52xx_ata_of_platform_driver);
|
||||
}
|
||||
|
||||
module_init(mpc52xx_ata_init);
|
||||
module_exit(mpc52xx_ata_exit);
|
||||
|
||||
MODULE_AUTHOR("Sylvain Munaut <tnt@246tNt.com>");
|
||||
MODULE_DESCRIPTION("Freescale MPC52xx IDE/ATA libata driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DEVICE_TABLE(of, mpc52xx_ata_of_match);
|
||||
MODULE_VERSION(DRV_VERSION);
|
||||
|
||||
298
drivers/ata/pata_mpiix.c
Normal file
298
drivers/ata/pata_mpiix.c
Normal file
@@ -0,0 +1,298 @@
|
||||
/*
|
||||
* 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.5"
|
||||
|
||||
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 };
|
||||
|
||||
if (!pci_test_config_bits(pdev, &mpiix_enable_bits))
|
||||
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/PPE for this device */
|
||||
if (adev->class == ATA_DEV_ATA)
|
||||
control |= PPE; /* Enable prefetch/posting for disk */
|
||||
if (ata_pio_need_iordy(adev))
|
||||
control |= IORDY;
|
||||
if (pio > 1)
|
||||
control |= FTIM; /* This drive is on the fast timing bank */
|
||||
|
||||
/* Mask out timing and clear both TIME bank selects */
|
||||
idetim &= 0xCCEE;
|
||||
idetim &= ~(0x07 << (4 * adev->devno));
|
||||
idetim |= control << (4 * 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,
|
||||
.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,
|
||||
#ifdef CONFIG_PM
|
||||
.resume = ata_scsi_device_resume,
|
||||
.suspend = ata_scsi_device_suspend,
|
||||
#endif
|
||||
};
|
||||
|
||||
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_data_xfer,
|
||||
|
||||
.irq_handler = ata_interrupt,
|
||||
.irq_clear = ata_bmdma_irq_clear,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
|
||||
.port_start = ata_port_start,
|
||||
};
|
||||
|
||||
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;
|
||||
static int printed_version;
|
||||
void __iomem *cmd_addr, *ctl_addr;
|
||||
u16 idetim;
|
||||
int irq;
|
||||
|
||||
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;
|
||||
|
||||
/* See if it's primary or secondary channel... */
|
||||
if (!(idetim & SECONDARY)) {
|
||||
irq = 14;
|
||||
cmd_addr = devm_ioport_map(&dev->dev, 0x1F0, 8);
|
||||
ctl_addr = devm_ioport_map(&dev->dev, 0x3F6, 1);
|
||||
} else {
|
||||
irq = 15;
|
||||
cmd_addr = devm_ioport_map(&dev->dev, 0x170, 8);
|
||||
ctl_addr = devm_ioport_map(&dev->dev, 0x376, 1);
|
||||
}
|
||||
|
||||
if (!cmd_addr || !ctl_addr)
|
||||
return -ENOMEM;
|
||||
|
||||
/* 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.node);
|
||||
probe.dev = pci_dev_to_dev(dev);
|
||||
probe.port_ops = &mpiix_port_ops;
|
||||
probe.sht = &mpiix_sht;
|
||||
probe.pio_mask = 0x1F;
|
||||
probe.irq_flags = IRQF_SHARED;
|
||||
probe.port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST;
|
||||
probe.n_ports = 1;
|
||||
|
||||
probe.irq = irq;
|
||||
probe.port[0].cmd_addr = cmd_addr;
|
||||
probe.port[0].ctl_addr = ctl_addr;
|
||||
probe.port[0].altstatus_addr = ctl_addr;
|
||||
|
||||
/* Let libata fill in the port details */
|
||||
ata_std_ports(&probe.port[0]);
|
||||
|
||||
/* Now add the port that is active */
|
||||
if (ata_device_add(&probe))
|
||||
return 0;
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static const struct pci_device_id mpiix[] = {
|
||||
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82371MX), },
|
||||
|
||||
{ },
|
||||
};
|
||||
|
||||
static struct pci_driver mpiix_pci_driver = {
|
||||
.name = DRV_NAME,
|
||||
.id_table = mpiix,
|
||||
.probe = mpiix_init_one,
|
||||
.remove = ata_pci_remove_one,
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = ata_pci_device_suspend,
|
||||
.resume = ata_pci_device_resume,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int __init mpiix_init(void)
|
||||
{
|
||||
return pci_register_driver(&mpiix_pci_driver);
|
||||
}
|
||||
|
||||
static void __exit mpiix_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&mpiix_pci_driver);
|
||||
}
|
||||
|
||||
MODULE_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);
|
||||
182
drivers/ata/pata_netcell.c
Normal file
182
drivers/ata/pata_netcell.c
Normal file
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
* 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.6"
|
||||
|
||||
/**
|
||||
* 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,
|
||||
.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,
|
||||
/* Use standard CHS mapping rules */
|
||||
.bios_param = ata_std_bios_param,
|
||||
#ifdef CONFIG_PM
|
||||
.resume = ata_scsi_device_resume,
|
||||
.suspend = ata_scsi_device_suspend,
|
||||
#endif
|
||||
};
|
||||
|
||||
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_data_xfer,
|
||||
|
||||
/* IRQ-related hooks */
|
||||
.irq_handler = ata_interrupt,
|
||||
.irq_clear = ata_bmdma_irq_clear,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
|
||||
/* Generic PATA PCI ATA helpers */
|
||||
.port_start = ata_port_start,
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* 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_VDEVICE(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,
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = ata_pci_device_suspend,
|
||||
.resume = ata_pci_device_resume,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int __init netcell_init(void)
|
||||
{
|
||||
return pci_register_driver(&netcell_pci_driver);
|
||||
}
|
||||
|
||||
static void __exit netcell_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&netcell_pci_driver);
|
||||
}
|
||||
|
||||
module_init(netcell_init);
|
||||
module_exit(netcell_exit);
|
||||
|
||||
MODULE_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);
|
||||
|
||||
240
drivers/ata/pata_ns87410.c
Normal file
240
drivers/ata/pata_ns87410.c
Normal file
@@ -0,0 +1,240 @@
|
||||
/*
|
||||
* 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.3"
|
||||
|
||||
/**
|
||||
* 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,
|
||||
.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,
|
||||
#ifdef CONFIG_PM
|
||||
.resume = ata_scsi_device_resume,
|
||||
.suspend = ata_scsi_device_suspend,
|
||||
#endif
|
||||
};
|
||||
|
||||
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_data_xfer,
|
||||
|
||||
.irq_handler = ata_interrupt,
|
||||
.irq_clear = ata_bmdma_irq_clear,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
|
||||
.port_start = ata_port_start,
|
||||
};
|
||||
|
||||
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_VDEVICE(NS, PCI_DEVICE_ID_NS_87410), },
|
||||
|
||||
{ },
|
||||
};
|
||||
|
||||
static struct pci_driver ns87410_pci_driver = {
|
||||
.name = DRV_NAME,
|
||||
.id_table = ns87410,
|
||||
.probe = ns87410_init_one,
|
||||
.remove = ata_pci_remove_one,
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = ata_pci_device_suspend,
|
||||
.resume = ata_pci_device_resume,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int __init ns87410_init(void)
|
||||
{
|
||||
return pci_register_driver(&ns87410_pci_driver);
|
||||
}
|
||||
|
||||
static void __exit ns87410_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&ns87410_pci_driver);
|
||||
}
|
||||
|
||||
MODULE_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);
|
||||
345
drivers/ata/pata_oldpiix.c
Normal file
345
drivers/ata/pata_oldpiix.c
Normal file
@@ -0,0 +1,345 @@
|
||||
/*
|
||||
* 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.4"
|
||||
|
||||
/**
|
||||
* 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 > 1)
|
||||
control |= 1; /* TIME */
|
||||
if (ata_pio_need_iordy(adev))
|
||||
control |= 2; /* IE */
|
||||
|
||||
/* Intel specifies that the prefetch/posting is for disk only */
|
||||
if (adev->class == ATA_DEV_ATA)
|
||||
control |= 4; /* PPE */
|
||||
|
||||
pci_read_config_word(dev, idetm_port, &idetm_data);
|
||||
|
||||
/*
|
||||
* Set PPE, IE and TIME as appropriate.
|
||||
* Clear the other drive's 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) {
|
||||
oldpiix_set_piomode(ap, adev);
|
||||
if (adev->dma_mode)
|
||||
oldpiix_set_dmamode(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,
|
||||
.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,
|
||||
#ifdef CONFIG_PM
|
||||
.resume = ata_scsi_device_resume,
|
||||
.suspend = ata_scsi_device_suspend,
|
||||
#endif
|
||||
};
|
||||
|
||||
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_data_xfer,
|
||||
|
||||
.irq_handler = ata_interrupt,
|
||||
.irq_clear = ata_bmdma_irq_clear,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
|
||||
.port_start = ata_port_start,
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* 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_VDEVICE(INTEL, 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,
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = ata_pci_device_suspend,
|
||||
.resume = ata_pci_device_resume,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int __init oldpiix_init(void)
|
||||
{
|
||||
return pci_register_driver(&oldpiix_pci_driver);
|
||||
}
|
||||
|
||||
static void __exit oldpiix_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&oldpiix_pci_driver);
|
||||
}
|
||||
|
||||
module_init(oldpiix_init);
|
||||
module_exit(oldpiix_exit);
|
||||
|
||||
MODULE_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);
|
||||
|
||||
273
drivers/ata/pata_opti.c
Normal file
273
drivers/ata/pata_opti.c
Normal file
@@ -0,0 +1,273 @@
|
||||
/*
|
||||
* 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.8"
|
||||
|
||||
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)
|
||||
{
|
||||
void __iomem *regio = ap->ioaddr.cmd_addr;
|
||||
|
||||
/* These 3 unlock the control register access */
|
||||
ioread16(regio + 1);
|
||||
ioread16(regio + 1);
|
||||
iowrite8(3, regio + 2);
|
||||
|
||||
/* Do the I/O */
|
||||
iowrite8(val, regio + reg);
|
||||
|
||||
/* Relock */
|
||||
iowrite8(0x83, regio + 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
void __iomem *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 }
|
||||
};
|
||||
|
||||
iowrite8(0xff, regio + 5);
|
||||
clock = ioread16(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,
|
||||
.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,
|
||||
#ifdef CONFIG_PM
|
||||
.resume = ata_scsi_device_resume,
|
||||
.suspend = ata_scsi_device_suspend,
|
||||
#endif
|
||||
};
|
||||
|
||||
static struct ata_port_operations opti_port_ops = {
|
||||
.port_disable = ata_port_disable,
|
||||
.set_piomode = opti_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 = 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_data_xfer,
|
||||
|
||||
.irq_handler = ata_interrupt,
|
||||
.irq_clear = ata_bmdma_irq_clear,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
|
||||
.port_start = ata_port_start,
|
||||
};
|
||||
|
||||
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_VDEVICE(OPTI, PCI_DEVICE_ID_OPTI_82C621), 0 },
|
||||
{ PCI_VDEVICE(OPTI, PCI_DEVICE_ID_OPTI_82C825), 1 },
|
||||
|
||||
{ },
|
||||
};
|
||||
|
||||
static struct pci_driver opti_pci_driver = {
|
||||
.name = DRV_NAME,
|
||||
.id_table = opti,
|
||||
.probe = opti_init_one,
|
||||
.remove = ata_pci_remove_one,
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = ata_pci_device_suspend,
|
||||
.resume = ata_pci_device_resume,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int __init opti_init(void)
|
||||
{
|
||||
return pci_register_driver(&opti_pci_driver);
|
||||
}
|
||||
|
||||
static void __exit opti_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&opti_pci_driver);
|
||||
}
|
||||
|
||||
|
||||
MODULE_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);
|
||||
552
drivers/ata/pata_optidma.c
Normal file
552
drivers/ata/pata_optidma.c
Normal file
@@ -0,0 +1,552 @@
|
||||
/*
|
||||
* 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.4"
|
||||
|
||||
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)
|
||||
{
|
||||
void __iomem *regio = ap->ioaddr.cmd_addr;
|
||||
|
||||
/* These 3 unlock the control register access */
|
||||
ioread16(regio + 1);
|
||||
ioread16(regio + 1);
|
||||
iowrite8(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)
|
||||
{
|
||||
void __iomem *regio = ap->ioaddr.cmd_addr;
|
||||
|
||||
/* Relock */
|
||||
iowrite8(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;
|
||||
void __iomem *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 */
|
||||
iowrite8(adev->devno, regio + MISC_REG);
|
||||
/* Now we load the data timings into read data/write data */
|
||||
if (mode < XFER_MW_DMA_0) {
|
||||
iowrite8(data_rec_timing[pci_clock][pio], regio + READ_REG);
|
||||
iowrite8(data_rec_timing[pci_clock][pio], regio + WRITE_REG);
|
||||
} else if (mode < XFER_UDMA_0) {
|
||||
iowrite8(dma_data_rec_timing[pci_clock][dma], regio + READ_REG);
|
||||
iowrite8(dma_data_rec_timing[pci_clock][dma], regio + WRITE_REG);
|
||||
}
|
||||
/* Finally we load the address setup into the misc register */
|
||||
iowrite8(addr | adev->devno, regio + MISC_REG);
|
||||
|
||||
/* Programming sequence complete, timing 0 dev 0, timing 1 dev 1 */
|
||||
iowrite8(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,
|
||||
.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,
|
||||
#ifdef CONFIG_PM
|
||||
.resume = ata_scsi_device_resume,
|
||||
.suspend = ata_scsi_device_suspend,
|
||||
#endif
|
||||
};
|
||||
|
||||
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_data_xfer,
|
||||
|
||||
.irq_handler = ata_interrupt,
|
||||
.irq_clear = ata_bmdma_irq_clear,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
|
||||
.port_start = ata_port_start,
|
||||
};
|
||||
|
||||
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_data_xfer,
|
||||
|
||||
.irq_handler = ata_interrupt,
|
||||
.irq_clear = ata_bmdma_irq_clear,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
|
||||
.port_start = ata_port_start,
|
||||
};
|
||||
|
||||
/**
|
||||
* 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_VDEVICE(OPTI, 0xD568), }, /* Opti 82C700 */
|
||||
|
||||
{ },
|
||||
};
|
||||
|
||||
static struct pci_driver optidma_pci_driver = {
|
||||
.name = DRV_NAME,
|
||||
.id_table = optidma,
|
||||
.probe = optidma_init_one,
|
||||
.remove = ata_pci_remove_one,
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = ata_pci_device_suspend,
|
||||
.resume = ata_pci_device_resume,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int __init optidma_init(void)
|
||||
{
|
||||
return pci_register_driver(&optidma_pci_driver);
|
||||
}
|
||||
|
||||
static void __exit optidma_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&optidma_pci_driver);
|
||||
}
|
||||
|
||||
MODULE_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);
|
||||
401
drivers/ata/pata_pcmcia.c
Normal file
401
drivers/ata/pata_pcmcia.c
Normal file
@@ -0,0 +1,401 @@
|
||||
/*
|
||||
* 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.3.0"
|
||||
|
||||
/*
|
||||
* 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,
|
||||
.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 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_data_xfer_noirq,
|
||||
|
||||
.irq_handler = ata_interrupt,
|
||||
.irq_clear = ata_bmdma_irq_clear,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
|
||||
.port_start = ata_port_start,
|
||||
};
|
||||
|
||||
#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;
|
||||
void __iomem *io_addr, *ctl_addr;
|
||||
|
||||
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;
|
||||
|
||||
/* See if we have a manufacturer identifier. Use it to set is_kme for
|
||||
vendor quirks */
|
||||
is_kme = ((pdev->manf_id == MANFID_KME) &&
|
||||
((pdev->card_id == PRODID_KME_KXLC005_A) ||
|
||||
(pdev->card_id == PRODID_KME_KXLC005_B)));
|
||||
|
||||
/* Not sure if this is right... look up the current Vcc */
|
||||
CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(pdev, &stk->conf));
|
||||
/* link->conf.Vcc = stk->conf.Vcc; */
|
||||
|
||||
pass = io_base = ctl_base = 0;
|
||||
tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
|
||||
tuple.Attributes = 0;
|
||||
CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(pdev, &tuple));
|
||||
|
||||
/* Now munch the resources looking for a suitable set */
|
||||
while (1) {
|
||||
if (pcmcia_get_tuple_data(pdev, &tuple) != 0)
|
||||
goto next_entry;
|
||||
if (pcmcia_parse_tuple(pdev, &tuple, &stk->parse) != 0)
|
||||
goto next_entry;
|
||||
/* Check for matching Vcc, unless we're desperate */
|
||||
if (!pass) {
|
||||
if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) {
|
||||
if (stk->conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000)
|
||||
goto next_entry;
|
||||
} else if (stk->dflt.vcc.present & (1 << CISTPL_POWER_VNOM)) {
|
||||
if (stk->conf.Vcc != stk->dflt.vcc.param[CISTPL_POWER_VNOM] / 10000)
|
||||
goto next_entry;
|
||||
}
|
||||
}
|
||||
|
||||
if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM))
|
||||
pdev->conf.Vpp = cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
|
||||
else if (stk->dflt.vpp1.present & (1 << CISTPL_POWER_VNOM))
|
||||
pdev->conf.Vpp = stk->dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000;
|
||||
|
||||
if ((cfg->io.nwin > 0) || (stk->dflt.io.nwin > 0)) {
|
||||
cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &stk->dflt.io;
|
||||
pdev->conf.ConfigIndex = cfg->index;
|
||||
pdev->io.BasePort1 = io->win[0].base;
|
||||
pdev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
|
||||
if (!(io->flags & CISTPL_IO_16BIT))
|
||||
pdev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
|
||||
if (io->nwin == 2) {
|
||||
pdev->io.NumPorts1 = 8;
|
||||
pdev->io.BasePort2 = io->win[1].base;
|
||||
pdev->io.NumPorts2 = (is_kme) ? 2 : 1;
|
||||
if (pcmcia_request_io(pdev, &pdev->io) != 0)
|
||||
goto next_entry;
|
||||
io_base = pdev->io.BasePort1;
|
||||
ctl_base = pdev->io.BasePort2;
|
||||
} else if ((io->nwin == 1) && (io->win[0].len >= 16)) {
|
||||
pdev->io.NumPorts1 = io->win[0].len;
|
||||
pdev->io.NumPorts2 = 0;
|
||||
if (pcmcia_request_io(pdev, &pdev->io) != 0)
|
||||
goto next_entry;
|
||||
io_base = pdev->io.BasePort1;
|
||||
ctl_base = pdev->io.BasePort1 + 0x0e;
|
||||
} else goto next_entry;
|
||||
/* If we've got this far, we're done */
|
||||
break;
|
||||
}
|
||||
next_entry:
|
||||
if (cfg->flags & CISTPL_CFTABLE_DEFAULT)
|
||||
memcpy(&stk->dflt, cfg, sizeof(stk->dflt));
|
||||
if (pass) {
|
||||
CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(pdev, &tuple));
|
||||
} else if (pcmcia_get_next_tuple(pdev, &tuple) != 0) {
|
||||
CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(pdev, &tuple));
|
||||
memset(&stk->dflt, 0, sizeof(stk->dflt));
|
||||
pass++;
|
||||
}
|
||||
}
|
||||
|
||||
CS_CHECK(RequestIRQ, pcmcia_request_irq(pdev, &pdev->irq));
|
||||
CS_CHECK(RequestConfiguration, pcmcia_request_configuration(pdev, &pdev->conf));
|
||||
|
||||
/* iomap */
|
||||
ret = -ENOMEM;
|
||||
io_addr = devm_ioport_map(&pdev->dev, io_base, 8);
|
||||
ctl_addr = devm_ioport_map(&pdev->dev, ctl_base, 1);
|
||||
if (!io_addr || !ctl_addr)
|
||||
goto failed;
|
||||
|
||||
/* Success. Disable the IRQ nIEN line, do quirks */
|
||||
iowrite8(0x02, ctl_addr);
|
||||
if (is_kme)
|
||||
iowrite8(0x81, ctl_addr + 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 = IRQF_SHARED;
|
||||
ae.port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST;
|
||||
ae.port[0].cmd_addr = io_addr;
|
||||
ae.port[0].altstatus_addr = ctl_addr;
|
||||
ae.port[0].ctl_addr = ctl_addr;
|
||||
ata_std_ports(&ae.port[0]);
|
||||
|
||||
ret = -ENODEV;
|
||||
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_detach(host);
|
||||
}
|
||||
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(0x000a, 0x0000), /* I-O Data CFA */
|
||||
PCMCIA_DEVICE_MANF_CARD(0x001c, 0x0001), /* Mitsubishi CFA */
|
||||
PCMCIA_DEVICE_MANF_CARD(0x0032, 0x0704),
|
||||
PCMCIA_DEVICE_MANF_CARD(0x0045, 0x0401), /* SanDisk CFA */
|
||||
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, 0x0100), /* Viking CFA */
|
||||
PCMCIA_DEVICE_MANF_CARD(0x4e01, 0x0200), /* Lexar, Viking CFA */
|
||||
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_ID1("TRANSCEND 512M ", 0xd0909443),
|
||||
PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS1GCF80", 0x709b1bf1, 0x2a54d4b1),
|
||||
PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS4GCF120", 0x709b1bf1, 0xf54a91c8),
|
||||
PCMCIA_DEVICE_PROD_ID12("WIT", "IDE16", 0x244e5994, 0x3e232852),
|
||||
PCMCIA_DEVICE_PROD_ID12("WEIDA", "TWTTI", 0xcc7cf69c, 0x212bb918),
|
||||
PCMCIA_DEVICE_PROD_ID1("STI Flash", 0xe4a13209),
|
||||
PCMCIA_DEVICE_PROD_ID12("STI", "Flash 5.0", 0xbf2df18d, 0x8cb57a0e),
|
||||
PCMCIA_MFC_DEVICE_PROD_ID12(1, "SanDisk", "ConnectPlus", 0x7a954bd9, 0x74be00c6),
|
||||
PCMCIA_DEVICE_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);
|
||||
842
drivers/ata/pata_pdc2027x.c
Normal file
842
drivers/ata/pata_pdc2027x.c
Normal file
@@ -0,0 +1,842 @@
|
||||
/*
|
||||
* 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>
|
||||
|
||||
#define DRV_NAME "pata_pdc2027x"
|
||||
#define DRV_VERSION "0.8"
|
||||
#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_MMIO_BAR = 5,
|
||||
|
||||
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_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_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20268), PDC_UDMA_100 },
|
||||
{ PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20269), PDC_UDMA_133 },
|
||||
{ PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20270), PDC_UDMA_100 },
|
||||
{ PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20271), PDC_UDMA_133 },
|
||||
{ PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20275), PDC_UDMA_133 },
|
||||
{ PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20276), PDC_UDMA_133 },
|
||||
{ PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20277), 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 = ata_pci_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,
|
||||
.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 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_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,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
|
||||
.port_start = ata_port_start,
|
||||
};
|
||||
|
||||
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_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,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
|
||||
.port_start = ata_port_start,
|
||||
};
|
||||
|
||||
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->iomap[PDC_MMIO_BAR] + 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)
|
||||
{
|
||||
void __iomem *mmio_base = probe_ent->iomap[PDC_MMIO_BAR];
|
||||
long counter;
|
||||
int retry = 1;
|
||||
u32 bccrl, bccrh, bccrlv, bccrhv;
|
||||
|
||||
retry:
|
||||
bccrl = readl(mmio_base + PDC_BYTE_COUNT) & 0xffff;
|
||||
bccrh = readl(mmio_base + PDC_BYTE_COUNT + 0x100) & 0xffff;
|
||||
rmb();
|
||||
|
||||
/* Read the counter values again for verification */
|
||||
bccrlv = readl(mmio_base + PDC_BYTE_COUNT) & 0xffff;
|
||||
bccrhv = readl(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)
|
||||
{
|
||||
void __iomem *mmio_base = probe_ent->iomap[PDC_MMIO_BAR];
|
||||
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(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, mmio_base + PDC_PLL_CTL);
|
||||
readw(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(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)
|
||||
{
|
||||
void __iomem *mmio_base = probe_ent->iomap[PDC_MMIO_BAR];
|
||||
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(mmio_base + PDC_SYS_CTL);
|
||||
PDPRINTK("scr[%X]\n", scr);
|
||||
writel(scr | (0x01 << 14), mmio_base + PDC_SYS_CTL);
|
||||
readl(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(mmio_base + PDC_SYS_CTL);
|
||||
PDPRINTK("scr[%X]\n", scr);
|
||||
writel(scr & ~(0x01 << 14), mmio_base + PDC_SYS_CTL);
|
||||
readl(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, void __iomem *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;
|
||||
void __iomem *mmio_base;
|
||||
int rc;
|
||||
|
||||
if (!printed_version++)
|
||||
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
|
||||
|
||||
rc = pcim_enable_device(pdev);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = pcim_iomap_regions(pdev, 1 << PDC_MMIO_BAR, DRV_NAME);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* Prepare the probe entry */
|
||||
probe_ent = devm_kzalloc(&pdev->dev, sizeof(*probe_ent), GFP_KERNEL);
|
||||
if (probe_ent == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
probe_ent->dev = pci_dev_to_dev(pdev);
|
||||
INIT_LIST_HEAD(&probe_ent->node);
|
||||
|
||||
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 = IRQF_SHARED;
|
||||
probe_ent->iomap = pcim_iomap_table(pdev);
|
||||
|
||||
mmio_base = probe_ent->iomap[PDC_MMIO_BAR];
|
||||
|
||||
pdc_ata_setup_port(&probe_ent->port[0], mmio_base + 0x17c0);
|
||||
probe_ent->port[0].bmdma_addr = mmio_base + 0x1000;
|
||||
pdc_ata_setup_port(&probe_ent->port[1], mmio_base + 0x15c0);
|
||||
probe_ent->port[1].bmdma_addr = mmio_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)
|
||||
return -EIO;
|
||||
|
||||
if (!ata_device_add(probe_ent))
|
||||
return -ENODEV;
|
||||
|
||||
devm_kfree(&pdev->dev, probe_ent);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* pdc2027x_init - Called after this module is loaded into the kernel.
|
||||
*/
|
||||
static int __init pdc2027x_init(void)
|
||||
{
|
||||
return pci_register_driver(&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);
|
||||
433
drivers/ata/pata_pdc202xx_old.c
Normal file
433
drivers/ata/pata_pdc202xx_old.c
Normal file
@@ -0,0 +1,433 @@
|
||||
/*
|
||||
* pata_pdc202xx_old.c - Promise PDC202xx PATA for new ATA layer
|
||||
* (C) 2005 Red Hat Inc
|
||||
* Alan Cox <alan@redhat.com>
|
||||
* (C) 2007 Bartlomiej Zolnierkiewicz
|
||||
*
|
||||
* 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.4.0"
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* pdc202xx_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 pdc202xx_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 + 8 * ap->port_no + 4 * 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 &= ~0x1F;
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* pdc202xx_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 pdc202xx_set_piomode(struct ata_port *ap, struct ata_device *adev)
|
||||
{
|
||||
pdc202xx_configure_piomode(ap, adev, adev->pio_mode - XFER_PIO_0);
|
||||
}
|
||||
|
||||
/**
|
||||
* pdc202xx_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 pdc202xx_set_dmamode(struct ata_port *ap, struct ata_device *adev)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
|
||||
int port = 0x60 + 8 * ap->port_no + 4 * 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 }
|
||||
};
|
||||
static u8 mdma_timing[3][2] = {
|
||||
{ 0x60, 0x03 },
|
||||
{ 0x60, 0x04 },
|
||||
{ 0xe0, 0x0f },
|
||||
};
|
||||
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 &= ~0xE0;
|
||||
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 |= mdma_timing[speed][0];
|
||||
r_cp |= mdma_timing[speed][1];
|
||||
}
|
||||
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;
|
||||
|
||||
void __iomem *master = ap->host->ports[0]->ioaddr.bmdma_addr;
|
||||
void __iomem *clock = master + 0x11;
|
||||
void __iomem *atapi_reg = master + 0x20 + (4 * ap->port_no);
|
||||
|
||||
u32 len;
|
||||
|
||||
/* Check we keep host level locking here */
|
||||
if (adev->dma_mode >= XFER_UDMA_2)
|
||||
iowrite8(ioread8(clock) | sel66, clock);
|
||||
else
|
||||
iowrite8(ioread8(clock) & ~sel66, clock);
|
||||
|
||||
/* The DMA clocks may have been trashed by a reset. FIXME: make conditional
|
||||
and move to qc_issue ? */
|
||||
pdc202xx_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)
|
||||
{
|
||||
len = qc->nbytes / 2;
|
||||
|
||||
if (tf->flags & ATA_TFLAG_WRITE)
|
||||
len |= 0x06000000;
|
||||
else
|
||||
len |= 0x05000000;
|
||||
|
||||
iowrite32(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 */
|
||||
void __iomem *master = ap->host->ports[0]->ioaddr.bmdma_addr;
|
||||
void __iomem *clock = master + 0x11;
|
||||
void __iomem *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)) {
|
||||
iowrite32(0, atapi_reg);
|
||||
iowrite8(ioread8(clock) & ~sel66, clock);
|
||||
}
|
||||
/* Check we keep host level locking here */
|
||||
/* Flip back to 33Mhz for PIO */
|
||||
if (adev->dma_mode >= XFER_UDMA_2)
|
||||
iowrite8(ioread8(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 pdc202xx_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,
|
||||
#ifdef CONFIG_PM
|
||||
.resume = ata_scsi_device_resume,
|
||||
.suspend = ata_scsi_device_suspend,
|
||||
#endif
|
||||
};
|
||||
|
||||
static struct ata_port_operations pdc2024x_port_ops = {
|
||||
.port_disable = ata_port_disable,
|
||||
.set_piomode = pdc202xx_set_piomode,
|
||||
.set_dmamode = pdc202xx_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_data_xfer,
|
||||
|
||||
.irq_handler = ata_interrupt,
|
||||
.irq_clear = ata_bmdma_irq_clear,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
|
||||
.port_start = ata_port_start,
|
||||
};
|
||||
|
||||
static struct ata_port_operations pdc2026x_port_ops = {
|
||||
.port_disable = ata_port_disable,
|
||||
.set_piomode = pdc202xx_set_piomode,
|
||||
.set_dmamode = pdc202xx_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_data_xfer,
|
||||
|
||||
.irq_handler = ata_interrupt,
|
||||
.irq_clear = ata_bmdma_irq_clear,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
|
||||
.port_start = ata_port_start,
|
||||
};
|
||||
|
||||
static int pdc202xx_init_one(struct pci_dev *dev, const struct pci_device_id *id)
|
||||
{
|
||||
static struct ata_port_info info[3] = {
|
||||
{
|
||||
.sht = &pdc202xx_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 = &pdc202xx_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 = &pdc202xx_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 const struct pci_device_id pdc202xx[] = {
|
||||
{ PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20246), 0 },
|
||||
{ PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20262), 1 },
|
||||
{ PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20263), 1 },
|
||||
{ PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20265), 2 },
|
||||
{ PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20267), 2 },
|
||||
|
||||
{ },
|
||||
};
|
||||
|
||||
static struct pci_driver pdc202xx_pci_driver = {
|
||||
.name = DRV_NAME,
|
||||
.id_table = pdc202xx,
|
||||
.probe = pdc202xx_init_one,
|
||||
.remove = ata_pci_remove_one,
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = ata_pci_device_suspend,
|
||||
.resume = ata_pci_device_resume,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int __init pdc202xx_init(void)
|
||||
{
|
||||
return pci_register_driver(&pdc202xx_pci_driver);
|
||||
}
|
||||
|
||||
static void __exit pdc202xx_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&pdc202xx_pci_driver);
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("Alan Cox");
|
||||
MODULE_DESCRIPTION("low-level driver for Promise 2024x and 20262-20267");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DEVICE_TABLE(pci, pdc202xx);
|
||||
MODULE_VERSION(DRV_VERSION);
|
||||
|
||||
module_init(pdc202xx_init);
|
||||
module_exit(pdc202xx_exit);
|
||||
261
drivers/ata/pata_platform.c
Normal file
261
drivers/ata/pata_platform.c
Normal file
@@ -0,0 +1,261 @@
|
||||
/*
|
||||
* Generic platform device PATA driver
|
||||
*
|
||||
* Copyright (C) 2006 Paul Mundt
|
||||
*
|
||||
* Based on pata_pcmcia:
|
||||
*
|
||||
* Copyright 2005-2006 Red Hat Inc <alan@redhat.com>, all rights reserved.
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file "COPYING" in the main directory of this archive
|
||||
* for more details.
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/blkdev.h>
|
||||
#include <scsi/scsi_host.h>
|
||||
#include <linux/ata.h>
|
||||
#include <linux/libata.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pata_platform.h>
|
||||
|
||||
#define DRV_NAME "pata_platform"
|
||||
#define DRV_VERSION "0.1.2"
|
||||
|
||||
static int pio_mask = 1;
|
||||
|
||||
/*
|
||||
* Provide our own set_mode() as we don't want to change anything that has
|
||||
* already been configured..
|
||||
*/
|
||||
static int pata_platform_set_mode(struct ata_port *ap, struct ata_device **unused)
|
||||
{
|
||||
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 = dev->xfer_mode = XFER_PIO_0;
|
||||
dev->xfer_shift = ATA_SHIFT_PIO;
|
||||
dev->flags |= ATA_DFLAG_PIO;
|
||||
ata_dev_printk(dev, KERN_INFO, "configured for PIO\n");
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct scsi_host_template pata_platform_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 struct ata_port_operations pata_platform_port_ops = {
|
||||
.set_mode = pata_platform_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,
|
||||
|
||||
.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_data_xfer_noirq,
|
||||
|
||||
.irq_handler = ata_interrupt,
|
||||
.irq_clear = ata_bmdma_irq_clear,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
|
||||
.port_start = ata_port_start,
|
||||
};
|
||||
|
||||
static void pata_platform_setup_port(struct ata_ioports *ioaddr,
|
||||
struct pata_platform_info *info)
|
||||
{
|
||||
unsigned int shift = 0;
|
||||
|
||||
/* Fixup the port shift for platforms that need it */
|
||||
if (info && info->ioport_shift)
|
||||
shift = info->ioport_shift;
|
||||
|
||||
ioaddr->data_addr = ioaddr->cmd_addr + (ATA_REG_DATA << shift);
|
||||
ioaddr->error_addr = ioaddr->cmd_addr + (ATA_REG_ERR << shift);
|
||||
ioaddr->feature_addr = ioaddr->cmd_addr + (ATA_REG_FEATURE << shift);
|
||||
ioaddr->nsect_addr = ioaddr->cmd_addr + (ATA_REG_NSECT << shift);
|
||||
ioaddr->lbal_addr = ioaddr->cmd_addr + (ATA_REG_LBAL << shift);
|
||||
ioaddr->lbam_addr = ioaddr->cmd_addr + (ATA_REG_LBAM << shift);
|
||||
ioaddr->lbah_addr = ioaddr->cmd_addr + (ATA_REG_LBAH << shift);
|
||||
ioaddr->device_addr = ioaddr->cmd_addr + (ATA_REG_DEVICE << shift);
|
||||
ioaddr->status_addr = ioaddr->cmd_addr + (ATA_REG_STATUS << shift);
|
||||
ioaddr->command_addr = ioaddr->cmd_addr + (ATA_REG_CMD << shift);
|
||||
}
|
||||
|
||||
/**
|
||||
* pata_platform_probe - attach a platform interface
|
||||
* @pdev: platform device
|
||||
*
|
||||
* Register a platform bus IDE interface. Such interfaces are PIO and we
|
||||
* assume do not support IRQ sharing.
|
||||
*
|
||||
* Platform devices are expected to contain 3 resources per port:
|
||||
*
|
||||
* - I/O Base (IORESOURCE_IO or IORESOURCE_MEM)
|
||||
* - CTL Base (IORESOURCE_IO or IORESOURCE_MEM)
|
||||
* - IRQ (IORESOURCE_IRQ)
|
||||
*
|
||||
* If the base resources are both mem types, the ioremap() is handled
|
||||
* here. For IORESOURCE_IO, it's assumed that there's no remapping
|
||||
* necessary.
|
||||
*/
|
||||
static int __devinit pata_platform_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *io_res, *ctl_res;
|
||||
struct ata_probe_ent ae;
|
||||
unsigned int mmio;
|
||||
|
||||
/*
|
||||
* Simple resource validation ..
|
||||
*/
|
||||
if (unlikely(pdev->num_resources != 3)) {
|
||||
dev_err(&pdev->dev, "invalid number of resources\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the I/O base first
|
||||
*/
|
||||
io_res = platform_get_resource(pdev, IORESOURCE_IO, 0);
|
||||
if (io_res == NULL) {
|
||||
io_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (unlikely(io_res == NULL))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Then the CTL base
|
||||
*/
|
||||
ctl_res = platform_get_resource(pdev, IORESOURCE_IO, 1);
|
||||
if (ctl_res == NULL) {
|
||||
ctl_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
|
||||
if (unlikely(ctl_res == NULL))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check for MMIO
|
||||
*/
|
||||
mmio = (( io_res->flags == IORESOURCE_MEM) &&
|
||||
(ctl_res->flags == IORESOURCE_MEM));
|
||||
|
||||
/*
|
||||
* Now that that's out of the way, wire up the port..
|
||||
*/
|
||||
memset(&ae, 0, sizeof(struct ata_probe_ent));
|
||||
INIT_LIST_HEAD(&ae.node);
|
||||
ae.dev = &pdev->dev;
|
||||
ae.port_ops = &pata_platform_port_ops;
|
||||
ae.sht = &pata_platform_sht;
|
||||
ae.n_ports = 1;
|
||||
ae.pio_mask = pio_mask;
|
||||
ae.irq = platform_get_irq(pdev, 0);
|
||||
ae.irq_flags = 0;
|
||||
ae.port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST;
|
||||
|
||||
/*
|
||||
* Handle the MMIO case
|
||||
*/
|
||||
if (mmio) {
|
||||
ae.port[0].cmd_addr = devm_ioremap(&pdev->dev, io_res->start,
|
||||
io_res->end - io_res->start + 1);
|
||||
ae.port[0].ctl_addr = devm_ioremap(&pdev->dev, ctl_res->start,
|
||||
ctl_res->end - ctl_res->start + 1);
|
||||
} else {
|
||||
ae.port[0].cmd_addr = devm_ioport_map(&pdev->dev, io_res->start,
|
||||
io_res->end - io_res->start + 1);
|
||||
ae.port[0].ctl_addr = devm_ioport_map(&pdev->dev, ctl_res->start,
|
||||
ctl_res->end - ctl_res->start + 1);
|
||||
}
|
||||
if (!ae.port[0].cmd_addr || !ae.port[0].ctl_addr) {
|
||||
dev_err(&pdev->dev, "failed to map IO/CTL base\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ae.port[0].altstatus_addr = ae.port[0].ctl_addr;
|
||||
|
||||
pata_platform_setup_port(&ae.port[0], pdev->dev.platform_data);
|
||||
|
||||
if (unlikely(ata_device_add(&ae) == 0))
|
||||
return -ENODEV;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* pata_platform_remove - unplug a platform interface
|
||||
* @pdev: platform device
|
||||
*
|
||||
* A platform bus ATA device has been unplugged. Perform the needed
|
||||
* cleanup. Also called on module unload for any active devices.
|
||||
*/
|
||||
static int __devexit pata_platform_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct ata_host *host = dev_get_drvdata(dev);
|
||||
|
||||
ata_host_detach(host);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver pata_platform_driver = {
|
||||
.probe = pata_platform_probe,
|
||||
.remove = __devexit_p(pata_platform_remove),
|
||||
.driver = {
|
||||
.name = DRV_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init pata_platform_init(void)
|
||||
{
|
||||
return platform_driver_register(&pata_platform_driver);
|
||||
}
|
||||
|
||||
static void __exit pata_platform_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&pata_platform_driver);
|
||||
}
|
||||
module_init(pata_platform_init);
|
||||
module_exit(pata_platform_exit);
|
||||
|
||||
module_param(pio_mask, int, 0);
|
||||
|
||||
MODULE_AUTHOR("Paul Mundt");
|
||||
MODULE_DESCRIPTION("low-level driver for platform device ATA");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_VERSION(DRV_VERSION);
|
||||
419
drivers/ata/pata_qdi.c
Normal file
419
drivers/ata/pata_qdi.c
Normal file
@@ -0,0 +1,419 @@
|
||||
/*
|
||||
* pata_qdi.c - QDI VLB ATA controllers
|
||||
* (C) 2006 Red Hat <alan@redhat.com>
|
||||
*
|
||||
* This driver mostly exists as a proof of concept for non PCI devices under
|
||||
* libata. While the QDI6580 was 'neat' in 1993 it is no longer terribly
|
||||
* useful.
|
||||
*
|
||||
* Tuning code written from the documentation at
|
||||
* http://www.ryston.cz/petr/vlb/qd6500.html
|
||||
* http://www.ryston.cz/petr/vlb/qd6580.html
|
||||
*
|
||||
* Probe code based on drivers/ide/legacy/qd65xx.c
|
||||
* Rewritten from the work of Colten Edwards <pje120@cs.usask.ca> by
|
||||
* Samuel Thibault <samuel.thibault@fnac.net>
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/delay.h>
|
||||
#include <scsi/scsi_host.h>
|
||||
#include <linux/libata.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#define DRV_NAME "pata_qdi"
|
||||
#define DRV_VERSION "0.3.0"
|
||||
|
||||
#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)
|
||||
iowrite32_rep(ap->ioaddr.data_addr, buf, buflen >> 2);
|
||||
else
|
||||
ioread32_rep(ap->ioaddr.data_addr, buf, buflen >> 2);
|
||||
|
||||
if (unlikely(slop)) {
|
||||
u32 pad;
|
||||
if (write_data) {
|
||||
memcpy(&pad, buf + buflen - slop, slop);
|
||||
pad = le32_to_cpu(pad);
|
||||
iowrite32(pad, ap->ioaddr.data_addr);
|
||||
} else {
|
||||
pad = ioread32(ap->ioaddr.data_addr);
|
||||
pad = cpu_to_le32(pad);
|
||||
memcpy(buf + buflen - slop, &pad, slop);
|
||||
}
|
||||
}
|
||||
} else
|
||||
ata_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,
|
||||
.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 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,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
|
||||
.port_start = ata_port_start,
|
||||
};
|
||||
|
||||
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,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
|
||||
.port_start = ata_port_start,
|
||||
};
|
||||
|
||||
/**
|
||||
* 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;
|
||||
void __iomem *io_addr, *ctl_addr;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Fill in a probe structure first of all
|
||||
*/
|
||||
|
||||
pdev = platform_device_register_simple(DRV_NAME, nr_qdi_host, NULL, 0);
|
||||
if (IS_ERR(pdev))
|
||||
return PTR_ERR(pdev);
|
||||
|
||||
ret = -ENOMEM;
|
||||
io_addr = devm_ioport_map(&pdev->dev, io, 8);
|
||||
ctl_addr = devm_ioport_map(&pdev->dev, io + 0x206, 1);
|
||||
if (!io_addr || !ctl_addr)
|
||||
goto fail;
|
||||
|
||||
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;
|
||||
ae.port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST;
|
||||
} else {
|
||||
ae.port_ops = &qdi6500_port_ops;
|
||||
ae.pio_mask = 0x07; /* Actually PIO3 !IORDY is possible */
|
||||
ae.port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST |
|
||||
ATA_FLAG_NO_IORDY;
|
||||
}
|
||||
|
||||
ae.sht = &qdi_sht;
|
||||
ae.n_ports = 1;
|
||||
ae.irq = irq;
|
||||
ae.irq_flags = 0;
|
||||
ae.port[0].cmd_addr = io_addr;
|
||||
ae.port[0].altstatus_addr = ctl_addr;
|
||||
ae.port[0].ctl_addr = ctl_addr;
|
||||
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 = -ENODEV;
|
||||
if (!ata_device_add(&ae))
|
||||
goto fail;
|
||||
|
||||
qdi_host[nr_qdi_host++] = dev_get_drvdata(&pdev->dev);
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
platform_device_unregister(pdev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* qdi_init - attach qdi interfaces
|
||||
*
|
||||
* Attach qdi IDE interfaces by scanning the ports it may occupy.
|
||||
*/
|
||||
|
||||
static __init int qdi_init(void)
|
||||
{
|
||||
unsigned long flags;
|
||||
static const unsigned long qd_port[2] = { 0x30, 0xB0 };
|
||||
static const unsigned long ide_port[2] = { 0x170, 0x1F0 };
|
||||
static const int ide_irq[2] = { 14, 15 };
|
||||
|
||||
int ct = 0;
|
||||
int i;
|
||||
|
||||
if (probe_qdi == 0)
|
||||
return -ENODEV;
|
||||
|
||||
/*
|
||||
* Check each possible QD65xx base address
|
||||
*/
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
unsigned long port = qd_port[i];
|
||||
u8 r, res;
|
||||
|
||||
|
||||
if (request_region(port, 2, "pata_qdi")) {
|
||||
/* Check for a card */
|
||||
local_irq_save(flags);
|
||||
r = inb_p(port);
|
||||
outb_p(0x19, port);
|
||||
res = inb_p(port);
|
||||
outb_p(r, port);
|
||||
local_irq_restore(flags);
|
||||
|
||||
/* Fail */
|
||||
if (res == 0x19)
|
||||
{
|
||||
release_region(port, 2);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Passes the presence test */
|
||||
r = inb_p(port + 1); /* Check port agrees with port set */
|
||||
if ((r & 2) >> 1 != i) {
|
||||
release_region(port, 2);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Check card type */
|
||||
if ((r & 0xF0) == 0xC0) {
|
||||
/* QD6500: single channel */
|
||||
if (r & 8) {
|
||||
/* Disabled ? */
|
||||
release_region(port, 2);
|
||||
continue;
|
||||
}
|
||||
if (qdi_init_one(port, 6500, ide_port[r & 0x01], ide_irq[r & 0x01], r & 0x04) == 0)
|
||||
ct++;
|
||||
}
|
||||
if (((r & 0xF0) == 0xA0) || (r & 0xF0) == 0x50) {
|
||||
/* QD6580: dual channel */
|
||||
if (!request_region(port + 2 , 2, "pata_qdi"))
|
||||
{
|
||||
release_region(port, 2);
|
||||
continue;
|
||||
}
|
||||
res = inb(port + 3);
|
||||
if (res & 1) {
|
||||
/* Single channel mode */
|
||||
if (qdi_init_one(port, 6580, ide_port[r & 0x01], ide_irq[r & 0x01], r & 0x04))
|
||||
ct++;
|
||||
} else {
|
||||
/* Dual channel mode */
|
||||
if (qdi_init_one(port, 6580, 0x1F0, 14, r & 0x04) == 0)
|
||||
ct++;
|
||||
if (qdi_init_one(port + 2, 6580, 0x170, 15, r & 0x04) == 0)
|
||||
ct++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ct != 0)
|
||||
return 0;
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static __exit void qdi_exit(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < nr_qdi_host; i++) {
|
||||
ata_host_detach(qdi_host[i]);
|
||||
/* Free the control resource. The 6580 dual channel has the resources
|
||||
* claimed as a pair of 2 byte resources so we need no special cases...
|
||||
*/
|
||||
release_region(qdi_data[i].timing, 2);
|
||||
platform_device_unregister(qdi_data[i].platform_dev);
|
||||
}
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("Alan Cox");
|
||||
MODULE_DESCRIPTION("low-level driver for qdi ATA");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_VERSION(DRV_VERSION);
|
||||
|
||||
module_init(qdi_init);
|
||||
module_exit(qdi_exit);
|
||||
|
||||
module_param(probe_qdi, int, 0);
|
||||
|
||||
341
drivers/ata/pata_radisys.c
Normal file
341
drivers/ata/pata_radisys.c
Normal file
@@ -0,0 +1,341 @@
|
||||
/*
|
||||
* 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,
|
||||
.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,
|
||||
#ifdef CONFIG_PM
|
||||
.resume = ata_scsi_device_resume,
|
||||
.suspend = ata_scsi_device_suspend,
|
||||
#endif
|
||||
};
|
||||
|
||||
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_data_xfer,
|
||||
|
||||
.irq_handler = ata_interrupt,
|
||||
.irq_clear = ata_bmdma_irq_clear,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
|
||||
.port_start = ata_port_start,
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* 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[] = {
|
||||
{ PCI_VDEVICE(RADISYS, 0x8201), },
|
||||
|
||||
{ } /* 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,
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = ata_pci_device_suspend,
|
||||
.resume = ata_pci_device_resume,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int __init radisys_init(void)
|
||||
{
|
||||
return pci_register_driver(&radisys_pci_driver);
|
||||
}
|
||||
|
||||
static void __exit radisys_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&radisys_pci_driver);
|
||||
}
|
||||
|
||||
module_init(radisys_init);
|
||||
module_exit(radisys_exit);
|
||||
|
||||
MODULE_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);
|
||||
|
||||
230
drivers/ata/pata_rz1000.c
Normal file
230
drivers/ata/pata_rz1000.c
Normal file
@@ -0,0 +1,230 @@
|
||||
/*
|
||||
* 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.3"
|
||||
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @unused: returned device on set_mode failure
|
||||
*
|
||||
* 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 int rz1000_set_mode(struct ata_port *ap, struct ata_device **unused)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ATA_MAX_DEVICES; i++) {
|
||||
struct ata_device *dev = &ap->device[i];
|
||||
if (ata_dev_ready(dev)) {
|
||||
/* We don't really care */
|
||||
dev->pio_mode = XFER_PIO_0;
|
||||
dev->xfer_mode = XFER_PIO_0;
|
||||
dev->xfer_shift = ATA_SHIFT_PIO;
|
||||
dev->flags |= ATA_DFLAG_PIO;
|
||||
ata_dev_printk(dev, KERN_INFO, "configured for PIO\n");
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
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,
|
||||
.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,
|
||||
#ifdef CONFIG_PM
|
||||
.resume = ata_scsi_device_resume,
|
||||
.suspend = ata_scsi_device_suspend,
|
||||
#endif
|
||||
};
|
||||
|
||||
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,
|
||||
|
||||
.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_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,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
|
||||
.port_start = ata_port_start,
|
||||
};
|
||||
|
||||
static int rz1000_fifo_disable(struct pci_dev *pdev)
|
||||
{
|
||||
u16 reg;
|
||||
/* Be exceptionally paranoid as we must be sure to apply the fix */
|
||||
if (pci_read_config_word(pdev, 0x40, ®) != 0)
|
||||
return -1;
|
||||
reg &= 0xDFFF;
|
||||
if (pci_write_config_word(pdev, 0x40, reg) != 0)
|
||||
return -1;
|
||||
printk(KERN_INFO DRV_NAME ": disabled chipset readahead.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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];
|
||||
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");
|
||||
|
||||
if (rz1000_fifo_disable(pdev) == 0) {
|
||||
port_info[0] = &info;
|
||||
port_info[1] = &info;
|
||||
return ata_pci_init_one(pdev, port_info, 2);
|
||||
}
|
||||
printk(KERN_ERR DRV_NAME ": failed to disable read-ahead on chipset..\n");
|
||||
/* Not safe to use so skip */
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int rz1000_reinit_one(struct pci_dev *pdev)
|
||||
{
|
||||
/* If this fails on resume (which is a "cant happen" case), we
|
||||
must stop as any progress risks data loss */
|
||||
if (rz1000_fifo_disable(pdev))
|
||||
panic("rz1000 fifo");
|
||||
return ata_pci_device_resume(pdev);
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct pci_device_id pata_rz1000[] = {
|
||||
{ PCI_VDEVICE(PCTECH, PCI_DEVICE_ID_PCTECH_RZ1000), },
|
||||
{ PCI_VDEVICE(PCTECH, PCI_DEVICE_ID_PCTECH_RZ1001), },
|
||||
|
||||
{ },
|
||||
};
|
||||
|
||||
static struct pci_driver rz1000_pci_driver = {
|
||||
.name = DRV_NAME,
|
||||
.id_table = pata_rz1000,
|
||||
.probe = rz1000_init_one,
|
||||
.remove = ata_pci_remove_one,
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = ata_pci_device_suspend,
|
||||
.resume = rz1000_reinit_one,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int __init rz1000_init(void)
|
||||
{
|
||||
return pci_register_driver(&rz1000_pci_driver);
|
||||
}
|
||||
|
||||
static void __exit rz1000_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&rz1000_pci_driver);
|
||||
}
|
||||
|
||||
MODULE_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);
|
||||
|
||||
297
drivers/ata/pata_sc1200.c
Normal file
297
drivers/ata/pata_sc1200.c
Normal file
@@ -0,0 +1,297 @@
|
||||
/*
|
||||
* 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.4"
|
||||
|
||||
#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,
|
||||
.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,
|
||||
#ifdef CONFIG_PM
|
||||
.resume = ata_scsi_device_resume,
|
||||
.suspend = ata_scsi_device_suspend,
|
||||
#endif
|
||||
};
|
||||
|
||||
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,
|
||||
|
||||
.freeze = ata_bmdma_freeze,
|
||||
.thaw = ata_bmdma_thaw,
|
||||
.error_handler = ata_bmdma_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 = sc1200_qc_issue_prot,
|
||||
|
||||
.data_xfer = ata_data_xfer,
|
||||
|
||||
.irq_handler = ata_interrupt,
|
||||
.irq_clear = ata_bmdma_irq_clear,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
|
||||
.port_start = ata_port_start,
|
||||
};
|
||||
|
||||
/**
|
||||
* 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 const struct pci_device_id sc1200[] = {
|
||||
{ PCI_VDEVICE(NS, PCI_DEVICE_ID_NS_SCx200_IDE), },
|
||||
|
||||
{ },
|
||||
};
|
||||
|
||||
static struct pci_driver sc1200_pci_driver = {
|
||||
.name = DRV_NAME,
|
||||
.id_table = sc1200,
|
||||
.probe = sc1200_init_one,
|
||||
.remove = ata_pci_remove_one,
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = ata_pci_device_suspend,
|
||||
.resume = ata_pci_device_resume,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int __init sc1200_init(void)
|
||||
{
|
||||
return pci_register_driver(&sc1200_pci_driver);
|
||||
}
|
||||
|
||||
static void __exit sc1200_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&sc1200_pci_driver);
|
||||
}
|
||||
|
||||
MODULE_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);
|
||||
1230
drivers/ata/pata_scc.c
Normal file
1230
drivers/ata/pata_scc.c
Normal file
File diff suppressed because it is too large
Load Diff
617
drivers/ata/pata_serverworks.c
Normal file
617
drivers/ata/pata_serverworks.c
Normal file
@@ -0,0 +1,617 @@
|
||||
/*
|
||||
* 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.4.0"
|
||||
|
||||
#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[ATA_ID_PROD_LEN + 1];
|
||||
int i;
|
||||
|
||||
/* Disk, UDMA */
|
||||
if (adev->class != ATA_DEV_ATA)
|
||||
return ata_pci_default_filter(ap, adev, mask);
|
||||
|
||||
/* Actually do need to check */
|
||||
ata_id_c_string(adev->id, model_num, ATA_ID_PROD, sizeof(model_num));
|
||||
|
||||
for (i = 0; (p = csb_bad_ata100[i]) != NULL; i++) {
|
||||
if (!strcmp(p, model_num))
|
||||
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,
|
||||
.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,
|
||||
#ifdef CONFIG_PM
|
||||
.resume = ata_scsi_device_resume,
|
||||
.suspend = ata_scsi_device_suspend,
|
||||
#endif
|
||||
};
|
||||
|
||||
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_data_xfer,
|
||||
|
||||
.irq_handler = ata_interrupt,
|
||||
.irq_clear = ata_bmdma_irq_clear,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
|
||||
.port_start = ata_port_start,
|
||||
};
|
||||
|
||||
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_data_xfer,
|
||||
|
||||
.irq_handler = ata_interrupt,
|
||||
.irq_clear = ata_bmdma_irq_clear,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
|
||||
.port_start = ata_port_start,
|
||||
};
|
||||
|
||||
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 &= ~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, ®4c);
|
||||
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, ®41);
|
||||
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);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int serverworks_reinit_one(struct pci_dev *pdev)
|
||||
{
|
||||
/* Force master latency timer to 64 PCI clocks */
|
||||
pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x40);
|
||||
|
||||
switch (pdev->device)
|
||||
{
|
||||
case PCI_DEVICE_ID_SERVERWORKS_OSB4IDE:
|
||||
serverworks_fixup_osb4(pdev);
|
||||
break;
|
||||
case PCI_DEVICE_ID_SERVERWORKS_CSB5IDE:
|
||||
ata_pci_clear_simplex(pdev);
|
||||
/* fall through */
|
||||
case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE:
|
||||
case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2:
|
||||
serverworks_fixup_csb(pdev);
|
||||
break;
|
||||
case PCI_DEVICE_ID_SERVERWORKS_HT1000IDE:
|
||||
serverworks_fixup_ht1000(pdev);
|
||||
break;
|
||||
}
|
||||
return ata_pci_device_resume(pdev);
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct pci_device_id serverworks[] = {
|
||||
{ PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4IDE), 0},
|
||||
{ PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5IDE), 2},
|
||||
{ PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6IDE), 2},
|
||||
{ PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2), 2},
|
||||
{ PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_HT1000IDE), 2},
|
||||
|
||||
{ },
|
||||
};
|
||||
|
||||
static struct pci_driver serverworks_pci_driver = {
|
||||
.name = DRV_NAME,
|
||||
.id_table = serverworks,
|
||||
.probe = serverworks_init_one,
|
||||
.remove = ata_pci_remove_one,
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = ata_pci_device_suspend,
|
||||
.resume = serverworks_reinit_one,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int __init serverworks_init(void)
|
||||
{
|
||||
return pci_register_driver(&serverworks_pci_driver);
|
||||
}
|
||||
|
||||
static void __exit serverworks_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&serverworks_pci_driver);
|
||||
}
|
||||
|
||||
MODULE_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);
|
||||
426
drivers/ata/pata_sil680.c
Normal file
426
drivers/ata/pata_sil680.c
Normal file
@@ -0,0 +1,426 @@
|
||||
/*
|
||||
* 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.4.5"
|
||||
|
||||
/**
|
||||
* 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, 0x2283, 0x1281, 0x10C3, 0x10C1 };
|
||||
|
||||
unsigned long tfaddr = sil680_selreg(ap, 0x02);
|
||||
unsigned long addr = sil680_seldev(ap, adev, 0x04);
|
||||
unsigned long addr_mask = 0x80 + 4 * ap->port_no;
|
||||
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
|
||||
int pio = adev->pio_mode - XFER_PIO_0;
|
||||
int lowest_pio = pio;
|
||||
int port_shift = 4 * adev->devno;
|
||||
u16 reg;
|
||||
u8 mode;
|
||||
|
||||
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, ®);
|
||||
pci_read_config_byte(pdev, addr_mask, &mode);
|
||||
|
||||
reg &= ~0x0200; /* Clear IORDY */
|
||||
mode &= ~(3 << port_shift); /* Clear IORDY and DMA bits */
|
||||
|
||||
if (ata_pio_need_iordy(adev)) {
|
||||
reg |= 0x0200; /* Enable IORDY */
|
||||
mode |= 1 << port_shift;
|
||||
}
|
||||
pci_write_config_word(pdev, tfaddr-2, reg);
|
||||
pci_write_config_byte(pdev, addr_mask, mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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,
|
||||
.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,
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = ata_scsi_device_suspend,
|
||||
.resume = ata_scsi_device_resume,
|
||||
#endif
|
||||
};
|
||||
|
||||
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_data_xfer,
|
||||
|
||||
.irq_handler = ata_interrupt,
|
||||
.irq_clear = ata_bmdma_irq_clear,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
|
||||
.port_start = ata_port_start,
|
||||
};
|
||||
|
||||
/**
|
||||
* sil680_init_chip - chip setup
|
||||
* @pdev: PCI device
|
||||
*
|
||||
* Perform all the chip setup which must be done both when the device
|
||||
* is powered up on boot and when we resume in case we resumed from RAM.
|
||||
* Returns the final clock settings.
|
||||
*/
|
||||
|
||||
static u8 sil680_init_chip(struct pci_dev *pdev)
|
||||
{
|
||||
u32 class_rev = 0;
|
||||
u8 tmpbyte = 0;
|
||||
|
||||
pci_read_config_dword(pdev, PCI_CLASS_REVISION, &class_rev);
|
||||
class_rev &= 0xff;
|
||||
/* FIXME: double check */
|
||||
pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, (class_rev) ? 1 : 255);
|
||||
|
||||
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);
|
||||
|
||||
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 tmpbyte & 0x30;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (!printed_version++)
|
||||
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
|
||||
|
||||
switch(sil680_init_chip(pdev))
|
||||
{
|
||||
case 0:
|
||||
port_info[0] = port_info[1] = &info_slow;
|
||||
break;
|
||||
case 0x30:
|
||||
return -ENODEV;
|
||||
}
|
||||
return ata_pci_init_one(pdev, port_info, 2);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int sil680_reinit_one(struct pci_dev *pdev)
|
||||
{
|
||||
sil680_init_chip(pdev);
|
||||
return ata_pci_device_resume(pdev);
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct pci_device_id sil680[] = {
|
||||
{ PCI_VDEVICE(CMD, PCI_DEVICE_ID_SII_680), },
|
||||
|
||||
{ },
|
||||
};
|
||||
|
||||
static struct pci_driver sil680_pci_driver = {
|
||||
.name = DRV_NAME,
|
||||
.id_table = sil680,
|
||||
.probe = sil680_init_one,
|
||||
.remove = ata_pci_remove_one,
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = ata_pci_device_suspend,
|
||||
.resume = sil680_reinit_one,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int __init sil680_init(void)
|
||||
{
|
||||
return pci_register_driver(&sil680_pci_driver);
|
||||
}
|
||||
|
||||
static void __exit sil680_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&sil680_pci_driver);
|
||||
}
|
||||
|
||||
MODULE_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);
|
||||
1063
drivers/ata/pata_sis.c
Normal file
1063
drivers/ata/pata_sis.c
Normal file
File diff suppressed because it is too large
Load Diff
369
drivers/ata/pata_sl82c105.c
Normal file
369
drivers/ata/pata_sl82c105.c
Normal file
@@ -0,0 +1,369 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
*
|
||||
* Note: The controller like many controllers has shared timings for
|
||||
* PIO and DMA. We thus flip to the DMA timings in dma_start and flip back
|
||||
* in the dma_stop function. Thus we actually don't need a set_dmamode
|
||||
* method as the PIO method is always called and will set the right PIO
|
||||
* timing parameters.
|
||||
*/
|
||||
|
||||
#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.3.0"
|
||||
|
||||
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_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;
|
||||
|
||||
udelay(100);
|
||||
sl82c105_reset_engine(ap);
|
||||
udelay(100);
|
||||
|
||||
/* 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);
|
||||
udelay(100);
|
||||
|
||||
/* This will redo the initial setup of the DMA device to matching
|
||||
PIO timings */
|
||||
sl82c105_set_piomode(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,
|
||||
.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 struct ata_port_operations sl82c105_port_ops = {
|
||||
.port_disable = ata_port_disable,
|
||||
.set_piomode = sl82c105_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 = sl82c105_error_handler,
|
||||
.post_internal_cmd = ata_bmdma_post_internal_cmd,
|
||||
|
||||
.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_data_xfer,
|
||||
|
||||
.irq_handler = ata_interrupt,
|
||||
.irq_clear = ata_bmdma_irq_clear,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
|
||||
.port_start = ata_port_start,
|
||||
};
|
||||
|
||||
/**
|
||||
* 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 const struct pci_device_id sl82c105[] = {
|
||||
{ PCI_VDEVICE(WINBOND, PCI_DEVICE_ID_WINBOND_82C105), },
|
||||
|
||||
{ },
|
||||
};
|
||||
|
||||
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);
|
||||
288
drivers/ata/pata_triflex.c
Normal file
288
drivers/ata/pata_triflex.c
Normal file
@@ -0,0 +1,288 @@
|
||||
/*
|
||||
* 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.7"
|
||||
|
||||
/**
|
||||
* 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,
|
||||
.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,
|
||||
#ifdef CONFIG_PM
|
||||
.resume = ata_scsi_device_resume,
|
||||
.suspend = ata_scsi_device_suspend,
|
||||
#endif
|
||||
};
|
||||
|
||||
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_data_xfer,
|
||||
|
||||
.irq_handler = ata_interrupt,
|
||||
.irq_clear = ata_bmdma_irq_clear,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
|
||||
.port_start = ata_port_start,
|
||||
};
|
||||
|
||||
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_VDEVICE(COMPAQ, PCI_DEVICE_ID_COMPAQ_TRIFLEX_IDE), },
|
||||
|
||||
{ },
|
||||
};
|
||||
|
||||
static struct pci_driver triflex_pci_driver = {
|
||||
.name = DRV_NAME,
|
||||
.id_table = triflex,
|
||||
.probe = triflex_init_one,
|
||||
.remove = ata_pci_remove_one,
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = ata_pci_device_suspend,
|
||||
.resume = ata_pci_device_resume,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int __init triflex_init(void)
|
||||
{
|
||||
return pci_register_driver(&triflex_pci_driver);
|
||||
}
|
||||
|
||||
static void __exit triflex_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&triflex_pci_driver);
|
||||
}
|
||||
|
||||
MODULE_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);
|
||||
637
drivers/ata/pata_via.c
Normal file
637
drivers/ata/pata_via.c
Normal file
@@ -0,0 +1,637 @@
|
||||
/*
|
||||
* 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
|
||||
* VIA VT8237S - UDMA133
|
||||
* VIA VT8251 - 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.2.1"
|
||||
|
||||
/*
|
||||
* 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[] = {
|
||||
{ "vt8237s", PCI_DEVICE_ID_VIA_8237S, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
|
||||
{ "vt8251", PCI_DEVICE_ID_VIA_8251, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
|
||||
{ "cx700", PCI_DEVICE_ID_VIA_CX700, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
|
||||
{ "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_100)
|
||||
ap->cbl = via_cable_detect(ap);
|
||||
/* The UDMA66 series has no cable detect so do drive side detect */
|
||||
else if ((config->flags & VIA_UDMA) < VIA_UDMA_66)
|
||||
ap->cbl = ATA_CBL_PATA40;
|
||||
else
|
||||
ap->cbl = ATA_CBL_PATA_UNK;
|
||||
|
||||
|
||||
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,
|
||||
.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,
|
||||
#ifdef CONFIG_PM
|
||||
.resume = ata_scsi_device_resume,
|
||||
.suspend = ata_scsi_device_suspend,
|
||||
#endif
|
||||
};
|
||||
|
||||
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_data_xfer,
|
||||
|
||||
.irq_handler = ata_interrupt,
|
||||
.irq_clear = ata_bmdma_irq_clear,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
|
||||
.port_start = ata_port_start,
|
||||
};
|
||||
|
||||
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_data_xfer_noirq,
|
||||
|
||||
.irq_handler = ata_interrupt,
|
||||
.irq_clear = ata_bmdma_irq_clear,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
|
||||
.port_start = ata_port_start,
|
||||
};
|
||||
|
||||
/**
|
||||
* via_config_fifo - set up the FIFO
|
||||
* @pdev: PCI device
|
||||
* @flags: configuration flags
|
||||
*
|
||||
* Set the FIFO properties for this device if neccessary. Used both on
|
||||
* set up and on and the resume path
|
||||
*/
|
||||
|
||||
static void via_config_fifo(struct pci_dev *pdev, unsigned int flags)
|
||||
{
|
||||
u8 enable;
|
||||
|
||||
/* 0x40 low bits indicate enabled channels */
|
||||
pci_read_config_byte(pdev, 0x40 , &enable);
|
||||
enable &= 3;
|
||||
|
||||
if (flags & VIA_SET_FIFO) {
|
||||
static const u8 fifo_setting[4] = {0x00, 0x60, 0x00, 0x20};
|
||||
u8 fifo;
|
||||
|
||||
pci_read_config_byte(pdev, 0x43, &fifo);
|
||||
|
||||
/* Clear PREQ# until DDACK# for errata */
|
||||
if (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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* via_init_one - discovery callback
|
||||
* @pdev: PCI device
|
||||
* @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_SETXFER_POLLING,
|
||||
.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_SETXFER_POLLING,
|
||||
.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_SETXFER_POLLING,
|
||||
.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_SETXFER_POLLING,
|
||||
.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_SETXFER_POLLING,
|
||||
.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_SETXFER_POLLING,
|
||||
.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. */
|
||||
via_config_fifo(pdev, config->flags);
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
/**
|
||||
* via_reinit_one - reinit after resume
|
||||
* @pdev; PCI device
|
||||
*
|
||||
* Called when the VIA PATA device is resumed. We must then
|
||||
* reconfigure the fifo and other setup we may have altered. In
|
||||
* addition the kernel needs to have the resume methods on PCI
|
||||
* quirk supported.
|
||||
*/
|
||||
|
||||
static int via_reinit_one(struct pci_dev *pdev)
|
||||
{
|
||||
u32 timing;
|
||||
struct ata_host *host = dev_get_drvdata(&pdev->dev);
|
||||
const struct via_isa_bridge *config = host->private_data;
|
||||
|
||||
via_config_fifo(pdev, config->flags);
|
||||
|
||||
if ((config->flags & VIA_UDMA) == VIA_UDMA_66) {
|
||||
/* The 66 MHz devices require we enable the clock */
|
||||
pci_read_config_dword(pdev, 0x50, &timing);
|
||||
timing |= 0x80008;
|
||||
pci_write_config_dword(pdev, 0x50, timing);
|
||||
}
|
||||
if (config->flags & VIA_BAD_CLK66) {
|
||||
/* Disable the 66MHz clock on problem devices */
|
||||
pci_read_config_dword(pdev, 0x50, &timing);
|
||||
timing &= ~0x80008;
|
||||
pci_write_config_dword(pdev, 0x50, timing);
|
||||
}
|
||||
return ata_pci_device_resume(pdev);
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct pci_device_id via[] = {
|
||||
{ PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_82C576_1), },
|
||||
{ PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_82C586_1), },
|
||||
{ PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_6410), },
|
||||
{ PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_SATA_EIDE), },
|
||||
|
||||
{ },
|
||||
};
|
||||
|
||||
static struct pci_driver via_pci_driver = {
|
||||
.name = DRV_NAME,
|
||||
.id_table = via,
|
||||
.probe = via_init_one,
|
||||
.remove = ata_pci_remove_one,
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = ata_pci_device_suspend,
|
||||
.resume = via_reinit_one,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int __init via_init(void)
|
||||
{
|
||||
return pci_register_driver(&via_pci_driver);
|
||||
}
|
||||
|
||||
static void __exit via_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&via_pci_driver);
|
||||
}
|
||||
|
||||
MODULE_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);
|
||||
317
drivers/ata/pata_winbond.c
Normal file
317
drivers/ata/pata_winbond.c
Normal file
@@ -0,0 +1,317 @@
|
||||
/*
|
||||
* pata_winbond.c - Winbond VLB ATA controllers
|
||||
* (C) 2006 Red Hat <alan@redhat.com>
|
||||
*
|
||||
* Support for the Winbond 83759A when operating in advanced mode.
|
||||
* Multichip mode is not currently supported.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/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_winbond"
|
||||
#define DRV_VERSION "0.0.2"
|
||||
|
||||
#define NR_HOST 4 /* Two winbond controllers, two channels each */
|
||||
|
||||
struct winbond_data {
|
||||
unsigned long config;
|
||||
struct platform_device *platform_dev;
|
||||
};
|
||||
|
||||
static struct ata_host *winbond_host[NR_HOST];
|
||||
static struct winbond_data winbond_data[NR_HOST];
|
||||
static int nr_winbond_host;
|
||||
|
||||
#ifdef MODULE
|
||||
static int probe_winbond = 1;
|
||||
#else
|
||||
static int probe_winbond;
|
||||
#endif
|
||||
|
||||
static spinlock_t winbond_lock = SPIN_LOCK_UNLOCKED;
|
||||
|
||||
static void winbond_writecfg(unsigned long port, u8 reg, u8 val)
|
||||
{
|
||||
unsigned long flags;
|
||||
spin_lock_irqsave(&winbond_lock, flags);
|
||||
outb(reg, port + 0x01);
|
||||
outb(val, port + 0x02);
|
||||
spin_unlock_irqrestore(&winbond_lock, flags);
|
||||
}
|
||||
|
||||
static u8 winbond_readcfg(unsigned long port, u8 reg)
|
||||
{
|
||||
u8 val;
|
||||
|
||||
unsigned long flags;
|
||||
spin_lock_irqsave(&winbond_lock, flags);
|
||||
outb(reg, port + 0x01);
|
||||
val = inb(port + 0x02);
|
||||
spin_unlock_irqrestore(&winbond_lock, flags);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static void winbond_set_piomode(struct ata_port *ap, struct ata_device *adev)
|
||||
{
|
||||
struct ata_timing t;
|
||||
struct winbond_data *winbond = ap->host->private_data;
|
||||
int active, recovery;
|
||||
u8 reg;
|
||||
int timing = 0x88 + (ap->port_no * 4) + (adev->devno * 2);
|
||||
|
||||
reg = winbond_readcfg(winbond->config, 0x81);
|
||||
|
||||
/* Get the timing data in cycles */
|
||||
if (reg & 0x40) /* Fast VLB bus, assume 50MHz */
|
||||
ata_timing_compute(adev, adev->pio_mode, &t, 20000, 1000);
|
||||
else
|
||||
ata_timing_compute(adev, adev->pio_mode, &t, 30303, 1000);
|
||||
|
||||
active = (FIT(t.active, 3, 17) - 1) & 0x0F;
|
||||
recovery = (FIT(t.recover, 1, 15) + 1) & 0x0F;
|
||||
timing = (active << 4) | recovery;
|
||||
winbond_writecfg(winbond->config, timing, reg);
|
||||
|
||||
/* Load the setup timing */
|
||||
|
||||
reg = 0x35;
|
||||
if (adev->class != ATA_DEV_ATA)
|
||||
reg |= 0x08; /* FIFO off */
|
||||
if (!ata_pio_need_iordy(adev))
|
||||
reg |= 0x02; /* IORDY off */
|
||||
reg |= (FIT(t.setup, 0, 3) << 6);
|
||||
winbond_writecfg(winbond->config, timing + 1, reg);
|
||||
}
|
||||
|
||||
|
||||
static void winbond_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)
|
||||
iowrite32_rep(ap->ioaddr.data_addr, buf, buflen >> 2);
|
||||
else
|
||||
ioread32_rep(ap->ioaddr.data_addr, buf, buflen >> 2);
|
||||
|
||||
if (unlikely(slop)) {
|
||||
u32 pad;
|
||||
if (write_data) {
|
||||
memcpy(&pad, buf + buflen - slop, slop);
|
||||
pad = le32_to_cpu(pad);
|
||||
iowrite32(pad, ap->ioaddr.data_addr);
|
||||
} else {
|
||||
pad = ioread32(ap->ioaddr.data_addr);
|
||||
pad = cpu_to_le16(pad);
|
||||
memcpy(buf + buflen - slop, &pad, slop);
|
||||
}
|
||||
}
|
||||
} else
|
||||
ata_data_xfer(adev, buf, buflen, write_data);
|
||||
}
|
||||
|
||||
static struct scsi_host_template winbond_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 struct ata_port_operations winbond_port_ops = {
|
||||
.port_disable = ata_port_disable,
|
||||
.set_piomode = winbond_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 = ata_qc_issue_prot,
|
||||
|
||||
.data_xfer = winbond_data_xfer,
|
||||
|
||||
.irq_handler = ata_interrupt,
|
||||
.irq_clear = ata_bmdma_irq_clear,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
|
||||
.port_start = ata_port_start,
|
||||
};
|
||||
|
||||
/**
|
||||
* winbond_init_one - attach a winbond interface
|
||||
* @type: Type to display
|
||||
* @io: I/O port start
|
||||
* @irq: interrupt line
|
||||
* @fast: True if on a > 33Mhz VLB
|
||||
*
|
||||
* Register a VLB bus IDE interface. Such interfaces are PIO and we
|
||||
* assume do not support IRQ sharing.
|
||||
*/
|
||||
|
||||
static __init int winbond_init_one(unsigned long port)
|
||||
{
|
||||
struct ata_probe_ent ae;
|
||||
struct platform_device *pdev;
|
||||
int ret;
|
||||
u8 reg;
|
||||
int i;
|
||||
|
||||
reg = winbond_readcfg(port, 0x81);
|
||||
reg |= 0x80; /* jumpered mode off */
|
||||
winbond_writecfg(port, 0x81, reg);
|
||||
reg = winbond_readcfg(port, 0x83);
|
||||
reg |= 0xF0; /* local control */
|
||||
winbond_writecfg(port, 0x83, reg);
|
||||
reg = winbond_readcfg(port, 0x85);
|
||||
reg |= 0xF0; /* programmable timing */
|
||||
winbond_writecfg(port, 0x85, reg);
|
||||
|
||||
reg = winbond_readcfg(port, 0x81);
|
||||
|
||||
if (!(reg & 0x03)) /* Disabled */
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < 2 ; i ++) {
|
||||
unsigned long cmd_port = 0x1F0 - (0x80 * i);
|
||||
void __iomem *cmd_addr, *ctl_addr;
|
||||
|
||||
if (reg & (1 << i)) {
|
||||
/*
|
||||
* Fill in a probe structure first of all
|
||||
*/
|
||||
|
||||
pdev = platform_device_register_simple(DRV_NAME, nr_winbond_host, NULL, 0);
|
||||
if (IS_ERR(pdev))
|
||||
return PTR_ERR(pdev);
|
||||
|
||||
cmd_addr = devm_ioport_map(&pdev->dev, cmd_port, 8);
|
||||
ctl_addr = devm_ioport_map(&pdev->dev, cmd_port + 0x0206, 1);
|
||||
if (!cmd_addr || !ctl_addr) {
|
||||
platform_device_unregister(pdev);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
memset(&ae, 0, sizeof(struct ata_probe_ent));
|
||||
INIT_LIST_HEAD(&ae.node);
|
||||
ae.dev = &pdev->dev;
|
||||
|
||||
ae.port_ops = &winbond_port_ops;
|
||||
ae.pio_mask = 0x1F;
|
||||
|
||||
ae.sht = &winbond_sht;
|
||||
|
||||
ae.n_ports = 1;
|
||||
ae.irq = 14 + i;
|
||||
ae.irq_flags = 0;
|
||||
ae.port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST;
|
||||
ae.port[0].cmd_addr = cmd_addr;
|
||||
ae.port[0].altstatus_addr = ctl_addr;
|
||||
ae.port[0].ctl_addr = ctl_addr;
|
||||
ata_std_ports(&ae.port[0]);
|
||||
/*
|
||||
* Hook in a private data structure per channel
|
||||
*/
|
||||
ae.private_data = &winbond_data[nr_winbond_host];
|
||||
winbond_data[nr_winbond_host].config = port;
|
||||
winbond_data[nr_winbond_host].platform_dev = pdev;
|
||||
|
||||
ret = ata_device_add(&ae);
|
||||
if (ret == 0) {
|
||||
platform_device_unregister(pdev);
|
||||
return -ENODEV;
|
||||
}
|
||||
winbond_host[nr_winbond_host++] = dev_get_drvdata(&pdev->dev);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* winbond_init - attach winbond interfaces
|
||||
*
|
||||
* Attach winbond IDE interfaces by scanning the ports it may occupy.
|
||||
*/
|
||||
|
||||
static __init int winbond_init(void)
|
||||
{
|
||||
static const unsigned long config[2] = { 0x130, 0x1B0 };
|
||||
|
||||
int ct = 0;
|
||||
int i;
|
||||
|
||||
if (probe_winbond == 0)
|
||||
return -ENODEV;
|
||||
|
||||
/*
|
||||
* Check both base addresses
|
||||
*/
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
if (probe_winbond & (1<<i)) {
|
||||
int ret = 0;
|
||||
unsigned long port = config[i];
|
||||
|
||||
if (request_region(port, 2, "pata_winbond")) {
|
||||
ret = winbond_init_one(port);
|
||||
if(ret <= 0)
|
||||
release_region(port, 2);
|
||||
else ct+= ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ct != 0)
|
||||
return 0;
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static __exit void winbond_exit(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < nr_winbond_host; i++) {
|
||||
ata_host_detach(winbond_host[i]);
|
||||
release_region(winbond_data[i].config, 2);
|
||||
platform_device_unregister(winbond_data[i].platform_dev);
|
||||
}
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("Alan Cox");
|
||||
MODULE_DESCRIPTION("low-level driver for Winbond VL ATA");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_VERSION(DRV_VERSION);
|
||||
|
||||
module_init(winbond_init);
|
||||
module_exit(winbond_exit);
|
||||
|
||||
module_param(probe_winbond, int, 0);
|
||||
|
||||
703
drivers/ata/pdc_adma.c
Normal file
703
drivers/ata/pdc_adma.c
Normal file
@@ -0,0 +1,703 @@
|
||||
/*
|
||||
* 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/device.h>
|
||||
#include <scsi/scsi_host.h>
|
||||
#include <linux/libata.h>
|
||||
|
||||
#define DRV_NAME "pdc_adma"
|
||||
#define DRV_VERSION "0.05"
|
||||
|
||||
/* 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))
|
||||
|
||||
/* macro to obtain addresses from ata_host */
|
||||
#define ADMA_HOST_REGS(host,port_no) \
|
||||
ADMA_REGS((host)->iomap[ADMA_MMIO_BAR], port_no)
|
||||
|
||||
enum {
|
||||
ADMA_MMIO_BAR = 4,
|
||||
|
||||
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);
|
||||
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_data_xfer,
|
||||
.irq_handler = adma_intr,
|
||||
.irq_clear = adma_irq_clear,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
.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_VDEVICE(PDC, 0x1841), 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 *chan = ADMA_HOST_REGS(ap->host, ap->port_no);
|
||||
|
||||
/* mask/clear ATA interrupts */
|
||||
writeb(ATA_NIEN, 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_HOST_REGS(ap->host, 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_HOST_REGS(ap->host, 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;
|
||||
|
||||
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_HOST_REGS(host, 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->print_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 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, void __iomem *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);
|
||||
pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
|
||||
if (!pp)
|
||||
return -ENOMEM;
|
||||
pp->pkt = dmam_alloc_coherent(dev, ADMA_PKT_BYTES, &pp->pkt_dma,
|
||||
GFP_KERNEL);
|
||||
if (!pp->pkt)
|
||||
return -ENOMEM;
|
||||
/* paranoia? */
|
||||
if ((pp->pkt_dma & 7) != 0) {
|
||||
printk("bad alignment for pp->pkt_dma: %08x\n",
|
||||
(u32)pp->pkt_dma);
|
||||
return -ENOMEM;
|
||||
}
|
||||
memset(pp->pkt, 0, ADMA_PKT_BYTES);
|
||||
ap->private_data = pp;
|
||||
adma_reinit_engine(ap);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void adma_port_stop(struct ata_port *ap)
|
||||
{
|
||||
adma_reset_engine(ADMA_HOST_REGS(ap->host, ap->port_no));
|
||||
}
|
||||
|
||||
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_HOST_REGS(host, port_no));
|
||||
}
|
||||
|
||||
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->iomap[ADMA_MMIO_BAR];
|
||||
|
||||
/* 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 = pcim_enable_device(pdev);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if ((pci_resource_flags(pdev, 4) & IORESOURCE_MEM) == 0)
|
||||
return -ENODEV;
|
||||
|
||||
rc = pcim_iomap_regions(pdev, 1 << ADMA_MMIO_BAR, DRV_NAME);
|
||||
if (rc)
|
||||
return rc;
|
||||
mmio_base = pcim_iomap_table(pdev)[ADMA_MMIO_BAR];
|
||||
|
||||
rc = adma_set_dma_masks(pdev, mmio_base);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
probe_ent = devm_kzalloc(&pdev->dev, sizeof(*probe_ent), GFP_KERNEL);
|
||||
if (probe_ent == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
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->n_ports = ADMA_PORTS;
|
||||
probe_ent->iomap = pcim_iomap_table(pdev);
|
||||
|
||||
for (port_no = 0; port_no < probe_ent->n_ports; ++port_no) {
|
||||
adma_ata_setup_port(&probe_ent->port[port_no],
|
||||
ADMA_ATA_REGS(mmio_base, port_no));
|
||||
}
|
||||
|
||||
pci_set_master(pdev);
|
||||
|
||||
/* initialize adapter */
|
||||
adma_host_init(board_idx, probe_ent);
|
||||
|
||||
if (!ata_device_add(probe_ent))
|
||||
return -ENODEV;
|
||||
|
||||
devm_kfree(&pdev->dev, probe_ent);
|
||||
return 0;
|
||||
}
|
||||
|
||||
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);
|
||||
782
drivers/ata/sata_inic162x.c
Normal file
782
drivers/ata/sata_inic162x.c
Normal file
@@ -0,0 +1,782 @@
|
||||
/*
|
||||
* sata_inic162x.c - Driver for Initio 162x SATA controllers
|
||||
*
|
||||
* Copyright 2006 SUSE Linux Products GmbH
|
||||
* Copyright 2006 Tejun Heo <teheo@novell.com>
|
||||
*
|
||||
* This file is released under GPL v2.
|
||||
*
|
||||
* This controller is eccentric and easily locks up if something isn't
|
||||
* right. Documentation is available at initio's website but it only
|
||||
* documents registers (not programming model).
|
||||
*
|
||||
* - ATA disks work.
|
||||
* - Hotplug works.
|
||||
* - ATAPI read works but burning doesn't. This thing is really
|
||||
* peculiar about ATAPI and I couldn't figure out how ATAPI PIO and
|
||||
* ATAPI DMA WRITE should be programmed. If you've got a clue, be
|
||||
* my guest.
|
||||
* - Both STR and STD work.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <scsi/scsi_host.h>
|
||||
#include <linux/libata.h>
|
||||
#include <linux/blkdev.h>
|
||||
#include <scsi/scsi_device.h>
|
||||
|
||||
#define DRV_NAME "sata_inic162x"
|
||||
#define DRV_VERSION "0.1"
|
||||
|
||||
enum {
|
||||
MMIO_BAR = 5,
|
||||
|
||||
NR_PORTS = 2,
|
||||
|
||||
HOST_CTL = 0x7c,
|
||||
HOST_STAT = 0x7e,
|
||||
HOST_IRQ_STAT = 0xbc,
|
||||
HOST_IRQ_MASK = 0xbe,
|
||||
|
||||
PORT_SIZE = 0x40,
|
||||
|
||||
/* registers for ATA TF operation */
|
||||
PORT_TF = 0x00,
|
||||
PORT_ALT_STAT = 0x08,
|
||||
PORT_IRQ_STAT = 0x09,
|
||||
PORT_IRQ_MASK = 0x0a,
|
||||
PORT_PRD_CTL = 0x0b,
|
||||
PORT_PRD_ADDR = 0x0c,
|
||||
PORT_PRD_XFERLEN = 0x10,
|
||||
|
||||
/* IDMA register */
|
||||
PORT_IDMA_CTL = 0x14,
|
||||
|
||||
PORT_SCR = 0x20,
|
||||
|
||||
/* HOST_CTL bits */
|
||||
HCTL_IRQOFF = (1 << 8), /* global IRQ off */
|
||||
HCTL_PWRDWN = (1 << 13), /* power down PHYs */
|
||||
HCTL_SOFTRST = (1 << 13), /* global reset (no phy reset) */
|
||||
HCTL_RPGSEL = (1 << 15), /* register page select */
|
||||
|
||||
HCTL_KNOWN_BITS = HCTL_IRQOFF | HCTL_PWRDWN | HCTL_SOFTRST |
|
||||
HCTL_RPGSEL,
|
||||
|
||||
/* HOST_IRQ_(STAT|MASK) bits */
|
||||
HIRQ_PORT0 = (1 << 0),
|
||||
HIRQ_PORT1 = (1 << 1),
|
||||
HIRQ_SOFT = (1 << 14),
|
||||
HIRQ_GLOBAL = (1 << 15), /* STAT only */
|
||||
|
||||
/* PORT_IRQ_(STAT|MASK) bits */
|
||||
PIRQ_OFFLINE = (1 << 0), /* device unplugged */
|
||||
PIRQ_ONLINE = (1 << 1), /* device plugged */
|
||||
PIRQ_COMPLETE = (1 << 2), /* completion interrupt */
|
||||
PIRQ_FATAL = (1 << 3), /* fatal error */
|
||||
PIRQ_ATA = (1 << 4), /* ATA interrupt */
|
||||
PIRQ_REPLY = (1 << 5), /* reply FIFO not empty */
|
||||
PIRQ_PENDING = (1 << 7), /* port IRQ pending (STAT only) */
|
||||
|
||||
PIRQ_ERR = PIRQ_OFFLINE | PIRQ_ONLINE | PIRQ_FATAL,
|
||||
|
||||
PIRQ_MASK_DMA_READ = PIRQ_REPLY | PIRQ_ATA,
|
||||
PIRQ_MASK_OTHER = PIRQ_REPLY | PIRQ_COMPLETE,
|
||||
PIRQ_MASK_FREEZE = 0xff,
|
||||
|
||||
/* PORT_PRD_CTL bits */
|
||||
PRD_CTL_START = (1 << 0),
|
||||
PRD_CTL_WR = (1 << 3),
|
||||
PRD_CTL_DMAEN = (1 << 7), /* DMA enable */
|
||||
|
||||
/* PORT_IDMA_CTL bits */
|
||||
IDMA_CTL_RST_ATA = (1 << 2), /* hardreset ATA bus */
|
||||
IDMA_CTL_RST_IDMA = (1 << 5), /* reset IDMA machinary */
|
||||
IDMA_CTL_GO = (1 << 7), /* IDMA mode go */
|
||||
IDMA_CTL_ATA_NIEN = (1 << 8), /* ATA IRQ disable */
|
||||
};
|
||||
|
||||
struct inic_host_priv {
|
||||
u16 cached_hctl;
|
||||
};
|
||||
|
||||
struct inic_port_priv {
|
||||
u8 dfl_prdctl;
|
||||
u8 cached_prdctl;
|
||||
u8 cached_pirq_mask;
|
||||
};
|
||||
|
||||
static int inic_slave_config(struct scsi_device *sdev)
|
||||
{
|
||||
/* This controller is braindamaged. dma_boundary is 0xffff
|
||||
* like others but it will lock up the whole machine HARD if
|
||||
* 65536 byte PRD entry is fed. Reduce maximum segment size.
|
||||
*/
|
||||
blk_queue_max_segment_size(sdev->request_queue, 65536 - 512);
|
||||
|
||||
return ata_scsi_slave_config(sdev);
|
||||
}
|
||||
|
||||
static struct scsi_host_template inic_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 = inic_slave_config,
|
||||
.slave_destroy = ata_scsi_slave_destroy,
|
||||
.bios_param = ata_std_bios_param,
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = ata_scsi_device_suspend,
|
||||
.resume = ata_scsi_device_resume,
|
||||
#endif
|
||||
};
|
||||
|
||||
static const int scr_map[] = {
|
||||
[SCR_STATUS] = 0,
|
||||
[SCR_ERROR] = 1,
|
||||
[SCR_CONTROL] = 2,
|
||||
};
|
||||
|
||||
static void __iomem * inic_port_base(struct ata_port *ap)
|
||||
{
|
||||
return ap->host->iomap[MMIO_BAR] + ap->port_no * PORT_SIZE;
|
||||
}
|
||||
|
||||
static void __inic_set_pirq_mask(struct ata_port *ap, u8 mask)
|
||||
{
|
||||
void __iomem *port_base = inic_port_base(ap);
|
||||
struct inic_port_priv *pp = ap->private_data;
|
||||
|
||||
writeb(mask, port_base + PORT_IRQ_MASK);
|
||||
pp->cached_pirq_mask = mask;
|
||||
}
|
||||
|
||||
static void inic_set_pirq_mask(struct ata_port *ap, u8 mask)
|
||||
{
|
||||
struct inic_port_priv *pp = ap->private_data;
|
||||
|
||||
if (pp->cached_pirq_mask != mask)
|
||||
__inic_set_pirq_mask(ap, mask);
|
||||
}
|
||||
|
||||
static void inic_reset_port(void __iomem *port_base)
|
||||
{
|
||||
void __iomem *idma_ctl = port_base + PORT_IDMA_CTL;
|
||||
u16 ctl;
|
||||
|
||||
ctl = readw(idma_ctl);
|
||||
ctl &= ~(IDMA_CTL_RST_IDMA | IDMA_CTL_ATA_NIEN | IDMA_CTL_GO);
|
||||
|
||||
/* mask IRQ and assert reset */
|
||||
writew(ctl | IDMA_CTL_RST_IDMA | IDMA_CTL_ATA_NIEN, idma_ctl);
|
||||
readw(idma_ctl); /* flush */
|
||||
|
||||
/* give it some time */
|
||||
msleep(1);
|
||||
|
||||
/* release reset */
|
||||
writew(ctl | IDMA_CTL_ATA_NIEN, idma_ctl);
|
||||
|
||||
/* clear irq */
|
||||
writeb(0xff, port_base + PORT_IRQ_STAT);
|
||||
|
||||
/* reenable ATA IRQ, turn off IDMA mode */
|
||||
writew(ctl, idma_ctl);
|
||||
}
|
||||
|
||||
static u32 inic_scr_read(struct ata_port *ap, unsigned sc_reg)
|
||||
{
|
||||
void __iomem *scr_addr = (void __iomem *)ap->ioaddr.scr_addr;
|
||||
void __iomem *addr;
|
||||
u32 val;
|
||||
|
||||
if (unlikely(sc_reg >= ARRAY_SIZE(scr_map)))
|
||||
return 0xffffffffU;
|
||||
|
||||
addr = scr_addr + scr_map[sc_reg] * 4;
|
||||
val = readl(scr_addr + scr_map[sc_reg] * 4);
|
||||
|
||||
/* this controller has stuck DIAG.N, ignore it */
|
||||
if (sc_reg == SCR_ERROR)
|
||||
val &= ~SERR_PHYRDY_CHG;
|
||||
return val;
|
||||
}
|
||||
|
||||
static void inic_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val)
|
||||
{
|
||||
void __iomem *scr_addr = (void __iomem *)ap->ioaddr.scr_addr;
|
||||
void __iomem *addr;
|
||||
|
||||
if (unlikely(sc_reg >= ARRAY_SIZE(scr_map)))
|
||||
return;
|
||||
|
||||
addr = scr_addr + scr_map[sc_reg] * 4;
|
||||
writel(val, scr_addr + scr_map[sc_reg] * 4);
|
||||
}
|
||||
|
||||
/*
|
||||
* In TF mode, inic162x is very similar to SFF device. TF registers
|
||||
* function the same. DMA engine behaves similary using the same PRD
|
||||
* format as BMDMA but different command register, interrupt and event
|
||||
* notification methods are used. The following inic_bmdma_*()
|
||||
* functions do the impedance matching.
|
||||
*/
|
||||
static void inic_bmdma_setup(struct ata_queued_cmd *qc)
|
||||
{
|
||||
struct ata_port *ap = qc->ap;
|
||||
struct inic_port_priv *pp = ap->private_data;
|
||||
void __iomem *port_base = inic_port_base(ap);
|
||||
int rw = qc->tf.flags & ATA_TFLAG_WRITE;
|
||||
|
||||
/* make sure device sees PRD table writes */
|
||||
wmb();
|
||||
|
||||
/* load transfer length */
|
||||
writel(qc->nbytes, port_base + PORT_PRD_XFERLEN);
|
||||
|
||||
/* turn on DMA and specify data direction */
|
||||
pp->cached_prdctl = pp->dfl_prdctl | PRD_CTL_DMAEN;
|
||||
if (!rw)
|
||||
pp->cached_prdctl |= PRD_CTL_WR;
|
||||
writeb(pp->cached_prdctl, port_base + PORT_PRD_CTL);
|
||||
|
||||
/* issue r/w command */
|
||||
ap->ops->exec_command(ap, &qc->tf);
|
||||
}
|
||||
|
||||
static void inic_bmdma_start(struct ata_queued_cmd *qc)
|
||||
{
|
||||
struct ata_port *ap = qc->ap;
|
||||
struct inic_port_priv *pp = ap->private_data;
|
||||
void __iomem *port_base = inic_port_base(ap);
|
||||
|
||||
/* start host DMA transaction */
|
||||
pp->cached_prdctl |= PRD_CTL_START;
|
||||
writeb(pp->cached_prdctl, port_base + PORT_PRD_CTL);
|
||||
}
|
||||
|
||||
static void inic_bmdma_stop(struct ata_queued_cmd *qc)
|
||||
{
|
||||
struct ata_port *ap = qc->ap;
|
||||
struct inic_port_priv *pp = ap->private_data;
|
||||
void __iomem *port_base = inic_port_base(ap);
|
||||
|
||||
/* stop DMA engine */
|
||||
writeb(pp->dfl_prdctl, port_base + PORT_PRD_CTL);
|
||||
}
|
||||
|
||||
static u8 inic_bmdma_status(struct ata_port *ap)
|
||||
{
|
||||
/* event is already verified by the interrupt handler */
|
||||
return ATA_DMA_INTR;
|
||||
}
|
||||
|
||||
static void inic_irq_clear(struct ata_port *ap)
|
||||
{
|
||||
/* noop */
|
||||
}
|
||||
|
||||
static void inic_host_intr(struct ata_port *ap)
|
||||
{
|
||||
void __iomem *port_base = inic_port_base(ap);
|
||||
struct ata_eh_info *ehi = &ap->eh_info;
|
||||
u8 irq_stat;
|
||||
|
||||
/* fetch and clear irq */
|
||||
irq_stat = readb(port_base + PORT_IRQ_STAT);
|
||||
writeb(irq_stat, port_base + PORT_IRQ_STAT);
|
||||
|
||||
if (likely(!(irq_stat & PIRQ_ERR))) {
|
||||
struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag);
|
||||
|
||||
if (unlikely(!qc || (qc->tf.flags & ATA_TFLAG_POLLING))) {
|
||||
ata_chk_status(ap); /* clear ATA interrupt */
|
||||
return;
|
||||
}
|
||||
|
||||
if (likely(ata_host_intr(ap, qc)))
|
||||
return;
|
||||
|
||||
ata_chk_status(ap); /* clear ATA interrupt */
|
||||
ata_port_printk(ap, KERN_WARNING, "unhandled "
|
||||
"interrupt, irq_stat=%x\n", irq_stat);
|
||||
return;
|
||||
}
|
||||
|
||||
/* error */
|
||||
ata_ehi_push_desc(ehi, "irq_stat=0x%x", irq_stat);
|
||||
|
||||
if (irq_stat & (PIRQ_OFFLINE | PIRQ_ONLINE)) {
|
||||
ata_ehi_hotplugged(ehi);
|
||||
ata_port_freeze(ap);
|
||||
} else
|
||||
ata_port_abort(ap);
|
||||
}
|
||||
|
||||
static irqreturn_t inic_interrupt(int irq, void *dev_instance)
|
||||
{
|
||||
struct ata_host *host = dev_instance;
|
||||
void __iomem *mmio_base = host->iomap[MMIO_BAR];
|
||||
u16 host_irq_stat;
|
||||
int i, handled = 0;;
|
||||
|
||||
host_irq_stat = readw(mmio_base + HOST_IRQ_STAT);
|
||||
|
||||
if (unlikely(!(host_irq_stat & HIRQ_GLOBAL)))
|
||||
goto out;
|
||||
|
||||
spin_lock(&host->lock);
|
||||
|
||||
for (i = 0; i < NR_PORTS; i++) {
|
||||
struct ata_port *ap = host->ports[i];
|
||||
|
||||
if (!(host_irq_stat & (HIRQ_PORT0 << i)))
|
||||
continue;
|
||||
|
||||
if (likely(ap && !(ap->flags & ATA_FLAG_DISABLED))) {
|
||||
inic_host_intr(ap);
|
||||
handled++;
|
||||
} else {
|
||||
if (ata_ratelimit())
|
||||
dev_printk(KERN_ERR, host->dev, "interrupt "
|
||||
"from disabled port %d (0x%x)\n",
|
||||
i, host_irq_stat);
|
||||
}
|
||||
}
|
||||
|
||||
spin_unlock(&host->lock);
|
||||
|
||||
out:
|
||||
return IRQ_RETVAL(handled);
|
||||
}
|
||||
|
||||
static unsigned int inic_qc_issue(struct ata_queued_cmd *qc)
|
||||
{
|
||||
struct ata_port *ap = qc->ap;
|
||||
|
||||
/* ATA IRQ doesn't wait for DMA transfer completion and vice
|
||||
* versa. Mask IRQ selectively to detect command completion.
|
||||
* Without it, ATA DMA read command can cause data corruption.
|
||||
*
|
||||
* Something similar might be needed for ATAPI writes. I
|
||||
* tried a lot of combinations but couldn't find the solution.
|
||||
*/
|
||||
if (qc->tf.protocol == ATA_PROT_DMA &&
|
||||
!(qc->tf.flags & ATA_TFLAG_WRITE))
|
||||
inic_set_pirq_mask(ap, PIRQ_MASK_DMA_READ);
|
||||
else
|
||||
inic_set_pirq_mask(ap, PIRQ_MASK_OTHER);
|
||||
|
||||
/* Issuing a command to yet uninitialized port locks up the
|
||||
* controller. Most of the time, this happens for the first
|
||||
* command after reset which are ATA and ATAPI IDENTIFYs.
|
||||
* Fast fail if stat is 0x7f or 0xff for those commands.
|
||||
*/
|
||||
if (unlikely(qc->tf.command == ATA_CMD_ID_ATA ||
|
||||
qc->tf.command == ATA_CMD_ID_ATAPI)) {
|
||||
u8 stat = ata_chk_status(ap);
|
||||
if (stat == 0x7f || stat == 0xff)
|
||||
return AC_ERR_HSM;
|
||||
}
|
||||
|
||||
return ata_qc_issue_prot(qc);
|
||||
}
|
||||
|
||||
static void inic_freeze(struct ata_port *ap)
|
||||
{
|
||||
void __iomem *port_base = inic_port_base(ap);
|
||||
|
||||
__inic_set_pirq_mask(ap, PIRQ_MASK_FREEZE);
|
||||
|
||||
ata_chk_status(ap);
|
||||
writeb(0xff, port_base + PORT_IRQ_STAT);
|
||||
|
||||
readb(port_base + PORT_IRQ_STAT); /* flush */
|
||||
}
|
||||
|
||||
static void inic_thaw(struct ata_port *ap)
|
||||
{
|
||||
void __iomem *port_base = inic_port_base(ap);
|
||||
|
||||
ata_chk_status(ap);
|
||||
writeb(0xff, port_base + PORT_IRQ_STAT);
|
||||
|
||||
__inic_set_pirq_mask(ap, PIRQ_MASK_OTHER);
|
||||
|
||||
readb(port_base + PORT_IRQ_STAT); /* flush */
|
||||
}
|
||||
|
||||
/*
|
||||
* SRST and SControl hardreset don't give valid signature on this
|
||||
* controller. Only controller specific hardreset mechanism works.
|
||||
*/
|
||||
static int inic_hardreset(struct ata_port *ap, unsigned int *class)
|
||||
{
|
||||
void __iomem *port_base = inic_port_base(ap);
|
||||
void __iomem *idma_ctl = port_base + PORT_IDMA_CTL;
|
||||
const unsigned long *timing = sata_ehc_deb_timing(&ap->eh_context);
|
||||
u16 val;
|
||||
int rc;
|
||||
|
||||
/* hammer it into sane state */
|
||||
inic_reset_port(port_base);
|
||||
|
||||
val = readw(idma_ctl);
|
||||
writew(val | IDMA_CTL_RST_ATA, idma_ctl);
|
||||
readw(idma_ctl); /* flush */
|
||||
msleep(1);
|
||||
writew(val & ~IDMA_CTL_RST_ATA, idma_ctl);
|
||||
|
||||
rc = sata_phy_resume(ap, timing);
|
||||
if (rc) {
|
||||
ata_port_printk(ap, KERN_WARNING, "failed to resume "
|
||||
"link after reset (errno=%d)\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
*class = ATA_DEV_NONE;
|
||||
if (ata_port_online(ap)) {
|
||||
struct ata_taskfile tf;
|
||||
|
||||
/* wait a while before checking status */
|
||||
msleep(150);
|
||||
|
||||
if (ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT)) {
|
||||
ata_port_printk(ap, KERN_WARNING,
|
||||
"device busy after hardreset\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
ata_tf_read(ap, &tf);
|
||||
*class = ata_dev_classify(&tf);
|
||||
if (*class == ATA_DEV_UNKNOWN)
|
||||
*class = ATA_DEV_NONE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void inic_error_handler(struct ata_port *ap)
|
||||
{
|
||||
void __iomem *port_base = inic_port_base(ap);
|
||||
struct inic_port_priv *pp = ap->private_data;
|
||||
unsigned long flags;
|
||||
|
||||
/* reset PIO HSM and stop DMA engine */
|
||||
inic_reset_port(port_base);
|
||||
|
||||
spin_lock_irqsave(ap->lock, flags);
|
||||
ap->hsm_task_state = HSM_ST_IDLE;
|
||||
writeb(pp->dfl_prdctl, port_base + PORT_PRD_CTL);
|
||||
spin_unlock_irqrestore(ap->lock, flags);
|
||||
|
||||
/* PIO and DMA engines have been stopped, perform recovery */
|
||||
ata_do_eh(ap, ata_std_prereset, NULL, inic_hardreset,
|
||||
ata_std_postreset);
|
||||
}
|
||||
|
||||
static void inic_post_internal_cmd(struct ata_queued_cmd *qc)
|
||||
{
|
||||
/* make DMA engine forget about the failed command */
|
||||
if (qc->err_mask)
|
||||
inic_reset_port(inic_port_base(qc->ap));
|
||||
}
|
||||
|
||||
static void inic_dev_config(struct ata_port *ap, struct ata_device *dev)
|
||||
{
|
||||
/* inic can only handle upto LBA28 max sectors */
|
||||
if (dev->max_sectors > ATA_MAX_SECTORS)
|
||||
dev->max_sectors = ATA_MAX_SECTORS;
|
||||
}
|
||||
|
||||
static void init_port(struct ata_port *ap)
|
||||
{
|
||||
void __iomem *port_base = inic_port_base(ap);
|
||||
|
||||
/* Setup PRD address */
|
||||
writel(ap->prd_dma, port_base + PORT_PRD_ADDR);
|
||||
}
|
||||
|
||||
static int inic_port_resume(struct ata_port *ap)
|
||||
{
|
||||
init_port(ap);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int inic_port_start(struct ata_port *ap)
|
||||
{
|
||||
void __iomem *port_base = inic_port_base(ap);
|
||||
struct inic_port_priv *pp;
|
||||
u8 tmp;
|
||||
int rc;
|
||||
|
||||
/* alloc and initialize private data */
|
||||
pp = devm_kzalloc(ap->host->dev, sizeof(*pp), GFP_KERNEL);
|
||||
if (!pp)
|
||||
return -ENOMEM;
|
||||
ap->private_data = pp;
|
||||
|
||||
/* default PRD_CTL value, DMAEN, WR and START off */
|
||||
tmp = readb(port_base + PORT_PRD_CTL);
|
||||
tmp &= ~(PRD_CTL_DMAEN | PRD_CTL_WR | PRD_CTL_START);
|
||||
pp->dfl_prdctl = tmp;
|
||||
|
||||
/* Alloc resources */
|
||||
rc = ata_port_start(ap);
|
||||
if (rc) {
|
||||
kfree(pp);
|
||||
return rc;
|
||||
}
|
||||
|
||||
init_port(ap);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct ata_port_operations inic_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,
|
||||
|
||||
.scr_read = inic_scr_read,
|
||||
.scr_write = inic_scr_write,
|
||||
|
||||
.bmdma_setup = inic_bmdma_setup,
|
||||
.bmdma_start = inic_bmdma_start,
|
||||
.bmdma_stop = inic_bmdma_stop,
|
||||
.bmdma_status = inic_bmdma_status,
|
||||
|
||||
.irq_handler = inic_interrupt,
|
||||
.irq_clear = inic_irq_clear,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
|
||||
.qc_prep = ata_qc_prep,
|
||||
.qc_issue = inic_qc_issue,
|
||||
.data_xfer = ata_data_xfer,
|
||||
|
||||
.freeze = inic_freeze,
|
||||
.thaw = inic_thaw,
|
||||
.error_handler = inic_error_handler,
|
||||
.post_internal_cmd = inic_post_internal_cmd,
|
||||
.dev_config = inic_dev_config,
|
||||
|
||||
.port_resume = inic_port_resume,
|
||||
|
||||
.port_start = inic_port_start,
|
||||
};
|
||||
|
||||
static struct ata_port_info inic_port_info = {
|
||||
.sht = &inic_sht,
|
||||
/* For some reason, ATA_PROT_ATAPI is broken on this
|
||||
* controller, and no, PIO_POLLING does't fix it. It somehow
|
||||
* manages to report the wrong ireason and ignoring ireason
|
||||
* results in machine lock up. Tell libata to always prefer
|
||||
* DMA.
|
||||
*/
|
||||
.flags = ATA_FLAG_SATA | ATA_FLAG_PIO_DMA,
|
||||
.pio_mask = 0x1f, /* pio0-4 */
|
||||
.mwdma_mask = 0x07, /* mwdma0-2 */
|
||||
.udma_mask = 0x7f, /* udma0-6 */
|
||||
.port_ops = &inic_port_ops
|
||||
};
|
||||
|
||||
static int init_controller(void __iomem *mmio_base, u16 hctl)
|
||||
{
|
||||
int i;
|
||||
u16 val;
|
||||
|
||||
hctl &= ~HCTL_KNOWN_BITS;
|
||||
|
||||
/* Soft reset whole controller. Spec says reset duration is 3
|
||||
* PCI clocks, be generous and give it 10ms.
|
||||
*/
|
||||
writew(hctl | HCTL_SOFTRST, mmio_base + HOST_CTL);
|
||||
readw(mmio_base + HOST_CTL); /* flush */
|
||||
|
||||
for (i = 0; i < 10; i++) {
|
||||
msleep(1);
|
||||
val = readw(mmio_base + HOST_CTL);
|
||||
if (!(val & HCTL_SOFTRST))
|
||||
break;
|
||||
}
|
||||
|
||||
if (val & HCTL_SOFTRST)
|
||||
return -EIO;
|
||||
|
||||
/* mask all interrupts and reset ports */
|
||||
for (i = 0; i < NR_PORTS; i++) {
|
||||
void __iomem *port_base = mmio_base + i * PORT_SIZE;
|
||||
|
||||
writeb(0xff, port_base + PORT_IRQ_MASK);
|
||||
inic_reset_port(port_base);
|
||||
}
|
||||
|
||||
/* port IRQ is masked now, unmask global IRQ */
|
||||
writew(hctl & ~HCTL_IRQOFF, mmio_base + HOST_CTL);
|
||||
val = readw(mmio_base + HOST_IRQ_MASK);
|
||||
val &= ~(HIRQ_PORT0 | HIRQ_PORT1);
|
||||
writew(val, mmio_base + HOST_IRQ_MASK);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int inic_pci_device_resume(struct pci_dev *pdev)
|
||||
{
|
||||
struct ata_host *host = dev_get_drvdata(&pdev->dev);
|
||||
struct inic_host_priv *hpriv = host->private_data;
|
||||
void __iomem *mmio_base = host->iomap[MMIO_BAR];
|
||||
int rc;
|
||||
|
||||
ata_pci_device_do_resume(pdev);
|
||||
|
||||
if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) {
|
||||
rc = init_controller(mmio_base, hpriv->cached_hctl);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
ata_host_resume(host);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int inic_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
{
|
||||
static int printed_version;
|
||||
struct ata_port_info *pinfo = &inic_port_info;
|
||||
struct ata_probe_ent *probe_ent;
|
||||
struct inic_host_priv *hpriv;
|
||||
void __iomem * const *iomap;
|
||||
int i, rc;
|
||||
|
||||
if (!printed_version++)
|
||||
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
|
||||
|
||||
rc = pcim_enable_device(pdev);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = pcim_iomap_regions(pdev, 0x3f, DRV_NAME);
|
||||
if (rc)
|
||||
return rc;
|
||||
iomap = pcim_iomap_table(pdev);
|
||||
|
||||
/* Set dma_mask. This devices doesn't support 64bit addressing. */
|
||||
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;
|
||||
}
|
||||
|
||||
probe_ent = devm_kzalloc(&pdev->dev, sizeof(*probe_ent), GFP_KERNEL);
|
||||
hpriv = devm_kzalloc(&pdev->dev, sizeof(*hpriv), GFP_KERNEL);
|
||||
if (!probe_ent || !hpriv)
|
||||
return -ENOMEM;
|
||||
|
||||
probe_ent->dev = &pdev->dev;
|
||||
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 = NR_PORTS;
|
||||
|
||||
probe_ent->irq = pdev->irq;
|
||||
probe_ent->irq_flags = IRQF_SHARED;
|
||||
|
||||
probe_ent->iomap = iomap;
|
||||
|
||||
for (i = 0; i < NR_PORTS; i++) {
|
||||
struct ata_ioports *port = &probe_ent->port[i];
|
||||
void __iomem *port_base = iomap[MMIO_BAR] + i * PORT_SIZE;
|
||||
|
||||
port->cmd_addr = iomap[2 * i];
|
||||
port->altstatus_addr =
|
||||
port->ctl_addr = (void __iomem *)
|
||||
((unsigned long)iomap[2 * i + 1] | ATA_PCI_CTL_OFS);
|
||||
port->scr_addr = port_base + PORT_SCR;
|
||||
|
||||
ata_std_ports(port);
|
||||
}
|
||||
|
||||
probe_ent->private_data = hpriv;
|
||||
hpriv->cached_hctl = readw(iomap[MMIO_BAR] + HOST_CTL);
|
||||
|
||||
rc = init_controller(iomap[MMIO_BAR], hpriv->cached_hctl);
|
||||
if (rc) {
|
||||
dev_printk(KERN_ERR, &pdev->dev,
|
||||
"failed to initialize controller\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
pci_set_master(pdev);
|
||||
|
||||
if (!ata_device_add(probe_ent))
|
||||
return -ENODEV;
|
||||
|
||||
devm_kfree(&pdev->dev, probe_ent);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct pci_device_id inic_pci_tbl[] = {
|
||||
{ PCI_VDEVICE(INIT, 0x1622), },
|
||||
{ },
|
||||
};
|
||||
|
||||
static struct pci_driver inic_pci_driver = {
|
||||
.name = DRV_NAME,
|
||||
.id_table = inic_pci_tbl,
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = ata_pci_device_suspend,
|
||||
.resume = inic_pci_device_resume,
|
||||
#endif
|
||||
.probe = inic_init_one,
|
||||
.remove = ata_pci_remove_one,
|
||||
};
|
||||
|
||||
static int __init inic_init(void)
|
||||
{
|
||||
return pci_register_driver(&inic_pci_driver);
|
||||
}
|
||||
|
||||
static void __exit inic_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&inic_pci_driver);
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("Tejun Heo");
|
||||
MODULE_DESCRIPTION("low-level driver for Initio 162x SATA");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_DEVICE_TABLE(pci, inic_pci_tbl);
|
||||
MODULE_VERSION(DRV_VERSION);
|
||||
|
||||
module_init(inic_init);
|
||||
module_exit(inic_exit);
|
||||
2396
drivers/ata/sata_mv.c
Normal file
2396
drivers/ata/sata_mv.c
Normal file
File diff suppressed because it is too large
Load Diff
1669
drivers/ata/sata_nv.c
Normal file
1669
drivers/ata/sata_nv.c
Normal file
File diff suppressed because it is too large
Load Diff
980
drivers/ata/sata_promise.c
Normal file
980
drivers/ata/sata_promise.c
Normal file
@@ -0,0 +1,980 @@
|
||||
/*
|
||||
* 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/device.h>
|
||||
#include <scsi/scsi.h>
|
||||
#include <scsi/scsi_host.h>
|
||||
#include <scsi/scsi_cmnd.h>
|
||||
#include <linux/libata.h>
|
||||
#include "sata_promise.h"
|
||||
|
||||
#define DRV_NAME "sata_promise"
|
||||
#define DRV_VERSION "2.00"
|
||||
|
||||
|
||||
enum {
|
||||
PDC_MMIO_BAR = 3,
|
||||
|
||||
/* register offsets */
|
||||
PDC_FEATURE = 0x04, /* Feature/Error reg (per port) */
|
||||
PDC_SECTOR_COUNT = 0x08, /* Sector count reg (per port) */
|
||||
PDC_SECTOR_NUMBER = 0x0C, /* Sector number reg (per port) */
|
||||
PDC_CYLINDER_LOW = 0x10, /* Cylinder low reg (per port) */
|
||||
PDC_CYLINDER_HIGH = 0x14, /* Cylinder high reg (per port) */
|
||||
PDC_DEVICE = 0x18, /* Device/Head reg (per port) */
|
||||
PDC_COMMAND = 0x1C, /* Command/status reg (per port) */
|
||||
PDC_ALTSTATUS = 0x38, /* Alternate-status/device-control reg (per port) */
|
||||
PDC_PKT_SUBMIT = 0x40, /* Command packet pointer addr */
|
||||
PDC_INT_SEQMASK = 0x40, /* Mask of asserted SEQ INTs */
|
||||
PDC_FLASH_CTL = 0x44, /* Flash control register */
|
||||
PDC_GLOBAL_CTL = 0x48, /* Global control/status (per port) */
|
||||
PDC_CTLSTAT = 0x60, /* IDE control and status (per port) */
|
||||
PDC_SATA_PLUG_CSR = 0x6C, /* SATA Plug control/status reg */
|
||||
PDC2_SATA_PLUG_CSR = 0x60, /* SATAII Plug control/status reg */
|
||||
PDC_TBG_MODE = 0x41C, /* TBG mode (not SATAII) */
|
||||
PDC_SLEW_CTL = 0x470, /* slew rate control reg (not SATAII) */
|
||||
|
||||
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_2057x = 3, /* SATAII150 Tx2plus */
|
||||
board_40518 = 4, /* SATAII150 Tx4 */
|
||||
|
||||
PDC_HAS_PATA = (1 << 1), /* PDC20375/20575 has PATA */
|
||||
|
||||
/* Sequence counter control registers bit definitions */
|
||||
PDC_SEQCNTRL_INT_MASK = (1 << 5), /* Sequence Interrupt Mask */
|
||||
|
||||
/* Feature register values */
|
||||
PDC_FEATURE_ATAPI_PIO = 0x00, /* ATAPI data xfer by PIO */
|
||||
PDC_FEATURE_ATAPI_DMA = 0x01, /* ATAPI data xfer by DMA */
|
||||
|
||||
/* Device/Head register values */
|
||||
PDC_DEVICE_SATA = 0xE0, /* Device/Head value for SATA devices */
|
||||
|
||||
/* PDC_CTLSTAT bit definitions */
|
||||
PDC_DMA_ENABLE = (1 << 7),
|
||||
PDC_IRQ_DISABLE = (1 << 10),
|
||||
PDC_RESET = (1 << 11), /* HDMA reset */
|
||||
|
||||
PDC_COMMON_FLAGS = ATA_FLAG_NO_LEGACY |
|
||||
ATA_FLAG_MMIO |
|
||||
ATA_FLAG_PIO_POLLING,
|
||||
|
||||
/* hp->flags bits */
|
||||
PDC_FLAG_GEN_II = (1 << 0),
|
||||
};
|
||||
|
||||
|
||||
struct pdc_port_priv {
|
||||
u8 *pkt;
|
||||
dma_addr_t pkt_dma;
|
||||
};
|
||||
|
||||
struct pdc_host_priv {
|
||||
unsigned long flags;
|
||||
unsigned long port_flags[ATA_MAX_PORTS];
|
||||
};
|
||||
|
||||
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);
|
||||
static int pdc_port_start(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 int pdc_check_atapi_dma(struct ata_queued_cmd *qc);
|
||||
static int pdc_old_check_atapi_dma(struct ata_queued_cmd *qc);
|
||||
static void pdc_irq_clear(struct ata_port *ap);
|
||||
static unsigned int pdc_qc_issue_prot(struct ata_queued_cmd *qc);
|
||||
static void pdc_freeze(struct ata_port *ap);
|
||||
static void pdc_thaw(struct ata_port *ap);
|
||||
static void pdc_error_handler(struct ata_port *ap);
|
||||
static void pdc_post_internal_cmd(struct ata_queued_cmd *qc);
|
||||
|
||||
|
||||
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,
|
||||
.check_atapi_dma = pdc_check_atapi_dma,
|
||||
|
||||
.qc_prep = pdc_qc_prep,
|
||||
.qc_issue = pdc_qc_issue_prot,
|
||||
.freeze = pdc_freeze,
|
||||
.thaw = pdc_thaw,
|
||||
.error_handler = pdc_error_handler,
|
||||
.post_internal_cmd = pdc_post_internal_cmd,
|
||||
.data_xfer = ata_data_xfer,
|
||||
.irq_handler = pdc_interrupt,
|
||||
.irq_clear = pdc_irq_clear,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
|
||||
.scr_read = pdc_sata_scr_read,
|
||||
.scr_write = pdc_sata_scr_write,
|
||||
.port_start = pdc_port_start,
|
||||
};
|
||||
|
||||
/* First-generation chips need a more restrictive ->check_atapi_dma op */
|
||||
static const struct ata_port_operations pdc_old_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,
|
||||
.check_atapi_dma = pdc_old_check_atapi_dma,
|
||||
|
||||
.qc_prep = pdc_qc_prep,
|
||||
.qc_issue = pdc_qc_issue_prot,
|
||||
.freeze = pdc_freeze,
|
||||
.thaw = pdc_thaw,
|
||||
.error_handler = pdc_error_handler,
|
||||
.post_internal_cmd = pdc_post_internal_cmd,
|
||||
.data_xfer = ata_data_xfer,
|
||||
.irq_handler = pdc_interrupt,
|
||||
.irq_clear = pdc_irq_clear,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
|
||||
.scr_read = pdc_sata_scr_read,
|
||||
.scr_write = pdc_sata_scr_write,
|
||||
.port_start = pdc_port_start,
|
||||
};
|
||||
|
||||
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,
|
||||
.check_atapi_dma = pdc_check_atapi_dma,
|
||||
|
||||
.qc_prep = pdc_qc_prep,
|
||||
.qc_issue = pdc_qc_issue_prot,
|
||||
.freeze = pdc_freeze,
|
||||
.thaw = pdc_thaw,
|
||||
.error_handler = pdc_error_handler,
|
||||
.post_internal_cmd = pdc_post_internal_cmd,
|
||||
.data_xfer = ata_data_xfer,
|
||||
.irq_handler = pdc_interrupt,
|
||||
.irq_clear = pdc_irq_clear,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
|
||||
.port_start = pdc_port_start,
|
||||
};
|
||||
|
||||
static const struct ata_port_info pdc_port_info[] = {
|
||||
/* board_2037x */
|
||||
{
|
||||
.sht = &pdc_ata_sht,
|
||||
.flags = PDC_COMMON_FLAGS,
|
||||
.pio_mask = 0x1f, /* pio0-4 */
|
||||
.mwdma_mask = 0x07, /* mwdma0-2 */
|
||||
.udma_mask = 0x7f, /* udma0-6 ; FIXME */
|
||||
.port_ops = &pdc_old_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_old_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_2057x */
|
||||
{
|
||||
.sht = &pdc_ata_sht,
|
||||
.flags = PDC_COMMON_FLAGS,
|
||||
.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_VDEVICE(PROMISE, 0x3371), board_2037x },
|
||||
{ PCI_VDEVICE(PROMISE, 0x3373), board_2037x },
|
||||
{ PCI_VDEVICE(PROMISE, 0x3375), board_2037x },
|
||||
{ PCI_VDEVICE(PROMISE, 0x3376), board_2037x },
|
||||
{ PCI_VDEVICE(PROMISE, 0x3570), board_2057x },
|
||||
{ PCI_VDEVICE(PROMISE, 0x3571), board_2057x },
|
||||
{ PCI_VDEVICE(PROMISE, 0x3574), board_2057x },
|
||||
{ PCI_VDEVICE(PROMISE, 0x3577), board_2057x },
|
||||
{ PCI_VDEVICE(PROMISE, 0x3d73), board_2057x },
|
||||
{ PCI_VDEVICE(PROMISE, 0x3d75), board_2057x },
|
||||
|
||||
{ PCI_VDEVICE(PROMISE, 0x3318), board_20319 },
|
||||
{ PCI_VDEVICE(PROMISE, 0x3319), board_20319 },
|
||||
{ PCI_VDEVICE(PROMISE, 0x3515), board_20319 },
|
||||
{ PCI_VDEVICE(PROMISE, 0x3519), board_20319 },
|
||||
{ PCI_VDEVICE(PROMISE, 0x3d17), board_40518 },
|
||||
{ PCI_VDEVICE(PROMISE, 0x3d18), board_40518 },
|
||||
|
||||
{ PCI_VDEVICE(PROMISE, 0x6629), board_20619 },
|
||||
|
||||
{ } /* 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_host_priv *hp = ap->host->private_data;
|
||||
struct pdc_port_priv *pp;
|
||||
int rc;
|
||||
|
||||
/* fix up port flags and cable type for SATA+PATA chips */
|
||||
ap->flags |= hp->port_flags[ap->port_no];
|
||||
if (ap->flags & ATA_FLAG_SATA)
|
||||
ap->cbl = ATA_CBL_SATA;
|
||||
|
||||
rc = ata_port_start(ap);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
|
||||
if (!pp)
|
||||
return -ENOMEM;
|
||||
|
||||
pp->pkt = dmam_alloc_coherent(dev, 128, &pp->pkt_dma, GFP_KERNEL);
|
||||
if (!pp->pkt)
|
||||
return -ENOMEM;
|
||||
|
||||
ap->private_data = pp;
|
||||
|
||||
/* fix up PHYMODE4 align timing */
|
||||
if ((hp->flags & PDC_FLAG_GEN_II) && sata_scr_valid(ap)) {
|
||||
void __iomem *mmio = (void __iomem *) ap->ioaddr.scr_addr;
|
||||
unsigned int tmp;
|
||||
|
||||
tmp = readl(mmio + 0x014);
|
||||
tmp = (tmp & ~3) | 1; /* set bits 1:0 = 0:1 */
|
||||
writel(tmp, mmio + 0x014);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pdc_reset_port(struct ata_port *ap)
|
||||
{
|
||||
void __iomem *mmio = 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_pata_cbl_detect(struct ata_port *ap)
|
||||
{
|
||||
u8 tmp;
|
||||
void __iomem *mmio = (void __iomem *) 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 u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg)
|
||||
{
|
||||
if (sc_reg > SCR_CONTROL || ap->cbl != ATA_CBL_SATA)
|
||||
return 0xffffffffU;
|
||||
return readl(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 || ap->cbl != ATA_CBL_SATA)
|
||||
return;
|
||||
writel(val, ap->ioaddr.scr_addr + (sc_reg * 4));
|
||||
}
|
||||
|
||||
static void pdc_atapi_pkt(struct ata_queued_cmd *qc)
|
||||
{
|
||||
struct ata_port *ap = qc->ap;
|
||||
dma_addr_t sg_table = ap->prd_dma;
|
||||
unsigned int cdb_len = qc->dev->cdb_len;
|
||||
u8 *cdb = qc->cdb;
|
||||
struct pdc_port_priv *pp = ap->private_data;
|
||||
u8 *buf = pp->pkt;
|
||||
u32 *buf32 = (u32 *) buf;
|
||||
unsigned int dev_sel, feature, nbytes;
|
||||
|
||||
/* set control bits (byte 0), zero delay seq id (byte 3),
|
||||
* and seq id (byte 2)
|
||||
*/
|
||||
switch (qc->tf.protocol) {
|
||||
case ATA_PROT_ATAPI_DMA:
|
||||
if (!(qc->tf.flags & ATA_TFLAG_WRITE))
|
||||
buf32[0] = cpu_to_le32(PDC_PKT_READ);
|
||||
else
|
||||
buf32[0] = 0;
|
||||
break;
|
||||
case ATA_PROT_ATAPI_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 */
|
||||
|
||||
/* select drive */
|
||||
if (sata_scr_valid(ap)) {
|
||||
dev_sel = PDC_DEVICE_SATA;
|
||||
} else {
|
||||
dev_sel = ATA_DEVICE_OBS;
|
||||
if (qc->dev->devno != 0)
|
||||
dev_sel |= ATA_DEV1;
|
||||
}
|
||||
buf[12] = (1 << 5) | ATA_REG_DEVICE;
|
||||
buf[13] = dev_sel;
|
||||
buf[14] = (1 << 5) | ATA_REG_DEVICE | PDC_PKT_CLEAR_BSY;
|
||||
buf[15] = dev_sel; /* once more, waiting for BSY to clear */
|
||||
|
||||
buf[16] = (1 << 5) | ATA_REG_NSECT;
|
||||
buf[17] = 0x00;
|
||||
buf[18] = (1 << 5) | ATA_REG_LBAL;
|
||||
buf[19] = 0x00;
|
||||
|
||||
/* set feature and byte counter registers */
|
||||
if (qc->tf.protocol != ATA_PROT_ATAPI_DMA) {
|
||||
feature = PDC_FEATURE_ATAPI_PIO;
|
||||
/* set byte counter register to real transfer byte count */
|
||||
nbytes = qc->nbytes;
|
||||
if (nbytes > 0xffff)
|
||||
nbytes = 0xffff;
|
||||
} else {
|
||||
feature = PDC_FEATURE_ATAPI_DMA;
|
||||
/* set byte counter register to 0 */
|
||||
nbytes = 0;
|
||||
}
|
||||
buf[20] = (1 << 5) | ATA_REG_FEATURE;
|
||||
buf[21] = feature;
|
||||
buf[22] = (1 << 5) | ATA_REG_BYTEL;
|
||||
buf[23] = nbytes & 0xFF;
|
||||
buf[24] = (1 << 5) | ATA_REG_BYTEH;
|
||||
buf[25] = (nbytes >> 8) & 0xFF;
|
||||
|
||||
/* send ATAPI packet command 0xA0 */
|
||||
buf[26] = (1 << 5) | ATA_REG_CMD;
|
||||
buf[27] = ATA_CMD_PACKET;
|
||||
|
||||
/* select drive and check DRQ */
|
||||
buf[28] = (1 << 5) | ATA_REG_DEVICE | PDC_PKT_WAIT_DRDY;
|
||||
buf[29] = dev_sel;
|
||||
|
||||
/* we can represent cdb lengths 2/4/6/8/10/12/14/16 */
|
||||
BUG_ON(cdb_len & ~0x1E);
|
||||
|
||||
/* append the CDB as the final part */
|
||||
buf[30] = (((cdb_len >> 1) & 7) << 5) | ATA_REG_DATA | PDC_LAST_REG;
|
||||
memcpy(buf+31, cdb, cdb_len);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
case ATA_PROT_ATAPI:
|
||||
ata_qc_prep(qc);
|
||||
break;
|
||||
|
||||
case ATA_PROT_ATAPI_DMA:
|
||||
ata_qc_prep(qc);
|
||||
/*FALLTHROUGH*/
|
||||
case ATA_PROT_ATAPI_NODATA:
|
||||
pdc_atapi_pkt(qc);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void pdc_freeze(struct ata_port *ap)
|
||||
{
|
||||
void __iomem *mmio = (void __iomem *) ap->ioaddr.cmd_addr;
|
||||
u32 tmp;
|
||||
|
||||
tmp = readl(mmio + PDC_CTLSTAT);
|
||||
tmp |= PDC_IRQ_DISABLE;
|
||||
tmp &= ~PDC_DMA_ENABLE;
|
||||
writel(tmp, mmio + PDC_CTLSTAT);
|
||||
readl(mmio + PDC_CTLSTAT); /* flush */
|
||||
}
|
||||
|
||||
static void pdc_thaw(struct ata_port *ap)
|
||||
{
|
||||
void __iomem *mmio = (void __iomem *) ap->ioaddr.cmd_addr;
|
||||
u32 tmp;
|
||||
|
||||
/* clear IRQ */
|
||||
readl(mmio + PDC_INT_SEQMASK);
|
||||
|
||||
/* turn IRQ back on */
|
||||
tmp = readl(mmio + PDC_CTLSTAT);
|
||||
tmp &= ~PDC_IRQ_DISABLE;
|
||||
writel(tmp, mmio + PDC_CTLSTAT);
|
||||
readl(mmio + PDC_CTLSTAT); /* flush */
|
||||
}
|
||||
|
||||
static int pdc_pre_reset(struct ata_port *ap)
|
||||
{
|
||||
if (!sata_scr_valid(ap))
|
||||
pdc_pata_cbl_detect(ap);
|
||||
return ata_std_prereset(ap);
|
||||
}
|
||||
|
||||
static void pdc_error_handler(struct ata_port *ap)
|
||||
{
|
||||
ata_reset_fn_t hardreset;
|
||||
|
||||
if (!(ap->pflags & ATA_PFLAG_FROZEN))
|
||||
pdc_reset_port(ap);
|
||||
|
||||
hardreset = NULL;
|
||||
if (sata_scr_valid(ap))
|
||||
hardreset = sata_std_hardreset;
|
||||
|
||||
/* perform recovery */
|
||||
ata_do_eh(ap, pdc_pre_reset, ata_std_softreset, hardreset,
|
||||
ata_std_postreset);
|
||||
}
|
||||
|
||||
static void pdc_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)
|
||||
pdc_reset_port(ap);
|
||||
}
|
||||
|
||||
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 = 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:
|
||||
case ATA_PROT_ATAPI_DMA:
|
||||
case ATA_PROT_ATAPI_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->iomap[PDC_MMIO_BAR];
|
||||
|
||||
readl(mmio + PDC_INT_SEQMASK);
|
||||
}
|
||||
|
||||
static irqreturn_t pdc_interrupt (int irq, void *dev_instance)
|
||||
{
|
||||
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->iomap[PDC_MMIO_BAR]) {
|
||||
VPRINTK("QUICK EXIT\n");
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
mmio_base = host->iomap[PDC_MMIO_BAR];
|
||||
|
||||
/* 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;
|
||||
void __iomem *mmio = ap->host->iomap[PDC_MMIO_BAR];
|
||||
unsigned int port_no = ap->port_no;
|
||||
u8 seq = (u8) (port_no + 1);
|
||||
|
||||
VPRINTK("ENTER, ap %p\n", ap);
|
||||
|
||||
writel(0x00000001, mmio + (seq * 4));
|
||||
readl(mmio + (seq * 4)); /* flush */
|
||||
|
||||
pp->pkt[2] = seq;
|
||||
wmb(); /* flush PRD, pkt writes */
|
||||
writel(pp->pkt_dma, ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
|
||||
readl(ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); /* flush */
|
||||
}
|
||||
|
||||
static unsigned int pdc_qc_issue_prot(struct ata_queued_cmd *qc)
|
||||
{
|
||||
switch (qc->tf.protocol) {
|
||||
case ATA_PROT_ATAPI_NODATA:
|
||||
if (qc->dev->flags & ATA_DFLAG_CDB_INTR)
|
||||
break;
|
||||
/*FALLTHROUGH*/
|
||||
case ATA_PROT_ATAPI_DMA:
|
||||
case ATA_PROT_DMA:
|
||||
case ATA_PROT_NODATA:
|
||||
pdc_packet_start(qc);
|
||||
return 0;
|
||||
|
||||
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 int pdc_check_atapi_dma(struct ata_queued_cmd *qc)
|
||||
{
|
||||
u8 *scsicmd = qc->scsicmd->cmnd;
|
||||
int pio = 1; /* atapi dma off by default */
|
||||
|
||||
/* Whitelist commands that may use DMA. */
|
||||
switch (scsicmd[0]) {
|
||||
case WRITE_12:
|
||||
case WRITE_10:
|
||||
case WRITE_6:
|
||||
case READ_12:
|
||||
case READ_10:
|
||||
case READ_6:
|
||||
case 0xad: /* READ_DVD_STRUCTURE */
|
||||
case 0xbe: /* READ_CD */
|
||||
pio = 0;
|
||||
}
|
||||
/* -45150 (FFFF4FA2) to -1 (FFFFFFFF) shall use PIO mode */
|
||||
if (scsicmd[0] == WRITE_10) {
|
||||
unsigned int lba;
|
||||
lba = (scsicmd[2] << 24) | (scsicmd[3] << 16) | (scsicmd[4] << 8) | scsicmd[5];
|
||||
if (lba >= 0xFFFF4FA2)
|
||||
pio = 1;
|
||||
}
|
||||
return pio;
|
||||
}
|
||||
|
||||
static int pdc_old_check_atapi_dma(struct ata_queued_cmd *qc)
|
||||
{
|
||||
struct ata_port *ap = qc->ap;
|
||||
|
||||
/* First generation chips cannot use ATAPI DMA on SATA ports */
|
||||
if (sata_scr_valid(ap))
|
||||
return 1;
|
||||
return pdc_check_atapi_dma(qc);
|
||||
}
|
||||
|
||||
static void pdc_ata_setup_port(struct ata_ioports *port, void __iomem *base,
|
||||
void __iomem *scr_addr)
|
||||
{
|
||||
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;
|
||||
port->scr_addr = scr_addr;
|
||||
}
|
||||
|
||||
|
||||
static void pdc_host_init(unsigned int chip_id, struct ata_probe_ent *pe)
|
||||
{
|
||||
void __iomem *mmio = pe->iomap[PDC_MMIO_BAR];
|
||||
struct pdc_host_priv *hp = pe->private_data;
|
||||
int hotplug_offset;
|
||||
u32 tmp;
|
||||
|
||||
if (hp->flags & PDC_FLAG_GEN_II)
|
||||
hotplug_offset = PDC2_SATA_PLUG_CSR;
|
||||
else
|
||||
hotplug_offset = PDC_SATA_PLUG_CSR;
|
||||
|
||||
/*
|
||||
* Except for the hotplug stuff, this is voodoo from the
|
||||
* Promise driver. Label this entire section
|
||||
* "TODO: figure out why we do this"
|
||||
*/
|
||||
|
||||
/* enable BMR_BURST, maybe change FIFO_SHD to 8 dwords */
|
||||
tmp = readl(mmio + PDC_FLASH_CTL);
|
||||
tmp |= 0x02000; /* bit 13 (enable bmr burst) */
|
||||
if (!(hp->flags & PDC_FLAG_GEN_II))
|
||||
tmp |= 0x10000; /* bit 16 (fifo threshold at 8 dw) */
|
||||
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);
|
||||
|
||||
/* don't initialise TBG or SLEW on 2nd generation chips */
|
||||
if (hp->flags & PDC_FLAG_GEN_II)
|
||||
return;
|
||||
|
||||
/* 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;
|
||||
struct pdc_host_priv *hp;
|
||||
void __iomem *base;
|
||||
unsigned int board_idx = (unsigned int) ent->driver_data;
|
||||
int rc;
|
||||
u8 tmp;
|
||||
|
||||
if (!printed_version++)
|
||||
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
|
||||
|
||||
rc = pcim_enable_device(pdev);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = pcim_iomap_regions(pdev, 1 << PDC_MMIO_BAR, DRV_NAME);
|
||||
if (rc == -EBUSY)
|
||||
pcim_pin_device(pdev);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
|
||||
if (rc)
|
||||
return rc;
|
||||
rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
probe_ent = devm_kzalloc(&pdev->dev, sizeof(*probe_ent), GFP_KERNEL);
|
||||
if (probe_ent == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
probe_ent->dev = pci_dev_to_dev(pdev);
|
||||
INIT_LIST_HEAD(&probe_ent->node);
|
||||
|
||||
hp = devm_kzalloc(&pdev->dev, sizeof(*hp), GFP_KERNEL);
|
||||
if (hp == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
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->iomap = pcim_iomap_table(pdev);
|
||||
|
||||
base = probe_ent->iomap[PDC_MMIO_BAR];
|
||||
|
||||
pdc_ata_setup_port(&probe_ent->port[0], base + 0x200, base + 0x400);
|
||||
pdc_ata_setup_port(&probe_ent->port[1], base + 0x280, base + 0x500);
|
||||
|
||||
/* notice 4-port boards */
|
||||
switch (board_idx) {
|
||||
case board_40518:
|
||||
hp->flags |= PDC_FLAG_GEN_II;
|
||||
/* Fall through */
|
||||
case board_20319:
|
||||
probe_ent->n_ports = 4;
|
||||
pdc_ata_setup_port(&probe_ent->port[2], base + 0x300, base + 0x600);
|
||||
pdc_ata_setup_port(&probe_ent->port[3], base + 0x380, base + 0x700);
|
||||
break;
|
||||
case board_2057x:
|
||||
hp->flags |= PDC_FLAG_GEN_II;
|
||||
/* Fall through */
|
||||
case board_2037x:
|
||||
/* TX2plus boards also have a PATA port */
|
||||
tmp = readb(base + PDC_FLASH_CTL+1);
|
||||
if (!(tmp & 0x80)) {
|
||||
probe_ent->n_ports = 3;
|
||||
pdc_ata_setup_port(&probe_ent->port[2], base + 0x300, NULL);
|
||||
hp->port_flags[2] = ATA_FLAG_SLAVE_POSS;
|
||||
printk(KERN_INFO DRV_NAME " PATA port found\n");
|
||||
} else
|
||||
probe_ent->n_ports = 2;
|
||||
hp->port_flags[0] = ATA_FLAG_SATA;
|
||||
hp->port_flags[1] = ATA_FLAG_SATA;
|
||||
break;
|
||||
case board_20619:
|
||||
probe_ent->n_ports = 4;
|
||||
pdc_ata_setup_port(&probe_ent->port[2], base + 0x300, NULL);
|
||||
pdc_ata_setup_port(&probe_ent->port[3], base + 0x380, NULL);
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
break;
|
||||
}
|
||||
|
||||
pci_set_master(pdev);
|
||||
|
||||
/* initialize adapter */
|
||||
pdc_host_init(board_idx, probe_ent);
|
||||
|
||||
if (!ata_device_add(probe_ent))
|
||||
return -ENODEV;
|
||||
|
||||
devm_kfree(&pdev->dev, probe_ent);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
157
drivers/ata/sata_promise.h
Normal file
157
drivers/ata/sata_promise.h
Normal file
@@ -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__ */
|
||||
688
drivers/ata/sata_qstor.c
Normal file
688
drivers/ata/sata_qstor.c
Normal file
@@ -0,0 +1,688 @@
|
||||
/*
|
||||
* 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/device.h>
|
||||
#include <scsi/scsi_host.h>
|
||||
#include <linux/libata.h>
|
||||
|
||||
#define DRV_NAME "sata_qstor"
|
||||
#define DRV_VERSION "0.07"
|
||||
|
||||
enum {
|
||||
QS_MMIO_BAR = 4,
|
||||
|
||||
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);
|
||||
static int qs_port_start(struct ata_port *ap);
|
||||
static void qs_host_stop(struct ata_host *host);
|
||||
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_data_xfer,
|
||||
.eng_timeout = qs_eng_timeout,
|
||||
.irq_handler = qs_intr,
|
||||
.irq_clear = qs_irq_clear,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
.scr_read = qs_scr_read,
|
||||
.scr_write = qs_scr_write,
|
||||
.port_start = qs_port_start,
|
||||
.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_VDEVICE(PDC, 0x2068), 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 void __iomem *qs_mmio_base(struct ata_host *host)
|
||||
{
|
||||
return host->iomap[QS_MMIO_BAR];
|
||||
}
|
||||
|
||||
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 = qs_mmio_base(ap->host) + (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 = qs_mmio_base(ap->host) + (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(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, 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->nbytes);
|
||||
*(__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 = qs_mmio_base(ap->host) + (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 = qs_mmio_base(host);
|
||||
|
||||
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->print_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 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, void __iomem *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 = qs_mmio_base(ap->host);
|
||||
void __iomem *chan = mmio_base + (ap->port_no * 0x4000);
|
||||
u64 addr;
|
||||
int rc;
|
||||
|
||||
rc = ata_port_start(ap);
|
||||
if (rc)
|
||||
return rc;
|
||||
qs_enter_reg_mode(ap);
|
||||
pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
|
||||
if (!pp)
|
||||
return -ENOMEM;
|
||||
pp->pkt = dmam_alloc_coherent(dev, QS_PKT_BYTES, &pp->pkt_dma,
|
||||
GFP_KERNEL);
|
||||
if (!pp->pkt)
|
||||
return -ENOMEM;
|
||||
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;
|
||||
}
|
||||
|
||||
static void qs_host_stop(struct ata_host *host)
|
||||
{
|
||||
void __iomem *mmio_base = qs_mmio_base(host);
|
||||
|
||||
writeb(0, mmio_base + QS_HCT_CTRL); /* disable host interrupts */
|
||||
writeb(QS_CNFG3_GSRST, mmio_base + QS_HCF_CNFG3); /* global reset */
|
||||
}
|
||||
|
||||
static void qs_host_init(unsigned int chip_id, struct ata_probe_ent *pe)
|
||||
{
|
||||
void __iomem *mmio_base = pe->iomap[QS_MMIO_BAR];
|
||||
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;
|
||||
void __iomem * const *iomap;
|
||||
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 = pcim_enable_device(pdev);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if ((pci_resource_flags(pdev, QS_MMIO_BAR) & IORESOURCE_MEM) == 0)
|
||||
return -ENODEV;
|
||||
|
||||
rc = pcim_iomap_regions(pdev, 1 << QS_MMIO_BAR, DRV_NAME);
|
||||
if (rc)
|
||||
return rc;
|
||||
iomap = pcim_iomap_table(pdev);
|
||||
|
||||
rc = qs_set_dma_masks(pdev, iomap[QS_MMIO_BAR]);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
probe_ent = devm_kzalloc(&pdev->dev, sizeof(*probe_ent), GFP_KERNEL);
|
||||
if (probe_ent == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
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->iomap = iomap;
|
||||
probe_ent->n_ports = QS_PORTS;
|
||||
|
||||
for (port_no = 0; port_no < probe_ent->n_ports; ++port_no) {
|
||||
void __iomem *chan =
|
||||
probe_ent->iomap[QS_MMIO_BAR] + (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);
|
||||
|
||||
if (ata_device_add(probe_ent) != QS_PORTS)
|
||||
return -EIO;
|
||||
|
||||
devm_kfree(&pdev->dev, probe_ent);
|
||||
return 0;
|
||||
}
|
||||
|
||||
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);
|
||||
732
drivers/ata/sata_sil.c
Normal file
732
drivers/ata/sata_sil.c
Normal file
@@ -0,0 +1,732 @@
|
||||
/*
|
||||
* 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.1"
|
||||
|
||||
enum {
|
||||
SIL_MMIO_BAR = 5,
|
||||
|
||||
/*
|
||||
* 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);
|
||||
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[] = {
|
||||
{ PCI_VDEVICE(CMD, 0x3112), sil_3112 },
|
||||
{ PCI_VDEVICE(CMD, 0x0240), sil_3112 },
|
||||
{ PCI_VDEVICE(CMD, 0x3512), sil_3512 },
|
||||
{ PCI_VDEVICE(CMD, 0x3114), sil_3114 },
|
||||
{ PCI_VDEVICE(ATI, 0x436e), sil_3112 },
|
||||
{ PCI_VDEVICE(ATI, 0x4379), sil_3112_no_sata_irq },
|
||||
{ PCI_VDEVICE(ATI, 0x437a), 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,
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = ata_scsi_device_suspend,
|
||||
.resume = ata_scsi_device_resume,
|
||||
#endif
|
||||
};
|
||||
|
||||
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_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,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
.scr_read = sil_scr_read,
|
||||
.scr_write = sil_scr_write,
|
||||
.port_start = ata_port_start,
|
||||
};
|
||||
|
||||
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 *mmio_base = host->iomap[SIL_MMIO_BAR];
|
||||
void __iomem *addr = 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 void __iomem *sil_scr_addr(struct ata_port *ap, unsigned int sc_reg)
|
||||
{
|
||||
void __iomem *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 NULL;
|
||||
}
|
||||
|
||||
static u32 sil_scr_read (struct ata_port *ap, unsigned int sc_reg)
|
||||
{
|
||||
void __iomem *mmio = 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 __iomem *mmio = sil_scr_addr(ap, sc_reg);
|
||||
if (mmio)
|
||||
writel(val, mmio);
|
||||
}
|
||||
|
||||
static void sil_host_intr(struct ata_port *ap, u32 bmdma2)
|
||||
{
|
||||
struct ata_eh_info *ehi = &ap->eh_info;
|
||||
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))
|
||||
goto freeze;
|
||||
|
||||
if (unlikely(qc->tf.flags & ATA_TFLAG_POLLING)) {
|
||||
/* this sometimes happens, just clear IRQ */
|
||||
ata_chk_status(ap);
|
||||
return;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
||||
if (unlikely(qc->err_mask) && (qc->tf.protocol == ATA_PROT_DMA ||
|
||||
qc->tf.protocol == ATA_PROT_ATAPI_DMA))
|
||||
ata_ehi_push_desc(ehi, "BMDMA2 stat 0x%x", bmdma2);
|
||||
|
||||
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 ata_host *host = dev_instance;
|
||||
void __iomem *mmio_base = host->iomap[SIL_MMIO_BAR];
|
||||
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->iomap[SIL_MMIO_BAR];
|
||||
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->iomap[SIL_MMIO_BAR];
|
||||
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)
|
||||
{
|
||||
int print_info = ap->eh_context.i.flags & ATA_EHI_PRINTINFO;
|
||||
unsigned int n, quirks = 0;
|
||||
unsigned char model_num[ATA_ID_PROD_LEN + 1];
|
||||
|
||||
ata_id_c_string(dev->id, model_num, ATA_ID_PROD, 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))) {
|
||||
if (print_info)
|
||||
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) {
|
||||
if (print_info)
|
||||
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 device *dev = &pdev->dev;
|
||||
struct ata_probe_ent *probe_ent;
|
||||
void __iomem *mmio_base;
|
||||
int rc;
|
||||
unsigned int i;
|
||||
|
||||
if (!printed_version++)
|
||||
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
|
||||
|
||||
rc = pcim_enable_device(pdev);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = pcim_iomap_regions(pdev, 1 << SIL_MMIO_BAR, DRV_NAME);
|
||||
if (rc == -EBUSY)
|
||||
pcim_pin_device(pdev);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
|
||||
if (rc)
|
||||
return rc;
|
||||
rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
probe_ent = devm_kzalloc(dev, sizeof(*probe_ent), GFP_KERNEL);
|
||||
if (probe_ent == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
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;
|
||||
|
||||
probe_ent->iomap = pcim_iomap_table(pdev);
|
||||
|
||||
mmio_base = probe_ent->iomap[SIL_MMIO_BAR];
|
||||
|
||||
for (i = 0; i < probe_ent->n_ports; i++) {
|
||||
probe_ent->port[i].cmd_addr = mmio_base + sil_port[i].tf;
|
||||
probe_ent->port[i].altstatus_addr =
|
||||
probe_ent->port[i].ctl_addr = mmio_base + sil_port[i].ctl;
|
||||
probe_ent->port[i].bmdma_addr = mmio_base + sil_port[i].bmdma;
|
||||
probe_ent->port[i].scr_addr = mmio_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);
|
||||
|
||||
if (!ata_device_add(probe_ent))
|
||||
return -ENODEV;
|
||||
|
||||
devm_kfree(dev, probe_ent);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int sil_pci_device_resume(struct pci_dev *pdev)
|
||||
{
|
||||
struct ata_host *host = dev_get_drvdata(&pdev->dev);
|
||||
int rc;
|
||||
|
||||
rc = ata_pci_device_do_resume(pdev);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
sil_init_controller(pdev, host->n_ports, host->ports[0]->flags,
|
||||
host->iomap[SIL_MMIO_BAR]);
|
||||
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);
|
||||
1174
drivers/ata/sata_sil24.c
Normal file
1174
drivers/ata/sata_sil24.c
Normal file
File diff suppressed because it is too large
Load Diff
389
drivers/ata/sata_sis.c
Normal file
389
drivers/ata/sata_sis.c
Normal file
@@ -0,0 +1,389 @@
|
||||
/*
|
||||
* 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>
|
||||
#include "sis.h"
|
||||
|
||||
#define DRV_NAME "sata_sis"
|
||||
#define DRV_VERSION "0.7"
|
||||
|
||||
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_VDEVICE(SI, 0x0180), sis_180 }, /* SiS 964/180 */
|
||||
{ PCI_VDEVICE(SI, 0x0181), sis_180 }, /* SiS 964/180 */
|
||||
{ PCI_VDEVICE(SI, 0x0182), sis_180 }, /* SiS 965/965L */
|
||||
{ PCI_VDEVICE(SI, 0x0183), sis_180 }, /* SiS 965/965L */
|
||||
{ PCI_VDEVICE(SI, 0x1182), sis_180 }, /* SiS 966/966L */
|
||||
{ PCI_VDEVICE(SI, 0x1183), sis_180 }, /* SiS 966/966L */
|
||||
|
||||
{ } /* 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_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,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
.scr_read = sis_scr_read,
|
||||
.scr_write = sis_scr_write,
|
||||
.port_start = ata_port_start,
|
||||
};
|
||||
|
||||
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(struct ata_port *ap, unsigned int sc_reg)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
|
||||
unsigned int addr = SIS_SCR_BASE + (4 * sc_reg);
|
||||
u8 pmr;
|
||||
|
||||
if (ap->port_no) {
|
||||
switch (pdev->device) {
|
||||
case 0x0180:
|
||||
case 0x0181:
|
||||
pci_read_config_byte(pdev, SIS_PMR, &pmr);
|
||||
if ((pmr & SIS_PMR_COMBINED) == 0)
|
||||
addr += SIS180_SATA1_OFS;
|
||||
break;
|
||||
|
||||
case 0x0182:
|
||||
case 0x0183:
|
||||
case 0x1182:
|
||||
case 0x1183:
|
||||
addr += SIS182_SATA1_OFS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
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, sc_reg);
|
||||
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 == 0x0182) || (pdev->device == 0x0183) || (pdev->device == 0x1182) ||
|
||||
(pdev->device == 0x1183) || (pmr & SIS_PMR_COMBINED))
|
||||
pci_read_config_dword(pdev, cfg_addr+0x10, &val2);
|
||||
|
||||
return (val|val2) & 0xfffffffb; /* avoid problems with powerdowned ports */
|
||||
}
|
||||
|
||||
static void sis_scr_cfg_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
|
||||
unsigned int cfg_addr = get_scr_cfg_addr(ap, sc_reg);
|
||||
u8 pmr;
|
||||
|
||||
if (sc_reg == SCR_ERROR) /* doesn't exist in PCI cfg space */
|
||||
return;
|
||||
|
||||
pci_read_config_byte(pdev, SIS_PMR, &pmr);
|
||||
|
||||
pci_write_config_dword(pdev, cfg_addr, val);
|
||||
|
||||
if ((pdev->device == 0x0182) || (pdev->device == 0x0183) || (pdev->device == 0x1182) ||
|
||||
(pdev->device == 0x1183) || (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 = ioread32(ap->ioaddr.scr_addr + (sc_reg * 4));
|
||||
|
||||
if ((pdev->device == 0x0182) || (pdev->device == 0x0183) || (pdev->device == 0x1182) ||
|
||||
(pdev->device == 0x1183) || (pmr & SIS_PMR_COMBINED))
|
||||
val2 = ioread32(ap->ioaddr.scr_addr + (sc_reg * 4) + 0x10);
|
||||
|
||||
return (val | val2) & 0xfffffffb;
|
||||
}
|
||||
|
||||
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 {
|
||||
iowrite32(val, ap->ioaddr.scr_addr + (sc_reg * 4));
|
||||
if ((pdev->device == 0x0182) || (pdev->device == 0x0183) || (pdev->device == 0x1182) ||
|
||||
(pdev->device == 0x1183) || (pmr & SIS_PMR_COMBINED))
|
||||
iowrite32(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, val;
|
||||
struct ata_port_info pi = sis_port_info, *ppi[2] = { &pi, &pi };
|
||||
u8 pmr;
|
||||
u8 port2_start = 0x20;
|
||||
|
||||
if (!printed_version++)
|
||||
dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n");
|
||||
|
||||
rc = pcim_enable_device(pdev);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = pci_request_regions(pdev, DRV_NAME);
|
||||
if (rc) {
|
||||
pcim_pin_device(pdev);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
|
||||
if (rc)
|
||||
return rc;
|
||||
rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* 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)
|
||||
pi.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 ((!(pi.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);
|
||||
pi.flags |= SIS_FLAG_CFGSCR;
|
||||
}
|
||||
|
||||
pci_read_config_byte(pdev, SIS_PMR, &pmr);
|
||||
switch (ent->device) {
|
||||
case 0x0180:
|
||||
case 0x0181:
|
||||
|
||||
/* The PATA-handling is provided by pata_sis */
|
||||
switch (pmr & 0x30) {
|
||||
case 0x10:
|
||||
ppi[1] = &sis_info133;
|
||||
break;
|
||||
|
||||
case 0x30:
|
||||
ppi[0] = &sis_info133;
|
||||
break;
|
||||
}
|
||||
if ((pmr & SIS_PMR_COMBINED) == 0) {
|
||||
dev_printk(KERN_INFO, &pdev->dev,
|
||||
"Detected SiS 180/181/964 chipset in SATA mode\n");
|
||||
port2_start = 64;
|
||||
} else {
|
||||
dev_printk(KERN_INFO, &pdev->dev,
|
||||
"Detected SiS 180/181 chipset in combined mode\n");
|
||||
port2_start=0;
|
||||
pi.flags |= ATA_FLAG_SLAVE_POSS;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x0182:
|
||||
case 0x0183:
|
||||
pci_read_config_dword ( pdev, 0x6C, &val);
|
||||
if (val & (1L << 31)) {
|
||||
dev_printk(KERN_INFO, &pdev->dev, "Detected SiS 182/965 chipset\n");
|
||||
pi.flags |= ATA_FLAG_SLAVE_POSS;
|
||||
} else {
|
||||
dev_printk(KERN_INFO, &pdev->dev, "Detected SiS 182/965L chipset\n");
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x1182:
|
||||
case 0x1183:
|
||||
pci_read_config_dword(pdev, 0x64, &val);
|
||||
if (val & 0x10000000) {
|
||||
dev_printk(KERN_INFO, &pdev->dev, "Detected SiS 1182/1183/966L SATA controller\n");
|
||||
} else {
|
||||
dev_printk(KERN_INFO, &pdev->dev, "Detected SiS 1182/1183/966 SATA controller\n");
|
||||
pi.flags |= ATA_FLAG_SLAVE_POSS;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
probe_ent = ata_pci_init_native_mode(pdev, ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY);
|
||||
if (!probe_ent)
|
||||
return -ENOMEM;
|
||||
|
||||
if (!(probe_ent->port_flags & SIS_FLAG_CFGSCR)) {
|
||||
void __iomem *mmio;
|
||||
|
||||
mmio = pcim_iomap(pdev, SIS_SCR_PCI_BAR, 0);
|
||||
if (!mmio)
|
||||
return -ENOMEM;
|
||||
|
||||
probe_ent->port[0].scr_addr = mmio;
|
||||
probe_ent->port[1].scr_addr = mmio + port2_start;
|
||||
}
|
||||
|
||||
pci_set_master(pdev);
|
||||
pci_intx(pdev, 1);
|
||||
|
||||
if (!ata_device_add(probe_ent))
|
||||
return -EIO;
|
||||
|
||||
devm_kfree(&pdev->dev, probe_ent);
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
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);
|
||||
520
drivers/ata/sata_svw.c
Normal file
520
drivers/ata/sata_svw.c
Normal file
@@ -0,0 +1,520 @@
|
||||
/*
|
||||
* 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.1"
|
||||
|
||||
enum {
|
||||
K2_FLAG_NO_ATAPI_DMA = (1 << 29),
|
||||
|
||||
/* 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,
|
||||
|
||||
board_svw4 = 0,
|
||||
board_svw8 = 1,
|
||||
};
|
||||
|
||||
static const struct k2_board_info {
|
||||
unsigned int n_ports;
|
||||
unsigned long port_flags;
|
||||
} k2_board_info[] = {
|
||||
/* board_svw4 */
|
||||
{ 4, K2_FLAG_NO_ATAPI_DMA },
|
||||
|
||||
/* board_svw8 */
|
||||
{ 8, K2_FLAG_NO_ATAPI_DMA },
|
||||
};
|
||||
|
||||
static u8 k2_stat_check_status(struct ata_port *ap);
|
||||
|
||||
|
||||
static int k2_sata_check_atapi_dma(struct ata_queued_cmd *qc)
|
||||
{
|
||||
if (qc->ap->flags & K2_FLAG_NO_ATAPI_DMA)
|
||||
return -1; /* ATAPI DMA not supported */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u32 k2_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 k2_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 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 __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 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 __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);
|
||||
/* 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 __iomem *) 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,
|
||||
.check_atapi_dma = k2_sata_check_atapi_dma,
|
||||
.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_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,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
.scr_read = k2_sata_scr_read,
|
||||
.scr_write = k2_sata_scr_write,
|
||||
.port_start = ata_port_start,
|
||||
};
|
||||
|
||||
static void k2_sata_setup_port(struct ata_ioports *port, void __iomem *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 device *dev = &pdev->dev;
|
||||
struct ata_probe_ent *probe_ent;
|
||||
void __iomem *mmio_base;
|
||||
const struct k2_board_info *board_info =
|
||||
&k2_board_info[ent->driver_data];
|
||||
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 = pcim_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 and iomap PCI regions */
|
||||
rc = pcim_iomap_regions(pdev, 1 << 5, DRV_NAME);
|
||||
if (rc == -EBUSY)
|
||||
pcim_pin_device(pdev);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
|
||||
if (rc)
|
||||
return rc;
|
||||
rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
probe_ent = devm_kzalloc(dev, sizeof(*probe_ent), GFP_KERNEL);
|
||||
if (probe_ent == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
probe_ent->dev = pci_dev_to_dev(pdev);
|
||||
INIT_LIST_HEAD(&probe_ent->node);
|
||||
|
||||
probe_ent->sht = &k2_sata_sht;
|
||||
probe_ent->port_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
|
||||
ATA_FLAG_MMIO | board_info->port_flags;
|
||||
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->iomap = pcim_iomap_table(pdev);
|
||||
|
||||
/* 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;
|
||||
|
||||
mmio_base = probe_ent->iomap[5];
|
||||
|
||||
/* 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 < board_info->n_ports; i++)
|
||||
k2_sata_setup_port(&probe_ent->port[i],
|
||||
mmio_base + i * K2_SATA_PORT_OFFSET);
|
||||
|
||||
/* 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);
|
||||
|
||||
pci_set_master(pdev);
|
||||
|
||||
if (!ata_device_add(probe_ent))
|
||||
return -ENODEV;
|
||||
|
||||
devm_kfree(dev, probe_ent);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 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[] = {
|
||||
{ PCI_VDEVICE(SERVERWORKS, 0x0240), board_svw4 },
|
||||
{ PCI_VDEVICE(SERVERWORKS, 0x0241), board_svw4 },
|
||||
{ PCI_VDEVICE(SERVERWORKS, 0x0242), board_svw8 },
|
||||
{ PCI_VDEVICE(SERVERWORKS, 0x024a), board_svw4 },
|
||||
{ PCI_VDEVICE(SERVERWORKS, 0x024b), board_svw4 },
|
||||
|
||||
{ }
|
||||
};
|
||||
|
||||
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);
|
||||
1417
drivers/ata/sata_sx4.c
Normal file
1417
drivers/ata/sata_sx4.c
Normal file
File diff suppressed because it is too large
Load Diff
289
drivers/ata/sata_uli.c
Normal file
289
drivers/ata/sata_uli.c
Normal file
@@ -0,0 +1,289 @@
|
||||
/*
|
||||
* 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.1"
|
||||
|
||||
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_VDEVICE(AL, 0x5289), uli_5289 },
|
||||
{ PCI_VDEVICE(AL, 0x5287), uli_5287 },
|
||||
{ PCI_VDEVICE(AL, 0x5281), 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_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,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
|
||||
.scr_read = uli_scr_read,
|
||||
.scr_write = uli_scr_write,
|
||||
|
||||
.port_start = ata_port_start,
|
||||
};
|
||||
|
||||
static struct ata_port_info uli_port_info = {
|
||||
.sht = &uli_sht,
|
||||
.flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
|
||||
ATA_FLAG_IGN_SIMPLEX,
|
||||
.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;
|
||||
struct uli_priv *hpriv;
|
||||
void __iomem * const *iomap;
|
||||
|
||||
if (!printed_version++)
|
||||
dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n");
|
||||
|
||||
rc = pcim_enable_device(pdev);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = pci_request_regions(pdev, DRV_NAME);
|
||||
if (rc) {
|
||||
pcim_pin_device(pdev);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
|
||||
if (rc)
|
||||
return rc;
|
||||
rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
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)
|
||||
return -ENOMEM;
|
||||
|
||||
hpriv = devm_kzalloc(&pdev->dev, sizeof(*hpriv), GFP_KERNEL);
|
||||
if (!hpriv)
|
||||
return -ENOMEM;
|
||||
|
||||
probe_ent->private_data = hpriv;
|
||||
|
||||
iomap = pcim_iomap_table(pdev);
|
||||
|
||||
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 = iomap[0] + 8;
|
||||
probe_ent->port[2].altstatus_addr =
|
||||
probe_ent->port[2].ctl_addr = (void __iomem *)
|
||||
((unsigned long)iomap[1] | ATA_PCI_CTL_OFS) + 4;
|
||||
probe_ent->port[2].bmdma_addr = iomap[4] + 16;
|
||||
hpriv->scr_cfg_addr[2] = ULI5287_BASE + ULI5287_OFFS*4;
|
||||
|
||||
probe_ent->port[3].cmd_addr = iomap[2] + 8;
|
||||
probe_ent->port[3].altstatus_addr =
|
||||
probe_ent->port[3].ctl_addr = (void __iomem *)
|
||||
((unsigned long)iomap[3] | ATA_PCI_CTL_OFS) + 4;
|
||||
probe_ent->port[3].bmdma_addr = iomap[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);
|
||||
|
||||
if (!ata_device_add(probe_ent))
|
||||
return -ENODEV;
|
||||
|
||||
devm_kfree(&pdev->dev, probe_ent);
|
||||
return 0;
|
||||
}
|
||||
|
||||
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);
|
||||
615
drivers/ata/sata_via.c
Normal file
615
drivers/ata/sata_via.c
Normal file
@@ -0,0 +1,615 @@
|
||||
/*
|
||||
* 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>
|
||||
|
||||
#define DRV_NAME "sata_via"
|
||||
#define DRV_VERSION "2.1"
|
||||
|
||||
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 */
|
||||
PATA_UDMA_TIMING = 0xB3, /* PATA timing for DMA/ cable detect */
|
||||
PATA_PIO_TIMING = 0xAB, /* PATA timing register */
|
||||
|
||||
PORT0 = (1 << 1),
|
||||
PORT1 = (1 << 0),
|
||||
ALL_PORTS = PORT0 | PORT1,
|
||||
PATA_PORT = 2, /* PATA is port 2 */
|
||||
N_PORTS = 3,
|
||||
|
||||
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 svia_noop_freeze(struct ata_port *ap);
|
||||
static void vt6420_error_handler(struct ata_port *ap);
|
||||
static void vt6421_sata_error_handler(struct ata_port *ap);
|
||||
static void vt6421_pata_error_handler(struct ata_port *ap);
|
||||
static void vt6421_set_pio_mode(struct ata_port *ap, struct ata_device *adev);
|
||||
static void vt6421_set_dma_mode(struct ata_port *ap, struct ata_device *adev);
|
||||
static int vt6421_port_start(struct ata_port *ap);
|
||||
|
||||
static const struct pci_device_id svia_pci_tbl[] = {
|
||||
{ PCI_VDEVICE(VIA, 0x5337), vt6420 },
|
||||
{ PCI_VDEVICE(VIA, 0x0591), vt6420 },
|
||||
{ PCI_VDEVICE(VIA, 0x3149), vt6420 },
|
||||
{ PCI_VDEVICE(VIA, 0x3249), vt6421 },
|
||||
|
||||
{ } /* terminate list */
|
||||
};
|
||||
|
||||
static struct pci_driver svia_pci_driver = {
|
||||
.name = DRV_NAME,
|
||||
.id_table = svia_pci_tbl,
|
||||
.probe = svia_init_one,
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = ata_pci_device_suspend,
|
||||
.resume = ata_pci_device_resume,
|
||||
#endif
|
||||
.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,
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = ata_scsi_device_suspend,
|
||||
.resume = ata_scsi_device_resume,
|
||||
#endif
|
||||
};
|
||||
|
||||
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_data_xfer,
|
||||
|
||||
.freeze = svia_noop_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,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
|
||||
.port_start = ata_port_start,
|
||||
};
|
||||
|
||||
static const struct ata_port_operations vt6421_pata_ops = {
|
||||
.port_disable = ata_port_disable,
|
||||
|
||||
.set_piomode = vt6421_set_pio_mode,
|
||||
.set_dmamode = vt6421_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,
|
||||
|
||||
.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_data_xfer,
|
||||
|
||||
.freeze = ata_bmdma_freeze,
|
||||
.thaw = ata_bmdma_thaw,
|
||||
.error_handler = vt6421_pata_error_handler,
|
||||
.post_internal_cmd = ata_bmdma_post_internal_cmd,
|
||||
|
||||
.irq_handler = ata_interrupt,
|
||||
.irq_clear = ata_bmdma_irq_clear,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
|
||||
.port_start = vt6421_port_start,
|
||||
};
|
||||
|
||||
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_data_xfer,
|
||||
|
||||
.freeze = ata_bmdma_freeze,
|
||||
.thaw = ata_bmdma_thaw,
|
||||
.error_handler = vt6421_sata_error_handler,
|
||||
.post_internal_cmd = ata_bmdma_post_internal_cmd,
|
||||
|
||||
.irq_handler = ata_interrupt,
|
||||
.irq_clear = ata_bmdma_irq_clear,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
|
||||
.scr_read = svia_scr_read,
|
||||
.scr_write = svia_scr_write,
|
||||
|
||||
.port_start = vt6421_port_start,
|
||||
};
|
||||
|
||||
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 ioread32(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;
|
||||
iowrite32(val, ap->ioaddr.scr_addr + (4 * sc_reg));
|
||||
}
|
||||
|
||||
static void svia_noop_freeze(struct ata_port *ap)
|
||||
{
|
||||
/* Some VIA controllers choke if ATA_NIEN is manipulated in
|
||||
* certain way. Leave it alone and just clear pending IRQ.
|
||||
*/
|
||||
ata_chk_status(ap);
|
||||
ata_bmdma_irq_clear(ap);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 (!(ap->pflags & 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 int vt6421_pata_prereset(struct ata_port *ap)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
|
||||
u8 tmp;
|
||||
|
||||
pci_read_config_byte(pdev, PATA_UDMA_TIMING, &tmp);
|
||||
if (tmp & 0x10)
|
||||
ap->cbl = ATA_CBL_PATA40;
|
||||
else
|
||||
ap->cbl = ATA_CBL_PATA80;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void vt6421_pata_error_handler(struct ata_port *ap)
|
||||
{
|
||||
return ata_bmdma_drive_eh(ap, vt6421_pata_prereset, ata_std_softreset,
|
||||
NULL, ata_std_postreset);
|
||||
}
|
||||
|
||||
static int vt6421_sata_prereset(struct ata_port *ap)
|
||||
{
|
||||
ap->cbl = ATA_CBL_SATA;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void vt6421_sata_error_handler(struct ata_port *ap)
|
||||
{
|
||||
return ata_bmdma_drive_eh(ap, vt6421_sata_prereset, ata_std_softreset,
|
||||
NULL, ata_std_postreset);
|
||||
}
|
||||
|
||||
static void vt6421_set_pio_mode(struct ata_port *ap, struct ata_device *adev)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
|
||||
static const u8 pio_bits[] = { 0xA8, 0x65, 0x65, 0x31, 0x20 };
|
||||
pci_write_config_byte(pdev, PATA_PIO_TIMING, pio_bits[adev->pio_mode - XFER_PIO_0]);
|
||||
}
|
||||
|
||||
static void vt6421_set_dma_mode(struct ata_port *ap, struct ata_device *adev)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
|
||||
static const u8 udma_bits[] = { 0xEE, 0xE8, 0xE6, 0xE4, 0xE2, 0xE1, 0xE0, 0xE0 };
|
||||
pci_write_config_byte(pdev, PATA_UDMA_TIMING, udma_bits[adev->pio_mode - XFER_UDMA_0]);
|
||||
}
|
||||
|
||||
static int vt6421_port_start(struct ata_port *ap)
|
||||
{
|
||||
if (ap->port_no == PATA_PORT) {
|
||||
ap->ops = &vt6421_pata_ops;
|
||||
ap->mwdma_mask = 0;
|
||||
ap->flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_NO_LEGACY | ATA_FLAG_SRST;
|
||||
}
|
||||
return ata_port_start(ap);
|
||||
}
|
||||
|
||||
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 void __iomem * svia_scr_addr(void __iomem *addr, unsigned int port)
|
||||
{
|
||||
return addr + (port * 128);
|
||||
}
|
||||
|
||||
static void __iomem * vt6421_scr_addr(void __iomem *addr, unsigned int port)
|
||||
{
|
||||
return addr + (port * 64);
|
||||
}
|
||||
|
||||
static void vt6421_init_addrs(struct ata_probe_ent *probe_ent,
|
||||
void __iomem * const *iomap, unsigned int port)
|
||||
{
|
||||
void __iomem *reg_addr = iomap[port];
|
||||
void __iomem *bmdma_addr = iomap[4] + (port * 8);
|
||||
|
||||
probe_ent->port[port].cmd_addr = reg_addr;
|
||||
probe_ent->port[port].altstatus_addr =
|
||||
probe_ent->port[port].ctl_addr = (void __iomem *)
|
||||
((unsigned long)(reg_addr + 8) | ATA_PCI_CTL_OFS);
|
||||
probe_ent->port[port].bmdma_addr = bmdma_addr;
|
||||
probe_ent->port[port].scr_addr = vt6421_scr_addr(iomap[5], port);
|
||||
|
||||
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];
|
||||
void __iomem *bar5;
|
||||
|
||||
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;
|
||||
|
||||
bar5 = pcim_iomap(pdev, 5, 0);
|
||||
if (!bar5) {
|
||||
dev_printk(KERN_ERR, &pdev->dev, "failed to iomap PCI BAR 5\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
probe_ent->port[0].scr_addr = svia_scr_addr(bar5, 0);
|
||||
probe_ent->port[1].scr_addr = svia_scr_addr(bar5, 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 = devm_kzalloc(&pdev->dev, 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 < 6; i++)
|
||||
if (!pcim_iomap(pdev, i, 0)) {
|
||||
dev_printk(KERN_ERR, &pdev->dev,
|
||||
"failed to iomap PCI BAR %d\n", i);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < N_PORTS; i++)
|
||||
vt6421_init_addrs(probe_ent, pcim_iomap_table(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;
|
||||
u8 tmp8;
|
||||
|
||||
if (!printed_version++)
|
||||
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
|
||||
|
||||
rc = pcim_enable_device(pdev);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = pci_request_regions(pdev, DRV_NAME);
|
||||
if (rc) {
|
||||
pcim_pin_device(pdev);
|
||||
return rc;
|
||||
}
|
||||
|
||||
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);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
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));
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
|
||||
if (rc)
|
||||
return rc;
|
||||
rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
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");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
svia_configure(pdev);
|
||||
|
||||
pci_set_master(pdev);
|
||||
|
||||
if (!ata_device_add(probe_ent))
|
||||
return -ENODEV;
|
||||
|
||||
devm_kfree(&pdev->dev, probe_ent);
|
||||
return 0;
|
||||
}
|
||||
|
||||
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);
|
||||
497
drivers/ata/sata_vsc.c
Normal file
497
drivers/ata/sata_vsc.c
Normal file
@@ -0,0 +1,497 @@
|
||||
/*
|
||||
* 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.1"
|
||||
|
||||
enum {
|
||||
VSC_MMIO_BAR = 0,
|
||||
|
||||
/* 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),
|
||||
};
|
||||
|
||||
static u32 vsc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg)
|
||||
{
|
||||
if (sc_reg > SCR_CONTROL)
|
||||
return 0xffffffffU;
|
||||
return readl(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, ap->ioaddr.scr_addr + (sc_reg * 4));
|
||||
}
|
||||
|
||||
|
||||
static void vsc_freeze(struct ata_port *ap)
|
||||
{
|
||||
void __iomem *mask_addr;
|
||||
|
||||
mask_addr = ap->host->iomap[VSC_MMIO_BAR] +
|
||||
VSC_SATA_INT_MASK_OFFSET + ap->port_no;
|
||||
|
||||
writeb(0, mask_addr);
|
||||
}
|
||||
|
||||
|
||||
static void vsc_thaw(struct ata_port *ap)
|
||||
{
|
||||
void __iomem *mask_addr;
|
||||
|
||||
mask_addr = ap->host->iomap[VSC_MMIO_BAR] +
|
||||
VSC_SATA_INT_MASK_OFFSET + ap->port_no;
|
||||
|
||||
writeb(0xff, mask_addr);
|
||||
}
|
||||
|
||||
|
||||
static void vsc_intr_mask_update(struct ata_port *ap, u8 ctl)
|
||||
{
|
||||
void __iomem *mask_addr;
|
||||
u8 mask;
|
||||
|
||||
mask_addr = ap->host->iomap[VSC_MMIO_BAR] +
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void vsc_error_intr(u8 port_status, struct ata_port *ap)
|
||||
{
|
||||
if (port_status & (VSC_SATA_INT_PHY_CHANGE | VSC_SATA_INT_ERROR_M))
|
||||
ata_port_freeze(ap);
|
||||
else
|
||||
ata_port_abort(ap);
|
||||
}
|
||||
|
||||
static void vsc_port_intr(u8 port_status, struct ata_port *ap)
|
||||
{
|
||||
struct ata_queued_cmd *qc;
|
||||
int handled = 0;
|
||||
|
||||
if (unlikely(port_status & VSC_SATA_INT_ERROR)) {
|
||||
vsc_error_intr(port_status, ap);
|
||||
return;
|
||||
}
|
||||
|
||||
qc = ata_qc_from_tag(ap, ap->active_tag);
|
||||
if (qc && likely(!(qc->tf.flags & ATA_TFLAG_POLLING)))
|
||||
handled = ata_host_intr(ap, qc);
|
||||
|
||||
/* We received an interrupt during a polled command,
|
||||
* or some other spurious condition. Interrupt reporting
|
||||
* with this hardware is fairly reliable so it is safe to
|
||||
* simply clear the interrupt
|
||||
*/
|
||||
if (unlikely(!handled))
|
||||
ata_chk_status(ap);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 ata_host *host = dev_instance;
|
||||
unsigned int i;
|
||||
unsigned int handled = 0;
|
||||
u32 status;
|
||||
|
||||
status = readl(host->iomap[VSC_MMIO_BAR] + VSC_SATA_INT_STAT_OFFSET);
|
||||
|
||||
if (unlikely(status == 0xffffffff || status == 0)) {
|
||||
if (status)
|
||||
dev_printk(KERN_ERR, host->dev,
|
||||
": IRQ status == 0xffffffff, "
|
||||
"PCI fault or device removal?\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
spin_lock(&host->lock);
|
||||
|
||||
for (i = 0; i < host->n_ports; i++) {
|
||||
u8 port_status = (status >> (8 * i)) & 0xff;
|
||||
if (port_status) {
|
||||
struct ata_port *ap = host->ports[i];
|
||||
|
||||
if (ap && !(ap->flags & ATA_FLAG_DISABLED)) {
|
||||
vsc_port_intr(port_status, ap);
|
||||
handled++;
|
||||
} else
|
||||
dev_printk(KERN_ERR, host->dev,
|
||||
": interrupt from disabled port %d\n", i);
|
||||
}
|
||||
}
|
||||
|
||||
spin_unlock(&host->lock);
|
||||
out:
|
||||
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_data_xfer,
|
||||
.freeze = vsc_freeze,
|
||||
.thaw = vsc_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,
|
||||
.irq_on = ata_irq_on,
|
||||
.irq_ack = ata_irq_ack,
|
||||
.scr_read = vsc_sata_scr_read,
|
||||
.scr_write = vsc_sata_scr_write,
|
||||
.port_start = ata_port_start,
|
||||
};
|
||||
|
||||
static void __devinit vsc_sata_setup_port(struct ata_ioports *port,
|
||||
void __iomem *base)
|
||||
{
|
||||
port->cmd_addr = base + VSC_SATA_TF_CMD_OFFSET;
|
||||
port->data_addr = base + VSC_SATA_TF_DATA_OFFSET;
|
||||
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;
|
||||
void __iomem *mmio_base;
|
||||
int rc;
|
||||
u8 cls;
|
||||
|
||||
if (!printed_version++)
|
||||
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
|
||||
|
||||
rc = pcim_enable_device(pdev);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/*
|
||||
* Check if we have needed resource mapped.
|
||||
*/
|
||||
if (pci_resource_len(pdev, 0) == 0)
|
||||
return -ENODEV;
|
||||
|
||||
rc = pcim_iomap_regions(pdev, 1 << VSC_MMIO_BAR, DRV_NAME);
|
||||
if (rc == -EBUSY)
|
||||
pcim_pin_device(pdev);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/*
|
||||
* Use 32 bit DMA mask, because 64 bit address support is poor.
|
||||
*/
|
||||
rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
|
||||
if (rc)
|
||||
return rc;
|
||||
rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
probe_ent = devm_kzalloc(&pdev->dev, sizeof(*probe_ent), GFP_KERNEL);
|
||||
if (probe_ent == NULL)
|
||||
return -ENOMEM;
|
||||
probe_ent->dev = pci_dev_to_dev(pdev);
|
||||
INIT_LIST_HEAD(&probe_ent->node);
|
||||
|
||||
/*
|
||||
* Due to a bug in the chip, the default cache line size can't be
|
||||
* used (unless the default is non-zero).
|
||||
*/
|
||||
pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &cls);
|
||||
if (cls == 0x00)
|
||||
pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 0x80);
|
||||
|
||||
if (pci_enable_msi(pdev) == 0)
|
||||
pci_intx(pdev, 0);
|
||||
else
|
||||
probe_ent->irq_flags = IRQF_SHARED;
|
||||
|
||||
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->iomap = pcim_iomap_table(pdev);
|
||||
|
||||
/* 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;
|
||||
|
||||
mmio_base = probe_ent->iomap[VSC_MMIO_BAR];
|
||||
|
||||
/* We have 4 ports per PCI function */
|
||||
vsc_sata_setup_port(&probe_ent->port[0], mmio_base + 1 * VSC_SATA_PORT_OFFSET);
|
||||
vsc_sata_setup_port(&probe_ent->port[1], mmio_base + 2 * VSC_SATA_PORT_OFFSET);
|
||||
vsc_sata_setup_port(&probe_ent->port[2], mmio_base + 3 * VSC_SATA_PORT_OFFSET);
|
||||
vsc_sata_setup_port(&probe_ent->port[3], mmio_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);
|
||||
|
||||
if (!ata_device_add(probe_ent))
|
||||
return -ENODEV;
|
||||
|
||||
devm_kfree(&pdev->dev, probe_ent);
|
||||
return 0;
|
||||
}
|
||||
|
||||
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);
|
||||
5
drivers/ata/sis.h
Normal file
5
drivers/ata/sis.h
Normal file
@@ -0,0 +1,5 @@
|
||||
|
||||
struct ata_port_info;
|
||||
|
||||
/* pata_sis.c */
|
||||
extern struct ata_port_info sis_info133;
|
||||
Reference in New Issue
Block a user