summaryrefslogtreecommitdiffstats
path: root/drivers/ide
diff options
context:
space:
mode:
authorTimothy Pearson <tpearson@raptorengineering.com>2017-08-23 14:45:25 -0500
committerTimothy Pearson <tpearson@raptorengineering.com>2017-08-23 14:45:25 -0500
commitfcbb27b0ec6dcbc5a5108cb8fb19eae64593d204 (patch)
tree22962a4387943edc841c72a4e636a068c66d58fd /drivers/ide
downloadast2050-linux-kernel-fcbb27b0ec6dcbc5a5108cb8fb19eae64593d204.zip
ast2050-linux-kernel-fcbb27b0ec6dcbc5a5108cb8fb19eae64593d204.tar.gz
Initial import of modified Linux 2.6.28 tree
Original upstream URL: git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git | branch linux-2.6.28.y
Diffstat (limited to 'drivers/ide')
-rw-r--r--drivers/ide/Kconfig910
-rw-r--r--drivers/ide/Makefile115
-rw-r--r--drivers/ide/aec62xx.c329
-rw-r--r--drivers/ide/ali14xx.c248
-rw-r--r--drivers/ide/alim15x3.c602
-rw-r--r--drivers/ide/amd74xx.c355
-rw-r--r--drivers/ide/atiixp.c209
-rw-r--r--drivers/ide/au1xxx-ide.c642
-rw-r--r--drivers/ide/buddha.c235
-rw-r--r--drivers/ide/cmd640.c836
-rw-r--r--drivers/ide/cmd64x.c532
-rw-r--r--drivers/ide/cs5520.c165
-rw-r--r--drivers/ide/cs5530.c295
-rw-r--r--drivers/ide/cs5535.c219
-rw-r--r--drivers/ide/cy82c693.c358
-rw-r--r--drivers/ide/delkin_cb.c192
-rw-r--r--drivers/ide/dtc2278.c153
-rw-r--r--drivers/ide/falconide.c153
-rw-r--r--drivers/ide/gayle.c190
-rw-r--r--drivers/ide/hpt366.c1643
-rw-r--r--drivers/ide/ht6560b.c351
-rw-r--r--drivers/ide/icside.c703
-rw-r--r--drivers/ide/ide-4drives.c63
-rw-r--r--drivers/ide/ide-acpi.c754
-rw-r--r--drivers/ide/ide-atapi.c597
-rw-r--r--drivers/ide/ide-cd.c2304
-rw-r--r--drivers/ide/ide-cd.h129
-rw-r--r--drivers/ide/ide-cd_ioctl.c471
-rw-r--r--drivers/ide/ide-cd_verbose.c359
-rw-r--r--drivers/ide/ide-cs.c473
-rw-r--r--drivers/ide/ide-disk.c742
-rw-r--r--drivers/ide/ide-disk.h29
-rw-r--r--drivers/ide/ide-disk_ioctl.c26
-rw-r--r--drivers/ide/ide-disk_proc.c129
-rw-r--r--drivers/ide/ide-dma-sff.c356
-rw-r--r--drivers/ide/ide-dma.c501
-rw-r--r--drivers/ide/ide-floppy.c578
-rw-r--r--drivers/ide/ide-floppy.h39
-rw-r--r--drivers/ide/ide-floppy_ioctl.c289
-rw-r--r--drivers/ide/ide-floppy_proc.c33
-rw-r--r--drivers/ide/ide-gd.c401
-rw-r--r--drivers/ide/ide-gd.h44
-rw-r--r--drivers/ide/ide-generic.c204
-rw-r--r--drivers/ide/ide-h8300.c217
-rw-r--r--drivers/ide/ide-io.c1539
-rw-r--r--drivers/ide/ide-ioctls.c298
-rw-r--r--drivers/ide/ide-iops.c1230
-rw-r--r--drivers/ide/ide-lib.c415
-rw-r--r--drivers/ide/ide-park.c121
-rw-r--r--drivers/ide/ide-pci-generic.c193
-rw-r--r--drivers/ide/ide-pio-blacklist.c94
-rw-r--r--drivers/ide/ide-pnp.c107
-rw-r--r--drivers/ide/ide-probe.c1852
-rw-r--r--drivers/ide/ide-proc.c723
-rw-r--r--drivers/ide/ide-scan-pci.c111
-rw-r--r--drivers/ide/ide-tape.c2489
-rw-r--r--drivers/ide/ide-taskfile.c682
-rw-r--r--drivers/ide/ide-timings.c203
-rw-r--r--drivers/ide/ide.c869
-rw-r--r--drivers/ide/ide_arm.c56
-rw-r--r--drivers/ide/ide_platform.c147
-rw-r--r--drivers/ide/it8213.c216
-rw-r--r--drivers/ide/it821x.c718
-rw-r--r--drivers/ide/jmicron.c176
-rw-r--r--drivers/ide/macide.c131
-rw-r--r--drivers/ide/ns87415.c366
-rw-r--r--drivers/ide/opti621.c247
-rw-r--r--drivers/ide/palm_bk3710.c424
-rw-r--r--drivers/ide/pdc202xx_new.c588
-rw-r--r--drivers/ide/pdc202xx_old.c453
-rw-r--r--drivers/ide/piix.c480
-rw-r--r--drivers/ide/pmac.c1712
-rw-r--r--drivers/ide/q40ide.c165
-rw-r--r--drivers/ide/qd65xx.c429
-rw-r--r--drivers/ide/qd65xx.h137
-rw-r--r--drivers/ide/rapide.c107
-rw-r--r--drivers/ide/rz1000.c85
-rw-r--r--drivers/ide/sc1200.c358
-rw-r--r--drivers/ide/scc_pata.c964
-rw-r--r--drivers/ide/serverworks.c470
-rw-r--r--drivers/ide/setup-pci.c694
-rw-r--r--drivers/ide/sgiioc4.c664
-rw-r--r--drivers/ide/siimage.c857
-rw-r--r--drivers/ide/sis5513.c641
-rw-r--r--drivers/ide/sl82c105.c371
-rw-r--r--drivers/ide/slc90e66.c181
-rw-r--r--drivers/ide/tc86c001.c270
-rw-r--r--drivers/ide/triflex.c142
-rw-r--r--drivers/ide/trm290.c375
-rw-r--r--drivers/ide/tx4938ide.c323
-rw-r--r--drivers/ide/tx4939ide.c760
-rw-r--r--drivers/ide/umc8672.c180
-rw-r--r--drivers/ide/via82cxxx.c514
93 files changed, 43500 insertions, 0 deletions
diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig
new file mode 100644
index 0000000..e6857e0
--- /dev/null
+++ b/drivers/ide/Kconfig
@@ -0,0 +1,910 @@
+#
+# IDE ATA ATAPI Block device driver configuration
+#
+
+# Select HAVE_IDE if IDE is supported
+config HAVE_IDE
+ bool
+
+menuconfig IDE
+ tristate "ATA/ATAPI/MFM/RLL support"
+ depends on HAVE_IDE
+ depends on BLOCK
+ ---help---
+ If you say Y here, your kernel will be able to manage low cost mass
+ storage units such as ATA/(E)IDE and ATAPI units. The most common
+ cases are IDE hard drives and ATAPI CD-ROM drives.
+
+ If your system is pure SCSI and doesn't use these interfaces, you
+ can say N here.
+
+ Integrated Disk Electronics (IDE aka ATA-1) is a connecting standard
+ for mass storage units such as hard disks. It was designed by
+ Western Digital and Compaq Computer in 1984. It was then named
+ ST506. Quite a number of disks use the IDE interface.
+
+ AT Attachment (ATA) is the superset of the IDE specifications.
+ ST506 was also called ATA-1.
+
+ Fast-IDE is ATA-2 (also named Fast ATA), Enhanced IDE (EIDE) is
+ ATA-3. It provides support for larger disks (up to 8.4GB by means of
+ the LBA standard), more disks (4 instead of 2) and for other mass
+ storage units such as tapes and cdrom. UDMA/33 (aka UltraDMA/33) is
+ ATA-4 and provides faster (and more CPU friendly) transfer modes
+ than previous PIO (Programmed processor Input/Output) from previous
+ ATA/IDE standards by means of fast DMA controllers.
+
+ ATA Packet Interface (ATAPI) is a protocol used by EIDE tape and
+ CD-ROM drives, similar in many respects to the SCSI protocol.
+
+ SMART IDE (Self Monitoring, Analysis and Reporting Technology) was
+ designed in order to prevent data corruption and disk crash by
+ detecting pre hardware failure conditions (heat, access time, and
+ the like...). Disks built since June 1995 may follow this standard.
+ The kernel itself doesn't manage this; however there are quite a
+ number of user programs such as smart that can query the status of
+ SMART parameters from disk drives.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ide.
+
+ For further information, please read <file:Documentation/ide/ide.txt>.
+
+ If unsure, say Y.
+
+if IDE
+
+comment "Please see Documentation/ide/ide.txt for help/info on IDE drives"
+
+config IDE_TIMINGS
+ bool
+
+config IDE_ATAPI
+ bool
+
+config BLK_DEV_IDE_SATA
+ bool "Support for SATA (deprecated; conflicts with libata SATA driver)"
+ default n
+ ---help---
+ There are two drivers for Serial ATA controllers.
+
+ The main driver, "libata", uses the SCSI subsystem
+ and supports most modern SATA controllers. In order to use it
+ you may take a look at "Serial ATA (prod) and Parallel ATA
+ (experimental) drivers".
+
+ The IDE driver (which you are currently configuring) supports
+ a few first-generation SATA controllers.
+
+ In order to eliminate conflicts between the two subsystems,
+ this config option enables the IDE driver's SATA support.
+ Normally this is disabled, as it is preferred that libata
+ supports SATA controllers, and this (IDE) driver supports
+ PATA controllers.
+
+ If unsure, say N.
+
+config IDE_GD
+ tristate "generic ATA/ATAPI disk support"
+ default y
+ help
+ Support for ATA/ATAPI disks (including ATAPI floppy drives).
+
+ To compile this driver as a module, choose M here.
+ The module will be called ide-gd_mod.
+
+ If unsure, say Y.
+
+config IDE_GD_ATA
+ bool "ATA disk support"
+ depends on IDE_GD
+ default y
+ help
+ This will include support for ATA hard disks.
+
+ If unsure, say Y.
+
+config IDE_GD_ATAPI
+ bool "ATAPI floppy support"
+ depends on IDE_GD
+ select IDE_ATAPI
+ help
+ This will include support for ATAPI floppy drives
+ (i.e. Iomega ZIP or MKE LS-120).
+
+ For information about jumper settings and the question
+ of when a ZIP drive uses a partition table, see
+ <http://www.win.tue.nl/~aeb/linux/zip/zip-1.html>.
+
+ If unsure, say N.
+
+config BLK_DEV_IDECS
+ tristate "PCMCIA IDE support"
+ depends on PCMCIA
+ help
+ Support for Compact Flash cards, outboard IDE disks, tape drives,
+ and CD-ROM drives connected through a PCMCIA card.
+
+config BLK_DEV_DELKIN
+ tristate "Cardbus IDE support (Delkin/ASKA/Workbit)"
+ depends on CARDBUS && PCI
+ help
+ Support for Delkin, ASKA, and Workbit Cardbus CompactFlash
+ Adapters. This may also work for similar SD and XD adapters.
+
+config BLK_DEV_IDECD
+ tristate "Include IDE/ATAPI CDROM support"
+ ---help---
+ If you have a CD-ROM drive using the ATAPI protocol, say Y. ATAPI is
+ a newer protocol used by IDE CD-ROM and TAPE drives, similar to the
+ SCSI protocol. Most new CD-ROM drives use ATAPI, including the
+ NEC-260, Mitsumi FX400, Sony 55E, and just about all non-SCSI
+ double(2X) or better speed drives.
+
+ If you say Y here, the CD-ROM drive will be identified at boot time
+ along with other IDE devices, as "hdb" or "hdc", or something
+ similar (check the boot messages with dmesg). If this is your only
+ CD-ROM drive, you can say N to all other CD-ROM options, but be sure
+ to say Y or M to "ISO 9660 CD-ROM file system support".
+
+ To compile this driver as a module, choose M here: the
+ module will be called ide-cd.
+
+config BLK_DEV_IDECD_VERBOSE_ERRORS
+ bool "Verbose error logging for IDE/ATAPI CDROM driver" if EMBEDDED
+ depends on BLK_DEV_IDECD
+ default y
+ help
+ Turn this on to have the driver print out the meanings of the
+ ATAPI error codes. This will use up additional 8kB of kernel-space
+ memory, though.
+
+config BLK_DEV_IDETAPE
+ tristate "Include IDE/ATAPI TAPE support"
+ select IDE_ATAPI
+ help
+ If you have an IDE tape drive using the ATAPI protocol, say Y.
+ ATAPI is a newer protocol used by IDE tape and CD-ROM drives,
+ similar to the SCSI protocol. If you have an SCSI tape drive
+ however, you can say N here.
+
+ You should also say Y if you have an OnStream DI-30 tape drive; this
+ will not work with the SCSI protocol, until there is support for the
+ SC-30 and SC-50 versions.
+
+ If you say Y here, the tape drive will be identified at boot time
+ along with other IDE devices, as "hdb" or "hdc", or something
+ similar, and will be mapped to a character device such as "ht0"
+ (check the boot messages with dmesg). Be sure to consult the
+ <file:drivers/ide/ide-tape.c> and <file:Documentation/ide/ide.txt>
+ files for usage information.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ide-tape.
+
+config BLK_DEV_IDESCSI
+ tristate "SCSI emulation support (DEPRECATED)"
+ depends on SCSI
+ select IDE_ATAPI
+ ---help---
+ WARNING: ide-scsi is no longer needed for cd writing applications!
+ The 2.6 kernel supports direct writing to ide-cd, which eliminates
+ the need for ide-scsi + the entire scsi stack just for writing a
+ cd. The new method is more efficient in every way.
+
+ This will provide SCSI host adapter emulation for IDE ATAPI devices,
+ and will allow you to use a SCSI device driver instead of a native
+ ATAPI driver.
+
+ If both this SCSI emulation and native ATAPI support are compiled
+ into the kernel, the native support will be used.
+
+config BLK_DEV_IDEACPI
+ bool "IDE ACPI support"
+ depends on ACPI
+ ---help---
+ Implement ACPI support for generic IDE devices. On modern
+ machines ACPI support is required to properly handle ACPI S3 states.
+
+config IDE_TASK_IOCTL
+ bool "IDE Taskfile Access"
+ help
+ This is a direct raw access to the media. It is a complex but
+ elegant solution to test and validate the domain of the hardware and
+ perform below the driver data recovery if needed. This is the most
+ basic form of media-forensics.
+
+ If you are unsure, say N here.
+
+config IDE_PROC_FS
+ bool "legacy /proc/ide/ support"
+ depends on IDE && PROC_FS
+ default y
+ help
+ This option enables support for the various files in
+ /proc/ide. In Linux 2.6 this has been superseded by
+ files in sysfs but many legacy applications rely on this.
+
+ If unsure say Y.
+
+comment "IDE chipset support/bugfixes"
+
+config IDE_GENERIC
+ tristate "generic/default IDE chipset support"
+ depends on ALPHA || X86 || IA64 || M32R || MIPS
+ help
+ This is the generic IDE driver. This driver attaches to the
+ fixed legacy ports (e.g. on PCs 0x1f0/0x170, 0x1e8/0x168 and
+ so on). Please note that if this driver is built into the
+ kernel or loaded before other ATA (IDE or libata) drivers
+ and the controller is located at legacy ports, this driver
+ may grab those ports and thus can prevent the controller
+ specific driver from attaching.
+
+ Also, currently, IDE generic doesn't allow IRQ sharing
+ meaning that the IRQs it grabs won't be available to other
+ controllers sharing those IRQs which usually makes drivers
+ for those controllers fail. Generally, it's not a good idea
+ to load IDE generic driver on modern systems.
+
+ If unsure, say N.
+
+config BLK_DEV_PLATFORM
+ tristate "Platform driver for IDE interfaces"
+ help
+ This is the platform IDE driver, used mostly for Memory Mapped
+ IDE devices, like Compact Flashes running in True IDE mode.
+
+ If unsure, say N.
+
+config BLK_DEV_CMD640
+ tristate "CMD640 chipset bugfix/support"
+ depends on X86
+ select IDE_TIMINGS
+ ---help---
+ The CMD-Technologies CMD640 IDE chip is used on many common 486 and
+ Pentium motherboards, usually in combination with a "Neptune" or
+ "SiS" chipset. Unfortunately, it has a number of rather nasty
+ design flaws that can cause severe data corruption under many common
+ conditions. Say Y here to include code which tries to automatically
+ detect and correct the problems under Linux. This option also
+ enables access to the secondary IDE ports in some CMD640 based
+ systems.
+
+ This driver will work automatically in PCI based systems (most new
+ systems have PCI slots). But if your system uses VESA local bus
+ (VLB) instead of PCI, you must also supply a kernel boot parameter
+ to enable the CMD640 bugfix/support: "cmd640.probe_vlb". (Try "man
+ bootparam" or see the documentation of your boot loader about how to
+ pass options to the kernel.)
+
+ The CMD640 chip is also used on add-in cards by Acculogic, and on
+ the "CSA-6400E PCI to IDE controller" that some people have. For
+ details, read <file:Documentation/ide/ide.txt>.
+
+config BLK_DEV_CMD640_ENHANCED
+ bool "CMD640 enhanced support"
+ depends on BLK_DEV_CMD640
+ help
+ This option includes support for setting/autotuning PIO modes and
+ prefetch on CMD640 IDE interfaces. For details, read
+ <file:Documentation/ide/ide.txt>. If you have a CMD640 IDE interface
+ and your BIOS does not already do this for you, then say Y here.
+ Otherwise say N.
+
+config BLK_DEV_IDEPNP
+ tristate "PNP EIDE support"
+ depends on PNP
+ help
+ If you have a PnP (Plug and Play) compatible EIDE card and
+ would like the kernel to automatically detect and activate
+ it, say Y here.
+
+config BLK_DEV_IDEDMA_SFF
+ bool
+
+if PCI
+
+comment "PCI IDE chipsets support"
+
+config BLK_DEV_IDEPCI
+ bool
+
+config IDEPCI_PCIBUS_ORDER
+ bool "Probe IDE PCI devices in the PCI bus order (DEPRECATED)"
+ depends on IDE=y && BLK_DEV_IDEPCI
+ default y
+ help
+ Probe IDE PCI devices in the order in which they appear on the
+ PCI bus (i.e. 00:1f.1 PCI device before 02:01.0 PCI device)
+ instead of the order in which IDE PCI host drivers are loaded.
+
+ Please note that this method of assuring stable naming of
+ IDE devices is unreliable and use other means for achieving
+ it (i.e. udev).
+
+ If in doubt, say N.
+
+# TODO: split it on per host driver config options (or module parameters)
+config BLK_DEV_OFFBOARD
+ bool "Boot off-board chipsets first support (DEPRECATED)"
+ depends on BLK_DEV_IDEPCI && (BLK_DEV_AEC62XX || BLK_DEV_GENERIC || BLK_DEV_HPT366 || BLK_DEV_PDC202XX_NEW || BLK_DEV_PDC202XX_OLD || BLK_DEV_TC86C001)
+ help
+ Normally, IDE controllers built into the motherboard (on-board
+ controllers) are assigned to ide0 and ide1 while those on add-in PCI
+ cards (off-board controllers) are relegated to ide2 and ide3.
+ Answering Y here will allow you to reverse the situation, with
+ off-board controllers on ide0/1 and on-board controllers on ide2/3.
+ This can improve the usability of some boot managers such as lilo
+ when booting from a drive on an off-board controller.
+
+ Note that, if you do this, the order of the hd* devices will be
+ rearranged which may require modification of fstab and other files.
+
+ Please also note that this method of assuring stable naming of
+ IDE devices is unreliable and use other means for achieving it
+ (i.e. udev).
+
+ If in doubt, say N.
+
+config BLK_DEV_GENERIC
+ tristate "Generic PCI IDE Chipset Support"
+ select BLK_DEV_IDEPCI
+ help
+ This option provides generic support for various PCI IDE Chipsets
+ which otherwise might not be supported.
+
+config BLK_DEV_OPTI621
+ tristate "OPTi 82C621 chipset enhanced support (EXPERIMENTAL)"
+ depends on EXPERIMENTAL
+ select BLK_DEV_IDEPCI
+ help
+ This is a driver for the OPTi 82C621 EIDE controller.
+ Please read the comments at the top of <file:drivers/ide/pci/opti621.c>.
+
+config BLK_DEV_RZ1000
+ tristate "RZ1000 chipset bugfix/support"
+ depends on X86
+ select BLK_DEV_IDEPCI
+ help
+ The PC-Technologies RZ1000 IDE chip is used on many common 486 and
+ Pentium motherboards, usually along with the "Neptune" chipset.
+ Unfortunately, it has a rather nasty design flaw that can cause
+ severe data corruption under many conditions. Say Y here to include
+ code which automatically detects and corrects the problem under
+ Linux. This may slow disk throughput by a few percent, but at least
+ things will operate 100% reliably.
+
+config BLK_DEV_IDEDMA_PCI
+ bool
+ select BLK_DEV_IDEPCI
+ select BLK_DEV_IDEDMA_SFF
+
+config BLK_DEV_AEC62XX
+ tristate "AEC62XX chipset support"
+ select BLK_DEV_IDEDMA_PCI
+ help
+ This driver adds explicit support for Acard AEC62xx (Artop ATP8xx)
+ IDE controllers. This allows the kernel to change PIO, DMA and UDMA
+ speeds and to configure the chip to optimum performance.
+
+config BLK_DEV_ALI15X3
+ tristate "ALI M15x3 chipset support"
+ select IDE_TIMINGS
+ select BLK_DEV_IDEDMA_PCI
+ help
+ This driver ensures (U)DMA support for ALI 1533, 1543 and 1543C
+ onboard chipsets. It also tests for Simplex mode and enables
+ normal dual channel support.
+
+ Please read the comments at the top of
+ <file:drivers/ide/pci/alim15x3.c>.
+
+ If unsure, say N.
+
+config BLK_DEV_AMD74XX
+ tristate "AMD and nVidia IDE support"
+ depends on !ARM
+ select IDE_TIMINGS
+ select BLK_DEV_IDEDMA_PCI
+ help
+ This driver adds explicit support for AMD-7xx and AMD-8111 chips
+ and also for the nVidia nForce chip. This allows the kernel to
+ change PIO, DMA and UDMA speeds and to configure the chip to
+ optimum performance.
+
+config BLK_DEV_ATIIXP
+ tristate "ATI IXP chipset IDE support"
+ depends on X86
+ select BLK_DEV_IDEDMA_PCI
+ help
+ This driver adds explicit support for ATI IXP chipset.
+ This allows the kernel to change PIO, DMA and UDMA speeds
+ and to configure the chip to optimum performance.
+
+ Say Y here if you have an ATI IXP chipset IDE controller.
+
+config BLK_DEV_CMD64X
+ tristate "CMD64{3|6|8|9} chipset support"
+ select IDE_TIMINGS
+ select BLK_DEV_IDEDMA_PCI
+ help
+ Say Y here if you have an IDE controller which uses any of these
+ chipsets: CMD643, CMD646, or CMD648.
+
+config BLK_DEV_TRIFLEX
+ tristate "Compaq Triflex IDE support"
+ select BLK_DEV_IDEDMA_PCI
+ help
+ Say Y here if you have a Compaq Triflex IDE controller, such
+ as those commonly found on Compaq Pentium-Pro systems
+
+config BLK_DEV_CY82C693
+ tristate "CY82C693 chipset support"
+ depends on ALPHA
+ select IDE_TIMINGS
+ select BLK_DEV_IDEDMA_PCI
+ help
+ This driver adds detection and support for the CY82C693 chipset
+ used on Digital's PC-Alpha 164SX boards.
+
+config BLK_DEV_CS5520
+ tristate "Cyrix CS5510/20 MediaGX chipset support (VERY EXPERIMENTAL)"
+ depends on EXPERIMENTAL
+ select BLK_DEV_IDEDMA_PCI
+ help
+ Include support for PIO tuning and virtual DMA on the Cyrix MediaGX
+ 5510/5520 chipset. This will automatically be detected and
+ configured if found.
+
+ It is safe to say Y to this question.
+
+config BLK_DEV_CS5530
+ tristate "Cyrix/National Semiconductor CS5530 MediaGX chipset support"
+ select BLK_DEV_IDEDMA_PCI
+ help
+ Include support for UDMA on the Cyrix MediaGX 5530 chipset. This
+ will automatically be detected and configured if found.
+
+ It is safe to say Y to this question.
+
+config BLK_DEV_CS5535
+ tristate "AMD CS5535 chipset support"
+ depends on X86 && !X86_64
+ select BLK_DEV_IDEDMA_PCI
+ help
+ Include support for UDMA on the NSC/AMD CS5535 companion chipset.
+ This will automatically be detected and configured if found.
+
+ It is safe to say Y to this question.
+
+config BLK_DEV_HPT366
+ tristate "HPT36X/37X chipset support"
+ select BLK_DEV_IDEDMA_PCI
+ help
+ HPT366 is an Ultra DMA chipset for ATA-66.
+ HPT368 is an Ultra DMA chipset for ATA-66 RAID Based.
+ HPT370 is an Ultra DMA chipset for ATA-100.
+ HPT372 is an Ultra DMA chipset for ATA-100.
+ HPT374 is an Ultra DMA chipset for ATA-100.
+
+ This driver adds up to 4 more EIDE devices sharing a single
+ interrupt.
+
+ The HPT366 chipset in its current form is bootable. One solution
+ for this problem are special LILO commands for redirecting the
+ reference to device 0x80. The other solution is to say Y to "Boot
+ off-board chipsets first support" (CONFIG_BLK_DEV_OFFBOARD) unless
+ your mother board has the chipset natively mounted. Regardless one
+ should use the fore mentioned option and call at LILO.
+
+ This driver requires dynamic tuning of the chipset during the
+ ide-probe at boot. It is reported to support DVD II drives, by the
+ manufacturer.
+
+config BLK_DEV_JMICRON
+ tristate "JMicron JMB36x support"
+ select BLK_DEV_IDEDMA_PCI
+ help
+ Basic support for the JMicron ATA controllers. For full support
+ use the libata drivers.
+
+config BLK_DEV_SC1200
+ tristate "National SCx200 chipset support"
+ select BLK_DEV_IDEDMA_PCI
+ help
+ This driver adds support for the on-board IDE controller on the
+ National SCx200 series of embedded x86 "Geode" systems.
+
+config BLK_DEV_PIIX
+ tristate "Intel PIIX/ICH chipsets support"
+ select BLK_DEV_IDEDMA_PCI
+ help
+ This driver adds explicit support for Intel PIIX and ICH chips.
+ This allows the kernel to change PIO, DMA and UDMA speeds and to
+ configure the chip to optimum performance.
+
+config BLK_DEV_IT8213
+ tristate "IT8213 IDE support"
+ select BLK_DEV_IDEDMA_PCI
+ help
+ This driver adds support for the ITE 8213 IDE controller.
+
+config BLK_DEV_IT821X
+ tristate "IT821X IDE support"
+ select BLK_DEV_IDEDMA_PCI
+ help
+ This driver adds support for the ITE 8211 IDE controller and the
+ IT 8212 IDE RAID controller in both RAID and pass-through mode.
+
+config BLK_DEV_NS87415
+ tristate "NS87415 chipset support"
+ select BLK_DEV_IDEDMA_PCI
+ help
+ This driver adds detection and support for the NS87415 chip
+ (used mainly on SPARC64 and PA-RISC machines).
+
+ Please read the comments at the top of <file:drivers/ide/pci/ns87415.c>.
+
+config BLK_DEV_PDC202XX_OLD
+ tristate "PROMISE PDC202{46|62|65|67} support"
+ select BLK_DEV_IDEDMA_PCI
+ help
+ Promise Ultra33 or PDC20246
+ Promise Ultra66 or PDC20262
+ Promise Ultra100 or PDC20265/PDC20267/PDC20268
+
+ This driver adds up to 4 more EIDE devices sharing a single
+ interrupt. This add-on card is a bootable PCI UDMA controller. Since
+ multiple cards can be installed and there are BIOS ROM problems that
+ happen if the BIOS revisions of all installed cards (three-max) do
+ not match, the driver attempts to do dynamic tuning of the chipset
+ at boot-time for max-speed. Ultra33 BIOS 1.25 or newer is required
+ for more than one card.
+
+ Please read the comments at the top of
+ <file:drivers/ide/pci/pdc202xx_old.c>.
+
+ If unsure, say N.
+
+config BLK_DEV_PDC202XX_NEW
+ tristate "PROMISE PDC202{68|69|70|71|75|76|77} support"
+ select BLK_DEV_IDEDMA_PCI
+
+config BLK_DEV_SVWKS
+ tristate "ServerWorks OSB4/CSB5/CSB6 chipsets support"
+ select BLK_DEV_IDEDMA_PCI
+ help
+ This driver adds PIO/(U)DMA support for the ServerWorks OSB4/CSB5
+ chipsets.
+
+config BLK_DEV_SGIIOC4
+ tristate "Silicon Graphics IOC4 chipset ATA/ATAPI support"
+ depends on (IA64_SGI_SN2 || IA64_GENERIC) && SGI_IOC4
+ select BLK_DEV_IDEDMA_PCI
+ help
+ This driver adds PIO & MultiMode DMA-2 support for the SGI IOC4
+ chipset, which has one channel and can support two devices.
+ Please say Y here if you have an Altix System from SGI.
+
+config BLK_DEV_SIIMAGE
+ tristate "Silicon Image chipset support"
+ select BLK_DEV_IDEDMA_PCI
+ help
+ This driver adds PIO/(U)DMA support for the SI CMD680 and SII
+ 3112 (Serial ATA) chips.
+
+config BLK_DEV_SIS5513
+ tristate "SiS5513 chipset support"
+ depends on X86
+ select BLK_DEV_IDEDMA_PCI
+ help
+ This driver ensures (U)DMA support for SIS5513 chipset family based
+ mainboards.
+
+ The following chipsets are supported:
+ ATA16: SiS5511, SiS5513
+ ATA33: SiS5591, SiS5597, SiS5598, SiS5600
+ ATA66: SiS530, SiS540, SiS620, SiS630, SiS640
+ ATA100: SiS635, SiS645, SiS650, SiS730, SiS735, SiS740,
+ SiS745, SiS750
+
+ Please read the comments at the top of <file:drivers/ide/pci/sis5513.c>.
+
+config BLK_DEV_SL82C105
+ tristate "Winbond SL82c105 support"
+ depends on (PPC || ARM)
+ select IDE_TIMINGS
+ select BLK_DEV_IDEDMA_PCI
+ help
+ If you have a Winbond SL82c105 IDE controller, say Y here to enable
+ special configuration for this chip. This is common on various CHRP
+ motherboards, but could be used elsewhere. If in doubt, say Y.
+
+config BLK_DEV_SLC90E66
+ tristate "SLC90E66 chipset support"
+ select BLK_DEV_IDEDMA_PCI
+ help
+ This driver ensures (U)DMA support for Victory66 SouthBridges for
+ SMsC with Intel NorthBridges. This is an Ultra66 based chipset.
+ The nice thing about it is that you can mix Ultra/DMA/PIO devices
+ and it will handle timing cycles. Since this is an improved
+ look-a-like to the PIIX4 it should be a nice addition.
+
+ Please read the comments at the top of
+ <file:drivers/ide/pci/slc90e66.c>.
+
+config BLK_DEV_TRM290
+ tristate "Tekram TRM290 chipset support"
+ select BLK_DEV_IDEDMA_PCI
+ help
+ This driver adds support for bus master DMA transfers
+ using the Tekram TRM290 PCI IDE chip. Volunteers are
+ needed for further tweaking and development.
+ Please read the comments at the top of <file:drivers/ide/pci/trm290.c>.
+
+config BLK_DEV_VIA82CXXX
+ tristate "VIA82CXXX chipset support"
+ select IDE_TIMINGS
+ select BLK_DEV_IDEDMA_PCI
+ help
+ This driver adds explicit support for VIA BusMastering IDE chips.
+ This allows the kernel to change PIO, DMA and UDMA speeds and to
+ configure the chip to optimum performance.
+
+config BLK_DEV_TC86C001
+ tristate "Toshiba TC86C001 support"
+ select BLK_DEV_IDEDMA_PCI
+ help
+ This driver adds support for Toshiba TC86C001 GOKU-S chip.
+
+config BLK_DEV_CELLEB
+ tristate "Toshiba's Cell Reference Set IDE support"
+ depends on PPC_CELLEB
+ select BLK_DEV_IDEDMA_PCI
+ help
+ This driver provides support for the on-board IDE controller on
+ Toshiba Cell Reference Board.
+ If unsure, say Y.
+
+endif
+
+# TODO: BLK_DEV_IDEDMA_PCI -> BLK_DEV_IDEDMA_SFF
+config BLK_DEV_IDE_PMAC
+ tristate "PowerMac on-board IDE support"
+ depends on PPC_PMAC && IDE=y
+ select IDE_TIMINGS
+ select BLK_DEV_IDEDMA_PCI
+ help
+ This driver provides support for the on-board IDE controller on
+ most of the recent Apple Power Macintoshes and PowerBooks.
+ If unsure, say Y.
+
+config BLK_DEV_IDE_PMAC_ATA100FIRST
+ bool "Probe on-board ATA/100 (Kauai) first"
+ depends on BLK_DEV_IDE_PMAC
+ help
+ This option will cause the ATA/100 controller found in UniNorth2
+ based machines (Windtunnel PowerMac, Aluminium PowerBooks, ...)
+ to be probed before the ATA/66 and ATA/33 controllers. Without
+ these, those machine used to have the hard disk on hdc and the
+ CD-ROM on hda. This option changes this to more natural hda for
+ hard disk and hdc for CD-ROM.
+
+config BLK_DEV_IDE_AU1XXX
+ bool "IDE for AMD Alchemy Au1200"
+ depends on SOC_AU1200
+choice
+ prompt "IDE Mode for AMD Alchemy Au1200"
+ default CONFIG_BLK_DEV_IDE_AU1XXX_PIO_DBDMA
+ depends on SOC_AU1200 && BLK_DEV_IDE_AU1XXX
+
+config BLK_DEV_IDE_AU1XXX_PIO_DBDMA
+ bool "PIO+DbDMA IDE for AMD Alchemy Au1200"
+
+config BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
+ bool "MDMA2+DbDMA IDE for AMD Alchemy Au1200"
+ depends on SOC_AU1200 && BLK_DEV_IDE_AU1XXX
+endchoice
+
+config BLK_DEV_IDE_AU1XXX_SEQTS_PER_RQ
+ int "Maximum transfer size (KB) per request (up to 128)"
+ default "128"
+ depends on BLK_DEV_IDE_AU1XXX
+
+config BLK_DEV_IDE_TX4938
+ tristate "TX4938 internal IDE support"
+ depends on SOC_TX4938
+ select IDE_TIMINGS
+
+config BLK_DEV_IDE_TX4939
+ tristate "TX4939 internal IDE support"
+ depends on SOC_TX4939
+ select BLK_DEV_IDEDMA_SFF
+
+config IDE_ARM
+ tristate "ARM IDE support"
+ depends on ARM && (ARCH_CLPS7500 || ARCH_RPC || ARCH_SHARK)
+ default y
+
+config BLK_DEV_IDE_ICSIDE
+ tristate "ICS IDE interface support"
+ depends on ARM && ARCH_ACORN
+ help
+ On Acorn systems, say Y here if you wish to use the ICS IDE
+ interface card. This is not required for ICS partition support.
+ If you are unsure, say N to this.
+
+config BLK_DEV_IDEDMA_ICS
+ bool "ICS DMA support"
+ depends on BLK_DEV_IDE_ICSIDE
+ help
+ Say Y here if you want to add DMA (Direct Memory Access) support to
+ the ICS IDE driver.
+
+config BLK_DEV_IDE_RAPIDE
+ tristate "RapIDE interface support"
+ depends on ARM && ARCH_ACORN
+ help
+ Say Y here if you want to support the Yellowstone RapIDE controller
+ manufactured for use with Acorn computers.
+
+config IDE_H8300
+ tristate "H8300 IDE support"
+ depends on H8300
+ default y
+ help
+ Enables the H8300 IDE driver.
+
+config BLK_DEV_GAYLE
+ tristate "Amiga Gayle IDE interface support"
+ depends on AMIGA
+ help
+ This is the IDE driver for the Amiga Gayle IDE interface. It supports
+ both the `A1200 style' and `A4000 style' of the Gayle IDE interface,
+ This includes on-board IDE interfaces on some Amiga models (A600,
+ A1200, A4000, and A4000T), and IDE interfaces on the Zorro expansion
+ bus (M-Tech E-Matrix 530 expansion card).
+ Say Y if you have an Amiga with a Gayle IDE interface and want to use
+ IDE devices (hard disks, CD-ROM drives, etc.) that are connected to
+ it.
+ Note that you also have to enable Zorro bus support if you want to
+ use Gayle IDE interfaces on the Zorro expansion bus.
+
+config BLK_DEV_IDEDOUBLER
+ bool "Amiga IDE Doubler support (EXPERIMENTAL)"
+ depends on BLK_DEV_GAYLE && EXPERIMENTAL
+ ---help---
+ This feature provides support for the so-called `IDE doublers' (made
+ by various manufacturers, e.g. Eyetech) that can be connected to
+ the on-board IDE interface of some Amiga models. Using such an IDE
+ doubler, you can connect up to four instead of two IDE devices to
+ the Amiga's on-board IDE interface.
+
+ Note that the normal Amiga Gayle IDE driver may not work correctly
+ if you have an IDE doubler and don't enable this feature!
+
+ Say Y if you have an IDE doubler. The feature is enabled at kernel
+ runtime using the "gayle.doubler" kernel boot parameter.
+
+config BLK_DEV_BUDDHA
+ tristate "Buddha/Catweasel/X-Surf IDE interface support (EXPERIMENTAL)"
+ depends on ZORRO && EXPERIMENTAL
+ help
+ This is the IDE driver for the IDE interfaces on the Buddha, Catweasel
+ and X-Surf expansion boards. It supports up to two interfaces on the
+ Buddha, three on the Catweasel and two on the X-Surf.
+
+ Say Y if you have a Buddha or Catweasel expansion board and want to
+ use IDE devices (hard disks, CD-ROM drives, etc.) that are connected
+ to one of its IDE interfaces.
+
+config BLK_DEV_FALCON_IDE
+ tristate "Falcon IDE interface support"
+ depends on ATARI
+ help
+ This is the IDE driver for the on-board IDE interface on the Atari
+ Falcon. Say Y if you have a Falcon and want to use IDE devices (hard
+ disks, CD-ROM drives, etc.) that are connected to the on-board IDE
+ interface.
+
+config BLK_DEV_MAC_IDE
+ tristate "Macintosh Quadra/Powerbook IDE interface support"
+ depends on MAC
+ help
+ This is the IDE driver for the on-board IDE interface on some m68k
+ Macintosh models. It supports both the `Quadra style' (used in
+ Quadra/ Centris 630 and Performa 588 models) and `Powerbook style'
+ (used in the Powerbook 150 and 190 models) IDE interface.
+
+ Say Y if you have such an Macintosh model and want to use IDE
+ devices (hard disks, CD-ROM drives, etc.) that are connected to the
+ on-board IDE interface.
+
+config BLK_DEV_Q40IDE
+ tristate "Q40/Q60 IDE interface support"
+ depends on Q40
+ help
+ Enable the on-board IDE controller in the Q40/Q60. This should
+ normally be on; disable it only if you are running a custom hard
+ drive subsystem through an expansion card.
+
+config BLK_DEV_PALMCHIP_BK3710
+ tristate "Palmchip bk3710 IDE controller support"
+ depends on ARCH_DAVINCI
+ select IDE_TIMINGS
+ select BLK_DEV_IDEDMA_SFF
+ help
+ Say Y here if you want to support the onchip IDE controller on the
+ TI DaVinci SoC
+
+# no isa -> no vlb
+if ISA && (ALPHA || X86 || MIPS)
+
+comment "Other IDE chipsets support"
+comment "Note: most of these also require special kernel boot parameters"
+
+config BLK_DEV_4DRIVES
+ tristate "Generic 4 drives/port support"
+ help
+ Certain older chipsets, including the Tekram 690CD, use a single set
+ of I/O ports at 0x1f0 to control up to four drives, instead of the
+ customary two drives per port. Support for this can be enabled at
+ runtime using the "ide-4drives.probe" kernel boot parameter if you
+ say Y here.
+
+config BLK_DEV_ALI14XX
+ tristate "ALI M14xx support"
+ select IDE_TIMINGS
+ help
+ This driver is enabled at runtime using the "ali14xx.probe" kernel
+ boot parameter. It enables support for the secondary IDE interface
+ of the ALI M1439/1443/1445/1487/1489 chipsets, and permits faster
+ I/O speeds to be set as well.
+ See the files <file:Documentation/ide/ide.txt> and
+ <file:drivers/ide/legacy/ali14xx.c> for more info.
+
+config BLK_DEV_DTC2278
+ tristate "DTC-2278 support"
+ help
+ This driver is enabled at runtime using the "dtc2278.probe" kernel
+ boot parameter. It enables support for the secondary IDE interface
+ of the DTC-2278 card, and permits faster I/O speeds to be set as
+ well. See the <file:Documentation/ide/ide.txt> and
+ <file:drivers/ide/legacy/dtc2278.c> files for more info.
+
+config BLK_DEV_HT6560B
+ tristate "Holtek HT6560B support"
+ select IDE_TIMINGS
+ help
+ This driver is enabled at runtime using the "ht6560b.probe" kernel
+ boot parameter. It enables support for the secondary IDE interface
+ of the Holtek card, and permits faster I/O speeds to be set as well.
+ See the <file:Documentation/ide/ide.txt> and
+ <file:drivers/ide/legacy/ht6560b.c> files for more info.
+
+config BLK_DEV_QD65XX
+ tristate "QDI QD65xx support"
+ select IDE_TIMINGS
+ help
+ This driver is enabled at runtime using the "qd65xx.probe" kernel
+ boot parameter. It permits faster I/O speeds to be set. See the
+ <file:Documentation/ide/ide.txt> and <file:drivers/ide/legacy/qd65xx.c>
+ for more info.
+
+config BLK_DEV_UMC8672
+ tristate "UMC-8672 support"
+ help
+ This driver is enabled at runtime using the "umc8672.probe" kernel
+ boot parameter. It enables support for the secondary IDE interface
+ of the UMC-8672, and permits faster I/O speeds to be set as well.
+ See the files <file:Documentation/ide/ide.txt> and
+ <file:drivers/ide/legacy/umc8672.c> for more info.
+
+endif
+
+config BLK_DEV_IDEDMA
+ def_bool BLK_DEV_IDEDMA_SFF || \
+ BLK_DEV_IDEDMA_ICS || BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
+
+endif # IDE
diff --git a/drivers/ide/Makefile b/drivers/ide/Makefile
new file mode 100644
index 0000000..7818d40
--- /dev/null
+++ b/drivers/ide/Makefile
@@ -0,0 +1,115 @@
+#
+# link order is important here
+#
+
+EXTRA_CFLAGS += -Idrivers/ide
+
+ide-core-y += ide.o ide-ioctls.o ide-io.o ide-iops.o ide-lib.o ide-probe.o \
+ ide-taskfile.o ide-park.o ide-pio-blacklist.o
+
+# core IDE code
+ide-core-$(CONFIG_IDE_TIMINGS) += ide-timings.o
+ide-core-$(CONFIG_IDE_ATAPI) += ide-atapi.o
+ide-core-$(CONFIG_BLK_DEV_IDEPCI) += setup-pci.o
+ide-core-$(CONFIG_BLK_DEV_IDEDMA) += ide-dma.o
+ide-core-$(CONFIG_BLK_DEV_IDEDMA_SFF) += ide-dma-sff.o
+ide-core-$(CONFIG_IDE_PROC_FS) += ide-proc.o
+ide-core-$(CONFIG_BLK_DEV_IDEACPI) += ide-acpi.o
+
+obj-$(CONFIG_IDE) += ide-core.o
+
+obj-$(CONFIG_IDE_ARM) += ide_arm.o
+
+obj-$(CONFIG_BLK_DEV_ALI14XX) += ali14xx.o
+obj-$(CONFIG_BLK_DEV_UMC8672) += umc8672.o
+obj-$(CONFIG_BLK_DEV_DTC2278) += dtc2278.o
+obj-$(CONFIG_BLK_DEV_HT6560B) += ht6560b.o
+obj-$(CONFIG_BLK_DEV_QD65XX) += qd65xx.o
+obj-$(CONFIG_BLK_DEV_4DRIVES) += ide-4drives.o
+
+obj-$(CONFIG_BLK_DEV_GAYLE) += gayle.o
+obj-$(CONFIG_BLK_DEV_FALCON_IDE) += falconide.o
+obj-$(CONFIG_BLK_DEV_MAC_IDE) += macide.o
+obj-$(CONFIG_BLK_DEV_Q40IDE) += q40ide.o
+obj-$(CONFIG_BLK_DEV_BUDDHA) += buddha.o
+
+obj-$(CONFIG_BLK_DEV_AEC62XX) += aec62xx.o
+obj-$(CONFIG_BLK_DEV_ALI15X3) += alim15x3.o
+obj-$(CONFIG_BLK_DEV_AMD74XX) += amd74xx.o
+obj-$(CONFIG_BLK_DEV_ATIIXP) += atiixp.o
+obj-$(CONFIG_BLK_DEV_CELLEB) += scc_pata.o
+obj-$(CONFIG_BLK_DEV_CMD64X) += cmd64x.o
+obj-$(CONFIG_BLK_DEV_CS5520) += cs5520.o
+obj-$(CONFIG_BLK_DEV_CS5530) += cs5530.o
+obj-$(CONFIG_BLK_DEV_CS5535) += cs5535.o
+obj-$(CONFIG_BLK_DEV_SC1200) += sc1200.o
+obj-$(CONFIG_BLK_DEV_CY82C693) += cy82c693.o
+obj-$(CONFIG_BLK_DEV_DELKIN) += delkin_cb.o
+obj-$(CONFIG_BLK_DEV_HPT366) += hpt366.o
+obj-$(CONFIG_BLK_DEV_IT8213) += it8213.o
+obj-$(CONFIG_BLK_DEV_IT821X) += it821x.o
+obj-$(CONFIG_BLK_DEV_JMICRON) += jmicron.o
+obj-$(CONFIG_BLK_DEV_NS87415) += ns87415.o
+obj-$(CONFIG_BLK_DEV_OPTI621) += opti621.o
+obj-$(CONFIG_BLK_DEV_PDC202XX_OLD) += pdc202xx_old.o
+obj-$(CONFIG_BLK_DEV_PDC202XX_NEW) += pdc202xx_new.o
+obj-$(CONFIG_BLK_DEV_PIIX) += piix.o
+obj-$(CONFIG_BLK_DEV_RZ1000) += rz1000.o
+obj-$(CONFIG_BLK_DEV_SVWKS) += serverworks.o
+obj-$(CONFIG_BLK_DEV_SGIIOC4) += sgiioc4.o
+obj-$(CONFIG_BLK_DEV_SIIMAGE) += siimage.o
+obj-$(CONFIG_BLK_DEV_SIS5513) += sis5513.o
+obj-$(CONFIG_BLK_DEV_SL82C105) += sl82c105.o
+obj-$(CONFIG_BLK_DEV_SLC90E66) += slc90e66.o
+obj-$(CONFIG_BLK_DEV_TC86C001) += tc86c001.o
+obj-$(CONFIG_BLK_DEV_TRIFLEX) += triflex.o
+obj-$(CONFIG_BLK_DEV_TRM290) += trm290.o
+obj-$(CONFIG_BLK_DEV_VIA82CXXX) += via82cxxx.o
+
+# Must appear at the end of the block
+obj-$(CONFIG_BLK_DEV_GENERIC) += ide-pci-generic.o
+
+obj-$(CONFIG_IDEPCI_PCIBUS_ORDER) += ide-scan-pci.o
+
+obj-$(CONFIG_BLK_DEV_CMD640) += cmd640.o
+
+obj-$(CONFIG_BLK_DEV_IDE_PMAC) += pmac.o
+
+obj-$(CONFIG_IDE_H8300) += ide-h8300.o
+
+obj-$(CONFIG_IDE_GENERIC) += ide-generic.o
+obj-$(CONFIG_BLK_DEV_IDEPNP) += ide-pnp.o
+
+ide-gd_mod-y += ide-gd.o
+ide-cd_mod-y += ide-cd.o ide-cd_ioctl.o ide-cd_verbose.o
+
+ifeq ($(CONFIG_IDE_GD_ATA), y)
+ ide-gd_mod-y += ide-disk.o ide-disk_ioctl.o
+ifeq ($(CONFIG_IDE_PROC_FS), y)
+ ide-gd_mod-y += ide-disk_proc.o
+endif
+endif
+
+ifeq ($(CONFIG_IDE_GD_ATAPI), y)
+ ide-gd_mod-y += ide-floppy.o ide-floppy_ioctl.o
+ifeq ($(CONFIG_IDE_PROC_FS), y)
+ ide-gd_mod-y += ide-floppy_proc.o
+endif
+endif
+
+obj-$(CONFIG_IDE_GD) += ide-gd_mod.o
+obj-$(CONFIG_BLK_DEV_IDECD) += ide-cd_mod.o
+obj-$(CONFIG_BLK_DEV_IDETAPE) += ide-tape.o
+
+obj-$(CONFIG_BLK_DEV_IDECS) += ide-cs.o
+
+obj-$(CONFIG_BLK_DEV_PLATFORM) += ide_platform.o
+
+obj-$(CONFIG_BLK_DEV_IDE_ICSIDE) += icside.o
+obj-$(CONFIG_BLK_DEV_IDE_RAPIDE) += rapide.o
+obj-$(CONFIG_BLK_DEV_PALMCHIP_BK3710) += palm_bk3710.o
+
+obj-$(CONFIG_BLK_DEV_IDE_AU1XXX) += au1xxx-ide.o
+
+obj-$(CONFIG_BLK_DEV_IDE_TX4938) += tx4938ide.o
+obj-$(CONFIG_BLK_DEV_IDE_TX4939) += tx4939ide.o
diff --git a/drivers/ide/aec62xx.c b/drivers/ide/aec62xx.c
new file mode 100644
index 0000000..4142c69
--- /dev/null
+++ b/drivers/ide/aec62xx.c
@@ -0,0 +1,329 @@
+/*
+ * Copyright (C) 1999-2002 Andre Hedrick <andre@linux-ide.org>
+ * Copyright (C) 2007 MontaVista Software, Inc. <source@mvista.com>
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#define DRV_NAME "aec62xx"
+
+struct chipset_bus_clock_list_entry {
+ u8 xfer_speed;
+ u8 chipset_settings;
+ u8 ultra_settings;
+};
+
+static const struct chipset_bus_clock_list_entry aec6xxx_33_base [] = {
+ { XFER_UDMA_6, 0x31, 0x07 },
+ { XFER_UDMA_5, 0x31, 0x06 },
+ { XFER_UDMA_4, 0x31, 0x05 },
+ { XFER_UDMA_3, 0x31, 0x04 },
+ { XFER_UDMA_2, 0x31, 0x03 },
+ { XFER_UDMA_1, 0x31, 0x02 },
+ { XFER_UDMA_0, 0x31, 0x01 },
+
+ { XFER_MW_DMA_2, 0x31, 0x00 },
+ { XFER_MW_DMA_1, 0x31, 0x00 },
+ { XFER_MW_DMA_0, 0x0a, 0x00 },
+ { XFER_PIO_4, 0x31, 0x00 },
+ { XFER_PIO_3, 0x33, 0x00 },
+ { XFER_PIO_2, 0x08, 0x00 },
+ { XFER_PIO_1, 0x0a, 0x00 },
+ { XFER_PIO_0, 0x00, 0x00 },
+ { 0, 0x00, 0x00 }
+};
+
+static const struct chipset_bus_clock_list_entry aec6xxx_34_base [] = {
+ { XFER_UDMA_6, 0x41, 0x06 },
+ { XFER_UDMA_5, 0x41, 0x05 },
+ { XFER_UDMA_4, 0x41, 0x04 },
+ { XFER_UDMA_3, 0x41, 0x03 },
+ { XFER_UDMA_2, 0x41, 0x02 },
+ { XFER_UDMA_1, 0x41, 0x01 },
+ { XFER_UDMA_0, 0x41, 0x01 },
+
+ { XFER_MW_DMA_2, 0x41, 0x00 },
+ { XFER_MW_DMA_1, 0x42, 0x00 },
+ { XFER_MW_DMA_0, 0x7a, 0x00 },
+ { XFER_PIO_4, 0x41, 0x00 },
+ { XFER_PIO_3, 0x43, 0x00 },
+ { XFER_PIO_2, 0x78, 0x00 },
+ { XFER_PIO_1, 0x7a, 0x00 },
+ { XFER_PIO_0, 0x70, 0x00 },
+ { 0, 0x00, 0x00 }
+};
+
+/*
+ * TO DO: active tuning and correction of cards without a bios.
+ */
+static u8 pci_bus_clock_list (u8 speed, struct chipset_bus_clock_list_entry * chipset_table)
+{
+ for ( ; chipset_table->xfer_speed ; chipset_table++)
+ if (chipset_table->xfer_speed == speed) {
+ return chipset_table->chipset_settings;
+ }
+ return chipset_table->chipset_settings;
+}
+
+static u8 pci_bus_clock_list_ultra (u8 speed, struct chipset_bus_clock_list_entry * chipset_table)
+{
+ for ( ; chipset_table->xfer_speed ; chipset_table++)
+ if (chipset_table->xfer_speed == speed) {
+ return chipset_table->ultra_settings;
+ }
+ return chipset_table->ultra_settings;
+}
+
+static void aec6210_set_mode(ide_drive_t *drive, const u8 speed)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+ struct ide_host *host = pci_get_drvdata(dev);
+ struct chipset_bus_clock_list_entry *bus_clock = host->host_priv;
+ u16 d_conf = 0;
+ u8 ultra = 0, ultra_conf = 0;
+ u8 tmp0 = 0, tmp1 = 0, tmp2 = 0;
+ unsigned long flags;
+
+ local_irq_save(flags);
+ /* 0x40|(2*drive->dn): Active, 0x41|(2*drive->dn): Recovery */
+ pci_read_config_word(dev, 0x40|(2*drive->dn), &d_conf);
+ tmp0 = pci_bus_clock_list(speed, bus_clock);
+ d_conf = ((tmp0 & 0xf0) << 4) | (tmp0 & 0xf);
+ pci_write_config_word(dev, 0x40|(2*drive->dn), d_conf);
+
+ tmp1 = 0x00;
+ tmp2 = 0x00;
+ pci_read_config_byte(dev, 0x54, &ultra);
+ tmp1 = ((0x00 << (2*drive->dn)) | (ultra & ~(3 << (2*drive->dn))));
+ ultra_conf = pci_bus_clock_list_ultra(speed, bus_clock);
+ tmp2 = ((ultra_conf << (2*drive->dn)) | (tmp1 & ~(3 << (2*drive->dn))));
+ pci_write_config_byte(dev, 0x54, tmp2);
+ local_irq_restore(flags);
+}
+
+static void aec6260_set_mode(ide_drive_t *drive, const u8 speed)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+ struct ide_host *host = pci_get_drvdata(dev);
+ struct chipset_bus_clock_list_entry *bus_clock = host->host_priv;
+ u8 unit = drive->dn & 1;
+ u8 tmp1 = 0, tmp2 = 0;
+ u8 ultra = 0, drive_conf = 0, ultra_conf = 0;
+ unsigned long flags;
+
+ local_irq_save(flags);
+ /* high 4-bits: Active, low 4-bits: Recovery */
+ pci_read_config_byte(dev, 0x40|drive->dn, &drive_conf);
+ drive_conf = pci_bus_clock_list(speed, bus_clock);
+ pci_write_config_byte(dev, 0x40|drive->dn, drive_conf);
+
+ pci_read_config_byte(dev, (0x44|hwif->channel), &ultra);
+ tmp1 = ((0x00 << (4*unit)) | (ultra & ~(7 << (4*unit))));
+ ultra_conf = pci_bus_clock_list_ultra(speed, bus_clock);
+ tmp2 = ((ultra_conf << (4*unit)) | (tmp1 & ~(7 << (4*unit))));
+ pci_write_config_byte(dev, (0x44|hwif->channel), tmp2);
+ local_irq_restore(flags);
+}
+
+static void aec_set_pio_mode(ide_drive_t *drive, const u8 pio)
+{
+ drive->hwif->port_ops->set_dma_mode(drive, pio + XFER_PIO_0);
+}
+
+static unsigned int init_chipset_aec62xx(struct pci_dev *dev)
+{
+ /* These are necessary to get AEC6280 Macintosh cards to work */
+ if ((dev->device == PCI_DEVICE_ID_ARTOP_ATP865) ||
+ (dev->device == PCI_DEVICE_ID_ARTOP_ATP865R)) {
+ u8 reg49h = 0, reg4ah = 0;
+ /* Clear reset and test bits. */
+ pci_read_config_byte(dev, 0x49, &reg49h);
+ pci_write_config_byte(dev, 0x49, reg49h & ~0x30);
+ /* Enable chip interrupt output. */
+ pci_read_config_byte(dev, 0x4a, &reg4ah);
+ pci_write_config_byte(dev, 0x4a, reg4ah & ~0x01);
+ /* Enable burst mode. */
+ pci_read_config_byte(dev, 0x4a, &reg4ah);
+ pci_write_config_byte(dev, 0x4a, reg4ah | 0x80);
+ }
+
+ return dev->irq;
+}
+
+static u8 atp86x_cable_detect(ide_hwif_t *hwif)
+{
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+ u8 ata66 = 0, mask = hwif->channel ? 0x02 : 0x01;
+
+ pci_read_config_byte(dev, 0x49, &ata66);
+
+ return (ata66 & mask) ? ATA_CBL_PATA40 : ATA_CBL_PATA80;
+}
+
+static const struct ide_port_ops atp850_port_ops = {
+ .set_pio_mode = aec_set_pio_mode,
+ .set_dma_mode = aec6210_set_mode,
+};
+
+static const struct ide_port_ops atp86x_port_ops = {
+ .set_pio_mode = aec_set_pio_mode,
+ .set_dma_mode = aec6260_set_mode,
+ .cable_detect = atp86x_cable_detect,
+};
+
+static const struct ide_port_info aec62xx_chipsets[] __devinitdata = {
+ { /* 0: AEC6210 */
+ .name = DRV_NAME,
+ .init_chipset = init_chipset_aec62xx,
+ .enablebits = {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
+ .port_ops = &atp850_port_ops,
+ .host_flags = IDE_HFLAG_SERIALIZE |
+ IDE_HFLAG_NO_ATAPI_DMA |
+ IDE_HFLAG_NO_DSC |
+ IDE_HFLAG_OFF_BOARD,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA2,
+ },
+ { /* 1: AEC6260 */
+ .name = DRV_NAME,
+ .init_chipset = init_chipset_aec62xx,
+ .port_ops = &atp86x_port_ops,
+ .host_flags = IDE_HFLAG_NO_ATAPI_DMA | IDE_HFLAG_NO_AUTODMA |
+ IDE_HFLAG_OFF_BOARD,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA4,
+ },
+ { /* 2: AEC6260R */
+ .name = DRV_NAME,
+ .init_chipset = init_chipset_aec62xx,
+ .enablebits = {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
+ .port_ops = &atp86x_port_ops,
+ .host_flags = IDE_HFLAG_NO_ATAPI_DMA |
+ IDE_HFLAG_NON_BOOTABLE,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA4,
+ },
+ { /* 3: AEC6280 */
+ .name = DRV_NAME,
+ .init_chipset = init_chipset_aec62xx,
+ .port_ops = &atp86x_port_ops,
+ .host_flags = IDE_HFLAG_NO_ATAPI_DMA |
+ IDE_HFLAG_OFF_BOARD,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA5,
+ },
+ { /* 4: AEC6280R */
+ .name = DRV_NAME,
+ .init_chipset = init_chipset_aec62xx,
+ .enablebits = {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
+ .port_ops = &atp86x_port_ops,
+ .host_flags = IDE_HFLAG_NO_ATAPI_DMA |
+ IDE_HFLAG_OFF_BOARD,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA5,
+ }
+};
+
+/**
+ * aec62xx_init_one - called when a AEC is found
+ * @dev: the aec62xx device
+ * @id: the matching pci id
+ *
+ * Called when the PCI registration layer (or the IDE initialization)
+ * finds a device matching our IDE device tables.
+ *
+ * NOTE: since we're going to modify the 'name' field for AEC-6[26]80[R]
+ * chips, pass a local copy of 'struct ide_port_info' down the call chain.
+ */
+
+static int __devinit aec62xx_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ const struct chipset_bus_clock_list_entry *bus_clock;
+ struct ide_port_info d;
+ u8 idx = id->driver_data;
+ int bus_speed = ide_pci_clk ? ide_pci_clk : 33;
+ int err;
+
+ if (bus_speed <= 33)
+ bus_clock = aec6xxx_33_base;
+ else
+ bus_clock = aec6xxx_34_base;
+
+ err = pci_enable_device(dev);
+ if (err)
+ return err;
+
+ d = aec62xx_chipsets[idx];
+
+ if (idx == 3 || idx == 4) {
+ unsigned long dma_base = pci_resource_start(dev, 4);
+
+ if (inb(dma_base + 2) & 0x10) {
+ printk(KERN_INFO DRV_NAME " %s: AEC6880%s card detected"
+ "\n", pci_name(dev), (idx == 4) ? "R" : "");
+ d.udma_mask = ATA_UDMA6;
+ }
+ }
+
+ err = ide_pci_init_one(dev, &d, (void *)bus_clock);
+ if (err)
+ pci_disable_device(dev);
+
+ return err;
+}
+
+static void __devexit aec62xx_remove(struct pci_dev *dev)
+{
+ ide_pci_remove(dev);
+ pci_disable_device(dev);
+}
+
+static const struct pci_device_id aec62xx_pci_tbl[] = {
+ { PCI_VDEVICE(ARTOP, PCI_DEVICE_ID_ARTOP_ATP850UF), 0 },
+ { PCI_VDEVICE(ARTOP, PCI_DEVICE_ID_ARTOP_ATP860), 1 },
+ { PCI_VDEVICE(ARTOP, PCI_DEVICE_ID_ARTOP_ATP860R), 2 },
+ { PCI_VDEVICE(ARTOP, PCI_DEVICE_ID_ARTOP_ATP865), 3 },
+ { PCI_VDEVICE(ARTOP, PCI_DEVICE_ID_ARTOP_ATP865R), 4 },
+ { 0, },
+};
+MODULE_DEVICE_TABLE(pci, aec62xx_pci_tbl);
+
+static struct pci_driver aec62xx_pci_driver = {
+ .name = "AEC62xx_IDE",
+ .id_table = aec62xx_pci_tbl,
+ .probe = aec62xx_init_one,
+ .remove = __devexit_p(aec62xx_remove),
+ .suspend = ide_pci_suspend,
+ .resume = ide_pci_resume,
+};
+
+static int __init aec62xx_ide_init(void)
+{
+ return ide_pci_register_driver(&aec62xx_pci_driver);
+}
+
+static void __exit aec62xx_ide_exit(void)
+{
+ pci_unregister_driver(&aec62xx_pci_driver);
+}
+
+module_init(aec62xx_ide_init);
+module_exit(aec62xx_ide_exit);
+
+MODULE_AUTHOR("Andre Hedrick");
+MODULE_DESCRIPTION("PCI driver module for ARTOP AEC62xx IDE");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/ali14xx.c b/drivers/ide/ali14xx.c
new file mode 100644
index 0000000..90da1f9
--- /dev/null
+++ b/drivers/ide/ali14xx.c
@@ -0,0 +1,248 @@
+/*
+ * Copyright (C) 1996 Linus Torvalds & author (see below)
+ */
+
+/*
+ * ALI M14xx chipset EIDE controller
+ *
+ * Works for ALI M1439/1443/1445/1487/1489 chipsets.
+ *
+ * Adapted from code developed by derekn@vw.ece.cmu.edu. -ml
+ * Derek's notes follow:
+ *
+ * I think the code should be pretty understandable,
+ * but I'll be happy to (try to) answer questions.
+ *
+ * The critical part is in the setupDrive function. The initRegisters
+ * function doesn't seem to be necessary, but the DOS driver does it, so
+ * I threw it in.
+ *
+ * I've only tested this on my system, which only has one disk. I posted
+ * it to comp.sys.linux.hardware, so maybe some other people will try it
+ * out.
+ *
+ * Derek Noonburg (derekn@ece.cmu.edu)
+ * 95-sep-26
+ *
+ * Update 96-jul-13:
+ *
+ * I've since upgraded to two disks and a CD-ROM, with no trouble, and
+ * I've also heard from several others who have used it successfully.
+ * This driver appears to work with both the 1443/1445 and the 1487/1489
+ * chipsets. I've added support for PIO mode 4 for the 1487. This
+ * seems to work just fine on the 1443 also, although I'm not sure it's
+ * advertised as supporting mode 4. (I've been running a WDC AC21200 in
+ * mode 4 for a while now with no trouble.) -Derek
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#define DRV_NAME "ali14xx"
+
+/* port addresses for auto-detection */
+#define ALI_NUM_PORTS 4
+static const int ports[ALI_NUM_PORTS] __initdata =
+ { 0x074, 0x0f4, 0x034, 0x0e4 };
+
+/* register initialization data */
+typedef struct { u8 reg, data; } RegInitializer;
+
+static const RegInitializer initData[] __initdata = {
+ {0x01, 0x0f}, {0x02, 0x00}, {0x03, 0x00}, {0x04, 0x00},
+ {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x2b}, {0x0a, 0x0f},
+ {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00}, {0x28, 0x00},
+ {0x29, 0x00}, {0x2a, 0x00}, {0x2f, 0x00}, {0x2b, 0x00},
+ {0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x00}, {0x30, 0x00},
+ {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00}, {0x34, 0xff},
+ {0x35, 0x03}, {0x00, 0x00}
+};
+
+/* timing parameter registers for each drive */
+static struct { u8 reg1, reg2, reg3, reg4; } regTab[4] = {
+ {0x03, 0x26, 0x04, 0x27}, /* drive 0 */
+ {0x05, 0x28, 0x06, 0x29}, /* drive 1 */
+ {0x2b, 0x30, 0x2c, 0x31}, /* drive 2 */
+ {0x2d, 0x32, 0x2e, 0x33}, /* drive 3 */
+};
+
+static int basePort; /* base port address */
+static int regPort; /* port for register number */
+static int dataPort; /* port for register data */
+static u8 regOn; /* output to base port to access registers */
+static u8 regOff; /* output to base port to close registers */
+
+/*------------------------------------------------------------------------*/
+
+/*
+ * Read a controller register.
+ */
+static inline u8 inReg(u8 reg)
+{
+ outb_p(reg, regPort);
+ return inb(dataPort);
+}
+
+/*
+ * Write a controller register.
+ */
+static void outReg(u8 data, u8 reg)
+{
+ outb_p(reg, regPort);
+ outb_p(data, dataPort);
+}
+
+static DEFINE_SPINLOCK(ali14xx_lock);
+
+/*
+ * Set PIO mode for the specified drive.
+ * This function computes timing parameters
+ * and sets controller registers accordingly.
+ */
+static void ali14xx_set_pio_mode(ide_drive_t *drive, const u8 pio)
+{
+ int driveNum;
+ int time1, time2;
+ u8 param1, param2, param3, param4;
+ unsigned long flags;
+ int bus_speed = ide_vlb_clk ? ide_vlb_clk : 50;
+ struct ide_timing *t = ide_timing_find_mode(XFER_PIO_0 + pio);
+
+ /* calculate timing, according to PIO mode */
+ time1 = ide_pio_cycle_time(drive, pio);
+ time2 = t->active;
+ param3 = param1 = (time2 * bus_speed + 999) / 1000;
+ param4 = param2 = (time1 * bus_speed + 999) / 1000 - param1;
+ if (pio < 3) {
+ param3 += 8;
+ param4 += 8;
+ }
+ printk(KERN_DEBUG "%s: PIO mode%d, t1=%dns, t2=%dns, cycles = %d+%d, %d+%d\n",
+ drive->name, pio, time1, time2, param1, param2, param3, param4);
+
+ /* stuff timing parameters into controller registers */
+ driveNum = (drive->hwif->index << 1) + (drive->dn & 1);
+ spin_lock_irqsave(&ali14xx_lock, flags);
+ outb_p(regOn, basePort);
+ outReg(param1, regTab[driveNum].reg1);
+ outReg(param2, regTab[driveNum].reg2);
+ outReg(param3, regTab[driveNum].reg3);
+ outReg(param4, regTab[driveNum].reg4);
+ outb_p(regOff, basePort);
+ spin_unlock_irqrestore(&ali14xx_lock, flags);
+}
+
+/*
+ * Auto-detect the IDE controller port.
+ */
+static int __init findPort(void)
+{
+ int i;
+ u8 t;
+ unsigned long flags;
+
+ local_irq_save(flags);
+ for (i = 0; i < ALI_NUM_PORTS; ++i) {
+ basePort = ports[i];
+ regOff = inb(basePort);
+ for (regOn = 0x30; regOn <= 0x33; ++regOn) {
+ outb_p(regOn, basePort);
+ if (inb(basePort) == regOn) {
+ regPort = basePort + 4;
+ dataPort = basePort + 8;
+ t = inReg(0) & 0xf0;
+ outb_p(regOff, basePort);
+ local_irq_restore(flags);
+ if (t != 0x50)
+ return 0;
+ return 1; /* success */
+ }
+ }
+ outb_p(regOff, basePort);
+ }
+ local_irq_restore(flags);
+ return 0;
+}
+
+/*
+ * Initialize controller registers with default values.
+ */
+static int __init initRegisters(void)
+{
+ const RegInitializer *p;
+ u8 t;
+ unsigned long flags;
+
+ local_irq_save(flags);
+ outb_p(regOn, basePort);
+ for (p = initData; p->reg != 0; ++p)
+ outReg(p->data, p->reg);
+ outb_p(0x01, regPort);
+ t = inb(regPort) & 0x01;
+ outb_p(regOff, basePort);
+ local_irq_restore(flags);
+ return t;
+}
+
+static const struct ide_port_ops ali14xx_port_ops = {
+ .set_pio_mode = ali14xx_set_pio_mode,
+};
+
+static const struct ide_port_info ali14xx_port_info = {
+ .name = DRV_NAME,
+ .chipset = ide_ali14xx,
+ .port_ops = &ali14xx_port_ops,
+ .host_flags = IDE_HFLAG_NO_DMA,
+ .pio_mask = ATA_PIO4,
+};
+
+static int __init ali14xx_probe(void)
+{
+ printk(KERN_DEBUG "ali14xx: base=0x%03x, regOn=0x%02x.\n",
+ basePort, regOn);
+
+ /* initialize controller registers */
+ if (!initRegisters()) {
+ printk(KERN_ERR "ali14xx: Chip initialization failed.\n");
+ return 1;
+ }
+
+ return ide_legacy_device_add(&ali14xx_port_info, 0);
+}
+
+static int probe_ali14xx;
+
+module_param_named(probe, probe_ali14xx, bool, 0);
+MODULE_PARM_DESC(probe, "probe for ALI M14xx chipsets");
+
+static int __init ali14xx_init(void)
+{
+ if (probe_ali14xx == 0)
+ goto out;
+
+ /* auto-detect IDE controller port */
+ if (findPort()) {
+ if (ali14xx_probe())
+ return -ENODEV;
+ return 0;
+ }
+ printk(KERN_ERR "ali14xx: not found.\n");
+out:
+ return -ENODEV;
+}
+
+module_init(ali14xx_init);
+
+MODULE_AUTHOR("see local file");
+MODULE_DESCRIPTION("support of ALI 14XX IDE chipsets");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/alim15x3.c b/drivers/ide/alim15x3.c
new file mode 100644
index 0000000..45d2356
--- /dev/null
+++ b/drivers/ide/alim15x3.c
@@ -0,0 +1,602 @@
+/*
+ * 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
+ * ALi (now ULi M5228) support by Clear Zhang <Clear.Zhang@ali.com.tw>
+ * Copyright (C) 2007 MontaVista Software, Inc. <source@mvista.com>
+ * Copyright (C) 2007 Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
+ *
+ * (U)DMA capable version of ali 1533/1543(C), 1535(D)
+ *
+ **********************************************************************
+ * 9/7/99 --Parts from the above author are included and need to be
+ * converted into standard interface, once I finish the thought.
+ *
+ * Recent changes
+ * Don't use LBA48 mode on ALi <= 0xC4
+ * Don't poke 0x79 with a non ALi northbridge
+ * Don't flip undefined bits on newer chipsets (fix Fujitsu laptop hang)
+ * Allow UDMA6 on revisions > 0xC4
+ *
+ * Documentation
+ * Chipset documentation available under NDA only
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+#include <linux/dmi.h>
+
+#include <asm/io.h>
+
+#define DRV_NAME "alim15x3"
+
+/*
+ * Allow UDMA on M1543C-E chipset for WDC disks that ignore CRC checking
+ * (this is DANGEROUS and could result in data corruption).
+ */
+static int wdc_udma;
+
+module_param(wdc_udma, bool, 0);
+MODULE_PARM_DESC(wdc_udma,
+ "allow UDMA on M1543C-E chipset for WDC disks (DANGEROUS)");
+
+/*
+ * ALi devices are not plug in. Otherwise these static values would
+ * need to go. They ought to go away anyway
+ */
+
+static u8 m5229_revision;
+static u8 chip_is_1543c_e;
+static struct pci_dev *isa_dev;
+
+/**
+ * ali_set_pio_mode - set host controller for PIO mode
+ * @drive: drive
+ * @pio: PIO mode number
+ *
+ * Program the controller for the given PIO mode.
+ */
+
+static void ali_set_pio_mode(ide_drive_t *drive, const u8 pio)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+ struct ide_timing *t = ide_timing_find_mode(XFER_PIO_0 + pio);
+ int s_time = t->setup, a_time = t->active, c_time = t->cycle;
+ u8 s_clc, a_clc, r_clc;
+ unsigned long flags;
+ int bus_speed = ide_pci_clk ? ide_pci_clk : 33;
+ int port = hwif->channel ? 0x5c : 0x58;
+ int portFIFO = hwif->channel ? 0x55 : 0x54;
+ u8 cd_dma_fifo = 0, unit = drive->dn & 1;
+
+ if ((s_clc = (s_time * bus_speed + 999) / 1000) >= 8)
+ s_clc = 0;
+ if ((a_clc = (a_time * bus_speed + 999) / 1000) >= 8)
+ a_clc = 0;
+
+ if (!(r_clc = (c_time * bus_speed + 999) / 1000 - a_clc - s_clc)) {
+ r_clc = 1;
+ } else {
+ if (r_clc >= 16)
+ r_clc = 0;
+ }
+ local_irq_save(flags);
+
+ /*
+ * PIO mode => ATA FIFO on, ATAPI FIFO off
+ */
+ pci_read_config_byte(dev, portFIFO, &cd_dma_fifo);
+ if (drive->media==ide_disk) {
+ if (unit) {
+ pci_write_config_byte(dev, portFIFO, (cd_dma_fifo & 0x0F) | 0x50);
+ } else {
+ pci_write_config_byte(dev, portFIFO, (cd_dma_fifo & 0xF0) | 0x05);
+ }
+ } else {
+ if (unit) {
+ pci_write_config_byte(dev, portFIFO, cd_dma_fifo & 0x0F);
+ } else {
+ pci_write_config_byte(dev, portFIFO, cd_dma_fifo & 0xF0);
+ }
+ }
+
+ pci_write_config_byte(dev, port, s_clc);
+ pci_write_config_byte(dev, port + unit + 2, (a_clc << 4) | r_clc);
+ local_irq_restore(flags);
+}
+
+/**
+ * ali_udma_filter - compute UDMA mask
+ * @drive: IDE device
+ *
+ * Return available UDMA modes.
+ *
+ * The actual rules for the ALi are:
+ * No UDMA on revisions <= 0x20
+ * Disk only for revisions < 0xC2
+ * Not WDC drives on M1543C-E (?)
+ */
+
+static u8 ali_udma_filter(ide_drive_t *drive)
+{
+ if (m5229_revision > 0x20 && m5229_revision < 0xC2) {
+ if (drive->media != ide_disk)
+ return 0;
+ if (wdc_udma == 0 && chip_is_1543c_e &&
+ strstr((char *)&drive->id[ATA_ID_PROD], "WDC "))
+ return 0;
+ }
+
+ return drive->hwif->ultra_mask;
+}
+
+/**
+ * ali_set_dma_mode - set host controller for DMA mode
+ * @drive: drive
+ * @speed: DMA mode
+ *
+ * Configure the hardware for the desired IDE transfer mode.
+ */
+
+static void ali_set_dma_mode(ide_drive_t *drive, const u8 speed)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+ u8 speed1 = speed;
+ u8 unit = drive->dn & 1;
+ u8 tmpbyte = 0x00;
+ int m5229_udma = (hwif->channel) ? 0x57 : 0x56;
+
+ if (speed == XFER_UDMA_6)
+ speed1 = 0x47;
+
+ if (speed < XFER_UDMA_0) {
+ u8 ultra_enable = (unit) ? 0x7f : 0xf7;
+ /*
+ * clear "ultra enable" bit
+ */
+ pci_read_config_byte(dev, m5229_udma, &tmpbyte);
+ tmpbyte &= ultra_enable;
+ pci_write_config_byte(dev, m5229_udma, tmpbyte);
+
+ /*
+ * FIXME: Oh, my... DMA timings are never set.
+ */
+ } else {
+ pci_read_config_byte(dev, m5229_udma, &tmpbyte);
+ tmpbyte &= (0x0f << ((1-unit) << 2));
+ /*
+ * enable ultra dma and set timing
+ */
+ tmpbyte |= ((0x08 | ((4-speed1)&0x07)) << (unit << 2));
+ pci_write_config_byte(dev, m5229_udma, tmpbyte);
+ if (speed >= XFER_UDMA_3) {
+ pci_read_config_byte(dev, 0x4b, &tmpbyte);
+ tmpbyte |= 1;
+ pci_write_config_byte(dev, 0x4b, tmpbyte);
+ }
+ }
+}
+
+/**
+ * ali15x3_dma_setup - begin a DMA phase
+ * @drive: target device
+ *
+ * Returns 1 if the DMA cannot be performed, zero on success.
+ */
+
+static int ali15x3_dma_setup(ide_drive_t *drive)
+{
+ if (m5229_revision < 0xC2 && drive->media != ide_disk) {
+ if (rq_data_dir(drive->hwif->hwgroup->rq))
+ return 1; /* try PIO instead of DMA */
+ }
+ return ide_dma_setup(drive);
+}
+
+/**
+ * init_chipset_ali15x3 - Initialise an ALi IDE controller
+ * @dev: PCI device
+ *
+ * This function initializes the ALI IDE controller and where
+ * appropriate also sets up the 1533 southbridge.
+ */
+
+static unsigned int init_chipset_ali15x3(struct pci_dev *dev)
+{
+ unsigned long flags;
+ u8 tmpbyte;
+ struct pci_dev *north = pci_get_slot(dev->bus, PCI_DEVFN(0,0));
+
+ m5229_revision = dev->revision;
+
+ isa_dev = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL);
+
+ local_irq_save(flags);
+
+ if (m5229_revision < 0xC2) {
+ /*
+ * revision 0x20 (1543-E, 1543-F)
+ * revision 0xC0, 0xC1 (1543C-C, 1543C-D, 1543C-E)
+ * clear CD-ROM DMA write bit, m5229, 0x4b, bit 7
+ */
+ pci_read_config_byte(dev, 0x4b, &tmpbyte);
+ /*
+ * clear bit 7
+ */
+ pci_write_config_byte(dev, 0x4b, tmpbyte & 0x7F);
+ /*
+ * check m1533, 0x5e, bit 1~4 == 1001 => & 00011110 = 00010010
+ */
+ if (m5229_revision >= 0x20 && isa_dev) {
+ pci_read_config_byte(isa_dev, 0x5e, &tmpbyte);
+ chip_is_1543c_e = ((tmpbyte & 0x1e) == 0x12) ? 1: 0;
+ }
+ goto out;
+ }
+
+ /*
+ * 1543C-B?, 1535, 1535D, 1553
+ * Note 1: not all "motherboard" support this detection
+ * Note 2: if no udma 66 device, the detection may "error".
+ * but in this case, we will not set the device to
+ * ultra 66, the detection result is not important
+ */
+
+ /*
+ * enable "Cable Detection", m5229, 0x4b, bit3
+ */
+ pci_read_config_byte(dev, 0x4b, &tmpbyte);
+ pci_write_config_byte(dev, 0x4b, tmpbyte | 0x08);
+
+ /*
+ * We should only tune the 1533 enable if we are using an ALi
+ * North bridge. We might have no north found on some zany
+ * box without a device at 0:0.0. The ALi bridge will be at
+ * 0:0.0 so if we didn't find one we know what is cooking.
+ */
+ if (north && north->vendor != PCI_VENDOR_ID_AL)
+ goto out;
+
+ if (m5229_revision < 0xC5 && isa_dev)
+ {
+ /*
+ * set south-bridge's enable bit, m1533, 0x79
+ */
+
+ pci_read_config_byte(isa_dev, 0x79, &tmpbyte);
+ if (m5229_revision == 0xC2) {
+ /*
+ * 1543C-B0 (m1533, 0x79, bit 2)
+ */
+ pci_write_config_byte(isa_dev, 0x79, tmpbyte | 0x04);
+ } else if (m5229_revision >= 0xC3) {
+ /*
+ * 1553/1535 (m1533, 0x79, bit 1)
+ */
+ pci_write_config_byte(isa_dev, 0x79, tmpbyte | 0x02);
+ }
+ }
+
+out:
+ /*
+ * CD_ROM DMA on (m5229, 0x53, bit0)
+ * Enable this bit even if we want to use PIO.
+ * PIO FIFO off (m5229, 0x53, bit1)
+ * The hardware will use 0x54h and 0x55h to control PIO FIFO.
+ * (Not on later devices it seems)
+ *
+ * 0x53 changes meaning on later revs - we must no touch
+ * bit 1 on them. Need to check if 0x20 is the right break.
+ */
+ if (m5229_revision >= 0x20) {
+ pci_read_config_byte(dev, 0x53, &tmpbyte);
+
+ if (m5229_revision <= 0x20)
+ tmpbyte = (tmpbyte & (~0x02)) | 0x01;
+ else if (m5229_revision == 0xc7 || m5229_revision == 0xc8)
+ tmpbyte |= 0x03;
+ else
+ tmpbyte |= 0x01;
+
+ pci_write_config_byte(dev, 0x53, tmpbyte);
+ }
+ pci_dev_put(north);
+ pci_dev_put(isa_dev);
+ local_irq_restore(flags);
+ return 0;
+}
+
+/*
+ * Cable special cases
+ */
+
+static const struct dmi_system_id cable_dmi_table[] = {
+ {
+ .ident = "HP Pavilion N5430",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "Hewlett-Packard"),
+ DMI_MATCH(DMI_BOARD_VERSION, "OmniBook N32N-736"),
+ },
+ },
+ {
+ .ident = "Toshiba Satellite S1800-814",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "S1800-814"),
+ },
+ },
+ { }
+};
+
+static int ali_cable_override(struct pci_dev *pdev)
+{
+ /* Fujitsu P2000 */
+ if (pdev->subsystem_vendor == 0x10CF &&
+ pdev->subsystem_device == 0x10AF)
+ return 1;
+
+ /* Mitac 8317 (Winbook-A) and relatives */
+ if (pdev->subsystem_vendor == 0x1071 &&
+ pdev->subsystem_device == 0x8317)
+ return 1;
+
+ /* Systems by DMI */
+ if (dmi_check_system(cable_dmi_table))
+ return 1;
+
+ return 0;
+}
+
+/**
+ * ali_cable_detect - cable detection
+ * @hwif: IDE interface
+ *
+ * This checks if the controller and the cable are capable
+ * of UDMA66 transfers. It doesn't check the drives.
+ * But see note 2 below!
+ *
+ * FIXME: frobs bits that are not defined on newer ALi devicea
+ */
+
+static u8 ali_cable_detect(ide_hwif_t *hwif)
+{
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+ unsigned long flags;
+ u8 cbl = ATA_CBL_PATA40, tmpbyte;
+
+ local_irq_save(flags);
+
+ if (m5229_revision >= 0xC2) {
+ /*
+ * m5229 80-pin cable detection (from Host View)
+ *
+ * 0x4a bit0 is 0 => primary channel has 80-pin
+ * 0x4a bit1 is 0 => secondary channel has 80-pin
+ *
+ * Certain laptops use short but suitable cables
+ * and don't implement the detect logic.
+ */
+ if (ali_cable_override(dev))
+ cbl = ATA_CBL_PATA40_SHORT;
+ else {
+ pci_read_config_byte(dev, 0x4a, &tmpbyte);
+ if ((tmpbyte & (1 << hwif->channel)) == 0)
+ cbl = ATA_CBL_PATA80;
+ }
+ }
+
+ local_irq_restore(flags);
+
+ return cbl;
+}
+
+#if !defined(CONFIG_SPARC64) && !defined(CONFIG_PPC)
+/**
+ * init_hwif_ali15x3 - Initialize the ALI IDE x86 stuff
+ * @hwif: interface to configure
+ *
+ * Obtain the IRQ tables for an ALi based IDE solution on the PC
+ * class platforms. This part of the code isn't applicable to the
+ * Sparc and PowerPC systems.
+ */
+
+static void __devinit init_hwif_ali15x3 (ide_hwif_t *hwif)
+{
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+ u8 ideic, inmir;
+ s8 irq_routing_table[] = { -1, 9, 3, 10, 4, 5, 7, 6,
+ 1, 11, 0, 12, 0, 14, 0, 15 };
+ int irq = -1;
+
+ if (dev->device == PCI_DEVICE_ID_AL_M5229)
+ hwif->irq = hwif->channel ? 15 : 14;
+
+ if (isa_dev) {
+ /*
+ * read IDE interface control
+ */
+ pci_read_config_byte(isa_dev, 0x58, &ideic);
+
+ /* bit0, bit1 */
+ ideic = ideic & 0x03;
+
+ /* get IRQ for IDE Controller */
+ if ((hwif->channel && ideic == 0x03) ||
+ (!hwif->channel && !ideic)) {
+ /*
+ * get SIRQ1 routing table
+ */
+ pci_read_config_byte(isa_dev, 0x44, &inmir);
+ inmir = inmir & 0x0f;
+ irq = irq_routing_table[inmir];
+ } else if (hwif->channel && !(ideic & 0x01)) {
+ /*
+ * get SIRQ2 routing table
+ */
+ pci_read_config_byte(isa_dev, 0x75, &inmir);
+ inmir = inmir & 0x0f;
+ irq = irq_routing_table[inmir];
+ }
+ if(irq >= 0)
+ hwif->irq = irq;
+ }
+}
+#else
+#define init_hwif_ali15x3 NULL
+#endif /* !defined(CONFIG_SPARC64) && !defined(CONFIG_PPC) */
+
+/**
+ * init_dma_ali15x3 - set up DMA on ALi15x3
+ * @hwif: IDE interface
+ * @d: IDE port info
+ *
+ * Set up the DMA functionality on the ALi 15x3.
+ */
+
+static int __devinit init_dma_ali15x3(ide_hwif_t *hwif,
+ const struct ide_port_info *d)
+{
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+ unsigned long base = ide_pci_dma_base(hwif, d);
+
+ if (base == 0)
+ return -1;
+
+ hwif->dma_base = base;
+
+ if (ide_pci_check_simplex(hwif, d) < 0)
+ return -1;
+
+ if (ide_pci_set_master(dev, d->name) < 0)
+ return -1;
+
+ if (!hwif->channel)
+ outb(inb(base + 2) & 0x60, base + 2);
+
+ printk(KERN_INFO " %s: BM-DMA at 0x%04lx-0x%04lx\n",
+ hwif->name, base, base + 7);
+
+ if (ide_allocate_dma_engine(hwif))
+ return -1;
+
+ hwif->dma_ops = &sff_dma_ops;
+
+ return 0;
+}
+
+static const struct ide_port_ops ali_port_ops = {
+ .set_pio_mode = ali_set_pio_mode,
+ .set_dma_mode = ali_set_dma_mode,
+ .udma_filter = ali_udma_filter,
+ .cable_detect = ali_cable_detect,
+};
+
+static const struct ide_dma_ops ali_dma_ops = {
+ .dma_host_set = ide_dma_host_set,
+ .dma_setup = ali15x3_dma_setup,
+ .dma_exec_cmd = ide_dma_exec_cmd,
+ .dma_start = ide_dma_start,
+ .dma_end = ide_dma_end,
+ .dma_test_irq = ide_dma_test_irq,
+ .dma_lost_irq = ide_dma_lost_irq,
+ .dma_timeout = ide_dma_timeout,
+};
+
+static const struct ide_port_info ali15x3_chipset __devinitdata = {
+ .name = DRV_NAME,
+ .init_chipset = init_chipset_ali15x3,
+ .init_hwif = init_hwif_ali15x3,
+ .init_dma = init_dma_ali15x3,
+ .port_ops = &ali_port_ops,
+ .pio_mask = ATA_PIO5,
+ .swdma_mask = ATA_SWDMA2,
+ .mwdma_mask = ATA_MWDMA2,
+};
+
+/**
+ * alim15x3_init_one - set up an ALi15x3 IDE controller
+ * @dev: PCI device to set up
+ *
+ * Perform the actual set up for an ALi15x3 that has been found by the
+ * hot plug layer.
+ */
+
+static int __devinit alim15x3_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ struct ide_port_info d = ali15x3_chipset;
+ u8 rev = dev->revision, idx = id->driver_data;
+
+ /* don't use LBA48 DMA on ALi devices before rev 0xC5 */
+ if (rev <= 0xC4)
+ d.host_flags |= IDE_HFLAG_NO_LBA48_DMA;
+
+ if (rev >= 0x20) {
+ if (rev == 0x20)
+ d.host_flags |= IDE_HFLAG_NO_ATAPI_DMA;
+
+ if (rev < 0xC2)
+ d.udma_mask = ATA_UDMA2;
+ else if (rev == 0xC2 || rev == 0xC3)
+ d.udma_mask = ATA_UDMA4;
+ else if (rev == 0xC4)
+ d.udma_mask = ATA_UDMA5;
+ else
+ d.udma_mask = ATA_UDMA6;
+
+ d.dma_ops = &ali_dma_ops;
+ } else {
+ d.host_flags |= IDE_HFLAG_NO_DMA;
+
+ d.mwdma_mask = d.swdma_mask = 0;
+ }
+
+ if (idx == 0)
+ d.host_flags |= IDE_HFLAG_CLEAR_SIMPLEX;
+
+ return ide_pci_init_one(dev, &d, NULL);
+}
+
+
+static const struct pci_device_id alim15x3_pci_tbl[] = {
+ { PCI_VDEVICE(AL, PCI_DEVICE_ID_AL_M5229), 0 },
+ { PCI_VDEVICE(AL, PCI_DEVICE_ID_AL_M5228), 1 },
+ { 0, },
+};
+MODULE_DEVICE_TABLE(pci, alim15x3_pci_tbl);
+
+static struct pci_driver alim15x3_pci_driver = {
+ .name = "ALI15x3_IDE",
+ .id_table = alim15x3_pci_tbl,
+ .probe = alim15x3_init_one,
+ .remove = ide_pci_remove,
+ .suspend = ide_pci_suspend,
+ .resume = ide_pci_resume,
+};
+
+static int __init ali15x3_ide_init(void)
+{
+ return ide_pci_register_driver(&alim15x3_pci_driver);
+}
+
+static void __exit ali15x3_ide_exit(void)
+{
+ pci_unregister_driver(&alim15x3_pci_driver);
+}
+
+module_init(ali15x3_ide_init);
+module_exit(ali15x3_ide_exit);
+
+MODULE_AUTHOR("Michael Aubry, Andrzej Krzysztofowicz, CJ, Andre Hedrick, Alan Cox");
+MODULE_DESCRIPTION("PCI driver module for ALi 15x3 IDE");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/amd74xx.c b/drivers/ide/amd74xx.c
new file mode 100644
index 0000000..c6bcd30
--- /dev/null
+++ b/drivers/ide/amd74xx.c
@@ -0,0 +1,355 @@
+/*
+ * AMD 755/756/766/8111 and nVidia nForce/2/2s/3/3s/CK804/MCP04
+ * IDE driver for Linux.
+ *
+ * Copyright (c) 2000-2002 Vojtech Pavlik
+ * Copyright (c) 2007-2008 Bartlomiej Zolnierkiewicz
+ *
+ * Based on the work of:
+ * Andre Hedrick
+ */
+
+/*
+ * 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/module.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/ide.h>
+
+#define DRV_NAME "amd74xx"
+
+enum {
+ AMD_IDE_CONFIG = 0x41,
+ AMD_CABLE_DETECT = 0x42,
+ AMD_DRIVE_TIMING = 0x48,
+ AMD_8BIT_TIMING = 0x4e,
+ AMD_ADDRESS_SETUP = 0x4c,
+ AMD_UDMA_TIMING = 0x50,
+};
+
+static unsigned int amd_80w;
+static unsigned int amd_clock;
+
+static char *amd_dma[] = { "16", "25", "33", "44", "66", "100", "133" };
+static unsigned char amd_cyc2udma[] = { 6, 6, 5, 4, 0, 1, 1, 2, 2, 3, 3, 3, 3, 3, 3, 7 };
+
+static inline u8 amd_offset(struct pci_dev *dev)
+{
+ return (dev->vendor == PCI_VENDOR_ID_NVIDIA) ? 0x10 : 0;
+}
+
+/*
+ * amd_set_speed() writes timing values to the chipset registers
+ */
+
+static void amd_set_speed(struct pci_dev *dev, u8 dn, u8 udma_mask,
+ struct ide_timing *timing)
+{
+ u8 t = 0, offset = amd_offset(dev);
+
+ pci_read_config_byte(dev, AMD_ADDRESS_SETUP + offset, &t);
+ t = (t & ~(3 << ((3 - dn) << 1))) | ((clamp_val(timing->setup, 1, 4) - 1) << ((3 - dn) << 1));
+ pci_write_config_byte(dev, AMD_ADDRESS_SETUP + offset, t);
+
+ pci_write_config_byte(dev, AMD_8BIT_TIMING + offset + (1 - (dn >> 1)),
+ ((clamp_val(timing->act8b, 1, 16) - 1) << 4) | (clamp_val(timing->rec8b, 1, 16) - 1));
+
+ pci_write_config_byte(dev, AMD_DRIVE_TIMING + offset + (3 - dn),
+ ((clamp_val(timing->active, 1, 16) - 1) << 4) | (clamp_val(timing->recover, 1, 16) - 1));
+
+ switch (udma_mask) {
+ case ATA_UDMA2: t = timing->udma ? (0xc0 | (clamp_val(timing->udma, 2, 5) - 2)) : 0x03; break;
+ case ATA_UDMA4: t = timing->udma ? (0xc0 | amd_cyc2udma[clamp_val(timing->udma, 2, 10)]) : 0x03; break;
+ case ATA_UDMA5: t = timing->udma ? (0xc0 | amd_cyc2udma[clamp_val(timing->udma, 1, 10)]) : 0x03; break;
+ case ATA_UDMA6: t = timing->udma ? (0xc0 | amd_cyc2udma[clamp_val(timing->udma, 1, 15)]) : 0x03; break;
+ default: return;
+ }
+
+ pci_write_config_byte(dev, AMD_UDMA_TIMING + offset + (3 - dn), t);
+}
+
+/*
+ * amd_set_drive() computes timing values and configures the chipset
+ * to a desired transfer mode. It also can be called by upper layers.
+ */
+
+static void amd_set_drive(ide_drive_t *drive, const u8 speed)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+ ide_drive_t *peer = hwif->drives + (~drive->dn & 1);
+ struct ide_timing t, p;
+ int T, UT;
+ u8 udma_mask = hwif->ultra_mask;
+
+ T = 1000000000 / amd_clock;
+ UT = (udma_mask == ATA_UDMA2) ? T : (T / 2);
+
+ ide_timing_compute(drive, speed, &t, T, UT);
+
+ if (peer->dev_flags & IDE_DFLAG_PRESENT) {
+ ide_timing_compute(peer, peer->current_speed, &p, T, UT);
+ ide_timing_merge(&p, &t, &t, IDE_TIMING_8BIT);
+ }
+
+ if (speed == XFER_UDMA_5 && amd_clock <= 33333) t.udma = 1;
+ if (speed == XFER_UDMA_6 && amd_clock <= 33333) t.udma = 15;
+
+ amd_set_speed(dev, drive->dn, udma_mask, &t);
+}
+
+/*
+ * amd_set_pio_mode() is a callback from upper layers for PIO-only tuning.
+ */
+
+static void amd_set_pio_mode(ide_drive_t *drive, const u8 pio)
+{
+ amd_set_drive(drive, XFER_PIO_0 + pio);
+}
+
+static void amd7409_cable_detect(struct pci_dev *dev)
+{
+ /* no host side cable detection */
+ amd_80w = 0x03;
+}
+
+static void amd7411_cable_detect(struct pci_dev *dev)
+{
+ int i;
+ u32 u = 0;
+ u8 t = 0, offset = amd_offset(dev);
+
+ pci_read_config_byte(dev, AMD_CABLE_DETECT + offset, &t);
+ pci_read_config_dword(dev, AMD_UDMA_TIMING + offset, &u);
+ amd_80w = ((t & 0x3) ? 1 : 0) | ((t & 0xc) ? 2 : 0);
+ for (i = 24; i >= 0; i -= 8)
+ if (((u >> i) & 4) && !(amd_80w & (1 << (1 - (i >> 4))))) {
+ printk(KERN_WARNING DRV_NAME " %s: BIOS didn't set "
+ "cable bits correctly. Enabling workaround.\n",
+ pci_name(dev));
+ amd_80w |= (1 << (1 - (i >> 4)));
+ }
+}
+
+/*
+ * The initialization callback. Initialize drive independent registers.
+ */
+
+static unsigned int init_chipset_amd74xx(struct pci_dev *dev)
+{
+ u8 t = 0, offset = amd_offset(dev);
+
+/*
+ * Check 80-wire cable presence.
+ */
+
+ if (dev->vendor == PCI_VENDOR_ID_AMD &&
+ dev->device == PCI_DEVICE_ID_AMD_COBRA_7401)
+ ; /* no UDMA > 2 */
+ else if (dev->vendor == PCI_VENDOR_ID_AMD &&
+ dev->device == PCI_DEVICE_ID_AMD_VIPER_7409)
+ amd7409_cable_detect(dev);
+ else
+ amd7411_cable_detect(dev);
+
+/*
+ * Take care of prefetch & postwrite.
+ */
+
+ pci_read_config_byte(dev, AMD_IDE_CONFIG + offset, &t);
+ /*
+ * Check for broken FIFO support.
+ */
+ if (dev->vendor == PCI_VENDOR_ID_AMD &&
+ dev->vendor == PCI_DEVICE_ID_AMD_VIPER_7411)
+ t &= 0x0f;
+ else
+ t |= 0xf0;
+ pci_write_config_byte(dev, AMD_IDE_CONFIG + offset, t);
+
+ return dev->irq;
+}
+
+static u8 amd_cable_detect(ide_hwif_t *hwif)
+{
+ if ((amd_80w >> hwif->channel) & 1)
+ return ATA_CBL_PATA80;
+ else
+ return ATA_CBL_PATA40;
+}
+
+static void __devinit init_hwif_amd74xx(ide_hwif_t *hwif)
+{
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+
+ if (hwif->irq == 0) /* 0 is bogus but will do for now */
+ hwif->irq = pci_get_legacy_ide_irq(dev, hwif->channel);
+}
+
+static const struct ide_port_ops amd_port_ops = {
+ .set_pio_mode = amd_set_pio_mode,
+ .set_dma_mode = amd_set_drive,
+ .cable_detect = amd_cable_detect,
+};
+
+#define IDE_HFLAGS_AMD \
+ (IDE_HFLAG_PIO_NO_BLACKLIST | \
+ IDE_HFLAG_POST_SET_MODE | \
+ IDE_HFLAG_IO_32BIT | \
+ IDE_HFLAG_UNMASK_IRQS)
+
+#define DECLARE_AMD_DEV(swdma, udma) \
+ { \
+ .name = DRV_NAME, \
+ .init_chipset = init_chipset_amd74xx, \
+ .init_hwif = init_hwif_amd74xx, \
+ .enablebits = {{0x40,0x02,0x02}, {0x40,0x01,0x01}}, \
+ .port_ops = &amd_port_ops, \
+ .host_flags = IDE_HFLAGS_AMD, \
+ .pio_mask = ATA_PIO5, \
+ .swdma_mask = swdma, \
+ .mwdma_mask = ATA_MWDMA2, \
+ .udma_mask = udma, \
+ }
+
+#define DECLARE_NV_DEV(udma) \
+ { \
+ .name = DRV_NAME, \
+ .init_chipset = init_chipset_amd74xx, \
+ .init_hwif = init_hwif_amd74xx, \
+ .enablebits = {{0x50,0x02,0x02}, {0x50,0x01,0x01}}, \
+ .port_ops = &amd_port_ops, \
+ .host_flags = IDE_HFLAGS_AMD, \
+ .pio_mask = ATA_PIO5, \
+ .swdma_mask = ATA_SWDMA2, \
+ .mwdma_mask = ATA_MWDMA2, \
+ .udma_mask = udma, \
+ }
+
+static const struct ide_port_info amd74xx_chipsets[] __devinitdata = {
+ /* 0: AMD7401 */ DECLARE_AMD_DEV(0x00, ATA_UDMA2),
+ /* 1: AMD7409 */ DECLARE_AMD_DEV(ATA_SWDMA2, ATA_UDMA4),
+ /* 2: AMD7411/7441 */ DECLARE_AMD_DEV(ATA_SWDMA2, ATA_UDMA5),
+ /* 3: AMD8111 */ DECLARE_AMD_DEV(ATA_SWDMA2, ATA_UDMA6),
+
+ /* 4: NFORCE */ DECLARE_NV_DEV(ATA_UDMA5),
+ /* 5: >= NFORCE2 */ DECLARE_NV_DEV(ATA_UDMA6),
+
+ /* 6: AMD5536 */ DECLARE_AMD_DEV(ATA_SWDMA2, ATA_UDMA5),
+};
+
+static int __devinit amd74xx_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ struct ide_port_info d;
+ u8 idx = id->driver_data;
+
+ d = amd74xx_chipsets[idx];
+
+ /*
+ * Check for bad SWDMA and incorrectly wired Serenade mainboards.
+ */
+ if (idx == 1) {
+ if (dev->revision <= 7)
+ d.swdma_mask = 0;
+ d.host_flags |= IDE_HFLAG_CLEAR_SIMPLEX;
+ } else if (idx == 3) {
+ if (dev->subsystem_vendor == PCI_VENDOR_ID_AMD &&
+ dev->subsystem_device == PCI_DEVICE_ID_AMD_SERENADE)
+ d.udma_mask = ATA_UDMA5;
+ }
+
+ /*
+ * It seems that on some nVidia controllers using AltStatus
+ * register can be unreliable so default to Status register
+ * if the device is in Compatibility Mode.
+ */
+ if (dev->vendor == PCI_VENDOR_ID_NVIDIA &&
+ ide_pci_is_in_compatibility_mode(dev))
+ d.host_flags |= IDE_HFLAG_BROKEN_ALTSTATUS;
+
+ printk(KERN_INFO "%s %s: UDMA%s controller\n",
+ d.name, pci_name(dev), amd_dma[fls(d.udma_mask) - 1]);
+
+ /*
+ * Determine the system bus clock.
+ */
+ amd_clock = (ide_pci_clk ? ide_pci_clk : 33) * 1000;
+
+ switch (amd_clock) {
+ case 33000: amd_clock = 33333; break;
+ case 37000: amd_clock = 37500; break;
+ case 41000: amd_clock = 41666; break;
+ }
+
+ if (amd_clock < 20000 || amd_clock > 50000) {
+ printk(KERN_WARNING "%s: User given PCI clock speed impossible"
+ " (%d), using 33 MHz instead.\n",
+ d.name, amd_clock);
+ amd_clock = 33333;
+ }
+
+ return ide_pci_init_one(dev, &d, NULL);
+}
+
+static const struct pci_device_id amd74xx_pci_tbl[] = {
+ { 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), 2 },
+ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_OPUS_7441), 2 },
+ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_8111_IDE), 3 },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_IDE), 4 },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2_IDE), 5 },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_IDE), 5 },
+#ifdef CONFIG_BLK_DEV_IDE_SATA
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_SATA), 5 },
+#endif
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3_IDE), 5 },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_IDE), 5 },
+#ifdef CONFIG_BLK_DEV_IDE_SATA
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA), 5 },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA2), 5 },
+#endif
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_IDE), 5 },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE), 5 },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_IDE), 5 },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_IDE), 5 },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_IDE), 5 },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP65_IDE), 5 },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP67_IDE), 5 },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP73_IDE), 5 },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP77_IDE), 5 },
+ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_CS5536_IDE), 6 },
+ { 0, },
+};
+MODULE_DEVICE_TABLE(pci, amd74xx_pci_tbl);
+
+static struct pci_driver amd74xx_pci_driver = {
+ .name = "AMD_IDE",
+ .id_table = amd74xx_pci_tbl,
+ .probe = amd74xx_probe,
+ .remove = ide_pci_remove,
+ .suspend = ide_pci_suspend,
+ .resume = ide_pci_resume,
+};
+
+static int __init amd74xx_ide_init(void)
+{
+ return ide_pci_register_driver(&amd74xx_pci_driver);
+}
+
+static void __exit amd74xx_ide_exit(void)
+{
+ pci_unregister_driver(&amd74xx_pci_driver);
+}
+
+module_init(amd74xx_ide_init);
+module_exit(amd74xx_ide_exit);
+
+MODULE_AUTHOR("Vojtech Pavlik");
+MODULE_DESCRIPTION("AMD PCI IDE driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/atiixp.c b/drivers/ide/atiixp.c
new file mode 100644
index 0000000..b2735d2
--- /dev/null
+++ b/drivers/ide/atiixp.c
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2003 ATI Inc. <hyu@ati.com>
+ * Copyright (C) 2004,2007 Bartlomiej Zolnierkiewicz
+ */
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#define DRV_NAME "atiixp"
+
+#define ATIIXP_IDE_PIO_TIMING 0x40
+#define ATIIXP_IDE_MDMA_TIMING 0x44
+#define ATIIXP_IDE_PIO_CONTROL 0x48
+#define ATIIXP_IDE_PIO_MODE 0x4a
+#define ATIIXP_IDE_UDMA_CONTROL 0x54
+#define ATIIXP_IDE_UDMA_MODE 0x56
+
+typedef struct {
+ u8 command_width;
+ u8 recover_width;
+} atiixp_ide_timing;
+
+static atiixp_ide_timing pio_timing[] = {
+ { 0x05, 0x0d },
+ { 0x04, 0x07 },
+ { 0x03, 0x04 },
+ { 0x02, 0x02 },
+ { 0x02, 0x00 },
+};
+
+static atiixp_ide_timing mdma_timing[] = {
+ { 0x07, 0x07 },
+ { 0x02, 0x01 },
+ { 0x02, 0x00 },
+};
+
+static DEFINE_SPINLOCK(atiixp_lock);
+
+/**
+ * atiixp_set_pio_mode - set host controller for PIO mode
+ * @drive: drive
+ * @pio: PIO mode number
+ *
+ * Set the interface PIO mode.
+ */
+
+static void atiixp_set_pio_mode(ide_drive_t *drive, const u8 pio)
+{
+ struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
+ unsigned long flags;
+ int timing_shift = (drive->dn & 2) ? 16 : 0 + (drive->dn & 1) ? 0 : 8;
+ u32 pio_timing_data;
+ u16 pio_mode_data;
+
+ spin_lock_irqsave(&atiixp_lock, flags);
+
+ pci_read_config_word(dev, ATIIXP_IDE_PIO_MODE, &pio_mode_data);
+ pio_mode_data &= ~(0x07 << (drive->dn * 4));
+ pio_mode_data |= (pio << (drive->dn * 4));
+ pci_write_config_word(dev, ATIIXP_IDE_PIO_MODE, pio_mode_data);
+
+ pci_read_config_dword(dev, ATIIXP_IDE_PIO_TIMING, &pio_timing_data);
+ pio_timing_data &= ~(0xff << timing_shift);
+ pio_timing_data |= (pio_timing[pio].recover_width << timing_shift) |
+ (pio_timing[pio].command_width << (timing_shift + 4));
+ pci_write_config_dword(dev, ATIIXP_IDE_PIO_TIMING, pio_timing_data);
+
+ spin_unlock_irqrestore(&atiixp_lock, flags);
+}
+
+/**
+ * atiixp_set_dma_mode - set host controller for DMA mode
+ * @drive: drive
+ * @speed: DMA mode
+ *
+ * Set a ATIIXP host controller to the desired DMA mode. This involves
+ * programming the right timing data into the PCI configuration space.
+ */
+
+static void atiixp_set_dma_mode(ide_drive_t *drive, const u8 speed)
+{
+ struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
+ unsigned long flags;
+ int timing_shift = (drive->dn & 2) ? 16 : 0 + (drive->dn & 1) ? 0 : 8;
+ u32 tmp32;
+ u16 tmp16;
+ u16 udma_ctl = 0;
+
+ spin_lock_irqsave(&atiixp_lock, flags);
+
+ pci_read_config_word(dev, ATIIXP_IDE_UDMA_CONTROL, &udma_ctl);
+
+ if (speed >= XFER_UDMA_0) {
+ pci_read_config_word(dev, ATIIXP_IDE_UDMA_MODE, &tmp16);
+ tmp16 &= ~(0x07 << (drive->dn * 4));
+ tmp16 |= ((speed & 0x07) << (drive->dn * 4));
+ pci_write_config_word(dev, ATIIXP_IDE_UDMA_MODE, tmp16);
+
+ udma_ctl |= (1 << drive->dn);
+ } else if (speed >= XFER_MW_DMA_0) {
+ u8 i = speed & 0x03;
+
+ pci_read_config_dword(dev, ATIIXP_IDE_MDMA_TIMING, &tmp32);
+ tmp32 &= ~(0xff << timing_shift);
+ tmp32 |= (mdma_timing[i].recover_width << timing_shift) |
+ (mdma_timing[i].command_width << (timing_shift + 4));
+ pci_write_config_dword(dev, ATIIXP_IDE_MDMA_TIMING, tmp32);
+
+ udma_ctl &= ~(1 << drive->dn);
+ }
+
+ pci_write_config_word(dev, ATIIXP_IDE_UDMA_CONTROL, udma_ctl);
+
+ spin_unlock_irqrestore(&atiixp_lock, flags);
+}
+
+static u8 atiixp_cable_detect(ide_hwif_t *hwif)
+{
+ struct pci_dev *pdev = to_pci_dev(hwif->dev);
+ u8 udma_mode = 0, ch = hwif->channel;
+
+ pci_read_config_byte(pdev, ATIIXP_IDE_UDMA_MODE + ch, &udma_mode);
+
+ if ((udma_mode & 0x07) >= 0x04 || (udma_mode & 0x70) >= 0x40)
+ return ATA_CBL_PATA80;
+ else
+ return ATA_CBL_PATA40;
+}
+
+static const struct ide_port_ops atiixp_port_ops = {
+ .set_pio_mode = atiixp_set_pio_mode,
+ .set_dma_mode = atiixp_set_dma_mode,
+ .cable_detect = atiixp_cable_detect,
+};
+
+static const struct ide_port_info atiixp_pci_info[] __devinitdata = {
+ { /* 0: IXP200/300/400/700 */
+ .name = DRV_NAME,
+ .enablebits = {{0x48,0x01,0x00}, {0x48,0x08,0x00}},
+ .port_ops = &atiixp_port_ops,
+ .host_flags = IDE_HFLAG_LEGACY_IRQS,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA5,
+ },
+ { /* 1: IXP600 */
+ .name = DRV_NAME,
+ .enablebits = {{0x48,0x01,0x00}, {0x00,0x00,0x00}},
+ .port_ops = &atiixp_port_ops,
+ .host_flags = IDE_HFLAG_SINGLE | IDE_HFLAG_LEGACY_IRQS,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA5,
+ },
+};
+
+/**
+ * atiixp_init_one - called when a ATIIXP is found
+ * @dev: the atiixp device
+ * @id: the matching pci id
+ *
+ * Called when the PCI registration layer (or the IDE initialization)
+ * finds a device matching our IDE device tables.
+ */
+
+static int __devinit atiixp_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ return ide_pci_init_one(dev, &atiixp_pci_info[id->driver_data], NULL);
+}
+
+static const struct pci_device_id atiixp_pci_tbl[] = {
+ { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP200_IDE), 0 },
+ { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP300_IDE), 0 },
+ { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP400_IDE), 0 },
+ { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP600_IDE), 1 },
+ { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP700_IDE), 0 },
+ { 0, },
+};
+MODULE_DEVICE_TABLE(pci, atiixp_pci_tbl);
+
+static struct pci_driver atiixp_pci_driver = {
+ .name = "ATIIXP_IDE",
+ .id_table = atiixp_pci_tbl,
+ .probe = atiixp_init_one,
+ .remove = ide_pci_remove,
+ .suspend = ide_pci_suspend,
+ .resume = ide_pci_resume,
+};
+
+static int __init atiixp_ide_init(void)
+{
+ return ide_pci_register_driver(&atiixp_pci_driver);
+}
+
+static void __exit atiixp_ide_exit(void)
+{
+ pci_unregister_driver(&atiixp_pci_driver);
+}
+
+module_init(atiixp_ide_init);
+module_exit(atiixp_ide_exit);
+
+MODULE_AUTHOR("HUI YU");
+MODULE_DESCRIPTION("PCI driver module for ATI IXP IDE");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/au1xxx-ide.c b/drivers/ide/au1xxx-ide.c
new file mode 100644
index 0000000..0ec8fd1
--- /dev/null
+++ b/drivers/ide/au1xxx-ide.c
@@ -0,0 +1,642 @@
+/*
+ * BRIEF MODULE DESCRIPTION
+ * AMD Alchemy Au1xxx IDE interface routines over the Static Bus
+ *
+ * Copyright (c) 2003-2005 AMD, Personal Connectivity Solutions
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * 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.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Note: for more information, please refer "AMD Alchemy Au1200/Au1550 IDE
+ * Interface and Linux Device Driver" Application Note.
+ */
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/ide.h>
+#include <linux/scatterlist.h>
+
+#include <asm/mach-au1x00/au1xxx.h>
+#include <asm/mach-au1x00/au1xxx_dbdma.h>
+#include <asm/mach-au1x00/au1xxx_ide.h>
+
+#define DRV_NAME "au1200-ide"
+#define DRV_AUTHOR "Enrico Walther <enrico.walther@amd.com> / Pete Popov <ppopov@embeddedalley.com>"
+
+/* enable the burstmode in the dbdma */
+#define IDE_AU1XXX_BURSTMODE 1
+
+static _auide_hwif auide_hwif;
+
+#if defined(CONFIG_BLK_DEV_IDE_AU1XXX_PIO_DBDMA)
+
+void auide_insw(unsigned long port, void *addr, u32 count)
+{
+ _auide_hwif *ahwif = &auide_hwif;
+ chan_tab_t *ctp;
+ au1x_ddma_desc_t *dp;
+
+ if(!put_dest_flags(ahwif->rx_chan, (void*)addr, count << 1,
+ DDMA_FLAGS_NOIE)) {
+ printk(KERN_ERR "%s failed %d\n", __func__, __LINE__);
+ return;
+ }
+ ctp = *((chan_tab_t **)ahwif->rx_chan);
+ dp = ctp->cur_ptr;
+ while (dp->dscr_cmd0 & DSCR_CMD0_V)
+ ;
+ ctp->cur_ptr = au1xxx_ddma_get_nextptr_virt(dp);
+}
+
+void auide_outsw(unsigned long port, void *addr, u32 count)
+{
+ _auide_hwif *ahwif = &auide_hwif;
+ chan_tab_t *ctp;
+ au1x_ddma_desc_t *dp;
+
+ if(!put_source_flags(ahwif->tx_chan, (void*)addr,
+ count << 1, DDMA_FLAGS_NOIE)) {
+ printk(KERN_ERR "%s failed %d\n", __func__, __LINE__);
+ return;
+ }
+ ctp = *((chan_tab_t **)ahwif->tx_chan);
+ dp = ctp->cur_ptr;
+ while (dp->dscr_cmd0 & DSCR_CMD0_V)
+ ;
+ ctp->cur_ptr = au1xxx_ddma_get_nextptr_virt(dp);
+}
+
+static void au1xxx_input_data(ide_drive_t *drive, struct request *rq,
+ void *buf, unsigned int len)
+{
+ auide_insw(drive->hwif->io_ports.data_addr, buf, (len + 1) / 2);
+}
+
+static void au1xxx_output_data(ide_drive_t *drive, struct request *rq,
+ void *buf, unsigned int len)
+{
+ auide_outsw(drive->hwif->io_ports.data_addr, buf, (len + 1) / 2);
+}
+#endif
+
+static void au1xxx_set_pio_mode(ide_drive_t *drive, const u8 pio)
+{
+ int mem_sttime = 0, mem_stcfg = au_readl(MEM_STCFG2);
+
+ /* set pio mode! */
+ switch(pio) {
+ case 0:
+ mem_sttime = SBC_IDE_TIMING(PIO0);
+
+ /* set configuration for RCS2# */
+ mem_stcfg |= TS_MASK;
+ mem_stcfg &= ~TCSOE_MASK;
+ mem_stcfg &= ~TOECS_MASK;
+ mem_stcfg |= SBC_IDE_PIO0_TCSOE | SBC_IDE_PIO0_TOECS;
+ break;
+
+ case 1:
+ mem_sttime = SBC_IDE_TIMING(PIO1);
+
+ /* set configuration for RCS2# */
+ mem_stcfg |= TS_MASK;
+ mem_stcfg &= ~TCSOE_MASK;
+ mem_stcfg &= ~TOECS_MASK;
+ mem_stcfg |= SBC_IDE_PIO1_TCSOE | SBC_IDE_PIO1_TOECS;
+ break;
+
+ case 2:
+ mem_sttime = SBC_IDE_TIMING(PIO2);
+
+ /* set configuration for RCS2# */
+ mem_stcfg &= ~TS_MASK;
+ mem_stcfg &= ~TCSOE_MASK;
+ mem_stcfg &= ~TOECS_MASK;
+ mem_stcfg |= SBC_IDE_PIO2_TCSOE | SBC_IDE_PIO2_TOECS;
+ break;
+
+ case 3:
+ mem_sttime = SBC_IDE_TIMING(PIO3);
+
+ /* set configuration for RCS2# */
+ mem_stcfg &= ~TS_MASK;
+ mem_stcfg &= ~TCSOE_MASK;
+ mem_stcfg &= ~TOECS_MASK;
+ mem_stcfg |= SBC_IDE_PIO3_TCSOE | SBC_IDE_PIO3_TOECS;
+
+ break;
+
+ case 4:
+ mem_sttime = SBC_IDE_TIMING(PIO4);
+
+ /* set configuration for RCS2# */
+ mem_stcfg &= ~TS_MASK;
+ mem_stcfg &= ~TCSOE_MASK;
+ mem_stcfg &= ~TOECS_MASK;
+ mem_stcfg |= SBC_IDE_PIO4_TCSOE | SBC_IDE_PIO4_TOECS;
+ break;
+ }
+
+ au_writel(mem_sttime,MEM_STTIME2);
+ au_writel(mem_stcfg,MEM_STCFG2);
+}
+
+static void auide_set_dma_mode(ide_drive_t *drive, const u8 speed)
+{
+ int mem_sttime = 0, mem_stcfg = au_readl(MEM_STCFG2);
+
+ switch(speed) {
+#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
+ case XFER_MW_DMA_2:
+ mem_sttime = SBC_IDE_TIMING(MDMA2);
+
+ /* set configuration for RCS2# */
+ mem_stcfg &= ~TS_MASK;
+ mem_stcfg &= ~TCSOE_MASK;
+ mem_stcfg &= ~TOECS_MASK;
+ mem_stcfg |= SBC_IDE_MDMA2_TCSOE | SBC_IDE_MDMA2_TOECS;
+
+ break;
+ case XFER_MW_DMA_1:
+ mem_sttime = SBC_IDE_TIMING(MDMA1);
+
+ /* set configuration for RCS2# */
+ mem_stcfg &= ~TS_MASK;
+ mem_stcfg &= ~TCSOE_MASK;
+ mem_stcfg &= ~TOECS_MASK;
+ mem_stcfg |= SBC_IDE_MDMA1_TCSOE | SBC_IDE_MDMA1_TOECS;
+
+ break;
+ case XFER_MW_DMA_0:
+ mem_sttime = SBC_IDE_TIMING(MDMA0);
+
+ /* set configuration for RCS2# */
+ mem_stcfg |= TS_MASK;
+ mem_stcfg &= ~TCSOE_MASK;
+ mem_stcfg &= ~TOECS_MASK;
+ mem_stcfg |= SBC_IDE_MDMA0_TCSOE | SBC_IDE_MDMA0_TOECS;
+
+ break;
+#endif
+ }
+
+ au_writel(mem_sttime,MEM_STTIME2);
+ au_writel(mem_stcfg,MEM_STCFG2);
+}
+
+/*
+ * Multi-Word DMA + DbDMA functions
+ */
+
+#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
+static int auide_build_dmatable(ide_drive_t *drive)
+{
+ int i, iswrite, count = 0;
+ ide_hwif_t *hwif = HWIF(drive);
+ struct request *rq = HWGROUP(drive)->rq;
+ _auide_hwif *ahwif = &auide_hwif;
+ struct scatterlist *sg;
+
+ iswrite = (rq_data_dir(rq) == WRITE);
+ /* Save for interrupt context */
+ ahwif->drive = drive;
+
+ hwif->sg_nents = i = ide_build_sglist(drive, rq);
+
+ if (!i)
+ return 0;
+
+ /* fill the descriptors */
+ sg = hwif->sg_table;
+ while (i && sg_dma_len(sg)) {
+ u32 cur_addr;
+ u32 cur_len;
+
+ cur_addr = sg_dma_address(sg);
+ cur_len = sg_dma_len(sg);
+
+ while (cur_len) {
+ u32 flags = DDMA_FLAGS_NOIE;
+ unsigned int tc = (cur_len < 0xfe00)? cur_len: 0xfe00;
+
+ if (++count >= PRD_ENTRIES) {
+ printk(KERN_WARNING "%s: DMA table too small\n",
+ drive->name);
+ goto use_pio_instead;
+ }
+
+ /* Lets enable intr for the last descriptor only */
+ if (1==i)
+ flags = DDMA_FLAGS_IE;
+ else
+ flags = DDMA_FLAGS_NOIE;
+
+ if (iswrite) {
+ if(!put_source_flags(ahwif->tx_chan,
+ (void*) sg_virt(sg),
+ tc, flags)) {
+ printk(KERN_ERR "%s failed %d\n",
+ __func__, __LINE__);
+ }
+ } else
+ {
+ if(!put_dest_flags(ahwif->rx_chan,
+ (void*) sg_virt(sg),
+ tc, flags)) {
+ printk(KERN_ERR "%s failed %d\n",
+ __func__, __LINE__);
+ }
+ }
+
+ cur_addr += tc;
+ cur_len -= tc;
+ }
+ sg = sg_next(sg);
+ i--;
+ }
+
+ if (count)
+ return 1;
+
+ use_pio_instead:
+ ide_destroy_dmatable(drive);
+
+ return 0; /* revert to PIO for this request */
+}
+
+static int auide_dma_end(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+
+ if (hwif->sg_nents) {
+ ide_destroy_dmatable(drive);
+ hwif->sg_nents = 0;
+ }
+
+ return 0;
+}
+
+static void auide_dma_start(ide_drive_t *drive )
+{
+}
+
+
+static void auide_dma_exec_cmd(ide_drive_t *drive, u8 command)
+{
+ /* issue cmd to drive */
+ ide_execute_command(drive, command, &ide_dma_intr,
+ (2*WAIT_CMD), NULL);
+}
+
+static int auide_dma_setup(ide_drive_t *drive)
+{
+ struct request *rq = HWGROUP(drive)->rq;
+
+ if (!auide_build_dmatable(drive)) {
+ ide_map_sg(drive, rq);
+ return 1;
+ }
+
+ drive->waiting_for_dma = 1;
+ return 0;
+}
+
+static int auide_dma_test_irq(ide_drive_t *drive)
+{
+ /* If dbdma didn't execute the STOP command yet, the
+ * active bit is still set
+ */
+ drive->waiting_for_dma++;
+ if (drive->waiting_for_dma >= DMA_WAIT_TIMEOUT) {
+ printk(KERN_WARNING "%s: timeout waiting for ddma to \
+ complete\n", drive->name);
+ return 1;
+ }
+ udelay(10);
+ return 0;
+}
+
+static void auide_dma_host_set(ide_drive_t *drive, int on)
+{
+}
+
+static void auide_ddma_tx_callback(int irq, void *param)
+{
+ _auide_hwif *ahwif = (_auide_hwif*)param;
+ ahwif->drive->waiting_for_dma = 0;
+}
+
+static void auide_ddma_rx_callback(int irq, void *param)
+{
+ _auide_hwif *ahwif = (_auide_hwif*)param;
+ ahwif->drive->waiting_for_dma = 0;
+}
+
+#endif /* end CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA */
+
+static void auide_init_dbdma_dev(dbdev_tab_t *dev, u32 dev_id, u32 tsize, u32 devwidth, u32 flags)
+{
+ dev->dev_id = dev_id;
+ dev->dev_physaddr = (u32)IDE_PHYS_ADDR;
+ dev->dev_intlevel = 0;
+ dev->dev_intpolarity = 0;
+ dev->dev_tsize = tsize;
+ dev->dev_devwidth = devwidth;
+ dev->dev_flags = flags;
+}
+
+#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
+static const struct ide_dma_ops au1xxx_dma_ops = {
+ .dma_host_set = auide_dma_host_set,
+ .dma_setup = auide_dma_setup,
+ .dma_exec_cmd = auide_dma_exec_cmd,
+ .dma_start = auide_dma_start,
+ .dma_end = auide_dma_end,
+ .dma_test_irq = auide_dma_test_irq,
+ .dma_lost_irq = ide_dma_lost_irq,
+ .dma_timeout = ide_dma_timeout,
+};
+
+static int auide_ddma_init(ide_hwif_t *hwif, const struct ide_port_info *d)
+{
+ _auide_hwif *auide = &auide_hwif;
+ dbdev_tab_t source_dev_tab, target_dev_tab;
+ u32 dev_id, tsize, devwidth, flags;
+
+ dev_id = IDE_DDMA_REQ;
+
+ tsize = 8; /* 1 */
+ devwidth = 32; /* 16 */
+
+#ifdef IDE_AU1XXX_BURSTMODE
+ flags = DEV_FLAGS_SYNC | DEV_FLAGS_BURSTABLE;
+#else
+ flags = DEV_FLAGS_SYNC;
+#endif
+
+ /* setup dev_tab for tx channel */
+ auide_init_dbdma_dev( &source_dev_tab,
+ dev_id,
+ tsize, devwidth, DEV_FLAGS_OUT | flags);
+ auide->tx_dev_id = au1xxx_ddma_add_device( &source_dev_tab );
+
+ auide_init_dbdma_dev( &source_dev_tab,
+ dev_id,
+ tsize, devwidth, DEV_FLAGS_IN | flags);
+ auide->rx_dev_id = au1xxx_ddma_add_device( &source_dev_tab );
+
+ /* We also need to add a target device for the DMA */
+ auide_init_dbdma_dev( &target_dev_tab,
+ (u32)DSCR_CMD0_ALWAYS,
+ tsize, devwidth, DEV_FLAGS_ANYUSE);
+ auide->target_dev_id = au1xxx_ddma_add_device(&target_dev_tab);
+
+ /* Get a channel for TX */
+ auide->tx_chan = au1xxx_dbdma_chan_alloc(auide->target_dev_id,
+ auide->tx_dev_id,
+ auide_ddma_tx_callback,
+ (void*)auide);
+
+ /* Get a channel for RX */
+ auide->rx_chan = au1xxx_dbdma_chan_alloc(auide->rx_dev_id,
+ auide->target_dev_id,
+ auide_ddma_rx_callback,
+ (void*)auide);
+
+ auide->tx_desc_head = (void*)au1xxx_dbdma_ring_alloc(auide->tx_chan,
+ NUM_DESCRIPTORS);
+ auide->rx_desc_head = (void*)au1xxx_dbdma_ring_alloc(auide->rx_chan,
+ NUM_DESCRIPTORS);
+
+ /* FIXME: check return value */
+ (void)ide_allocate_dma_engine(hwif);
+
+ au1xxx_dbdma_start( auide->tx_chan );
+ au1xxx_dbdma_start( auide->rx_chan );
+
+ return 0;
+}
+#else
+static int auide_ddma_init(ide_hwif_t *hwif, const struct ide_port_info *d)
+{
+ _auide_hwif *auide = &auide_hwif;
+ dbdev_tab_t source_dev_tab;
+ int flags;
+
+#ifdef IDE_AU1XXX_BURSTMODE
+ flags = DEV_FLAGS_SYNC | DEV_FLAGS_BURSTABLE;
+#else
+ flags = DEV_FLAGS_SYNC;
+#endif
+
+ /* setup dev_tab for tx channel */
+ auide_init_dbdma_dev( &source_dev_tab,
+ (u32)DSCR_CMD0_ALWAYS,
+ 8, 32, DEV_FLAGS_OUT | flags);
+ auide->tx_dev_id = au1xxx_ddma_add_device( &source_dev_tab );
+
+ auide_init_dbdma_dev( &source_dev_tab,
+ (u32)DSCR_CMD0_ALWAYS,
+ 8, 32, DEV_FLAGS_IN | flags);
+ auide->rx_dev_id = au1xxx_ddma_add_device( &source_dev_tab );
+
+ /* Get a channel for TX */
+ auide->tx_chan = au1xxx_dbdma_chan_alloc(DSCR_CMD0_ALWAYS,
+ auide->tx_dev_id,
+ NULL,
+ (void*)auide);
+
+ /* Get a channel for RX */
+ auide->rx_chan = au1xxx_dbdma_chan_alloc(auide->rx_dev_id,
+ DSCR_CMD0_ALWAYS,
+ NULL,
+ (void*)auide);
+
+ auide->tx_desc_head = (void*)au1xxx_dbdma_ring_alloc(auide->tx_chan,
+ NUM_DESCRIPTORS);
+ auide->rx_desc_head = (void*)au1xxx_dbdma_ring_alloc(auide->rx_chan,
+ NUM_DESCRIPTORS);
+
+ au1xxx_dbdma_start( auide->tx_chan );
+ au1xxx_dbdma_start( auide->rx_chan );
+
+ return 0;
+}
+#endif
+
+static void auide_setup_ports(hw_regs_t *hw, _auide_hwif *ahwif)
+{
+ int i;
+ unsigned long *ata_regs = hw->io_ports_array;
+
+ /* FIXME? */
+ for (i = 0; i < 8; i++)
+ *ata_regs++ = ahwif->regbase + (i << IDE_REG_SHIFT);
+
+ /* set the Alternative Status register */
+ *ata_regs = ahwif->regbase + (14 << IDE_REG_SHIFT);
+}
+
+#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_PIO_DBDMA
+static const struct ide_tp_ops au1xxx_tp_ops = {
+ .exec_command = ide_exec_command,
+ .read_status = ide_read_status,
+ .read_altstatus = ide_read_altstatus,
+ .read_sff_dma_status = ide_read_sff_dma_status,
+
+ .set_irq = ide_set_irq,
+
+ .tf_load = ide_tf_load,
+ .tf_read = ide_tf_read,
+
+ .input_data = au1xxx_input_data,
+ .output_data = au1xxx_output_data,
+};
+#endif
+
+static const struct ide_port_ops au1xxx_port_ops = {
+ .set_pio_mode = au1xxx_set_pio_mode,
+ .set_dma_mode = auide_set_dma_mode,
+};
+
+static const struct ide_port_info au1xxx_port_info = {
+ .init_dma = auide_ddma_init,
+#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_PIO_DBDMA
+ .tp_ops = &au1xxx_tp_ops,
+#endif
+ .port_ops = &au1xxx_port_ops,
+#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
+ .dma_ops = &au1xxx_dma_ops,
+#endif
+ .host_flags = IDE_HFLAG_POST_SET_MODE |
+ IDE_HFLAG_NO_IO_32BIT |
+ IDE_HFLAG_UNMASK_IRQS,
+ .pio_mask = ATA_PIO4,
+#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
+ .mwdma_mask = ATA_MWDMA2,
+#endif
+};
+
+static int au_ide_probe(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ _auide_hwif *ahwif = &auide_hwif;
+ struct resource *res;
+ struct ide_host *host;
+ int ret = 0;
+ hw_regs_t hw, *hws[] = { &hw, NULL, NULL, NULL };
+
+#if defined(CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA)
+ char *mode = "MWDMA2";
+#elif defined(CONFIG_BLK_DEV_IDE_AU1XXX_PIO_DBDMA)
+ char *mode = "PIO+DDMA(offload)";
+#endif
+
+ memset(&auide_hwif, 0, sizeof(_auide_hwif));
+ ahwif->irq = platform_get_irq(pdev, 0);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ if (res == NULL) {
+ pr_debug("%s %d: no base address\n", DRV_NAME, pdev->id);
+ ret = -ENODEV;
+ goto out;
+ }
+ if (ahwif->irq < 0) {
+ pr_debug("%s %d: no IRQ\n", DRV_NAME, pdev->id);
+ ret = -ENODEV;
+ goto out;
+ }
+
+ if (!request_mem_region(res->start, res->end - res->start + 1,
+ pdev->name)) {
+ pr_debug("%s: request_mem_region failed\n", DRV_NAME);
+ ret = -EBUSY;
+ goto out;
+ }
+
+ ahwif->regbase = (u32)ioremap(res->start, res->end - res->start + 1);
+ if (ahwif->regbase == 0) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ memset(&hw, 0, sizeof(hw));
+ auide_setup_ports(&hw, ahwif);
+ hw.irq = ahwif->irq;
+ hw.dev = dev;
+ hw.chipset = ide_au1xxx;
+
+ ret = ide_host_add(&au1xxx_port_info, hws, &host);
+ if (ret)
+ goto out;
+
+ auide_hwif.hwif = host->ports[0];
+
+ dev_set_drvdata(dev, host);
+
+ printk(KERN_INFO "Au1xxx IDE(builtin) configured for %s\n", mode );
+
+ out:
+ return ret;
+}
+
+static int au_ide_remove(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct resource *res;
+ struct ide_host *host = dev_get_drvdata(dev);
+ _auide_hwif *ahwif = &auide_hwif;
+
+ ide_host_remove(host);
+
+ iounmap((void *)ahwif->regbase);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ release_mem_region(res->start, res->end - res->start + 1);
+
+ return 0;
+}
+
+static struct device_driver au1200_ide_driver = {
+ .name = "au1200-ide",
+ .bus = &platform_bus_type,
+ .probe = au_ide_probe,
+ .remove = au_ide_remove,
+};
+
+static int __init au_ide_init(void)
+{
+ return driver_register(&au1200_ide_driver);
+}
+
+static void __exit au_ide_exit(void)
+{
+ driver_unregister(&au1200_ide_driver);
+}
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("AU1200 IDE driver");
+
+module_init(au_ide_init);
+module_exit(au_ide_exit);
diff --git a/drivers/ide/buddha.c b/drivers/ide/buddha.c
new file mode 100644
index 0000000..c5a3c9e
--- /dev/null
+++ b/drivers/ide/buddha.c
@@ -0,0 +1,235 @@
+/*
+ * Amiga Buddha, Catweasel and X-Surf IDE Driver
+ *
+ * Copyright (C) 1997, 2001 by Geert Uytterhoeven and others
+ *
+ * This driver was written based on the specifications in README.buddha and
+ * the X-Surf info from Inside_XSurf.txt available at
+ * http://www.jschoenfeld.com
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive for
+ * more details.
+ *
+ * TODO:
+ * - test it :-)
+ * - tune the timings using the speed-register
+ */
+
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/zorro.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/amigahw.h>
+#include <asm/amigaints.h>
+
+
+ /*
+ * The Buddha has 2 IDE interfaces, the Catweasel has 3, X-Surf has 2
+ */
+
+#define BUDDHA_NUM_HWIFS 2
+#define CATWEASEL_NUM_HWIFS 3
+#define XSURF_NUM_HWIFS 2
+
+#define MAX_NUM_HWIFS 3
+
+ /*
+ * Bases of the IDE interfaces (relative to the board address)
+ */
+
+#define BUDDHA_BASE1 0x800
+#define BUDDHA_BASE2 0xa00
+#define BUDDHA_BASE3 0xc00
+
+#define XSURF_BASE1 0xb000 /* 2.5" Interface */
+#define XSURF_BASE2 0xd000 /* 3.5" Interface */
+
+static u_int buddha_bases[CATWEASEL_NUM_HWIFS] __initdata = {
+ BUDDHA_BASE1, BUDDHA_BASE2, BUDDHA_BASE3
+};
+
+static u_int xsurf_bases[XSURF_NUM_HWIFS] __initdata = {
+ XSURF_BASE1, XSURF_BASE2
+};
+
+ /*
+ * Offsets from one of the above bases
+ */
+
+#define BUDDHA_CONTROL 0x11a
+
+ /*
+ * Other registers
+ */
+
+#define BUDDHA_IRQ1 0xf00 /* MSB = 1, Harddisk is source of */
+#define BUDDHA_IRQ2 0xf40 /* interrupt */
+#define BUDDHA_IRQ3 0xf80
+
+#define XSURF_IRQ1 0x7e
+#define XSURF_IRQ2 0x7e
+
+static int buddha_irqports[CATWEASEL_NUM_HWIFS] __initdata = {
+ BUDDHA_IRQ1, BUDDHA_IRQ2, BUDDHA_IRQ3
+};
+
+static int xsurf_irqports[XSURF_NUM_HWIFS] __initdata = {
+ XSURF_IRQ1, XSURF_IRQ2
+};
+
+#define BUDDHA_IRQ_MR 0xfc0 /* master interrupt enable */
+
+
+ /*
+ * Board information
+ */
+
+typedef enum BuddhaType_Enum {
+ BOARD_BUDDHA, BOARD_CATWEASEL, BOARD_XSURF
+} BuddhaType;
+
+static const char *buddha_board_name[] = { "Buddha", "Catweasel", "X-Surf" };
+
+ /*
+ * Check and acknowledge the interrupt status
+ */
+
+static int buddha_ack_intr(ide_hwif_t *hwif)
+{
+ unsigned char ch;
+
+ ch = z_readb(hwif->io_ports.irq_addr);
+ if (!(ch & 0x80))
+ return 0;
+ return 1;
+}
+
+static int xsurf_ack_intr(ide_hwif_t *hwif)
+{
+ unsigned char ch;
+
+ ch = z_readb(hwif->io_ports.irq_addr);
+ /* X-Surf needs a 0 written to IRQ register to ensure ISA bit A11 stays at 0 */
+ z_writeb(0, hwif->io_ports.irq_addr);
+ if (!(ch & 0x80))
+ return 0;
+ return 1;
+}
+
+static void __init buddha_setup_ports(hw_regs_t *hw, unsigned long base,
+ unsigned long ctl, unsigned long irq_port,
+ ide_ack_intr_t *ack_intr)
+{
+ int i;
+
+ memset(hw, 0, sizeof(*hw));
+
+ hw->io_ports.data_addr = base;
+
+ for (i = 1; i < 8; i++)
+ hw->io_ports_array[i] = base + 2 + i * 4;
+
+ hw->io_ports.ctl_addr = ctl;
+ hw->io_ports.irq_addr = irq_port;
+
+ hw->irq = IRQ_AMIGA_PORTS;
+ hw->ack_intr = ack_intr;
+
+ hw->chipset = ide_generic;
+}
+
+ /*
+ * Probe for a Buddha or Catweasel IDE interface
+ */
+
+static int __init buddha_init(void)
+{
+ struct zorro_dev *z = NULL;
+ u_long buddha_board = 0;
+ BuddhaType type;
+ int buddha_num_hwifs, i;
+
+ while ((z = zorro_find_device(ZORRO_WILDCARD, z))) {
+ unsigned long board;
+ hw_regs_t hw[MAX_NUM_HWIFS], *hws[] = { NULL, NULL, NULL, NULL };
+
+ if (z->id == ZORRO_PROD_INDIVIDUAL_COMPUTERS_BUDDHA) {
+ buddha_num_hwifs = BUDDHA_NUM_HWIFS;
+ type=BOARD_BUDDHA;
+ } else if (z->id == ZORRO_PROD_INDIVIDUAL_COMPUTERS_CATWEASEL) {
+ buddha_num_hwifs = CATWEASEL_NUM_HWIFS;
+ type=BOARD_CATWEASEL;
+ } else if (z->id == ZORRO_PROD_INDIVIDUAL_COMPUTERS_X_SURF) {
+ buddha_num_hwifs = XSURF_NUM_HWIFS;
+ type=BOARD_XSURF;
+ } else
+ continue;
+
+ board = z->resource.start;
+
+/*
+ * FIXME: we now have selectable mmio v/s iomio transports.
+ */
+
+ if(type != BOARD_XSURF) {
+ if (!request_mem_region(board+BUDDHA_BASE1, 0x800, "IDE"))
+ continue;
+ } else {
+ if (!request_mem_region(board+XSURF_BASE1, 0x1000, "IDE"))
+ continue;
+ if (!request_mem_region(board+XSURF_BASE2, 0x1000, "IDE"))
+ goto fail_base2;
+ if (!request_mem_region(board+XSURF_IRQ1, 0x8, "IDE")) {
+ release_mem_region(board+XSURF_BASE2, 0x1000);
+fail_base2:
+ release_mem_region(board+XSURF_BASE1, 0x1000);
+ continue;
+ }
+ }
+ buddha_board = ZTWO_VADDR(board);
+
+ /* write to BUDDHA_IRQ_MR to enable the board IRQ */
+ /* X-Surf doesn't have this. IRQs are always on */
+ if (type != BOARD_XSURF)
+ z_writeb(0, buddha_board+BUDDHA_IRQ_MR);
+
+ printk(KERN_INFO "ide: %s IDE controller\n",
+ buddha_board_name[type]);
+
+ for (i = 0; i < buddha_num_hwifs; i++) {
+ unsigned long base, ctl, irq_port;
+ ide_ack_intr_t *ack_intr;
+
+ if (type != BOARD_XSURF) {
+ base = buddha_board + buddha_bases[i];
+ ctl = base + BUDDHA_CONTROL;
+ irq_port = buddha_board + buddha_irqports[i];
+ ack_intr = buddha_ack_intr;
+ } else {
+ base = buddha_board + xsurf_bases[i];
+ /* X-Surf has no CS1* (Control/AltStat) */
+ ctl = 0;
+ irq_port = buddha_board + xsurf_irqports[i];
+ ack_intr = xsurf_ack_intr;
+ }
+
+ buddha_setup_ports(&hw[i], base, ctl, irq_port,
+ ack_intr);
+
+ hws[i] = &hw[i];
+ }
+
+ ide_host_add(NULL, hws, NULL);
+ }
+
+ return 0;
+}
+
+module_init(buddha_init);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/cmd640.c b/drivers/ide/cmd640.c
new file mode 100644
index 0000000..e430664
--- /dev/null
+++ b/drivers/ide/cmd640.c
@@ -0,0 +1,836 @@
+/*
+ * Copyright (C) 1995-1996 Linus Torvalds & authors (see below)
+ */
+
+/*
+ * Original authors: abramov@cecmow.enet.dec.com (Igor Abramov)
+ * mlord@pobox.com (Mark Lord)
+ *
+ * See linux/MAINTAINERS for address of current maintainer.
+ *
+ * This file provides support for the advanced features and bugs
+ * of IDE interfaces using the CMD Technologies 0640 IDE interface chip.
+ *
+ * These chips are basically fucked by design, and getting this driver
+ * to work on every motherboard design that uses this screwed chip seems
+ * bloody well impossible. However, we're still trying.
+ *
+ * Version 0.97 worked for everybody.
+ *
+ * User feedback is essential. Many thanks to the beta test team:
+ *
+ * A.Hartgers@stud.tue.nl, JZDQC@CUNYVM.CUNY.edu, abramov@cecmow.enet.dec.com,
+ * bardj@utopia.ppp.sn.no, bart@gaga.tue.nl, bbol001@cs.auckland.ac.nz,
+ * chrisc@dbass.demon.co.uk, dalecki@namu26.Num.Math.Uni-Goettingen.de,
+ * derekn@vw.ece.cmu.edu, florian@btp2x3.phy.uni-bayreuth.de,
+ * flynn@dei.unipd.it, gadio@netvision.net.il, godzilla@futuris.net,
+ * j@pobox.com, jkemp1@mises.uni-paderborn.de, jtoppe@hiwaay.net,
+ * kerouac@ssnet.com, meskes@informatik.rwth-aachen.de, hzoli@cs.elte.hu,
+ * peter@udgaard.isgtec.com, phil@tazenda.demon.co.uk, roadcapw@cfw.com,
+ * s0033las@sun10.vsz.bme.hu, schaffer@tam.cornell.edu, sjd@slip.net,
+ * steve@ei.org, ulrpeg@bigcomm.gun.de, ism@tardis.ed.ac.uk, mack@cray.com
+ * liug@mama.indstate.edu, and others.
+ *
+ * Version 0.01 Initial version, hacked out of ide.c,
+ * and #include'd rather than compiled separately.
+ * This will get cleaned up in a subsequent release.
+ *
+ * Version 0.02 Fixes for vlb initialization code, enable prefetch
+ * for versions 'B' and 'C' of chip by default,
+ * some code cleanup.
+ *
+ * Version 0.03 Added reset of secondary interface,
+ * and black list for devices which are not compatible
+ * with prefetch mode. Separate function for setting
+ * prefetch is added, possibly it will be called some
+ * day from ioctl processing code.
+ *
+ * Version 0.04 Now configs/compiles separate from ide.c
+ *
+ * Version 0.05 Major rewrite of interface timing code.
+ * Added new function cmd640_set_mode to set PIO mode
+ * from ioctl call. New drives added to black list.
+ *
+ * Version 0.06 More code cleanup. Prefetch is enabled only for
+ * detected hard drives, not included in prefetch
+ * black list.
+ *
+ * Version 0.07 Changed to more conservative drive tuning policy.
+ * Unknown drives, which report PIO < 4 are set to
+ * (reported_PIO - 1) if it is supported, or to PIO0.
+ * List of known drives extended by info provided by
+ * CMD at their ftp site.
+ *
+ * Version 0.08 Added autotune/noautotune support.
+ *
+ * Version 0.09 Try to be smarter about 2nd port enabling.
+ * Version 0.10 Be nice and don't reset 2nd port.
+ * Version 0.11 Try to handle more weird situations.
+ *
+ * Version 0.12 Lots of bug fixes from Laszlo Peter
+ * irq unmasking disabled for reliability.
+ * try to be even smarter about the second port.
+ * tidy up source code formatting.
+ * Version 0.13 permit irq unmasking again.
+ * Version 0.90 massive code cleanup, some bugs fixed.
+ * defaults all drives to PIO mode0, prefetch off.
+ * autotune is OFF by default, with compile time flag.
+ * prefetch can be turned OFF/ON using "hdparm -p8/-p9"
+ * (requires hdparm-3.1 or newer)
+ * Version 0.91 first release to linux-kernel list.
+ * Version 0.92 move initial reg dump to separate callable function
+ * change "readahead" to "prefetch" to avoid confusion
+ * Version 0.95 respect original BIOS timings unless autotuning.
+ * tons of code cleanup and rearrangement.
+ * added CONFIG_BLK_DEV_CMD640_ENHANCED option
+ * prevent use of unmask when prefetch is on
+ * Version 0.96 prevent use of io_32bit when prefetch is off
+ * Version 0.97 fix VLB secondary interface for sjd@slip.net
+ * other minor tune-ups: 0.96 was very good.
+ * Version 0.98 ignore PCI version when disabled by BIOS
+ * Version 0.99 display setup/active/recovery clocks with PIO mode
+ * Version 1.00 Mmm.. cannot depend on PCMD_ENA in all systems
+ * Version 1.01 slow/fast devsel can be selected with "hdparm -p6/-p7"
+ * ("fast" is necessary for 32bit I/O in some systems)
+ * Version 1.02 fix bug that resulted in slow "setup times"
+ * (patch courtesy of Zoltan Hidvegi)
+ */
+
+#define CMD640_PREFETCH_MASKS 1
+
+/*#define CMD640_DUMP_REGS */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#define DRV_NAME "cmd640"
+
+static int cmd640_vlb;
+
+/*
+ * CMD640 specific registers definition.
+ */
+
+#define VID 0x00
+#define DID 0x02
+#define PCMD 0x04
+#define PCMD_ENA 0x01
+#define PSTTS 0x06
+#define REVID 0x08
+#define PROGIF 0x09
+#define SUBCL 0x0a
+#define BASCL 0x0b
+#define BaseA0 0x10
+#define BaseA1 0x14
+#define BaseA2 0x18
+#define BaseA3 0x1c
+#define INTLINE 0x3c
+#define INPINE 0x3d
+
+#define CFR 0x50
+#define CFR_DEVREV 0x03
+#define CFR_IDE01INTR 0x04
+#define CFR_DEVID 0x18
+#define CFR_AT_VESA_078h 0x20
+#define CFR_DSA1 0x40
+#define CFR_DSA0 0x80
+
+#define CNTRL 0x51
+#define CNTRL_DIS_RA0 0x40
+#define CNTRL_DIS_RA1 0x80
+#define CNTRL_ENA_2ND 0x08
+
+#define CMDTIM 0x52
+#define ARTTIM0 0x53
+#define DRWTIM0 0x54
+#define ARTTIM1 0x55
+#define DRWTIM1 0x56
+#define ARTTIM23 0x57
+#define ARTTIM23_DIS_RA2 0x04
+#define ARTTIM23_DIS_RA3 0x08
+#define DRWTIM23 0x58
+#define BRST 0x59
+
+/*
+ * Registers and masks for easy access by drive index:
+ */
+static u8 prefetch_regs[4] = {CNTRL, CNTRL, ARTTIM23, ARTTIM23};
+static u8 prefetch_masks[4] = {CNTRL_DIS_RA0, CNTRL_DIS_RA1, ARTTIM23_DIS_RA2, ARTTIM23_DIS_RA3};
+
+#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
+
+static u8 arttim_regs[4] = {ARTTIM0, ARTTIM1, ARTTIM23, ARTTIM23};
+static u8 drwtim_regs[4] = {DRWTIM0, DRWTIM1, DRWTIM23, DRWTIM23};
+
+/*
+ * Current cmd640 timing values for each drive.
+ * The defaults for each are the slowest possible timings.
+ */
+static u8 setup_counts[4] = {4, 4, 4, 4}; /* Address setup count (in clocks) */
+static u8 active_counts[4] = {16, 16, 16, 16}; /* Active count (encoded) */
+static u8 recovery_counts[4] = {16, 16, 16, 16}; /* Recovery count (encoded) */
+
+#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
+
+static DEFINE_SPINLOCK(cmd640_lock);
+
+/*
+ * Interface to access cmd640x registers
+ */
+static unsigned int cmd640_key;
+static void (*__put_cmd640_reg)(u16 reg, u8 val);
+static u8 (*__get_cmd640_reg)(u16 reg);
+
+/*
+ * This is read from the CFR reg, and is used in several places.
+ */
+static unsigned int cmd640_chip_version;
+
+/*
+ * The CMD640x chip does not support DWORD config write cycles, but some
+ * of the BIOSes use them to implement the config services.
+ * Therefore, we must use direct IO instead.
+ */
+
+/* PCI method 1 access */
+
+static void put_cmd640_reg_pci1(u16 reg, u8 val)
+{
+ outl_p((reg & 0xfc) | cmd640_key, 0xcf8);
+ outb_p(val, (reg & 3) | 0xcfc);
+}
+
+static u8 get_cmd640_reg_pci1(u16 reg)
+{
+ outl_p((reg & 0xfc) | cmd640_key, 0xcf8);
+ return inb_p((reg & 3) | 0xcfc);
+}
+
+/* PCI method 2 access (from CMD datasheet) */
+
+static void put_cmd640_reg_pci2(u16 reg, u8 val)
+{
+ outb_p(0x10, 0xcf8);
+ outb_p(val, cmd640_key + reg);
+ outb_p(0, 0xcf8);
+}
+
+static u8 get_cmd640_reg_pci2(u16 reg)
+{
+ u8 b;
+
+ outb_p(0x10, 0xcf8);
+ b = inb_p(cmd640_key + reg);
+ outb_p(0, 0xcf8);
+ return b;
+}
+
+/* VLB access */
+
+static void put_cmd640_reg_vlb(u16 reg, u8 val)
+{
+ outb_p(reg, cmd640_key);
+ outb_p(val, cmd640_key + 4);
+}
+
+static u8 get_cmd640_reg_vlb(u16 reg)
+{
+ outb_p(reg, cmd640_key);
+ return inb_p(cmd640_key + 4);
+}
+
+static u8 get_cmd640_reg(u16 reg)
+{
+ unsigned long flags;
+ u8 b;
+
+ spin_lock_irqsave(&cmd640_lock, flags);
+ b = __get_cmd640_reg(reg);
+ spin_unlock_irqrestore(&cmd640_lock, flags);
+ return b;
+}
+
+static void put_cmd640_reg(u16 reg, u8 val)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&cmd640_lock, flags);
+ __put_cmd640_reg(reg, val);
+ spin_unlock_irqrestore(&cmd640_lock, flags);
+}
+
+static int __init match_pci_cmd640_device(void)
+{
+ const u8 ven_dev[4] = {0x95, 0x10, 0x40, 0x06};
+ unsigned int i;
+ for (i = 0; i < 4; i++) {
+ if (get_cmd640_reg(i) != ven_dev[i])
+ return 0;
+ }
+#ifdef STUPIDLY_TRUST_BROKEN_PCMD_ENA_BIT
+ if ((get_cmd640_reg(PCMD) & PCMD_ENA) == 0) {
+ printk("ide: cmd640 on PCI disabled by BIOS\n");
+ return 0;
+ }
+#endif /* STUPIDLY_TRUST_BROKEN_PCMD_ENA_BIT */
+ return 1; /* success */
+}
+
+/*
+ * Probe for CMD640x -- pci method 1
+ */
+static int __init probe_for_cmd640_pci1(void)
+{
+ __get_cmd640_reg = get_cmd640_reg_pci1;
+ __put_cmd640_reg = put_cmd640_reg_pci1;
+ for (cmd640_key = 0x80000000;
+ cmd640_key <= 0x8000f800;
+ cmd640_key += 0x800) {
+ if (match_pci_cmd640_device())
+ return 1; /* success */
+ }
+ return 0;
+}
+
+/*
+ * Probe for CMD640x -- pci method 2
+ */
+static int __init probe_for_cmd640_pci2(void)
+{
+ __get_cmd640_reg = get_cmd640_reg_pci2;
+ __put_cmd640_reg = put_cmd640_reg_pci2;
+ for (cmd640_key = 0xc000; cmd640_key <= 0xcf00; cmd640_key += 0x100) {
+ if (match_pci_cmd640_device())
+ return 1; /* success */
+ }
+ return 0;
+}
+
+/*
+ * Probe for CMD640x -- vlb
+ */
+static int __init probe_for_cmd640_vlb(void)
+{
+ u8 b;
+
+ __get_cmd640_reg = get_cmd640_reg_vlb;
+ __put_cmd640_reg = put_cmd640_reg_vlb;
+ cmd640_key = 0x178;
+ b = get_cmd640_reg(CFR);
+ if (b == 0xff || b == 0x00 || (b & CFR_AT_VESA_078h)) {
+ cmd640_key = 0x78;
+ b = get_cmd640_reg(CFR);
+ if (b == 0xff || b == 0x00 || !(b & CFR_AT_VESA_078h))
+ return 0;
+ }
+ return 1; /* success */
+}
+
+/*
+ * Returns 1 if an IDE interface/drive exists at 0x170,
+ * Returns 0 otherwise.
+ */
+static int __init secondary_port_responding(void)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&cmd640_lock, flags);
+
+ outb_p(0x0a, 0x176); /* select drive0 */
+ udelay(100);
+ if ((inb_p(0x176) & 0x1f) != 0x0a) {
+ outb_p(0x1a, 0x176); /* select drive1 */
+ udelay(100);
+ if ((inb_p(0x176) & 0x1f) != 0x1a) {
+ spin_unlock_irqrestore(&cmd640_lock, flags);
+ return 0; /* nothing responded */
+ }
+ }
+ spin_unlock_irqrestore(&cmd640_lock, flags);
+ return 1; /* success */
+}
+
+#ifdef CMD640_DUMP_REGS
+/*
+ * Dump out all cmd640 registers. May be called from ide.c
+ */
+static void cmd640_dump_regs(void)
+{
+ unsigned int reg = cmd640_vlb ? 0x50 : 0x00;
+
+ /* Dump current state of chip registers */
+ printk("ide: cmd640 internal register dump:");
+ for (; reg <= 0x59; reg++) {
+ if (!(reg & 0x0f))
+ printk("\n%04x:", reg);
+ printk(" %02x", get_cmd640_reg(reg));
+ }
+ printk("\n");
+}
+#endif
+
+static void __set_prefetch_mode(ide_drive_t *drive, int mode)
+{
+ if (mode) { /* want prefetch on? */
+#if CMD640_PREFETCH_MASKS
+ drive->dev_flags |= IDE_DFLAG_NO_UNMASK;
+ drive->dev_flags &= ~IDE_DFLAG_UNMASK;
+#endif
+ drive->dev_flags &= ~IDE_DFLAG_NO_IO_32BIT;
+ } else {
+ drive->dev_flags &= ~IDE_DFLAG_NO_UNMASK;
+ drive->dev_flags |= IDE_DFLAG_NO_IO_32BIT;
+ drive->io_32bit = 0;
+ }
+}
+
+#ifndef CONFIG_BLK_DEV_CMD640_ENHANCED
+/*
+ * Check whether prefetch is on for a drive,
+ * and initialize the unmask flags for safe operation.
+ */
+static void __init check_prefetch(ide_drive_t *drive, unsigned int index)
+{
+ u8 b = get_cmd640_reg(prefetch_regs[index]);
+
+ __set_prefetch_mode(drive, (b & prefetch_masks[index]) ? 0 : 1);
+}
+#else
+
+/*
+ * Sets prefetch mode for a drive.
+ */
+static void set_prefetch_mode(ide_drive_t *drive, unsigned int index, int mode)
+{
+ unsigned long flags;
+ int reg = prefetch_regs[index];
+ u8 b;
+
+ spin_lock_irqsave(&cmd640_lock, flags);
+ b = __get_cmd640_reg(reg);
+ __set_prefetch_mode(drive, mode);
+ if (mode)
+ b &= ~prefetch_masks[index]; /* enable prefetch */
+ else
+ b |= prefetch_masks[index]; /* disable prefetch */
+ __put_cmd640_reg(reg, b);
+ spin_unlock_irqrestore(&cmd640_lock, flags);
+}
+
+/*
+ * Dump out current drive clocks settings
+ */
+static void display_clocks(unsigned int index)
+{
+ u8 active_count, recovery_count;
+
+ active_count = active_counts[index];
+ if (active_count == 1)
+ ++active_count;
+ recovery_count = recovery_counts[index];
+ if (active_count > 3 && recovery_count == 1)
+ ++recovery_count;
+ if (cmd640_chip_version > 1)
+ recovery_count += 1; /* cmd640b uses (count + 1)*/
+ printk(", clocks=%d/%d/%d\n", setup_counts[index], active_count, recovery_count);
+}
+
+/*
+ * Pack active and recovery counts into single byte representation
+ * used by controller
+ */
+static inline u8 pack_nibbles(u8 upper, u8 lower)
+{
+ return ((upper & 0x0f) << 4) | (lower & 0x0f);
+}
+
+/*
+ * This routine writes the prepared setup/active/recovery counts
+ * for a drive into the cmd640 chipset registers to active them.
+ */
+static void program_drive_counts(ide_drive_t *drive, unsigned int index)
+{
+ unsigned long flags;
+ u8 setup_count = setup_counts[index];
+ u8 active_count = active_counts[index];
+ u8 recovery_count = recovery_counts[index];
+
+ /*
+ * Set up address setup count and drive read/write timing registers.
+ * Primary interface has individual count/timing registers for
+ * each drive. Secondary interface has one common set of registers,
+ * so we merge the timings, using the slowest value for each timing.
+ */
+ if (index > 1) {
+ ide_hwif_t *hwif = drive->hwif;
+ ide_drive_t *peer = &hwif->drives[!(drive->dn & 1)];
+ unsigned int mate = index ^ 1;
+
+ if (peer->dev_flags & IDE_DFLAG_PRESENT) {
+ if (setup_count < setup_counts[mate])
+ setup_count = setup_counts[mate];
+ if (active_count < active_counts[mate])
+ active_count = active_counts[mate];
+ if (recovery_count < recovery_counts[mate])
+ recovery_count = recovery_counts[mate];
+ }
+ }
+
+ /*
+ * Convert setup_count to internal chipset representation
+ */
+ switch (setup_count) {
+ case 4: setup_count = 0x00; break;
+ case 3: setup_count = 0x80; break;
+ case 1:
+ case 2: setup_count = 0x40; break;
+ default: setup_count = 0xc0; /* case 5 */
+ }
+
+ /*
+ * Now that everything is ready, program the new timings
+ */
+ spin_lock_irqsave(&cmd640_lock, flags);
+ /*
+ * Program the address_setup clocks into ARTTIM reg,
+ * and then the active/recovery counts into the DRWTIM reg
+ * (this converts counts of 16 into counts of zero -- okay).
+ */
+ setup_count |= __get_cmd640_reg(arttim_regs[index]) & 0x3f;
+ __put_cmd640_reg(arttim_regs[index], setup_count);
+ __put_cmd640_reg(drwtim_regs[index], pack_nibbles(active_count, recovery_count));
+ spin_unlock_irqrestore(&cmd640_lock, flags);
+}
+
+/*
+ * Set a specific pio_mode for a drive
+ */
+static void cmd640_set_mode(ide_drive_t *drive, unsigned int index,
+ u8 pio_mode, unsigned int cycle_time)
+{
+ struct ide_timing *t;
+ int setup_time, active_time, recovery_time, clock_time;
+ u8 setup_count, active_count, recovery_count, recovery_count2, cycle_count;
+ int bus_speed;
+
+ if (cmd640_vlb)
+ bus_speed = ide_vlb_clk ? ide_vlb_clk : 50;
+ else
+ bus_speed = ide_pci_clk ? ide_pci_clk : 33;
+
+ if (pio_mode > 5)
+ pio_mode = 5;
+
+ t = ide_timing_find_mode(XFER_PIO_0 + pio_mode);
+ setup_time = t->setup;
+ active_time = t->active;
+
+ recovery_time = cycle_time - (setup_time + active_time);
+ clock_time = 1000 / bus_speed;
+ cycle_count = DIV_ROUND_UP(cycle_time, clock_time);
+
+ setup_count = DIV_ROUND_UP(setup_time, clock_time);
+
+ active_count = DIV_ROUND_UP(active_time, clock_time);
+ if (active_count < 2)
+ active_count = 2; /* minimum allowed by cmd640 */
+
+ recovery_count = DIV_ROUND_UP(recovery_time, clock_time);
+ recovery_count2 = cycle_count - (setup_count + active_count);
+ if (recovery_count2 > recovery_count)
+ recovery_count = recovery_count2;
+ if (recovery_count < 2)
+ recovery_count = 2; /* minimum allowed by cmd640 */
+ if (recovery_count > 17) {
+ active_count += recovery_count - 17;
+ recovery_count = 17;
+ }
+ if (active_count > 16)
+ active_count = 16; /* maximum allowed by cmd640 */
+ if (cmd640_chip_version > 1)
+ recovery_count -= 1; /* cmd640b uses (count + 1)*/
+ if (recovery_count > 16)
+ recovery_count = 16; /* maximum allowed by cmd640 */
+
+ setup_counts[index] = setup_count;
+ active_counts[index] = active_count;
+ recovery_counts[index] = recovery_count;
+
+ /*
+ * In a perfect world, we might set the drive pio mode here
+ * (using WIN_SETFEATURE) before continuing.
+ *
+ * But we do not, because:
+ * 1) this is the wrong place to do it (proper is do_special() in ide.c)
+ * 2) in practice this is rarely, if ever, necessary
+ */
+ program_drive_counts(drive, index);
+}
+
+static void cmd640_set_pio_mode(ide_drive_t *drive, const u8 pio)
+{
+ unsigned int index = 0, cycle_time;
+ u8 b;
+
+ switch (pio) {
+ case 6: /* set fast-devsel off */
+ case 7: /* set fast-devsel on */
+ b = get_cmd640_reg(CNTRL) & ~0x27;
+ if (pio & 1)
+ b |= 0x27;
+ put_cmd640_reg(CNTRL, b);
+ printk("%s: %sabled cmd640 fast host timing (devsel)\n",
+ drive->name, (pio & 1) ? "en" : "dis");
+ return;
+ case 8: /* set prefetch off */
+ case 9: /* set prefetch on */
+ set_prefetch_mode(drive, index, pio & 1);
+ printk("%s: %sabled cmd640 prefetch\n",
+ drive->name, (pio & 1) ? "en" : "dis");
+ return;
+ }
+
+ cycle_time = ide_pio_cycle_time(drive, pio);
+ cmd640_set_mode(drive, index, pio, cycle_time);
+
+ printk("%s: selected cmd640 PIO mode%d (%dns)",
+ drive->name, pio, cycle_time);
+
+ display_clocks(index);
+}
+#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
+
+static void cmd640_init_dev(ide_drive_t *drive)
+{
+ unsigned int i = drive->hwif->channel * 2 + (drive->dn & 1);
+
+#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
+ /*
+ * Reset timing to the slowest speed and turn off prefetch.
+ * This way, the drive identify code has a better chance.
+ */
+ setup_counts[i] = 4; /* max possible */
+ active_counts[i] = 16; /* max possible */
+ recovery_counts[i] = 16; /* max possible */
+ program_drive_counts(drive, i);
+ set_prefetch_mode(drive, i, 0);
+ printk(KERN_INFO DRV_NAME ": drive%d timings/prefetch cleared\n", i);
+#else
+ /*
+ * Set the drive unmask flags to match the prefetch setting.
+ */
+ check_prefetch(drive, i);
+ printk(KERN_INFO DRV_NAME ": drive%d timings/prefetch(%s) preserved\n",
+ i, (drive->dev_flags & IDE_DFLAG_NO_IO_32BIT) ? "off" : "on");
+#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
+}
+
+
+static const struct ide_port_ops cmd640_port_ops = {
+ .init_dev = cmd640_init_dev,
+#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
+ .set_pio_mode = cmd640_set_pio_mode,
+#endif
+};
+
+static int pci_conf1(void)
+{
+ unsigned long flags;
+ u32 tmp;
+
+ spin_lock_irqsave(&cmd640_lock, flags);
+ outb(0x01, 0xCFB);
+ tmp = inl(0xCF8);
+ outl(0x80000000, 0xCF8);
+ if (inl(0xCF8) == 0x80000000) {
+ outl(tmp, 0xCF8);
+ spin_unlock_irqrestore(&cmd640_lock, flags);
+ return 1;
+ }
+ outl(tmp, 0xCF8);
+ spin_unlock_irqrestore(&cmd640_lock, flags);
+ return 0;
+}
+
+static int pci_conf2(void)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&cmd640_lock, flags);
+ outb(0x00, 0xCFB);
+ outb(0x00, 0xCF8);
+ outb(0x00, 0xCFA);
+ if (inb(0xCF8) == 0x00 && inb(0xCF8) == 0x00) {
+ spin_unlock_irqrestore(&cmd640_lock, flags);
+ return 1;
+ }
+ spin_unlock_irqrestore(&cmd640_lock, flags);
+ return 0;
+}
+
+static const struct ide_port_info cmd640_port_info __initdata = {
+ .chipset = ide_cmd640,
+ .host_flags = IDE_HFLAG_SERIALIZE |
+ IDE_HFLAG_NO_DMA |
+ IDE_HFLAG_ABUSE_PREFETCH |
+ IDE_HFLAG_ABUSE_FAST_DEVSEL,
+ .port_ops = &cmd640_port_ops,
+ .pio_mask = ATA_PIO5,
+};
+
+static int cmd640x_init_one(unsigned long base, unsigned long ctl)
+{
+ if (!request_region(base, 8, DRV_NAME)) {
+ printk(KERN_ERR "%s: I/O resource 0x%lX-0x%lX not free.\n",
+ DRV_NAME, base, base + 7);
+ return -EBUSY;
+ }
+
+ if (!request_region(ctl, 1, DRV_NAME)) {
+ printk(KERN_ERR "%s: I/O resource 0x%lX not free.\n",
+ DRV_NAME, ctl);
+ release_region(base, 8);
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+/*
+ * Probe for a cmd640 chipset, and initialize it if found.
+ */
+static int __init cmd640x_init(void)
+{
+ int second_port_cmd640 = 0, rc;
+ const char *bus_type, *port2;
+ u8 b, cfr;
+ hw_regs_t hw[2], *hws[] = { NULL, NULL, NULL, NULL };
+
+ if (cmd640_vlb && probe_for_cmd640_vlb()) {
+ bus_type = "VLB";
+ } else {
+ cmd640_vlb = 0;
+ /* Find out what kind of PCI probing is supported otherwise
+ Justin Gibbs will sulk.. */
+ if (pci_conf1() && probe_for_cmd640_pci1())
+ bus_type = "PCI (type1)";
+ else if (pci_conf2() && probe_for_cmd640_pci2())
+ bus_type = "PCI (type2)";
+ else
+ return 0;
+ }
+ /*
+ * Undocumented magic (there is no 0x5b reg in specs)
+ */
+ put_cmd640_reg(0x5b, 0xbd);
+ if (get_cmd640_reg(0x5b) != 0xbd) {
+ printk(KERN_ERR "ide: cmd640 init failed: wrong value in reg 0x5b\n");
+ return 0;
+ }
+ put_cmd640_reg(0x5b, 0);
+
+#ifdef CMD640_DUMP_REGS
+ cmd640_dump_regs();
+#endif
+
+ /*
+ * Documented magic begins here
+ */
+ cfr = get_cmd640_reg(CFR);
+ cmd640_chip_version = cfr & CFR_DEVREV;
+ if (cmd640_chip_version == 0) {
+ printk("ide: bad cmd640 revision: %d\n", cmd640_chip_version);
+ return 0;
+ }
+
+ rc = cmd640x_init_one(0x1f0, 0x3f6);
+ if (rc)
+ return rc;
+
+ rc = cmd640x_init_one(0x170, 0x376);
+ if (rc) {
+ release_region(0x3f6, 1);
+ release_region(0x1f0, 8);
+ return rc;
+ }
+
+ memset(&hw, 0, sizeof(hw));
+
+ ide_std_init_ports(&hw[0], 0x1f0, 0x3f6);
+ hw[0].irq = 14;
+ hw[0].chipset = ide_cmd640;
+
+ ide_std_init_ports(&hw[1], 0x170, 0x376);
+ hw[1].irq = 15;
+ hw[1].chipset = ide_cmd640;
+
+ printk(KERN_INFO "cmd640: buggy cmd640%c interface on %s, config=0x%02x"
+ "\n", 'a' + cmd640_chip_version - 1, bus_type, cfr);
+
+ /*
+ * Initialize data for primary port
+ */
+ hws[0] = &hw[0];
+
+ /*
+ * Ensure compatibility by always using the slowest timings
+ * for access to the drive's command register block,
+ * and reset the prefetch burstsize to default (512 bytes).
+ *
+ * Maybe we need a way to NOT do these on *some* systems?
+ */
+ put_cmd640_reg(CMDTIM, 0);
+ put_cmd640_reg(BRST, 0x40);
+
+ b = get_cmd640_reg(CNTRL);
+
+ /*
+ * Try to enable the secondary interface, if not already enabled
+ */
+ if (secondary_port_responding()) {
+ if ((b & CNTRL_ENA_2ND)) {
+ second_port_cmd640 = 1;
+ port2 = "okay";
+ } else if (cmd640_vlb) {
+ second_port_cmd640 = 1;
+ port2 = "alive";
+ } else
+ port2 = "not cmd640";
+ } else {
+ put_cmd640_reg(CNTRL, b ^ CNTRL_ENA_2ND); /* toggle the bit */
+ if (secondary_port_responding()) {
+ second_port_cmd640 = 1;
+ port2 = "enabled";
+ } else {
+ put_cmd640_reg(CNTRL, b); /* restore original setting */
+ port2 = "not responding";
+ }
+ }
+
+ /*
+ * Initialize data for secondary cmd640 port, if enabled
+ */
+ if (second_port_cmd640)
+ hws[1] = &hw[1];
+
+ printk(KERN_INFO "cmd640: %sserialized, secondary interface %s\n",
+ second_port_cmd640 ? "" : "not ", port2);
+
+#ifdef CMD640_DUMP_REGS
+ cmd640_dump_regs();
+#endif
+
+ return ide_host_add(&cmd640_port_info, hws, NULL);
+}
+
+module_param_named(probe_vlb, cmd640_vlb, bool, 0);
+MODULE_PARM_DESC(probe_vlb, "probe for VLB version of CMD640 chipset");
+
+module_init(cmd640x_init);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/cmd64x.c b/drivers/ide/cmd64x.c
new file mode 100644
index 0000000..935385c
--- /dev/null
+++ b/drivers/ide/cmd64x.c
@@ -0,0 +1,532 @@
+/*
+ * cmd64x.c: Enable interrupts at initialization time on Ultra/PCI machines.
+ * 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>
+ * Copyright (C) 2007 MontaVista Software, Inc. <source@mvista.com>
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#define DRV_NAME "cmd64x"
+
+#define CMD_DEBUG 0
+
+#if CMD_DEBUG
+#define cmdprintk(x...) printk(x)
+#else
+#define cmdprintk(x...)
+#endif
+
+/*
+ * CMD64x specific registers definition.
+ */
+#define CFR 0x50
+#define CFR_INTR_CH0 0x04
+
+#define CMDTIM 0x52
+#define ARTTIM0 0x53
+#define DRWTIM0 0x54
+#define ARTTIM1 0x55
+#define DRWTIM1 0x56
+#define ARTTIM23 0x57
+#define ARTTIM23_DIS_RA2 0x04
+#define ARTTIM23_DIS_RA3 0x08
+#define ARTTIM23_INTR_CH1 0x10
+#define DRWTIM2 0x58
+#define BRST 0x59
+#define DRWTIM3 0x5b
+
+#define BMIDECR0 0x70
+#define MRDMODE 0x71
+#define MRDMODE_INTR_CH0 0x04
+#define MRDMODE_INTR_CH1 0x08
+#define UDIDETCR0 0x73
+#define DTPR0 0x74
+#define BMIDECR1 0x78
+#define BMIDECSR 0x79
+#define UDIDETCR1 0x7B
+#define DTPR1 0x7C
+
+static u8 quantize_timing(int timing, int quant)
+{
+ return (timing + quant - 1) / quant;
+}
+
+/*
+ * This routine calculates active/recovery counts and then writes them into
+ * the chipset registers.
+ */
+static void program_cycle_times (ide_drive_t *drive, int cycle_time, int active_time)
+{
+ struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
+ int clock_time = 1000 / (ide_pci_clk ? ide_pci_clk : 33);
+ u8 cycle_count, active_count, recovery_count, drwtim;
+ static const u8 recovery_values[] =
+ {15, 15, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 0};
+ static const u8 drwtim_regs[4] = {DRWTIM0, DRWTIM1, DRWTIM2, DRWTIM3};
+
+ cmdprintk("program_cycle_times parameters: total=%d, active=%d\n",
+ cycle_time, active_time);
+
+ cycle_count = quantize_timing( cycle_time, clock_time);
+ active_count = quantize_timing(active_time, clock_time);
+ recovery_count = cycle_count - active_count;
+
+ /*
+ * In case we've got too long recovery phase, try to lengthen
+ * the active phase
+ */
+ if (recovery_count > 16) {
+ active_count += recovery_count - 16;
+ recovery_count = 16;
+ }
+ if (active_count > 16) /* shouldn't actually happen... */
+ active_count = 16;
+
+ cmdprintk("Final counts: total=%d, active=%d, recovery=%d\n",
+ cycle_count, active_count, recovery_count);
+
+ /*
+ * Convert values to internal chipset representation
+ */
+ recovery_count = recovery_values[recovery_count];
+ active_count &= 0x0f;
+
+ /* Program the active/recovery counts into the DRWTIM register */
+ drwtim = (active_count << 4) | recovery_count;
+ (void) pci_write_config_byte(dev, drwtim_regs[drive->dn], drwtim);
+ cmdprintk("Write 0x%02x to reg 0x%x\n", drwtim, drwtim_regs[drive->dn]);
+}
+
+/*
+ * This routine writes into the chipset registers
+ * PIO setup/active/recovery timings.
+ */
+static void cmd64x_tune_pio(ide_drive_t *drive, const u8 pio)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+ struct ide_timing *t = ide_timing_find_mode(XFER_PIO_0 + pio);
+ unsigned int cycle_time;
+ u8 setup_count, arttim = 0;
+
+ static const u8 setup_values[] = {0x40, 0x40, 0x40, 0x80, 0, 0xc0};
+ static const u8 arttim_regs[4] = {ARTTIM0, ARTTIM1, ARTTIM23, ARTTIM23};
+
+ cycle_time = ide_pio_cycle_time(drive, pio);
+
+ program_cycle_times(drive, cycle_time, t->active);
+
+ setup_count = quantize_timing(t->setup,
+ 1000 / (ide_pci_clk ? ide_pci_clk : 33));
+
+ /*
+ * The primary channel has individual address setup timing registers
+ * for each drive and the hardware selects the slowest timing itself.
+ * The secondary channel has one common register and we have to select
+ * the slowest address setup timing ourselves.
+ */
+ if (hwif->channel) {
+ ide_drive_t *drives = hwif->drives;
+
+ drive->drive_data = setup_count;
+ setup_count = max(drives[0].drive_data, drives[1].drive_data);
+ }
+
+ if (setup_count > 5) /* shouldn't actually happen... */
+ setup_count = 5;
+ cmdprintk("Final address setup count: %d\n", setup_count);
+
+ /*
+ * Program the address setup clocks into the ARTTIM registers.
+ * Avoid clearing the secondary channel's interrupt bit.
+ */
+ (void) pci_read_config_byte (dev, arttim_regs[drive->dn], &arttim);
+ if (hwif->channel)
+ arttim &= ~ARTTIM23_INTR_CH1;
+ arttim &= ~0xc0;
+ arttim |= setup_values[setup_count];
+ (void) pci_write_config_byte(dev, arttim_regs[drive->dn], arttim);
+ cmdprintk("Write 0x%02x to reg 0x%x\n", arttim, arttim_regs[drive->dn]);
+}
+
+/*
+ * Attempts to set drive's PIO mode.
+ * Special cases are 8: prefetch off, 9: prefetch on (both never worked)
+ */
+
+static void cmd64x_set_pio_mode(ide_drive_t *drive, const u8 pio)
+{
+ /*
+ * Filter out the prefetch control values
+ * to prevent PIO5 from being programmed
+ */
+ if (pio == 8 || pio == 9)
+ return;
+
+ cmd64x_tune_pio(drive, pio);
+}
+
+static void cmd64x_set_dma_mode(ide_drive_t *drive, const u8 speed)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+ u8 unit = drive->dn & 0x01;
+ u8 regU = 0, pciU = hwif->channel ? UDIDETCR1 : UDIDETCR0;
+
+ if (speed >= XFER_SW_DMA_0) {
+ (void) pci_read_config_byte(dev, pciU, &regU);
+ regU &= ~(unit ? 0xCA : 0x35);
+ }
+
+ switch(speed) {
+ case XFER_UDMA_5:
+ regU |= unit ? 0x0A : 0x05;
+ break;
+ case XFER_UDMA_4:
+ regU |= unit ? 0x4A : 0x15;
+ break;
+ case XFER_UDMA_3:
+ regU |= unit ? 0x8A : 0x25;
+ break;
+ case XFER_UDMA_2:
+ regU |= unit ? 0x42 : 0x11;
+ break;
+ case XFER_UDMA_1:
+ regU |= unit ? 0x82 : 0x21;
+ break;
+ case XFER_UDMA_0:
+ regU |= unit ? 0xC2 : 0x31;
+ break;
+ case XFER_MW_DMA_2:
+ program_cycle_times(drive, 120, 70);
+ break;
+ case XFER_MW_DMA_1:
+ program_cycle_times(drive, 150, 80);
+ break;
+ case XFER_MW_DMA_0:
+ program_cycle_times(drive, 480, 215);
+ break;
+ }
+
+ if (speed >= XFER_SW_DMA_0)
+ (void) pci_write_config_byte(dev, pciU, regU);
+}
+
+static int cmd648_dma_end(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ unsigned long base = hwif->dma_base - (hwif->channel * 8);
+ int err = ide_dma_end(drive);
+ u8 irq_mask = hwif->channel ? MRDMODE_INTR_CH1 :
+ MRDMODE_INTR_CH0;
+ u8 mrdmode = inb(base + 1);
+
+ /* clear the interrupt bit */
+ outb((mrdmode & ~(MRDMODE_INTR_CH0 | MRDMODE_INTR_CH1)) | irq_mask,
+ base + 1);
+
+ return err;
+}
+
+static int cmd64x_dma_end(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+ int irq_reg = hwif->channel ? ARTTIM23 : CFR;
+ u8 irq_mask = hwif->channel ? ARTTIM23_INTR_CH1 :
+ CFR_INTR_CH0;
+ u8 irq_stat = 0;
+ int err = ide_dma_end(drive);
+
+ (void) pci_read_config_byte(dev, irq_reg, &irq_stat);
+ /* clear the interrupt bit */
+ (void) pci_write_config_byte(dev, irq_reg, irq_stat | irq_mask);
+
+ return err;
+}
+
+static int cmd648_dma_test_irq(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ unsigned long base = hwif->dma_base - (hwif->channel * 8);
+ u8 irq_mask = hwif->channel ? MRDMODE_INTR_CH1 :
+ MRDMODE_INTR_CH0;
+ u8 dma_stat = inb(hwif->dma_base + ATA_DMA_STATUS);
+ u8 mrdmode = inb(base + 1);
+
+#ifdef DEBUG
+ printk("%s: dma_stat: 0x%02x mrdmode: 0x%02x irq_mask: 0x%02x\n",
+ drive->name, dma_stat, mrdmode, irq_mask);
+#endif
+ if (!(mrdmode & irq_mask))
+ return 0;
+
+ /* return 1 if INTR asserted */
+ if (dma_stat & 4)
+ return 1;
+
+ return 0;
+}
+
+static int cmd64x_dma_test_irq(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+ int irq_reg = hwif->channel ? ARTTIM23 : CFR;
+ u8 irq_mask = hwif->channel ? ARTTIM23_INTR_CH1 :
+ CFR_INTR_CH0;
+ u8 dma_stat = inb(hwif->dma_base + ATA_DMA_STATUS);
+ u8 irq_stat = 0;
+
+ (void) pci_read_config_byte(dev, irq_reg, &irq_stat);
+
+#ifdef DEBUG
+ printk("%s: dma_stat: 0x%02x irq_stat: 0x%02x irq_mask: 0x%02x\n",
+ drive->name, dma_stat, irq_stat, irq_mask);
+#endif
+ if (!(irq_stat & irq_mask))
+ return 0;
+
+ /* return 1 if INTR asserted */
+ if (dma_stat & 4)
+ return 1;
+
+ return 0;
+}
+
+/*
+ * ASUS P55T2P4D with CMD646 chipset revision 0x01 requires the old
+ * event order for DMA transfers.
+ */
+
+static int cmd646_1_dma_end(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ u8 dma_stat = 0, dma_cmd = 0;
+
+ drive->waiting_for_dma = 0;
+ /* get DMA status */
+ dma_stat = inb(hwif->dma_base + ATA_DMA_STATUS);
+ /* read DMA command state */
+ dma_cmd = inb(hwif->dma_base + ATA_DMA_CMD);
+ /* stop DMA */
+ outb(dma_cmd & ~1, hwif->dma_base + ATA_DMA_CMD);
+ /* clear the INTR & ERROR bits */
+ outb(dma_stat | 6, hwif->dma_base + ATA_DMA_STATUS);
+ /* and free any DMA resources */
+ ide_destroy_dmatable(drive);
+ /* verify good DMA status */
+ return (dma_stat & 7) != 4;
+}
+
+static unsigned int init_chipset_cmd64x(struct pci_dev *dev)
+{
+ u8 mrdmode = 0;
+
+ /* Set a good latency timer and cache line size value. */
+ (void) pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64);
+ /* FIXME: pci_set_master() to ensure a good latency timer value */
+
+ /*
+ * Enable interrupts, select MEMORY READ LINE for reads.
+ *
+ * NOTE: although not mentioned in the PCI0646U specs,
+ * bits 0-1 are write only and won't be read back as
+ * set or not -- PCI0646U2 specs clarify this point.
+ */
+ (void) pci_read_config_byte (dev, MRDMODE, &mrdmode);
+ mrdmode &= ~0x30;
+ (void) pci_write_config_byte(dev, MRDMODE, (mrdmode | 0x02));
+
+ return 0;
+}
+
+static u8 cmd64x_cable_detect(ide_hwif_t *hwif)
+{
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+ u8 bmidecsr = 0, mask = hwif->channel ? 0x02 : 0x01;
+
+ switch (dev->device) {
+ case PCI_DEVICE_ID_CMD_648:
+ case PCI_DEVICE_ID_CMD_649:
+ pci_read_config_byte(dev, BMIDECSR, &bmidecsr);
+ return (bmidecsr & mask) ? ATA_CBL_PATA80 : ATA_CBL_PATA40;
+ default:
+ return ATA_CBL_PATA40;
+ }
+}
+
+static const struct ide_port_ops cmd64x_port_ops = {
+ .set_pio_mode = cmd64x_set_pio_mode,
+ .set_dma_mode = cmd64x_set_dma_mode,
+ .cable_detect = cmd64x_cable_detect,
+};
+
+static const struct ide_dma_ops cmd64x_dma_ops = {
+ .dma_host_set = ide_dma_host_set,
+ .dma_setup = ide_dma_setup,
+ .dma_exec_cmd = ide_dma_exec_cmd,
+ .dma_start = ide_dma_start,
+ .dma_end = cmd64x_dma_end,
+ .dma_test_irq = cmd64x_dma_test_irq,
+ .dma_lost_irq = ide_dma_lost_irq,
+ .dma_timeout = ide_dma_timeout,
+};
+
+static const struct ide_dma_ops cmd646_rev1_dma_ops = {
+ .dma_host_set = ide_dma_host_set,
+ .dma_setup = ide_dma_setup,
+ .dma_exec_cmd = ide_dma_exec_cmd,
+ .dma_start = ide_dma_start,
+ .dma_end = cmd646_1_dma_end,
+ .dma_test_irq = ide_dma_test_irq,
+ .dma_lost_irq = ide_dma_lost_irq,
+ .dma_timeout = ide_dma_timeout,
+};
+
+static const struct ide_dma_ops cmd648_dma_ops = {
+ .dma_host_set = ide_dma_host_set,
+ .dma_setup = ide_dma_setup,
+ .dma_exec_cmd = ide_dma_exec_cmd,
+ .dma_start = ide_dma_start,
+ .dma_end = cmd648_dma_end,
+ .dma_test_irq = cmd648_dma_test_irq,
+ .dma_lost_irq = ide_dma_lost_irq,
+ .dma_timeout = ide_dma_timeout,
+};
+
+static const struct ide_port_info cmd64x_chipsets[] __devinitdata = {
+ { /* 0: CMD643 */
+ .name = DRV_NAME,
+ .init_chipset = init_chipset_cmd64x,
+ .enablebits = {{0x00,0x00,0x00}, {0x51,0x08,0x08}},
+ .port_ops = &cmd64x_port_ops,
+ .dma_ops = &cmd64x_dma_ops,
+ .host_flags = IDE_HFLAG_CLEAR_SIMPLEX |
+ IDE_HFLAG_ABUSE_PREFETCH,
+ .pio_mask = ATA_PIO5,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = 0x00, /* no udma */
+ },
+ { /* 1: CMD646 */
+ .name = DRV_NAME,
+ .init_chipset = init_chipset_cmd64x,
+ .enablebits = {{0x51,0x04,0x04}, {0x51,0x08,0x08}},
+ .chipset = ide_cmd646,
+ .port_ops = &cmd64x_port_ops,
+ .dma_ops = &cmd648_dma_ops,
+ .host_flags = IDE_HFLAG_ABUSE_PREFETCH,
+ .pio_mask = ATA_PIO5,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA2,
+ },
+ { /* 2: CMD648 */
+ .name = DRV_NAME,
+ .init_chipset = init_chipset_cmd64x,
+ .enablebits = {{0x51,0x04,0x04}, {0x51,0x08,0x08}},
+ .port_ops = &cmd64x_port_ops,
+ .dma_ops = &cmd648_dma_ops,
+ .host_flags = IDE_HFLAG_ABUSE_PREFETCH,
+ .pio_mask = ATA_PIO5,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA4,
+ },
+ { /* 3: CMD649 */
+ .name = DRV_NAME,
+ .init_chipset = init_chipset_cmd64x,
+ .enablebits = {{0x51,0x04,0x04}, {0x51,0x08,0x08}},
+ .port_ops = &cmd64x_port_ops,
+ .dma_ops = &cmd648_dma_ops,
+ .host_flags = IDE_HFLAG_ABUSE_PREFETCH,
+ .pio_mask = ATA_PIO5,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA5,
+ }
+};
+
+static int __devinit cmd64x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ struct ide_port_info d;
+ u8 idx = id->driver_data;
+
+ d = cmd64x_chipsets[idx];
+
+ if (idx == 1) {
+ /*
+ * UltraDMA only supported on PCI646U and PCI646U2, which
+ * correspond to revisions 0x03, 0x05 and 0x07 respectively.
+ * Actually, although the CMD tech support people won't
+ * tell me the details, the 0x03 revision cannot support
+ * UDMA correctly without hardware modifications, and even
+ * then it only works with Quantum disks due to some
+ * hold time assumptions in the 646U part which are fixed
+ * in the 646U2.
+ *
+ * So we only do UltraDMA on revision 0x05 and 0x07 chipsets.
+ */
+ if (dev->revision < 5) {
+ d.udma_mask = 0x00;
+ /*
+ * The original PCI0646 didn't have the primary
+ * channel enable bit, it appeared starting with
+ * PCI0646U (i.e. revision ID 3).
+ */
+ if (dev->revision < 3) {
+ d.enablebits[0].reg = 0;
+ if (dev->revision == 1)
+ d.dma_ops = &cmd646_rev1_dma_ops;
+ else
+ d.dma_ops = &cmd64x_dma_ops;
+ }
+ }
+ }
+
+ return ide_pci_init_one(dev, &d, NULL);
+}
+
+static const struct pci_device_id cmd64x_pci_tbl[] = {
+ { 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), 2 },
+ { PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_649), 3 },
+ { 0, },
+};
+MODULE_DEVICE_TABLE(pci, cmd64x_pci_tbl);
+
+static struct pci_driver cmd64x_pci_driver = {
+ .name = "CMD64x_IDE",
+ .id_table = cmd64x_pci_tbl,
+ .probe = cmd64x_init_one,
+ .remove = ide_pci_remove,
+ .suspend = ide_pci_suspend,
+ .resume = ide_pci_resume,
+};
+
+static int __init cmd64x_ide_init(void)
+{
+ return ide_pci_register_driver(&cmd64x_pci_driver);
+}
+
+static void __exit cmd64x_ide_exit(void)
+{
+ pci_unregister_driver(&cmd64x_pci_driver);
+}
+
+module_init(cmd64x_ide_init);
+module_exit(cmd64x_ide_exit);
+
+MODULE_AUTHOR("Eddie Dost, David Miller, Andre Hedrick");
+MODULE_DESCRIPTION("PCI driver module for CMD64x IDE");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/cs5520.c b/drivers/ide/cs5520.c
new file mode 100644
index 0000000..5efb467
--- /dev/null
+++ b/drivers/ide/cs5520.c
@@ -0,0 +1,165 @@
+/*
+ * 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.
+ *
+ * *** 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.
+ *
+ * For the avoidance of doubt the "preferred form" of this code is one which
+ * is in an open non patent encumbered format. Where cryptographic key signing
+ * forms part of the process of creating an executable the information
+ * including keys needed to generate an equivalently functional executable
+ * are deemed to be part of the source code.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+#include <linux/dma-mapping.h>
+
+#define DRV_NAME "cs5520"
+
+struct pio_clocks
+{
+ int address;
+ int assert;
+ int recovery;
+};
+
+static struct pio_clocks cs5520_pio_clocks[]={
+ {3, 6, 11},
+ {2, 5, 6},
+ {1, 4, 3},
+ {1, 3, 2},
+ {1, 2, 1}
+};
+
+static void cs5520_set_pio_mode(ide_drive_t *drive, const u8 pio)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *pdev = to_pci_dev(hwif->dev);
+ int controller = drive->dn > 1 ? 1 : 0;
+
+ /* 8bit CAT/CRT - 8bit command timing for channel */
+ pci_write_config_byte(pdev, 0x62 + controller,
+ (cs5520_pio_clocks[pio].recovery << 4) |
+ (cs5520_pio_clocks[pio].assert));
+
+ /* 0x64 - 16bit Primary, 0x68 - 16bit Secondary */
+
+ /* FIXME: should these use address ? */
+ /* Data read timing */
+ pci_write_config_byte(pdev, 0x64 + 4*controller + (drive->dn&1),
+ (cs5520_pio_clocks[pio].recovery << 4) |
+ (cs5520_pio_clocks[pio].assert));
+ /* Write command timing */
+ pci_write_config_byte(pdev, 0x66 + 4*controller + (drive->dn&1),
+ (cs5520_pio_clocks[pio].recovery << 4) |
+ (cs5520_pio_clocks[pio].assert));
+}
+
+static void cs5520_set_dma_mode(ide_drive_t *drive, const u8 speed)
+{
+ printk(KERN_ERR "cs55x0: bad ide timing.\n");
+
+ cs5520_set_pio_mode(drive, 0);
+}
+
+static const struct ide_port_ops cs5520_port_ops = {
+ .set_pio_mode = cs5520_set_pio_mode,
+ .set_dma_mode = cs5520_set_dma_mode,
+};
+
+static const struct ide_port_info cyrix_chipset __devinitdata = {
+ .name = DRV_NAME,
+ .enablebits = { { 0x60, 0x01, 0x01 }, { 0x60, 0x02, 0x02 } },
+ .port_ops = &cs5520_port_ops,
+ .host_flags = IDE_HFLAG_ISA_PORTS | IDE_HFLAG_CS5520,
+ .pio_mask = ATA_PIO4,
+};
+
+/*
+ * The 5510/5520 are a bit weird. They don't quite set up the way
+ * the PCI helper layer expects so we must do much of the set up
+ * work longhand.
+ */
+
+static int __devinit cs5520_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ const struct ide_port_info *d = &cyrix_chipset;
+ hw_regs_t hw[4], *hws[] = { NULL, NULL, NULL, NULL };
+
+ ide_setup_pci_noise(dev, d);
+
+ /* We must not grab the entire device, it has 'ISA' space in its
+ * BARS too and we will freak out other bits of the kernel
+ */
+ if (pci_enable_device_io(dev)) {
+ printk(KERN_WARNING "%s: Unable to enable 55x0.\n", d->name);
+ return -ENODEV;
+ }
+ pci_set_master(dev);
+ if (pci_set_dma_mask(dev, DMA_32BIT_MASK)) {
+ printk(KERN_WARNING "%s: No suitable DMA available.\n",
+ d->name);
+ return -ENODEV;
+ }
+
+ /*
+ * Now the chipset is configured we can let the core
+ * do all the device setup for us
+ */
+
+ ide_pci_setup_ports(dev, d, 14, &hw[0], &hws[0]);
+
+ return ide_host_add(d, hws, NULL);
+}
+
+static const struct pci_device_id cs5520_pci_tbl[] = {
+ { PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5510), 0 },
+ { PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5520), 1 },
+ { 0, },
+};
+MODULE_DEVICE_TABLE(pci, cs5520_pci_tbl);
+
+static struct pci_driver cs5520_pci_driver = {
+ .name = "Cyrix_IDE",
+ .id_table = cs5520_pci_tbl,
+ .probe = cs5520_init_one,
+ .suspend = ide_pci_suspend,
+ .resume = ide_pci_resume,
+};
+
+static int __init cs5520_ide_init(void)
+{
+ return ide_pci_register_driver(&cs5520_pci_driver);
+}
+
+module_init(cs5520_ide_init);
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("PCI driver module for Cyrix 5510/5520 IDE");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/cs5530.c b/drivers/ide/cs5530.c
new file mode 100644
index 0000000..d8ede85
--- /dev/null
+++ b/drivers/ide/cs5530.c
@@ -0,0 +1,295 @@
+/*
+ * Copyright (C) 2000 Andre Hedrick <andre@linux-ide.org>
+ * Copyright (C) 2000 Mark Lord <mlord@pobox.com>
+ * Copyright (C) 2007 Bartlomiej Zolnierkiewicz
+ *
+ * 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.
+ *
+ * Documentation:
+ * CS5530 documentation available from National Semiconductor.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+
+#define DRV_NAME "cs5530"
+
+/*
+ * Here are the standard PIO mode 0-4 timings for each "format".
+ * Format-0 uses fast data reg timings, with slower command reg timings.
+ * Format-1 uses fast timings for all registers, but won't work with all drives.
+ */
+static unsigned int cs5530_pio_timings[2][5] = {
+ {0x00009172, 0x00012171, 0x00020080, 0x00032010, 0x00040010},
+ {0xd1329172, 0x71212171, 0x30200080, 0x20102010, 0x00100010}
+};
+
+/*
+ * After chip reset, the PIO timings are set to 0x0000e132, which is not valid.
+ */
+#define CS5530_BAD_PIO(timings) (((timings)&~0x80000000)==0x0000e132)
+#define CS5530_BASEREG(hwif) (((hwif)->dma_base & ~0xf) + ((hwif)->channel ? 0x30 : 0x20))
+
+/**
+ * cs5530_set_pio_mode - set host controller for PIO mode
+ * @drive: drive
+ * @pio: PIO mode number
+ *
+ * Handles setting of PIO mode for the chipset.
+ *
+ * The init_hwif_cs5530() routine guarantees that all drives
+ * will have valid default PIO timings set up before we get here.
+ */
+
+static void cs5530_set_pio_mode(ide_drive_t *drive, const u8 pio)
+{
+ unsigned long basereg = CS5530_BASEREG(drive->hwif);
+ unsigned int format = (inl(basereg + 4) >> 31) & 1;
+
+ outl(cs5530_pio_timings[format][pio], basereg + ((drive->dn & 1)<<3));
+}
+
+/**
+ * cs5530_udma_filter - UDMA filter
+ * @drive: drive
+ *
+ * cs5530_udma_filter() does UDMA mask filtering for the given drive
+ * taking into the consideration capabilities of the mate device.
+ *
+ * The CS5530 specifies that two drives sharing a cable cannot mix
+ * UDMA/MDMA. It has to be one or the other, for the pair, though
+ * different timings can still be chosen for each drive. We could
+ * set the appropriate timing bits on the fly, but that might be
+ * a bit confusing. So, for now we statically handle this requirement
+ * by looking at our mate drive to see what it is capable of, before
+ * choosing a mode for our own drive.
+ *
+ * Note: This relies on the fact we never fail from UDMA to MWDMA2
+ * but instead drop to PIO.
+ */
+
+static u8 cs5530_udma_filter(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ ide_drive_t *mate = ide_get_pair_dev(drive);
+ u16 *mateid;
+ u8 mask = hwif->ultra_mask;
+
+ if (mate == NULL)
+ goto out;
+ mateid = mate->id;
+
+ if (ata_id_has_dma(mateid) && __ide_dma_bad_drive(mate) == 0) {
+ if ((mateid[ATA_ID_FIELD_VALID] & 4) &&
+ (mateid[ATA_ID_UDMA_MODES] & 7))
+ goto out;
+ if ((mateid[ATA_ID_FIELD_VALID] & 2) &&
+ (mateid[ATA_ID_MWDMA_MODES] & 7))
+ mask = 0;
+ }
+out:
+ return mask;
+}
+
+static void cs5530_set_dma_mode(ide_drive_t *drive, const u8 mode)
+{
+ unsigned long basereg;
+ unsigned int reg, timings = 0;
+
+ switch (mode) {
+ case XFER_UDMA_0: timings = 0x00921250; break;
+ case XFER_UDMA_1: timings = 0x00911140; break;
+ case XFER_UDMA_2: timings = 0x00911030; break;
+ case XFER_MW_DMA_0: timings = 0x00077771; break;
+ case XFER_MW_DMA_1: timings = 0x00012121; break;
+ case XFER_MW_DMA_2: timings = 0x00002020; break;
+ }
+ basereg = CS5530_BASEREG(drive->hwif);
+ reg = inl(basereg + 4); /* get drive0 config register */
+ timings |= reg & 0x80000000; /* preserve PIO format bit */
+ if ((drive-> dn & 1) == 0) { /* are we configuring drive0? */
+ outl(timings, basereg + 4); /* write drive0 config register */
+ } else {
+ if (timings & 0x00100000)
+ reg |= 0x00100000; /* enable UDMA timings for both drives */
+ else
+ reg &= ~0x00100000; /* disable UDMA timings for both drives */
+ outl(reg, basereg + 4); /* write drive0 config register */
+ outl(timings, basereg + 12); /* write drive1 config register */
+ }
+}
+
+/**
+ * init_chipset_5530 - set up 5530 bridge
+ * @dev: PCI device
+ *
+ * Initialize the cs5530 bridge for reliable IDE DMA operation.
+ */
+
+static unsigned int init_chipset_cs5530(struct pci_dev *dev)
+{
+ struct pci_dev *master_0 = NULL, *cs5530_0 = NULL;
+
+ if (pci_resource_start(dev, 4) == 0)
+ return -EFAULT;
+
+ 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 out;
+ }
+ if (!cs5530_0) {
+ printk(KERN_ERR DRV_NAME ": unable to locate CS5530 LEGACY function\n");
+ goto out;
+ }
+
+ /*
+ * Enable BusMaster and MemoryWriteAndInvalidate for the cs5530:
+ * --> OR 0x14 into 16-bit PCI COMMAND reg of function 0 of the cs5530
+ */
+
+ pci_set_master(cs5530_0);
+ pci_try_set_mwi(cs5530_0);
+
+ /*
+ * Set PCI CacheLineSize to 16-bytes:
+ * --> Write 0x04 into 8-bit PCI CACHELINESIZE reg of function 0 of the cs5530
+ */
+
+ 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);
+
+out:
+ pci_dev_put(master_0);
+ pci_dev_put(cs5530_0);
+ return 0;
+}
+
+/**
+ * init_hwif_cs5530 - initialise an IDE channel
+ * @hwif: IDE to initialize
+ *
+ * This gets invoked by the IDE driver once for each channel. It
+ * performs channel-specific pre-initialization before drive probing.
+ */
+
+static void __devinit init_hwif_cs5530 (ide_hwif_t *hwif)
+{
+ unsigned long basereg;
+ u32 d0_timings;
+
+ basereg = CS5530_BASEREG(hwif);
+ d0_timings = inl(basereg + 0);
+ if (CS5530_BAD_PIO(d0_timings))
+ outl(cs5530_pio_timings[(d0_timings >> 31) & 1][0], basereg + 0);
+ if (CS5530_BAD_PIO(inl(basereg + 8)))
+ outl(cs5530_pio_timings[(d0_timings >> 31) & 1][0], basereg + 8);
+}
+
+static const struct ide_port_ops cs5530_port_ops = {
+ .set_pio_mode = cs5530_set_pio_mode,
+ .set_dma_mode = cs5530_set_dma_mode,
+ .udma_filter = cs5530_udma_filter,
+};
+
+static const struct ide_port_info cs5530_chipset __devinitdata = {
+ .name = DRV_NAME,
+ .init_chipset = init_chipset_cs5530,
+ .init_hwif = init_hwif_cs5530,
+ .port_ops = &cs5530_port_ops,
+ .host_flags = IDE_HFLAG_SERIALIZE |
+ IDE_HFLAG_POST_SET_MODE,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA2,
+};
+
+static int __devinit cs5530_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ return ide_pci_init_one(dev, &cs5530_chipset, NULL);
+}
+
+static const struct pci_device_id cs5530_pci_tbl[] = {
+ { PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5530_IDE), 0 },
+ { 0, },
+};
+MODULE_DEVICE_TABLE(pci, cs5530_pci_tbl);
+
+static struct pci_driver cs5530_pci_driver = {
+ .name = "CS5530 IDE",
+ .id_table = cs5530_pci_tbl,
+ .probe = cs5530_init_one,
+ .remove = ide_pci_remove,
+ .suspend = ide_pci_suspend,
+ .resume = ide_pci_resume,
+};
+
+static int __init cs5530_ide_init(void)
+{
+ return ide_pci_register_driver(&cs5530_pci_driver);
+}
+
+static void __exit cs5530_ide_exit(void)
+{
+ pci_unregister_driver(&cs5530_pci_driver);
+}
+
+module_init(cs5530_ide_init);
+module_exit(cs5530_ide_exit);
+
+MODULE_AUTHOR("Mark Lord");
+MODULE_DESCRIPTION("PCI driver module for Cyrix/NS 5530 IDE");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/cs5535.c b/drivers/ide/cs5535.c
new file mode 100644
index 0000000..983d957
--- /dev/null
+++ b/drivers/ide/cs5535.c
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2004-2005 Advanced Micro Devices, Inc.
+ * Copyright (C) 2007 Bartlomiej Zolnierkiewicz
+ *
+ * History:
+ * 09/20/2005 - Jaya Kumar <jayakumar.ide@gmail.com>
+ * - Reworked tuneproc, set_drive, misc mods to prep for mainline
+ * - Work was sponsored by CIS (M) Sdn Bhd.
+ * Ported to Kernel 2.6.11 on June 26, 2005 by
+ * Wolfgang Zuleger <wolfgang.zuleger@gmx.de>
+ * Alexander Kiausch <alex.kiausch@t-online.de>
+ * Originally developed by AMD for 2.4/2.6
+ *
+ * Development of this chipset driver was funded
+ * by the nice folks at National Semiconductor/AMD.
+ *
+ * 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.
+ *
+ * Documentation:
+ * CS5535 documentation available from AMD
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#define DRV_NAME "cs5535"
+
+#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
+
+/* Format I PIO settings. We separate out cmd and data for safer timings */
+
+static unsigned int cs5535_pio_cmd_timings[5] =
+{ 0xF7F4, 0x53F3, 0x13F1, 0x5131, 0x1131 };
+static unsigned int cs5535_pio_dta_timings[5] =
+{ 0xF7F4, 0xF173, 0x8141, 0x5131, 0x1131 };
+
+static unsigned int cs5535_mwdma_timings[3] =
+{ 0x7F0FFFF3, 0x7F035352, 0x7f024241 };
+
+static unsigned int cs5535_udma_timings[5] =
+{ 0x7F7436A1, 0x7F733481, 0x7F723261, 0x7F713161, 0x7F703061 };
+
+/* Macros to check if the register is the reset value - reset value is an
+ invalid timing and indicates the register has not been set previously */
+
+#define CS5535_BAD_PIO(timings) ( (timings&~0x80000000UL) == 0x00009172 )
+#define CS5535_BAD_DMA(timings) ( (timings & 0x000FFFFF) == 0x00077771 )
+
+/****
+ * cs5535_set_speed - Configure the chipset to the new speed
+ * @drive: Drive to set up
+ * @speed: desired speed
+ *
+ * cs5535_set_speed() configures the chipset to a new speed.
+ */
+static void cs5535_set_speed(ide_drive_t *drive, const u8 speed)
+{
+ u32 reg = 0, dummy;
+ u8 unit = drive->dn & 1;
+
+ /* Set the PIO timings */
+ if (speed < XFER_SW_DMA_0) {
+ ide_drive_t *pair = ide_get_pair_dev(drive);
+ u8 cmd, pioa;
+
+ cmd = pioa = speed - XFER_PIO_0;
+
+ if (pair) {
+ u8 piob = ide_get_best_pio_mode(pair, 255, 4);
+
+ if (piob < cmd)
+ cmd = piob;
+ }
+
+ /* Write the speed of the current drive */
+ reg = (cs5535_pio_cmd_timings[cmd] << 16) |
+ cs5535_pio_dta_timings[pioa];
+ wrmsr(unit ? ATAC_CH0D1_PIO : ATAC_CH0D0_PIO, reg, 0);
+
+ /* And if nessesary - change the speed of the other drive */
+ rdmsr(unit ? ATAC_CH0D0_PIO : ATAC_CH0D1_PIO, reg, dummy);
+
+ if (((reg >> 16) & cs5535_pio_cmd_timings[cmd]) !=
+ cs5535_pio_cmd_timings[cmd]) {
+ reg &= 0x0000FFFF;
+ reg |= cs5535_pio_cmd_timings[cmd] << 16;
+ wrmsr(unit ? ATAC_CH0D0_PIO : ATAC_CH0D1_PIO, reg, 0);
+ }
+
+ /* Set bit 31 of the DMA register for PIO format 1 timings */
+ rdmsr(unit ? ATAC_CH0D1_DMA : ATAC_CH0D0_DMA, reg, dummy);
+ wrmsr(unit ? ATAC_CH0D1_DMA : ATAC_CH0D0_DMA,
+ reg | 0x80000000UL, 0);
+ } else {
+ rdmsr(unit ? ATAC_CH0D1_DMA : ATAC_CH0D0_DMA, reg, dummy);
+
+ reg &= 0x80000000UL; /* Preserve the PIO format bit */
+
+ if (speed >= XFER_UDMA_0 && speed <= XFER_UDMA_4)
+ reg |= cs5535_udma_timings[speed - XFER_UDMA_0];
+ else if (speed >= XFER_MW_DMA_0 && speed <= XFER_MW_DMA_2)
+ reg |= cs5535_mwdma_timings[speed - XFER_MW_DMA_0];
+ else
+ return;
+
+ wrmsr(unit ? ATAC_CH0D1_DMA : ATAC_CH0D0_DMA, reg, 0);
+ }
+}
+
+/**
+ * cs5535_set_dma_mode - set host controller for DMA mode
+ * @drive: drive
+ * @speed: DMA mode
+ *
+ * Programs the chipset for DMA mode.
+ */
+
+static void cs5535_set_dma_mode(ide_drive_t *drive, const u8 speed)
+{
+ cs5535_set_speed(drive, speed);
+}
+
+/**
+ * cs5535_set_pio_mode - set host controller for PIO mode
+ * @drive: drive
+ * @pio: PIO mode number
+ *
+ * A callback from the upper layers for PIO-only tuning.
+ */
+
+static void cs5535_set_pio_mode(ide_drive_t *drive, const u8 pio)
+{
+ cs5535_set_speed(drive, XFER_PIO_0 + pio);
+}
+
+static u8 cs5535_cable_detect(ide_hwif_t *hwif)
+{
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+ u8 bit;
+
+ /* if a 80 wire cable was detected */
+ pci_read_config_byte(dev, CS5535_CABLE_DETECT, &bit);
+
+ return (bit & 1) ? ATA_CBL_PATA80 : ATA_CBL_PATA40;
+}
+
+static const struct ide_port_ops cs5535_port_ops = {
+ .set_pio_mode = cs5535_set_pio_mode,
+ .set_dma_mode = cs5535_set_dma_mode,
+ .cable_detect = cs5535_cable_detect,
+};
+
+static const struct ide_port_info cs5535_chipset __devinitdata = {
+ .name = DRV_NAME,
+ .port_ops = &cs5535_port_ops,
+ .host_flags = IDE_HFLAG_SINGLE | IDE_HFLAG_POST_SET_MODE,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA4,
+};
+
+static int __devinit cs5535_init_one(struct pci_dev *dev,
+ const struct pci_device_id *id)
+{
+ return ide_pci_init_one(dev, &cs5535_chipset, NULL);
+}
+
+static const struct pci_device_id cs5535_pci_tbl[] = {
+ { PCI_VDEVICE(NS, PCI_DEVICE_ID_NS_CS5535_IDE), 0 },
+ { 0, },
+};
+
+MODULE_DEVICE_TABLE(pci, cs5535_pci_tbl);
+
+static struct pci_driver cs5535_pci_driver = {
+ .name = "CS5535_IDE",
+ .id_table = cs5535_pci_tbl,
+ .probe = cs5535_init_one,
+ .remove = ide_pci_remove,
+ .suspend = ide_pci_suspend,
+ .resume = ide_pci_resume,
+};
+
+static int __init cs5535_ide_init(void)
+{
+ return ide_pci_register_driver(&cs5535_pci_driver);
+}
+
+static void __exit cs5535_ide_exit(void)
+{
+ pci_unregister_driver(&cs5535_pci_driver);
+}
+
+module_init(cs5535_ide_init);
+module_exit(cs5535_ide_exit);
+
+MODULE_AUTHOR("AMD");
+MODULE_DESCRIPTION("PCI driver module for AMD/NS CS5535 IDE");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/cy82c693.c b/drivers/ide/cy82c693.c
new file mode 100644
index 0000000..5297f07
--- /dev/null
+++ b/drivers/ide/cy82c693.c
@@ -0,0 +1,358 @@
+/*
+ * Copyright (C) 1998-2000 Andreas S. Krebs (akrebs@altavista.net), Maintainer
+ * Copyright (C) 1998-2002 Andre Hedrick <andre@linux-ide.org>, Integrator
+ *
+ * CYPRESS CY82C693 chipset IDE controller
+ *
+ * The CY82C693 chipset is used on Digital's PC-Alpha 164SX boards.
+ * Writing the driver was quite simple, since most of the job is
+ * done by the generic pci-ide support.
+ * The hard part was finding the CY82C693's datasheet on Cypress's
+ * web page :-(. But Altavista solved this problem :-).
+ *
+ *
+ * Notes:
+ * - I recently got a 16.8G IBM DTTA, so I was able to test it with
+ * a large and fast disk - the results look great, so I'd say the
+ * driver is working fine :-)
+ * hdparm -t reports 8.17 MB/sec at about 6% CPU usage for the DTTA
+ * - this is my first linux driver, so there's probably a lot of room
+ * for optimizations and bug fixing, so feel free to do it.
+ * - if using PIO mode it's a good idea to set the PIO mode and
+ * 32-bit I/O support (if possible), e.g. hdparm -p2 -c1 /dev/hda
+ * - I had some problems with my IBM DHEA with PIO modes < 2
+ * (lost interrupts) ?????
+ * - first tests with DMA look okay, they seem to work, but there is a
+ * problem with sound - the BusMaster IDE TimeOut should fixed this
+ *
+ * Ancient History:
+ * AMH@1999-08-24: v0.34 init_cy82c693_chip moved to pci_init_cy82c693
+ * ASK@1999-01-23: v0.33 made a few minor code clean ups
+ * removed DMA clock speed setting by default
+ * added boot message
+ * ASK@1998-11-01: v0.32 added support to set BusMaster IDE TimeOut
+ * added support to set DMA Controller Clock Speed
+ * ASK@1998-10-31: v0.31 fixed problem with setting to high DMA modes
+ * on some drives.
+ * ASK@1998-10-29: v0.3 added support to set DMA modes
+ * ASK@1998-10-28: v0.2 added support to set PIO modes
+ * ASK@1998-10-27: v0.1 first version - chipset detection
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#define DRV_NAME "cy82c693"
+
+/*
+ * The following are used to debug the driver.
+ */
+#define CY82C693_DEBUG_INFO 0
+
+/*
+ * NOTE: the value for busmaster timeout is tricky and I got it by
+ * trial and error! By using a to low value will cause DMA timeouts
+ * and drop IDE performance, and by using a to high value will cause
+ * audio playback to scatter.
+ * If you know a better value or how to calc it, please let me know.
+ */
+
+/* twice the value written in cy82c693ub datasheet */
+#define BUSMASTER_TIMEOUT 0x50
+/*
+ * the value above was tested on my machine and it seems to work okay
+ */
+
+/* here are the offset definitions for the registers */
+#define CY82_IDE_CMDREG 0x04
+#define CY82_IDE_ADDRSETUP 0x48
+#define CY82_IDE_MASTER_IOR 0x4C
+#define CY82_IDE_MASTER_IOW 0x4D
+#define CY82_IDE_SLAVE_IOR 0x4E
+#define CY82_IDE_SLAVE_IOW 0x4F
+#define CY82_IDE_MASTER_8BIT 0x50
+#define CY82_IDE_SLAVE_8BIT 0x51
+
+#define CY82_INDEX_PORT 0x22
+#define CY82_DATA_PORT 0x23
+
+#define CY82_INDEX_CHANNEL0 0x30
+#define CY82_INDEX_CHANNEL1 0x31
+#define CY82_INDEX_TIMEOUT 0x32
+
+/* the min and max PCI bus speed in MHz - from datasheet */
+#define CY82C963_MIN_BUS_SPEED 25
+#define CY82C963_MAX_BUS_SPEED 33
+
+/* the struct for the PIO mode timings */
+typedef struct pio_clocks_s {
+ u8 address_time; /* Address setup (clocks) */
+ u8 time_16r; /* clocks for 16bit IOR (0xF0=Active/data, 0x0F=Recovery) */
+ u8 time_16w; /* clocks for 16bit IOW (0xF0=Active/data, 0x0F=Recovery) */
+ u8 time_8; /* clocks for 8bit (0xF0=Active/data, 0x0F=Recovery) */
+} pio_clocks_t;
+
+/*
+ * calc clocks using bus_speed
+ * returns (rounded up) time in bus clocks for time in ns
+ */
+static int calc_clk(int time, int bus_speed)
+{
+ int clocks;
+
+ clocks = (time*bus_speed+999)/1000 - 1;
+
+ if (clocks < 0)
+ clocks = 0;
+
+ if (clocks > 0x0F)
+ clocks = 0x0F;
+
+ return clocks;
+}
+
+/*
+ * compute the values for the clock registers for PIO
+ * mode and pci_clk [MHz] speed
+ *
+ * NOTE: for mode 0,1 and 2 drives 8-bit IDE command control registers are used
+ * for mode 3 and 4 drives 8 and 16-bit timings are the same
+ *
+ */
+static void compute_clocks(u8 pio, pio_clocks_t *p_pclk)
+{
+ struct ide_timing *t = ide_timing_find_mode(XFER_PIO_0 + pio);
+ int clk1, clk2;
+ int bus_speed = ide_pci_clk ? ide_pci_clk : 33;
+
+ /* we don't check against CY82C693's min and max speed,
+ * so you can play with the idebus=xx parameter
+ */
+
+ /* let's calc the address setup time clocks */
+ p_pclk->address_time = (u8)calc_clk(t->setup, bus_speed);
+
+ /* let's calc the active and recovery time clocks */
+ clk1 = calc_clk(t->active, bus_speed);
+
+ /* calc recovery timing */
+ clk2 = t->cycle - t->active - t->setup;
+
+ clk2 = calc_clk(clk2, bus_speed);
+
+ clk1 = (clk1<<4)|clk2; /* combine active and recovery clocks */
+
+ /* note: we use the same values for 16bit IOR and IOW
+ * those are all the same, since I don't have other
+ * timings than those from ide-lib.c
+ */
+
+ p_pclk->time_16r = (u8)clk1;
+ p_pclk->time_16w = (u8)clk1;
+
+ /* what are good values for 8bit ?? */
+ p_pclk->time_8 = (u8)clk1;
+}
+
+/*
+ * set DMA mode a specific channel for CY82C693
+ */
+
+static void cy82c693_set_dma_mode(ide_drive_t *drive, const u8 mode)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ u8 single = (mode & 0x10) >> 4, index = 0, data = 0;
+
+ index = hwif->channel ? CY82_INDEX_CHANNEL1 : CY82_INDEX_CHANNEL0;
+
+ data = (mode & 3) | (single << 2);
+
+ outb(index, CY82_INDEX_PORT);
+ outb(data, CY82_DATA_PORT);
+
+#if CY82C693_DEBUG_INFO
+ printk(KERN_INFO "%s (ch=%d, dev=%d): set DMA mode to %d (single=%d)\n",
+ drive->name, hwif->channel, drive->dn & 1, mode & 3, single);
+#endif /* CY82C693_DEBUG_INFO */
+
+ /*
+ * note: below we set the value for Bus Master IDE TimeOut Register
+ * I'm not absolutly sure what this does, but it solved my problem
+ * with IDE DMA and sound, so I now can play sound and work with
+ * my IDE driver at the same time :-)
+ *
+ * If you know the correct (best) value for this register please
+ * let me know - ASK
+ */
+
+ data = BUSMASTER_TIMEOUT;
+ outb(CY82_INDEX_TIMEOUT, CY82_INDEX_PORT);
+ outb(data, CY82_DATA_PORT);
+
+#if CY82C693_DEBUG_INFO
+ printk(KERN_INFO "%s: Set IDE Bus Master TimeOut Register to 0x%X\n",
+ drive->name, data);
+#endif /* CY82C693_DEBUG_INFO */
+}
+
+static void cy82c693_set_pio_mode(ide_drive_t *drive, const u8 pio)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+ pio_clocks_t pclk;
+ unsigned int addrCtrl;
+
+ /* select primary or secondary channel */
+ if (hwif->index > 0) { /* drive is on the secondary channel */
+ dev = pci_get_slot(dev->bus, dev->devfn+1);
+ if (!dev) {
+ printk(KERN_ERR "%s: tune_drive: "
+ "Cannot find secondary interface!\n",
+ drive->name);
+ return;
+ }
+ }
+
+ /* let's calc the values for this PIO mode */
+ compute_clocks(pio, &pclk);
+
+ /* now let's write the clocks registers */
+ if ((drive->dn & 1) == 0) {
+ /*
+ * set master drive
+ * address setup control register
+ * is 32 bit !!!
+ */
+ pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl);
+
+ addrCtrl &= (~0xF);
+ addrCtrl |= (unsigned int)pclk.address_time;
+ pci_write_config_dword(dev, CY82_IDE_ADDRSETUP, addrCtrl);
+
+ /* now let's set the remaining registers */
+ pci_write_config_byte(dev, CY82_IDE_MASTER_IOR, pclk.time_16r);
+ pci_write_config_byte(dev, CY82_IDE_MASTER_IOW, pclk.time_16w);
+ pci_write_config_byte(dev, CY82_IDE_MASTER_8BIT, pclk.time_8);
+
+ addrCtrl &= 0xF;
+ } else {
+ /*
+ * set slave drive
+ * address setup control register
+ * is 32 bit !!!
+ */
+ pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl);
+
+ addrCtrl &= (~0xF0);
+ addrCtrl |= ((unsigned int)pclk.address_time<<4);
+ pci_write_config_dword(dev, CY82_IDE_ADDRSETUP, addrCtrl);
+
+ /* now let's set the remaining registers */
+ pci_write_config_byte(dev, CY82_IDE_SLAVE_IOR, pclk.time_16r);
+ pci_write_config_byte(dev, CY82_IDE_SLAVE_IOW, pclk.time_16w);
+ pci_write_config_byte(dev, CY82_IDE_SLAVE_8BIT, pclk.time_8);
+
+ addrCtrl >>= 4;
+ addrCtrl &= 0xF;
+ }
+
+#if CY82C693_DEBUG_INFO
+ printk(KERN_INFO "%s (ch=%d, dev=%d): set PIO timing to "
+ "(addr=0x%X, ior=0x%X, iow=0x%X, 8bit=0x%X)\n",
+ drive->name, hwif->channel, drive->dn & 1,
+ addrCtrl, pclk.time_16r, pclk.time_16w, pclk.time_8);
+#endif /* CY82C693_DEBUG_INFO */
+}
+
+static void __devinit init_iops_cy82c693(ide_hwif_t *hwif)
+{
+ static ide_hwif_t *primary;
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+
+ if (PCI_FUNC(dev->devfn) == 1)
+ primary = hwif;
+ else {
+ hwif->mate = primary;
+ hwif->channel = 1;
+ }
+}
+
+static const struct ide_port_ops cy82c693_port_ops = {
+ .set_pio_mode = cy82c693_set_pio_mode,
+ .set_dma_mode = cy82c693_set_dma_mode,
+};
+
+static const struct ide_port_info cy82c693_chipset __devinitdata = {
+ .name = DRV_NAME,
+ .init_iops = init_iops_cy82c693,
+ .port_ops = &cy82c693_port_ops,
+ .chipset = ide_cy82c693,
+ .host_flags = IDE_HFLAG_SINGLE,
+ .pio_mask = ATA_PIO4,
+ .swdma_mask = ATA_SWDMA2,
+ .mwdma_mask = ATA_MWDMA2,
+};
+
+static int __devinit cy82c693_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ struct pci_dev *dev2;
+ int ret = -ENODEV;
+
+ /* CY82C693 is more than only a IDE controller.
+ Function 1 is primary IDE channel, function 2 - secondary. */
+ if ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE &&
+ PCI_FUNC(dev->devfn) == 1) {
+ dev2 = pci_get_slot(dev->bus, dev->devfn + 1);
+ ret = ide_pci_init_two(dev, dev2, &cy82c693_chipset, NULL);
+ if (ret)
+ pci_dev_put(dev2);
+ }
+ return ret;
+}
+
+static void __devexit cy82c693_remove(struct pci_dev *dev)
+{
+ struct ide_host *host = pci_get_drvdata(dev);
+ struct pci_dev *dev2 = host->dev[1] ? to_pci_dev(host->dev[1]) : NULL;
+
+ ide_pci_remove(dev);
+ pci_dev_put(dev2);
+}
+
+static const struct pci_device_id cy82c693_pci_tbl[] = {
+ { PCI_VDEVICE(CONTAQ, PCI_DEVICE_ID_CONTAQ_82C693), 0 },
+ { 0, },
+};
+MODULE_DEVICE_TABLE(pci, cy82c693_pci_tbl);
+
+static struct pci_driver cy82c693_pci_driver = {
+ .name = "Cypress_IDE",
+ .id_table = cy82c693_pci_tbl,
+ .probe = cy82c693_init_one,
+ .remove = __devexit_p(cy82c693_remove),
+ .suspend = ide_pci_suspend,
+ .resume = ide_pci_resume,
+};
+
+static int __init cy82c693_ide_init(void)
+{
+ return ide_pci_register_driver(&cy82c693_pci_driver);
+}
+
+static void __exit cy82c693_ide_exit(void)
+{
+ pci_unregister_driver(&cy82c693_pci_driver);
+}
+
+module_init(cy82c693_ide_init);
+module_exit(cy82c693_ide_exit);
+
+MODULE_AUTHOR("Andreas Krebs, Andre Hedrick");
+MODULE_DESCRIPTION("PCI driver module for the Cypress CY82C693 IDE");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/delkin_cb.c b/drivers/ide/delkin_cb.c
new file mode 100644
index 0000000..8f1b2d9
--- /dev/null
+++ b/drivers/ide/delkin_cb.c
@@ -0,0 +1,192 @@
+/*
+ * Created 20 Oct 2004 by Mark Lord
+ *
+ * Basic support for Delkin/ASKA/Workbit Cardbus CompactFlash adapter
+ *
+ * Modeled after the 16-bit PCMCIA driver: ide-cs.c
+ *
+ * This is slightly peculiar, in that it is a PCI driver,
+ * but is NOT an IDE PCI driver -- the IDE layer does not directly
+ * support hot insertion/removal of PCI interfaces, so this driver
+ * is unable to use the IDE PCI interfaces. Instead, it uses the
+ * same interfaces as the ide-cs (PCMCIA) driver uses.
+ * On the plus side, the driver is also smaller/simpler this way.
+ *
+ * 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/types.h>
+#include <linux/module.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+
+#include <asm/io.h>
+
+/*
+ * No chip documentation has yet been found,
+ * so these configuration values were pulled from
+ * a running Win98 system using "debug".
+ * This gives around 3MByte/second read performance,
+ * which is about 2/3 of what the chip is capable of.
+ *
+ * There is also a 4KByte mmio region on the card,
+ * but its purpose has yet to be reverse-engineered.
+ */
+static const u8 setup[] = {
+ 0x00, 0x05, 0xbe, 0x01, 0x20, 0x8f, 0x00, 0x00,
+ 0xa4, 0x1f, 0xb3, 0x1b, 0x00, 0x00, 0x00, 0x80,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xa4, 0x83, 0x02, 0x13,
+};
+
+static const struct ide_port_ops delkin_cb_port_ops = {
+ .quirkproc = ide_undecoded_slave,
+};
+
+static unsigned int delkin_cb_init_chipset(struct pci_dev *dev)
+{
+ unsigned long base = pci_resource_start(dev, 0);
+ int i;
+
+ outb(0x02, base + 0x1e); /* set nIEN to block interrupts */
+ inb(base + 0x17); /* read status to clear interrupts */
+
+ for (i = 0; i < sizeof(setup); ++i) {
+ if (setup[i])
+ outb(setup[i], base + i);
+ }
+
+ return 0;
+}
+
+static const struct ide_port_info delkin_cb_port_info = {
+ .port_ops = &delkin_cb_port_ops,
+ .host_flags = IDE_HFLAG_IO_32BIT | IDE_HFLAG_UNMASK_IRQS |
+ IDE_HFLAG_NO_DMA,
+ .init_chipset = delkin_cb_init_chipset,
+};
+
+static int __devinit
+delkin_cb_probe (struct pci_dev *dev, const struct pci_device_id *id)
+{
+ struct ide_host *host;
+ unsigned long base;
+ int rc;
+ hw_regs_t hw, *hws[] = { &hw, NULL, NULL, NULL };
+
+ rc = pci_enable_device(dev);
+ if (rc) {
+ printk(KERN_ERR "delkin_cb: pci_enable_device failed (%d)\n", rc);
+ return rc;
+ }
+ rc = pci_request_regions(dev, "delkin_cb");
+ if (rc) {
+ printk(KERN_ERR "delkin_cb: pci_request_regions failed (%d)\n", rc);
+ pci_disable_device(dev);
+ return rc;
+ }
+ base = pci_resource_start(dev, 0);
+
+ delkin_cb_init_chipset(dev);
+
+ memset(&hw, 0, sizeof(hw));
+ ide_std_init_ports(&hw, base + 0x10, base + 0x1e);
+ hw.irq = dev->irq;
+ hw.dev = &dev->dev;
+ hw.chipset = ide_pci; /* this enables IRQ sharing */
+
+ rc = ide_host_add(&delkin_cb_port_info, hws, &host);
+ if (rc)
+ goto out_disable;
+
+ pci_set_drvdata(dev, host);
+
+ return 0;
+
+out_disable:
+ pci_release_regions(dev);
+ pci_disable_device(dev);
+ return rc;
+}
+
+static void
+delkin_cb_remove (struct pci_dev *dev)
+{
+ struct ide_host *host = pci_get_drvdata(dev);
+
+ ide_host_remove(host);
+
+ pci_release_regions(dev);
+ pci_disable_device(dev);
+}
+
+#ifdef CONFIG_PM
+static int delkin_cb_suspend(struct pci_dev *dev, pm_message_t state)
+{
+ pci_save_state(dev);
+ pci_disable_device(dev);
+ pci_set_power_state(dev, pci_choose_state(dev, state));
+
+ return 0;
+}
+
+static int delkin_cb_resume(struct pci_dev *dev)
+{
+ struct ide_host *host = pci_get_drvdata(dev);
+ int rc;
+
+ pci_set_power_state(dev, PCI_D0);
+
+ rc = pci_enable_device(dev);
+ if (rc)
+ return rc;
+
+ pci_restore_state(dev);
+ pci_set_master(dev);
+
+ if (host->init_chipset)
+ host->init_chipset(dev);
+
+ return 0;
+}
+#else
+#define delkin_cb_suspend NULL
+#define delkin_cb_resume NULL
+#endif
+
+static struct pci_device_id delkin_cb_pci_tbl[] __devinitdata = {
+ { 0x1145, 0xf021, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { 0x1145, 0xf024, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { 0, },
+};
+MODULE_DEVICE_TABLE(pci, delkin_cb_pci_tbl);
+
+static struct pci_driver delkin_cb_pci_driver = {
+ .name = "Delkin-ASKA-Workbit Cardbus IDE",
+ .id_table = delkin_cb_pci_tbl,
+ .probe = delkin_cb_probe,
+ .remove = delkin_cb_remove,
+ .suspend = delkin_cb_suspend,
+ .resume = delkin_cb_resume,
+};
+
+static int __init delkin_cb_init(void)
+{
+ return pci_register_driver(&delkin_cb_pci_driver);
+}
+
+static void __exit delkin_cb_exit(void)
+{
+ pci_unregister_driver(&delkin_cb_pci_driver);
+}
+
+module_init(delkin_cb_init);
+module_exit(delkin_cb_exit);
+
+MODULE_AUTHOR("Mark Lord");
+MODULE_DESCRIPTION("Basic support for Delkin/ASKA/Workbit Cardbus IDE");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/ide/dtc2278.c b/drivers/ide/dtc2278.c
new file mode 100644
index 0000000..689b2e4
--- /dev/null
+++ b/drivers/ide/dtc2278.c
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 1996 Linus Torvalds & author (see below)
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#define DRV_NAME "dtc2278"
+
+/*
+ * Changing this #undef to #define may solve start up problems in some systems.
+ */
+#undef ALWAYS_SET_DTC2278_PIO_MODE
+
+/*
+ * From: andy@cercle.cts.com (Dyan Wile)
+ *
+ * Below is a patch for DTC-2278 - alike software-programmable controllers
+ * The code enables the secondary IDE controller and the PIO4 (3?) timings on
+ * the primary (EIDE). You may probably have to enable the 32-bit support to
+ * get the full speed. You better get the disk interrupts disabled ( hdparm -u0
+ * /dev/hd.. ) for the drives connected to the EIDE interface. (I get my
+ * filesystem corrupted with -u1, but under heavy disk load only :-)
+ *
+ * This card is now forced to use the "serialize" feature,
+ * and irq-unmasking is disallowed. If io_32bit is enabled,
+ * it must be done for BOTH drives on each interface.
+ *
+ * This code was written for the DTC2278E, but might work with any of these:
+ *
+ * DTC2278S has only a single IDE interface.
+ * DTC2278D has two IDE interfaces and is otherwise identical to the S version.
+ * DTC2278E also has serial ports and a printer port
+ * DTC2278EB: has onboard BIOS, and "works like a charm" -- Kent Bradford <kent@theory.caltech.edu>
+ *
+ * There may be a fourth controller type. The S and D versions use the
+ * Winbond chip, and I think the E version does also.
+ *
+ */
+
+static void sub22 (char b, char c)
+{
+ int i;
+
+ for(i = 0; i < 3; ++i) {
+ inb(0x3f6);
+ outb_p(b,0xb0);
+ inb(0x3f6);
+ outb_p(c,0xb4);
+ inb(0x3f6);
+ if(inb(0xb4) == c) {
+ outb_p(7,0xb0);
+ inb(0x3f6);
+ return; /* success */
+ }
+ }
+}
+
+static DEFINE_SPINLOCK(dtc2278_lock);
+
+static void dtc2278_set_pio_mode(ide_drive_t *drive, const u8 pio)
+{
+ unsigned long flags;
+
+ if (pio >= 3) {
+ spin_lock_irqsave(&dtc2278_lock, flags);
+ /*
+ * This enables PIO mode4 (3?) on the first interface
+ */
+ sub22(1,0xc3);
+ sub22(0,0xa0);
+ spin_unlock_irqrestore(&dtc2278_lock, flags);
+ } else {
+ /* we don't know how to set it back again.. */
+ /* Actually we do - there is a data sheet available for the
+ Winbond but does anyone actually care */
+ }
+}
+
+static const struct ide_port_ops dtc2278_port_ops = {
+ .set_pio_mode = dtc2278_set_pio_mode,
+};
+
+static const struct ide_port_info dtc2278_port_info __initdata = {
+ .name = DRV_NAME,
+ .chipset = ide_dtc2278,
+ .port_ops = &dtc2278_port_ops,
+ .host_flags = IDE_HFLAG_SERIALIZE |
+ IDE_HFLAG_NO_UNMASK_IRQS |
+ IDE_HFLAG_IO_32BIT |
+ /* disallow ->io_32bit changes */
+ IDE_HFLAG_NO_IO_32BIT |
+ IDE_HFLAG_NO_DMA,
+ .pio_mask = ATA_PIO4,
+};
+
+static int __init dtc2278_probe(void)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+ /*
+ * This enables the second interface
+ */
+ outb_p(4,0xb0);
+ inb(0x3f6);
+ outb_p(0x20,0xb4);
+ inb(0x3f6);
+#ifdef ALWAYS_SET_DTC2278_PIO_MODE
+ /*
+ * This enables PIO mode4 (3?) on the first interface
+ * and may solve start-up problems for some people.
+ */
+ sub22(1,0xc3);
+ sub22(0,0xa0);
+#endif
+ local_irq_restore(flags);
+
+ return ide_legacy_device_add(&dtc2278_port_info, 0);
+}
+
+static int probe_dtc2278;
+
+module_param_named(probe, probe_dtc2278, bool, 0);
+MODULE_PARM_DESC(probe, "probe for DTC2278xx chipsets");
+
+static int __init dtc2278_init(void)
+{
+ if (probe_dtc2278 == 0)
+ return -ENODEV;
+
+ if (dtc2278_probe()) {
+ printk(KERN_ERR "dtc2278: ide interfaces already in use!\n");
+ return -EBUSY;
+ }
+ return 0;
+}
+
+module_init(dtc2278_init);
+
+MODULE_AUTHOR("See Local File");
+MODULE_DESCRIPTION("support of DTC-2278 VLB IDE chipsets");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/falconide.c b/drivers/ide/falconide.c
new file mode 100644
index 0000000..39d500d
--- /dev/null
+++ b/drivers/ide/falconide.c
@@ -0,0 +1,153 @@
+/*
+ * Atari Falcon IDE Driver
+ *
+ * Created 12 Jul 1997 by Geert Uytterhoeven
+ *
+ * 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/module.h>
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/setup.h>
+#include <asm/atarihw.h>
+#include <asm/atariints.h>
+#include <asm/atari_stdma.h>
+
+#define DRV_NAME "falconide"
+
+ /*
+ * Base of the IDE interface
+ */
+
+#define ATA_HD_BASE 0xfff00000
+
+ /*
+ * Offsets from the above base
+ */
+
+#define ATA_HD_CONTROL 0x39
+
+ /*
+ * falconide_intr_lock is used to obtain access to the IDE interrupt,
+ * which is shared between several drivers.
+ */
+
+int falconide_intr_lock;
+EXPORT_SYMBOL(falconide_intr_lock);
+
+static void falconide_input_data(ide_drive_t *drive, struct request *rq,
+ void *buf, unsigned int len)
+{
+ unsigned long data_addr = drive->hwif->io_ports.data_addr;
+
+ if (drive->media == ide_disk && rq && rq->cmd_type == REQ_TYPE_FS)
+ return insw(data_addr, buf, (len + 1) / 2);
+
+ insw_swapw(data_addr, buf, (len + 1) / 2);
+}
+
+static void falconide_output_data(ide_drive_t *drive, struct request *rq,
+ void *buf, unsigned int len)
+{
+ unsigned long data_addr = drive->hwif->io_ports.data_addr;
+
+ if (drive->media == ide_disk && rq && rq->cmd_type == REQ_TYPE_FS)
+ return outsw(data_addr, buf, (len + 1) / 2);
+
+ outsw_swapw(data_addr, buf, (len + 1) / 2);
+}
+
+/* Atari has a byte-swapped IDE interface */
+static const struct ide_tp_ops falconide_tp_ops = {
+ .exec_command = ide_exec_command,
+ .read_status = ide_read_status,
+ .read_altstatus = ide_read_altstatus,
+ .read_sff_dma_status = ide_read_sff_dma_status,
+
+ .set_irq = ide_set_irq,
+
+ .tf_load = ide_tf_load,
+ .tf_read = ide_tf_read,
+
+ .input_data = falconide_input_data,
+ .output_data = falconide_output_data,
+};
+
+static const struct ide_port_info falconide_port_info = {
+ .tp_ops = &falconide_tp_ops,
+ .host_flags = IDE_HFLAG_NO_DMA,
+};
+
+static void __init falconide_setup_ports(hw_regs_t *hw)
+{
+ int i;
+
+ memset(hw, 0, sizeof(*hw));
+
+ hw->io_ports.data_addr = ATA_HD_BASE;
+
+ for (i = 1; i < 8; i++)
+ hw->io_ports_array[i] = ATA_HD_BASE + 1 + i * 4;
+
+ hw->io_ports.ctl_addr = ATA_HD_BASE + ATA_HD_CONTROL;
+
+ hw->irq = IRQ_MFP_IDE;
+ hw->ack_intr = NULL;
+
+ hw->chipset = ide_generic;
+}
+
+ /*
+ * Probe for a Falcon IDE interface
+ */
+
+static int __init falconide_init(void)
+{
+ struct ide_host *host;
+ hw_regs_t hw, *hws[] = { &hw, NULL, NULL, NULL };
+ int rc;
+
+ if (!MACH_IS_ATARI || !ATARIHW_PRESENT(IDE))
+ return -ENODEV;
+
+ printk(KERN_INFO "ide: Falcon IDE controller\n");
+
+ if (!request_mem_region(ATA_HD_BASE, 0x40, DRV_NAME)) {
+ printk(KERN_ERR "%s: resources busy\n", DRV_NAME);
+ return -EBUSY;
+ }
+
+ falconide_setup_ports(&hw);
+
+ host = ide_host_alloc(&falconide_port_info, hws);
+ if (host == NULL) {
+ rc = -ENOMEM;
+ goto err;
+ }
+
+ ide_get_lock(NULL, NULL);
+ rc = ide_host_register(host, &falconide_port_info, hws);
+ ide_release_lock();
+
+ if (rc)
+ goto err_free;
+
+ return 0;
+err_free:
+ ide_host_free(host);
+err:
+ release_mem_region(ATA_HD_BASE, 0x40);
+ return rc;
+}
+
+module_init(falconide_init);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/gayle.c b/drivers/ide/gayle.c
new file mode 100644
index 0000000..6915068
--- /dev/null
+++ b/drivers/ide/gayle.c
@@ -0,0 +1,190 @@
+/*
+ * Amiga Gayle IDE Driver
+ *
+ * Created 9 Jul 1997 by Geert Uytterhoeven
+ *
+ * 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/types.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+#include <linux/zorro.h>
+#include <linux/module.h>
+
+#include <asm/setup.h>
+#include <asm/amigahw.h>
+#include <asm/amigaints.h>
+#include <asm/amigayle.h>
+
+
+ /*
+ * Bases of the IDE interfaces
+ */
+
+#define GAYLE_BASE_4000 0xdd2020 /* A4000/A4000T */
+#define GAYLE_BASE_1200 0xda0000 /* A1200/A600 and E-Matrix 530 */
+
+#define GAYLE_IDEREG_SIZE 0x2000
+
+ /*
+ * Offsets from one of the above bases
+ */
+
+#define GAYLE_CONTROL 0x101a
+
+ /*
+ * These are at different offsets from the base
+ */
+
+#define GAYLE_IRQ_4000 0xdd3020 /* MSB = 1, Harddisk is source of */
+#define GAYLE_IRQ_1200 0xda9000 /* interrupt */
+
+
+ /*
+ * Offset of the secondary port for IDE doublers
+ * Note that GAYLE_CONTROL is NOT available then!
+ */
+
+#define GAYLE_NEXT_PORT 0x1000
+
+#ifndef CONFIG_BLK_DEV_IDEDOUBLER
+#define GAYLE_NUM_HWIFS 1
+#define GAYLE_NUM_PROBE_HWIFS GAYLE_NUM_HWIFS
+#define GAYLE_HAS_CONTROL_REG 1
+#else /* CONFIG_BLK_DEV_IDEDOUBLER */
+#define GAYLE_NUM_HWIFS 2
+#define GAYLE_NUM_PROBE_HWIFS (ide_doubler ? GAYLE_NUM_HWIFS : \
+ GAYLE_NUM_HWIFS-1)
+#define GAYLE_HAS_CONTROL_REG (!ide_doubler)
+
+static int ide_doubler;
+module_param_named(doubler, ide_doubler, bool, 0);
+MODULE_PARM_DESC(doubler, "enable support for IDE doublers");
+#endif /* CONFIG_BLK_DEV_IDEDOUBLER */
+
+
+ /*
+ * Check and acknowledge the interrupt status
+ */
+
+static int gayle_ack_intr_a4000(ide_hwif_t *hwif)
+{
+ unsigned char ch;
+
+ ch = z_readb(hwif->io_ports.irq_addr);
+ if (!(ch & GAYLE_IRQ_IDE))
+ return 0;
+ return 1;
+}
+
+static int gayle_ack_intr_a1200(ide_hwif_t *hwif)
+{
+ unsigned char ch;
+
+ ch = z_readb(hwif->io_ports.irq_addr);
+ if (!(ch & GAYLE_IRQ_IDE))
+ return 0;
+ (void)z_readb(hwif->io_ports.status_addr);
+ z_writeb(0x7c, hwif->io_ports.irq_addr);
+ return 1;
+}
+
+static void __init gayle_setup_ports(hw_regs_t *hw, unsigned long base,
+ unsigned long ctl, unsigned long irq_port,
+ ide_ack_intr_t *ack_intr)
+{
+ int i;
+
+ memset(hw, 0, sizeof(*hw));
+
+ hw->io_ports.data_addr = base;
+
+ for (i = 1; i < 8; i++)
+ hw->io_ports_array[i] = base + 2 + i * 4;
+
+ hw->io_ports.ctl_addr = ctl;
+ hw->io_ports.irq_addr = irq_port;
+
+ hw->irq = IRQ_AMIGA_PORTS;
+ hw->ack_intr = ack_intr;
+
+ hw->chipset = ide_generic;
+}
+
+ /*
+ * Probe for a Gayle IDE interface (and optionally for an IDE doubler)
+ */
+
+static int __init gayle_init(void)
+{
+ unsigned long phys_base, res_start, res_n;
+ unsigned long base, ctrlport, irqport;
+ ide_ack_intr_t *ack_intr;
+ int a4000, i, rc;
+ hw_regs_t hw[GAYLE_NUM_HWIFS], *hws[] = { NULL, NULL, NULL, NULL };
+
+ if (!MACH_IS_AMIGA)
+ return -ENODEV;
+
+ if ((a4000 = AMIGAHW_PRESENT(A4000_IDE)) || AMIGAHW_PRESENT(A1200_IDE))
+ goto found;
+
+#ifdef CONFIG_ZORRO
+ if (zorro_find_device(ZORRO_PROD_MTEC_VIPER_MK_V_E_MATRIX_530_SCSI_IDE,
+ NULL))
+ goto found;
+#endif
+ return -ENODEV;
+
+found:
+ printk(KERN_INFO "ide: Gayle IDE controller (A%d style%s)\n",
+ a4000 ? 4000 : 1200,
+#ifdef CONFIG_BLK_DEV_IDEDOUBLER
+ ide_doubler ? ", IDE doubler" :
+#endif
+ "");
+
+ if (a4000) {
+ phys_base = GAYLE_BASE_4000;
+ irqport = (unsigned long)ZTWO_VADDR(GAYLE_IRQ_4000);
+ ack_intr = gayle_ack_intr_a4000;
+ } else {
+ phys_base = GAYLE_BASE_1200;
+ irqport = (unsigned long)ZTWO_VADDR(GAYLE_IRQ_1200);
+ ack_intr = gayle_ack_intr_a1200;
+ }
+/*
+ * FIXME: we now have selectable modes between mmio v/s iomio
+ */
+
+ res_start = ((unsigned long)phys_base) & ~(GAYLE_NEXT_PORT-1);
+ res_n = GAYLE_IDEREG_SIZE;
+
+ if (!request_mem_region(res_start, res_n, "IDE"))
+ return -EBUSY;
+
+ for (i = 0; i < GAYLE_NUM_PROBE_HWIFS; i++) {
+ base = (unsigned long)ZTWO_VADDR(phys_base + i * GAYLE_NEXT_PORT);
+ ctrlport = GAYLE_HAS_CONTROL_REG ? (base + GAYLE_CONTROL) : 0;
+
+ gayle_setup_ports(&hw[i], base, ctrlport, irqport, ack_intr);
+
+ hws[i] = &hw[i];
+ }
+
+ rc = ide_host_add(NULL, hws, NULL);
+ if (rc)
+ release_mem_region(res_start, res_n);
+
+ return rc;
+}
+
+module_init(gayle_init);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/hpt366.c b/drivers/ide/hpt366.c
new file mode 100644
index 0000000..f5afd46
--- /dev/null
+++ b/drivers/ide/hpt366.c
@@ -0,0 +1,1643 @@
+/*
+ * Copyright (C) 1999-2003 Andre Hedrick <andre@linux-ide.org>
+ * Portions Copyright (C) 2001 Sun Microsystems, Inc.
+ * Portions Copyright (C) 2003 Red Hat Inc
+ * Portions Copyright (C) 2007 Bartlomiej Zolnierkiewicz
+ * Portions Copyright (C) 2005-2008 MontaVista Software, Inc.
+ *
+ * Thanks to HighPoint Technologies for their assistance, and hardware.
+ * Special Thanks to Jon Burchmore in SanDiego for the deep pockets, his
+ * donation of an ABit BP6 mainboard, processor, and memory acellerated
+ * development and support.
+ *
+ *
+ * HighPoint has its own drivers (open source except for the RAID part)
+ * available from http://www.highpoint-tech.com/BIOS%20+%20Driver/.
+ * This may be useful to anyone wanting to work on this driver, however do not
+ * trust them too much since the code tends to become less and less meaningful
+ * as the time passes... :-/
+ *
+ * Note that final HPT370 support was done by force extraction of GPL.
+ *
+ * - add function for getting/setting power status of drive
+ * - the HPT370's state machine can get confused. reset it before each dma
+ * xfer to prevent that from happening.
+ * - reset state engine whenever we get an error.
+ * - check for busmaster state at end of dma.
+ * - use new highpoint timings.
+ * - detect bus speed using highpoint register.
+ * - use pll if we don't have a clock table. added a 66MHz table that's
+ * just 2x the 33MHz table.
+ * - removed turnaround. NOTE: we never want to switch between pll and
+ * pci clocks as the chip can glitch in those cases. the highpoint
+ * approved workaround slows everything down too much to be useful. in
+ * addition, we would have to serialize access to each chip.
+ * Adrian Sun <a.sun@sun.com>
+ *
+ * add drive timings for 66MHz PCI bus,
+ * fix ATA Cable signal detection, fix incorrect /proc info
+ * add /proc display for per-drive PIO/DMA/UDMA mode and
+ * per-channel ATA-33/66 Cable detect.
+ * Duncan Laurie <void@sun.com>
+ *
+ * fixup /proc output for multiple controllers
+ * Tim Hockin <thockin@sun.com>
+ *
+ * On hpt366:
+ * Reset the hpt366 on error, reset on dma
+ * Fix disabling Fast Interrupt hpt366.
+ * Mike Waychison <crlf@sun.com>
+ *
+ * Added support for 372N clocking and clock switching. The 372N needs
+ * different clocks on read/write. This requires overloading rw_disk and
+ * other deeply crazy things. Thanks to <http://www.hoerstreich.de> for
+ * keeping me sane.
+ * Alan Cox <alan@lxorguk.ukuu.org.uk>
+ *
+ * - fix the clock turnaround code: it was writing to the wrong ports when
+ * called for the secondary channel, caching the current clock mode per-
+ * channel caused the cached register value to get out of sync with the
+ * actual one, the channels weren't serialized, the turnaround shouldn't
+ * be done on 66 MHz PCI bus
+ * - disable UltraATA/100 for HPT370 by default as the 33 MHz clock being used
+ * does not allow for this speed anyway
+ * - avoid touching disabled channels (e.g. HPT371/N are single channel chips,
+ * their primary channel is kind of virtual, it isn't tied to any pins)
+ * - fix/remove bad/unused timing tables and use one set of tables for the whole
+ * HPT37x chip family; save space by introducing the separate transfer mode
+ * table in which the mode lookup is done
+ * - use f_CNT value saved by the HighPoint BIOS as reading it directly gives
+ * the wrong PCI frequency since DPLL has already been calibrated by BIOS;
+ * read it only from the function 0 of HPT374 chips
+ * - fix the hotswap code: it caused RESET- to glitch when tristating the bus,
+ * and for HPT36x the obsolete HDIO_TRISTATE_HWIF handler was called instead
+ * - pass to init_chipset() handlers a copy of the IDE PCI device structure as
+ * they tamper with its fields
+ * - pass to the init_setup handlers a copy of the ide_pci_device_t structure
+ * since they may tamper with its fields
+ * - prefix the driver startup messages with the real chip name
+ * - claim the extra 240 bytes of I/O space for all chips
+ * - optimize the UltraDMA filtering and the drive list lookup code
+ * - use pci_get_slot() to get to the function 1 of HPT36x/374
+ * - cache offset of the channel's misc. control registers (MCRs) being used
+ * throughout the driver
+ * - only touch the relevant MCR when detecting the cable type on HPT374's
+ * function 1
+ * - rename all the register related variables consistently
+ * - move all the interrupt twiddling code from the speedproc handlers into
+ * init_hwif_hpt366(), also grouping all the DMA related code together there
+ * - merge HPT36x/HPT37x speedproc handlers, fix PIO timing register mask and
+ * separate the UltraDMA and MWDMA masks there to avoid changing PIO timings
+ * when setting an UltraDMA mode
+ * - fix hpt3xx_tune_drive() to set the PIO mode requested, not always select
+ * the best possible one
+ * - clean up DMA timeout handling for HPT370
+ * - switch to using the enumeration type to differ between the numerous chip
+ * variants, matching PCI device/revision ID with the chip type early, at the
+ * init_setup stage
+ * - extend the hpt_info structure to hold the DPLL and PCI clock frequencies,
+ * stop duplicating it for each channel by storing the pointer in the pci_dev
+ * structure: first, at the init_setup stage, point it to a static "template"
+ * with only the chip type and its specific base DPLL frequency, the highest
+ * UltraDMA mode, and the chip settings table pointer filled, then, at the
+ * init_chipset stage, allocate per-chip instance and fill it with the rest
+ * of the necessary information
+ * - get rid of the constant thresholds in the HPT37x PCI clock detection code,
+ * switch to calculating PCI clock frequency based on the chip's base DPLL
+ * frequency
+ * - switch to using the DPLL clock and enable UltraATA/133 mode by default on
+ * anything newer than HPT370/A (except HPT374 that is not capable of this
+ * mode according to the manual)
+ * - fold PCI clock detection and DPLL setup code into init_chipset_hpt366(),
+ * also fixing the interchanged 25/40 MHz PCI clock cases for HPT36x chips;
+ * unify HPT36x/37x timing setup code and the speedproc handlers by joining
+ * the register setting lists into the table indexed by the clock selected
+ * - set the correct hwif->ultra_mask for each individual chip
+ * - add Ultra and MW DMA mode filtering for the HPT37[24] based SATA cards
+ * Sergei Shtylyov, <sshtylyov@ru.mvista.com> or <source@mvista.com>
+ */
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/blkdev.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/ide.h>
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+#define DRV_NAME "hpt366"
+
+/* various tuning parameters */
+#define HPT_RESET_STATE_ENGINE
+#undef HPT_DELAY_INTERRUPT
+#define HPT_SERIALIZE_IO 0
+
+static const char *quirk_drives[] = {
+ "QUANTUM FIREBALLlct08 08",
+ "QUANTUM FIREBALLP KA6.4",
+ "QUANTUM FIREBALLP LM20.4",
+ "QUANTUM FIREBALLP LM20.5",
+ NULL
+};
+
+static const char *bad_ata100_5[] = {
+ "IBM-DTLA-307075",
+ "IBM-DTLA-307060",
+ "IBM-DTLA-307045",
+ "IBM-DTLA-307030",
+ "IBM-DTLA-307020",
+ "IBM-DTLA-307015",
+ "IBM-DTLA-305040",
+ "IBM-DTLA-305030",
+ "IBM-DTLA-305020",
+ "IC35L010AVER07-0",
+ "IC35L020AVER07-0",
+ "IC35L030AVER07-0",
+ "IC35L040AVER07-0",
+ "IC35L060AVER07-0",
+ "WDC AC310200R",
+ NULL
+};
+
+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",
+ "MAXTOR STM3320620A",
+ NULL
+};
+
+static const char *bad_ata66_3[] = {
+ "WDC AC310200R",
+ NULL
+};
+
+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 u8 xfer_speeds[] = {
+ XFER_UDMA_6,
+ XFER_UDMA_5,
+ XFER_UDMA_4,
+ XFER_UDMA_3,
+ XFER_UDMA_2,
+ XFER_UDMA_1,
+ XFER_UDMA_0,
+
+ XFER_MW_DMA_2,
+ XFER_MW_DMA_1,
+ XFER_MW_DMA_0,
+
+ XFER_PIO_4,
+ XFER_PIO_3,
+ XFER_PIO_2,
+ XFER_PIO_1,
+ XFER_PIO_0
+};
+
+/* Key for bus clock timings
+ * 36x 37x
+ * bits bits
+ * 0:3 0:3 data_high_time. Inactive time of DIOW_/DIOR_ for PIO and MW DMA.
+ * cycles = value + 1
+ * 4:7 4:8 data_low_time. Active time of DIOW_/DIOR_ for PIO and MW DMA.
+ * cycles = value + 1
+ * 8:11 9:12 cmd_high_time. Inactive time of DIOW_/DIOR_ during task file
+ * register access.
+ * 12:15 13:17 cmd_low_time. Active time of DIOW_/DIOR_ during task file
+ * register access.
+ * 16:18 18:20 udma_cycle_time. Clock cycles for UDMA xfer.
+ * - 21 CLK frequency: 0=ATA clock, 1=dual ATA clock.
+ * 19:21 22:24 pre_high_time. Time to initialize the 1st cycle for PIO and
+ * MW DMA xfer.
+ * 22:24 25:27 cmd_pre_high_time. Time to initialize the 1st PIO cycle for
+ * task file register access.
+ * 28 28 UDMA enable.
+ * 29 29 DMA enable.
+ * 30 30 PIO MST enable. If set, the chip is in bus master mode during
+ * PIO xfer.
+ * 31 31 FIFO enable.
+ */
+
+static u32 forty_base_hpt36x[] = {
+ /* XFER_UDMA_6 */ 0x900fd943,
+ /* XFER_UDMA_5 */ 0x900fd943,
+ /* 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
+};
+
+static u32 thirty_three_base_hpt36x[] = {
+ /* XFER_UDMA_6 */ 0x90c9a731,
+ /* XFER_UDMA_5 */ 0x90c9a731,
+ /* 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 */
+};
+
+static u32 twenty_five_base_hpt36x[] = {
+ /* XFER_UDMA_6 */ 0x90c98521,
+ /* XFER_UDMA_5 */ 0x90c98521,
+ /* 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
+};
+
+#if 0
+/* These are the timing tables from the HighPoint open source drivers... */
+static u32 thirty_three_base_hpt37x[] = {
+ /* XFER_UDMA_6 */ 0x12446231, /* 0x12646231 ?? */
+ /* XFER_UDMA_5 */ 0x12446231,
+ /* XFER_UDMA_4 */ 0x12446231,
+ /* XFER_UDMA_3 */ 0x126c6231,
+ /* XFER_UDMA_2 */ 0x12486231,
+ /* XFER_UDMA_1 */ 0x124c6233,
+ /* XFER_UDMA_0 */ 0x12506297,
+
+ /* XFER_MW_DMA_2 */ 0x22406c31,
+ /* XFER_MW_DMA_1 */ 0x22406c33,
+ /* XFER_MW_DMA_0 */ 0x22406c97,
+
+ /* XFER_PIO_4 */ 0x06414e31,
+ /* XFER_PIO_3 */ 0x06414e42,
+ /* XFER_PIO_2 */ 0x06414e53,
+ /* XFER_PIO_1 */ 0x06814e93,
+ /* XFER_PIO_0 */ 0x06814ea7
+};
+
+static u32 fifty_base_hpt37x[] = {
+ /* XFER_UDMA_6 */ 0x12848242,
+ /* XFER_UDMA_5 */ 0x12848242,
+ /* XFER_UDMA_4 */ 0x12ac8242,
+ /* XFER_UDMA_3 */ 0x128c8242,
+ /* XFER_UDMA_2 */ 0x120c8242,
+ /* XFER_UDMA_1 */ 0x12148254,
+ /* XFER_UDMA_0 */ 0x121882ea,
+
+ /* XFER_MW_DMA_2 */ 0x22808242,
+ /* XFER_MW_DMA_1 */ 0x22808254,
+ /* XFER_MW_DMA_0 */ 0x228082ea,
+
+ /* XFER_PIO_4 */ 0x0a81f442,
+ /* XFER_PIO_3 */ 0x0a81f443,
+ /* XFER_PIO_2 */ 0x0a81f454,
+ /* XFER_PIO_1 */ 0x0ac1f465,
+ /* XFER_PIO_0 */ 0x0ac1f48a
+};
+
+static u32 sixty_six_base_hpt37x[] = {
+ /* XFER_UDMA_6 */ 0x1c869c62,
+ /* XFER_UDMA_5 */ 0x1cae9c62, /* 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 */ 0x2c829d2e,
+
+ /* XFER_PIO_4 */ 0x0c829c62,
+ /* XFER_PIO_3 */ 0x0c829c84,
+ /* XFER_PIO_2 */ 0x0c829ca6,
+ /* XFER_PIO_1 */ 0x0d029d26,
+ /* XFER_PIO_0 */ 0x0d029d5e
+};
+#else
+/*
+ * The following are the new timing tables with PIO mode data/taskfile transfer
+ * overclocking fixed...
+ */
+
+/* This table is taken from the HPT370 data manual rev. 1.02 */
+static u32 thirty_three_base_hpt37x[] = {
+ /* XFER_UDMA_6 */ 0x16455031, /* 0x16655031 ?? */
+ /* XFER_UDMA_5 */ 0x16455031,
+ /* XFER_UDMA_4 */ 0x16455031,
+ /* XFER_UDMA_3 */ 0x166d5031,
+ /* XFER_UDMA_2 */ 0x16495031,
+ /* XFER_UDMA_1 */ 0x164d5033,
+ /* XFER_UDMA_0 */ 0x16515097,
+
+ /* XFER_MW_DMA_2 */ 0x26515031,
+ /* XFER_MW_DMA_1 */ 0x26515033,
+ /* XFER_MW_DMA_0 */ 0x26515097,
+
+ /* XFER_PIO_4 */ 0x06515021,
+ /* XFER_PIO_3 */ 0x06515022,
+ /* XFER_PIO_2 */ 0x06515033,
+ /* XFER_PIO_1 */ 0x06915065,
+ /* XFER_PIO_0 */ 0x06d1508a
+};
+
+static u32 fifty_base_hpt37x[] = {
+ /* XFER_UDMA_6 */ 0x1a861842,
+ /* XFER_UDMA_5 */ 0x1a861842,
+ /* XFER_UDMA_4 */ 0x1aae1842,
+ /* XFER_UDMA_3 */ 0x1a8e1842,
+ /* XFER_UDMA_2 */ 0x1a0e1842,
+ /* XFER_UDMA_1 */ 0x1a161854,
+ /* XFER_UDMA_0 */ 0x1a1a18ea,
+
+ /* XFER_MW_DMA_2 */ 0x2a821842,
+ /* XFER_MW_DMA_1 */ 0x2a821854,
+ /* XFER_MW_DMA_0 */ 0x2a8218ea,
+
+ /* XFER_PIO_4 */ 0x0a821842,
+ /* XFER_PIO_3 */ 0x0a821843,
+ /* XFER_PIO_2 */ 0x0a821855,
+ /* XFER_PIO_1 */ 0x0ac218a8,
+ /* XFER_PIO_0 */ 0x0b02190c
+};
+
+static u32 sixty_six_base_hpt37x[] = {
+ /* XFER_UDMA_6 */ 0x1c86fe62,
+ /* XFER_UDMA_5 */ 0x1caefe62, /* 0x1c8afe62 */
+ /* XFER_UDMA_4 */ 0x1c8afe62,
+ /* XFER_UDMA_3 */ 0x1c8efe62,
+ /* XFER_UDMA_2 */ 0x1c92fe62,
+ /* XFER_UDMA_1 */ 0x1c9afe62,
+ /* XFER_UDMA_0 */ 0x1c82fe62,
+
+ /* XFER_MW_DMA_2 */ 0x2c82fe62,
+ /* XFER_MW_DMA_1 */ 0x2c82fe66,
+ /* XFER_MW_DMA_0 */ 0x2c82ff2e,
+
+ /* XFER_PIO_4 */ 0x0c82fe62,
+ /* XFER_PIO_3 */ 0x0c82fe84,
+ /* XFER_PIO_2 */ 0x0c82fea6,
+ /* XFER_PIO_1 */ 0x0d02ff26,
+ /* XFER_PIO_0 */ 0x0d42ff7f
+};
+#endif
+
+#define HPT366_DEBUG_DRIVE_INFO 0
+#define HPT371_ALLOW_ATA133_6 1
+#define HPT302_ALLOW_ATA133_6 1
+#define HPT372_ALLOW_ATA133_6 1
+#define HPT370_ALLOW_ATA100_5 0
+#define HPT366_ALLOW_ATA66_4 1
+#define HPT366_ALLOW_ATA66_3 1
+#define HPT366_MAX_DEVS 8
+
+/* Supported ATA clock frequencies */
+enum ata_clock {
+ ATA_CLOCK_25MHZ,
+ ATA_CLOCK_33MHZ,
+ ATA_CLOCK_40MHZ,
+ ATA_CLOCK_50MHZ,
+ ATA_CLOCK_66MHZ,
+ NUM_ATA_CLOCKS
+};
+
+struct hpt_timings {
+ u32 pio_mask;
+ u32 dma_mask;
+ u32 ultra_mask;
+ u32 *clock_table[NUM_ATA_CLOCKS];
+};
+
+/*
+ * Hold all the HighPoint chip information in one place.
+ */
+
+struct hpt_info {
+ char *chip_name; /* Chip name */
+ u8 chip_type; /* Chip type */
+ u8 udma_mask; /* Allowed UltraDMA modes mask. */
+ u8 dpll_clk; /* DPLL clock in MHz */
+ u8 pci_clk; /* PCI clock in MHz */
+ struct hpt_timings *timings; /* Chipset timing data */
+ u8 clock; /* ATA clock selected */
+};
+
+/* Supported HighPoint chips */
+enum {
+ HPT36x,
+ HPT370,
+ HPT370A,
+ HPT374,
+ HPT372,
+ HPT372A,
+ HPT302,
+ HPT371,
+ HPT372N,
+ HPT302N,
+ HPT371N
+};
+
+static struct hpt_timings hpt36x_timings = {
+ .pio_mask = 0xc1f8ffff,
+ .dma_mask = 0x303800ff,
+ .ultra_mask = 0x30070000,
+ .clock_table = {
+ [ATA_CLOCK_25MHZ] = twenty_five_base_hpt36x,
+ [ATA_CLOCK_33MHZ] = thirty_three_base_hpt36x,
+ [ATA_CLOCK_40MHZ] = forty_base_hpt36x,
+ [ATA_CLOCK_50MHZ] = NULL,
+ [ATA_CLOCK_66MHZ] = NULL
+ }
+};
+
+static struct hpt_timings hpt37x_timings = {
+ .pio_mask = 0xcfc3ffff,
+ .dma_mask = 0x31c001ff,
+ .ultra_mask = 0x303c0000,
+ .clock_table = {
+ [ATA_CLOCK_25MHZ] = NULL,
+ [ATA_CLOCK_33MHZ] = thirty_three_base_hpt37x,
+ [ATA_CLOCK_40MHZ] = NULL,
+ [ATA_CLOCK_50MHZ] = fifty_base_hpt37x,
+ [ATA_CLOCK_66MHZ] = sixty_six_base_hpt37x
+ }
+};
+
+static const struct hpt_info hpt36x __devinitdata = {
+ .chip_name = "HPT36x",
+ .chip_type = HPT36x,
+ .udma_mask = HPT366_ALLOW_ATA66_3 ? (HPT366_ALLOW_ATA66_4 ? ATA_UDMA4 : ATA_UDMA3) : ATA_UDMA2,
+ .dpll_clk = 0, /* no DPLL */
+ .timings = &hpt36x_timings
+};
+
+static const struct hpt_info hpt370 __devinitdata = {
+ .chip_name = "HPT370",
+ .chip_type = HPT370,
+ .udma_mask = HPT370_ALLOW_ATA100_5 ? ATA_UDMA5 : ATA_UDMA4,
+ .dpll_clk = 48,
+ .timings = &hpt37x_timings
+};
+
+static const struct hpt_info hpt370a __devinitdata = {
+ .chip_name = "HPT370A",
+ .chip_type = HPT370A,
+ .udma_mask = HPT370_ALLOW_ATA100_5 ? ATA_UDMA5 : ATA_UDMA4,
+ .dpll_clk = 48,
+ .timings = &hpt37x_timings
+};
+
+static const struct hpt_info hpt374 __devinitdata = {
+ .chip_name = "HPT374",
+ .chip_type = HPT374,
+ .udma_mask = ATA_UDMA5,
+ .dpll_clk = 48,
+ .timings = &hpt37x_timings
+};
+
+static const struct hpt_info hpt372 __devinitdata = {
+ .chip_name = "HPT372",
+ .chip_type = HPT372,
+ .udma_mask = HPT372_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
+ .dpll_clk = 55,
+ .timings = &hpt37x_timings
+};
+
+static const struct hpt_info hpt372a __devinitdata = {
+ .chip_name = "HPT372A",
+ .chip_type = HPT372A,
+ .udma_mask = HPT372_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
+ .dpll_clk = 66,
+ .timings = &hpt37x_timings
+};
+
+static const struct hpt_info hpt302 __devinitdata = {
+ .chip_name = "HPT302",
+ .chip_type = HPT302,
+ .udma_mask = HPT302_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
+ .dpll_clk = 66,
+ .timings = &hpt37x_timings
+};
+
+static const struct hpt_info hpt371 __devinitdata = {
+ .chip_name = "HPT371",
+ .chip_type = HPT371,
+ .udma_mask = HPT371_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
+ .dpll_clk = 66,
+ .timings = &hpt37x_timings
+};
+
+static const struct hpt_info hpt372n __devinitdata = {
+ .chip_name = "HPT372N",
+ .chip_type = HPT372N,
+ .udma_mask = HPT372_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
+ .dpll_clk = 77,
+ .timings = &hpt37x_timings
+};
+
+static const struct hpt_info hpt302n __devinitdata = {
+ .chip_name = "HPT302N",
+ .chip_type = HPT302N,
+ .udma_mask = HPT302_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
+ .dpll_clk = 77,
+ .timings = &hpt37x_timings
+};
+
+static const struct hpt_info hpt371n __devinitdata = {
+ .chip_name = "HPT371N",
+ .chip_type = HPT371N,
+ .udma_mask = HPT371_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
+ .dpll_clk = 77,
+ .timings = &hpt37x_timings
+};
+
+static int check_in_drive_list(ide_drive_t *drive, const char **list)
+{
+ char *m = (char *)&drive->id[ATA_ID_PROD];
+
+ while (*list)
+ if (!strcmp(*list++, m))
+ return 1;
+ return 0;
+}
+
+static struct hpt_info *hpt3xx_get_info(struct device *dev)
+{
+ struct ide_host *host = dev_get_drvdata(dev);
+ struct hpt_info *info = (struct hpt_info *)host->host_priv;
+
+ return dev == host->dev[1] ? info + 1 : info;
+}
+
+/*
+ * The Marvell bridge chips used on the HighPoint SATA cards do not seem
+ * to support the UltraDMA modes 1, 2, and 3 as well as any MWDMA modes...
+ */
+
+static u8 hpt3xx_udma_filter(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct hpt_info *info = hpt3xx_get_info(hwif->dev);
+ u8 mask = hwif->ultra_mask;
+
+ switch (info->chip_type) {
+ case HPT36x:
+ if (!HPT366_ALLOW_ATA66_4 ||
+ check_in_drive_list(drive, bad_ata66_4))
+ mask = ATA_UDMA3;
+
+ if (!HPT366_ALLOW_ATA66_3 ||
+ check_in_drive_list(drive, bad_ata66_3))
+ mask = ATA_UDMA2;
+ break;
+ case HPT370:
+ if (!HPT370_ALLOW_ATA100_5 ||
+ check_in_drive_list(drive, bad_ata100_5))
+ mask = ATA_UDMA4;
+ break;
+ case HPT370A:
+ if (!HPT370_ALLOW_ATA100_5 ||
+ check_in_drive_list(drive, bad_ata100_5))
+ return ATA_UDMA4;
+ case HPT372 :
+ case HPT372A:
+ case HPT372N:
+ case HPT374 :
+ if (ata_id_is_sata(drive->id))
+ mask &= ~0x0e;
+ /* Fall thru */
+ default:
+ return mask;
+ }
+
+ return check_in_drive_list(drive, bad_ata33) ? 0x00 : mask;
+}
+
+static u8 hpt3xx_mdma_filter(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct hpt_info *info = hpt3xx_get_info(hwif->dev);
+
+ switch (info->chip_type) {
+ case HPT372 :
+ case HPT372A:
+ case HPT372N:
+ case HPT374 :
+ if (ata_id_is_sata(drive->id))
+ return 0x00;
+ /* Fall thru */
+ default:
+ return 0x07;
+ }
+}
+
+static u32 get_speed_setting(u8 speed, struct hpt_info *info)
+{
+ int i;
+
+ /*
+ * Lookup the transfer mode table to get the index into
+ * the timing table.
+ *
+ * NOTE: For XFER_PIO_SLOW, PIO mode 0 timings will be used.
+ */
+ for (i = 0; i < ARRAY_SIZE(xfer_speeds) - 1; i++)
+ if (xfer_speeds[i] == speed)
+ break;
+
+ return info->timings->clock_table[info->clock][i];
+}
+
+static void hpt3xx_set_mode(ide_drive_t *drive, const u8 speed)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+ struct hpt_info *info = hpt3xx_get_info(hwif->dev);
+ struct hpt_timings *t = info->timings;
+ u8 itr_addr = 0x40 + (drive->dn * 4);
+ u32 old_itr = 0;
+ u32 new_itr = get_speed_setting(speed, info);
+ u32 itr_mask = speed < XFER_MW_DMA_0 ? t->pio_mask :
+ (speed < XFER_UDMA_0 ? t->dma_mask :
+ t->ultra_mask);
+
+ pci_read_config_dword(dev, itr_addr, &old_itr);
+ new_itr = (old_itr & ~itr_mask) | (new_itr & itr_mask);
+ /*
+ * Disable on-chip PIO FIFO/buffer (and PIO MST mode as well)
+ * to avoid problems handling I/O errors later
+ */
+ new_itr &= ~0xc0000000;
+
+ pci_write_config_dword(dev, itr_addr, new_itr);
+}
+
+static void hpt3xx_set_pio_mode(ide_drive_t *drive, const u8 pio)
+{
+ hpt3xx_set_mode(drive, XFER_PIO_0 + pio);
+}
+
+static void hpt3xx_quirkproc(ide_drive_t *drive)
+{
+ char *m = (char *)&drive->id[ATA_ID_PROD];
+ const char **list = quirk_drives;
+
+ while (*list)
+ if (strstr(m, *list++)) {
+ drive->quirk_list = 1;
+ return;
+ }
+
+ drive->quirk_list = 0;
+}
+
+static void hpt3xx_maskproc(ide_drive_t *drive, int mask)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+ struct hpt_info *info = hpt3xx_get_info(hwif->dev);
+
+ if (drive->quirk_list == 0)
+ return;
+
+ if (info->chip_type >= HPT370) {
+ u8 scr1 = 0;
+
+ pci_read_config_byte(dev, 0x5a, &scr1);
+ if (((scr1 & 0x10) >> 4) != mask) {
+ if (mask)
+ scr1 |= 0x10;
+ else
+ scr1 &= ~0x10;
+ pci_write_config_byte(dev, 0x5a, scr1);
+ }
+ } else if (mask)
+ disable_irq(hwif->irq);
+ else
+ enable_irq(hwif->irq);
+}
+
+/*
+ * This is specific to the HPT366 UDMA chipset
+ * by HighPoint|Triones Technologies, Inc.
+ */
+static void hpt366_dma_lost_irq(ide_drive_t *drive)
+{
+ struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
+ u8 mcr1 = 0, mcr3 = 0, scr1 = 0;
+
+ pci_read_config_byte(dev, 0x50, &mcr1);
+ pci_read_config_byte(dev, 0x52, &mcr3);
+ pci_read_config_byte(dev, 0x5a, &scr1);
+ printk("%s: (%s) mcr1=0x%02x, mcr3=0x%02x, scr1=0x%02x\n",
+ drive->name, __func__, mcr1, mcr3, scr1);
+ if (scr1 & 0x10)
+ pci_write_config_byte(dev, 0x5a, scr1 & ~0x10);
+ ide_dma_lost_irq(drive);
+}
+
+static void hpt370_clear_engine(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+
+ pci_write_config_byte(dev, hwif->select_data, 0x37);
+ udelay(10);
+}
+
+static void hpt370_irq_timeout(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+ u16 bfifo = 0;
+ u8 dma_cmd;
+
+ pci_read_config_word(dev, hwif->select_data + 2, &bfifo);
+ printk(KERN_DEBUG "%s: %d bytes in FIFO\n", drive->name, bfifo & 0x1ff);
+
+ /* get DMA command mode */
+ dma_cmd = inb(hwif->dma_base + ATA_DMA_CMD);
+ /* stop DMA */
+ outb(dma_cmd & ~0x1, hwif->dma_base + ATA_DMA_CMD);
+ hpt370_clear_engine(drive);
+}
+
+static void hpt370_dma_start(ide_drive_t *drive)
+{
+#ifdef HPT_RESET_STATE_ENGINE
+ hpt370_clear_engine(drive);
+#endif
+ ide_dma_start(drive);
+}
+
+static int hpt370_dma_end(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ u8 dma_stat = inb(hwif->dma_base + ATA_DMA_STATUS);
+
+ if (dma_stat & 0x01) {
+ /* wait a little */
+ udelay(20);
+ dma_stat = inb(hwif->dma_base + ATA_DMA_STATUS);
+ if (dma_stat & 0x01)
+ hpt370_irq_timeout(drive);
+ }
+ return ide_dma_end(drive);
+}
+
+static void hpt370_dma_timeout(ide_drive_t *drive)
+{
+ hpt370_irq_timeout(drive);
+ ide_dma_timeout(drive);
+}
+
+/* returns 1 if DMA IRQ issued, 0 otherwise */
+static int hpt374_dma_test_irq(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+ u16 bfifo = 0;
+ u8 dma_stat;
+
+ pci_read_config_word(dev, hwif->select_data + 2, &bfifo);
+ if (bfifo & 0x1FF) {
+// printk("%s: %d bytes in FIFO\n", drive->name, bfifo);
+ return 0;
+ }
+
+ dma_stat = inb(hwif->dma_base + ATA_DMA_STATUS);
+ /* return 1 if INTR asserted */
+ if (dma_stat & 4)
+ return 1;
+
+ return 0;
+}
+
+static int hpt374_dma_end(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+ u8 mcr = 0, mcr_addr = hwif->select_data;
+ u8 bwsr = 0, mask = hwif->channel ? 0x02 : 0x01;
+
+ pci_read_config_byte(dev, 0x6a, &bwsr);
+ pci_read_config_byte(dev, mcr_addr, &mcr);
+ if (bwsr & mask)
+ pci_write_config_byte(dev, mcr_addr, mcr | 0x30);
+ return ide_dma_end(drive);
+}
+
+/**
+ * hpt3xxn_set_clock - perform clock switching dance
+ * @hwif: hwif to switch
+ * @mode: clocking mode (0x21 for write, 0x23 otherwise)
+ *
+ * Switch the DPLL clock on the HPT3xxN devices. This is a right mess.
+ */
+
+static void hpt3xxn_set_clock(ide_hwif_t *hwif, u8 mode)
+{
+ unsigned long base = hwif->extra_base;
+ u8 scr2 = inb(base + 0x6b);
+
+ if ((scr2 & 0x7f) == mode)
+ return;
+
+ /* Tristate the bus */
+ outb(0x80, base + 0x63);
+ outb(0x80, base + 0x67);
+
+ /* Switch clock and reset channels */
+ outb(mode, base + 0x6b);
+ outb(0xc0, base + 0x69);
+
+ /*
+ * Reset the state machines.
+ * NOTE: avoid accidentally enabling the disabled channels.
+ */
+ outb(inb(base + 0x60) | 0x32, base + 0x60);
+ outb(inb(base + 0x64) | 0x32, base + 0x64);
+
+ /* Complete reset */
+ outb(0x00, base + 0x69);
+
+ /* Reconnect channels to bus */
+ outb(0x00, base + 0x63);
+ outb(0x00, base + 0x67);
+}
+
+/**
+ * hpt3xxn_rw_disk - prepare for I/O
+ * @drive: drive for command
+ * @rq: block request structure
+ *
+ * This is called when a disk I/O is issued to HPT3xxN.
+ * We need it because of the clock switching.
+ */
+
+static void hpt3xxn_rw_disk(ide_drive_t *drive, struct request *rq)
+{
+ hpt3xxn_set_clock(HWIF(drive), rq_data_dir(rq) ? 0x23 : 0x21);
+}
+
+/**
+ * hpt37x_calibrate_dpll - calibrate the DPLL
+ * @dev: PCI device
+ *
+ * Perform a calibration cycle on the DPLL.
+ * Returns 1 if this succeeds
+ */
+static int hpt37x_calibrate_dpll(struct pci_dev *dev, u16 f_low, u16 f_high)
+{
+ u32 dpll = (f_high << 16) | f_low | 0x100;
+ u8 scr2;
+ int i;
+
+ pci_write_config_dword(dev, 0x5c, dpll);
+
+ /* Wait for oscillator ready */
+ for(i = 0; i < 0x5000; ++i) {
+ udelay(50);
+ pci_read_config_byte(dev, 0x5b, &scr2);
+ if (scr2 & 0x80)
+ break;
+ }
+ /* See if it stays ready (we'll just bail out if it's not yet) */
+ for(i = 0; i < 0x1000; ++i) {
+ pci_read_config_byte(dev, 0x5b, &scr2);
+ /* DPLL destabilized? */
+ if(!(scr2 & 0x80))
+ return 0;
+ }
+ /* Turn off tuning, we have the DPLL set */
+ pci_read_config_dword (dev, 0x5c, &dpll);
+ pci_write_config_dword(dev, 0x5c, (dpll & ~0x100));
+ return 1;
+}
+
+static void hpt3xx_disable_fast_irq(struct pci_dev *dev, u8 mcr_addr)
+{
+ struct ide_host *host = pci_get_drvdata(dev);
+ struct hpt_info *info = host->host_priv + (&dev->dev == host->dev[1]);
+ u8 chip_type = info->chip_type;
+ u8 new_mcr, old_mcr = 0;
+
+ /*
+ * Disable the "fast interrupt" prediction. Don't hold off
+ * on interrupts. (== 0x01 despite what the docs say)
+ */
+ pci_read_config_byte(dev, mcr_addr + 1, &old_mcr);
+
+ if (chip_type >= HPT374)
+ new_mcr = old_mcr & ~0x07;
+ else if (chip_type >= HPT370) {
+ new_mcr = old_mcr;
+ new_mcr &= ~0x02;
+#ifdef HPT_DELAY_INTERRUPT
+ new_mcr &= ~0x01;
+#else
+ new_mcr |= 0x01;
+#endif
+ } else /* HPT366 and HPT368 */
+ new_mcr = old_mcr & ~0x80;
+
+ if (new_mcr != old_mcr)
+ pci_write_config_byte(dev, mcr_addr + 1, new_mcr);
+}
+
+static unsigned int init_chipset_hpt366(struct pci_dev *dev)
+{
+ unsigned long io_base = pci_resource_start(dev, 4);
+ struct hpt_info *info = hpt3xx_get_info(&dev->dev);
+ const char *name = DRV_NAME;
+ u8 pci_clk, dpll_clk = 0; /* PCI and DPLL clock in MHz */
+ u8 chip_type;
+ enum ata_clock clock;
+
+ chip_type = info->chip_type;
+
+ 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);
+
+ /*
+ * First, try to estimate the PCI clock frequency...
+ */
+ if (chip_type >= HPT370) {
+ u8 scr1 = 0;
+ u16 f_cnt = 0;
+ u32 temp = 0;
+
+ /* Interrupt force enable. */
+ pci_read_config_byte(dev, 0x5a, &scr1);
+ if (scr1 & 0x10)
+ pci_write_config_byte(dev, 0x5a, scr1 & ~0x10);
+
+ /*
+ * HighPoint does this for HPT372A.
+ * NOTE: This register is only writeable via I/O space.
+ */
+ if (chip_type == HPT372A)
+ outb(0x0e, io_base + 0x9c);
+
+ /*
+ * Default to PCI clock. Make sure MA15/16 are set to output
+ * to prevent drives having problems with 40-pin cables.
+ */
+ pci_write_config_byte(dev, 0x5b, 0x23);
+
+ /*
+ * We'll have to read f_CNT value in order to determine
+ * the PCI clock frequency according to the following ratio:
+ *
+ * f_CNT = Fpci * 192 / Fdpll
+ *
+ * First try reading the register in which the HighPoint BIOS
+ * saves f_CNT value before reprogramming the DPLL from its
+ * default setting (which differs for the various chips).
+ *
+ * NOTE: This register is only accessible via I/O space;
+ * HPT374 BIOS only saves it for the function 0, so we have to
+ * always read it from there -- no need to check the result of
+ * pci_get_slot() for the function 0 as the whole device has
+ * been already "pinned" (via function 1) in init_setup_hpt374()
+ */
+ if (chip_type == HPT374 && (PCI_FUNC(dev->devfn) & 1)) {
+ struct pci_dev *dev1 = pci_get_slot(dev->bus,
+ dev->devfn - 1);
+ unsigned long io_base = pci_resource_start(dev1, 4);
+
+ temp = inl(io_base + 0x90);
+ pci_dev_put(dev1);
+ } else
+ temp = inl(io_base + 0x90);
+
+ /*
+ * In case the signature check fails, we'll have to
+ * resort to reading the f_CNT register itself in hopes
+ * that nobody has touched the DPLL yet...
+ */
+ if ((temp & 0xFFFFF000) != 0xABCDE000) {
+ int i;
+
+ printk(KERN_WARNING "%s %s: no clock data saved by "
+ "BIOS\n", name, pci_name(dev));
+
+ /* Calculate the average value of f_CNT. */
+ for (temp = i = 0; i < 128; i++) {
+ pci_read_config_word(dev, 0x78, &f_cnt);
+ temp += f_cnt & 0x1ff;
+ mdelay(1);
+ }
+ f_cnt = temp / 128;
+ } else
+ f_cnt = temp & 0x1ff;
+
+ dpll_clk = info->dpll_clk;
+ pci_clk = (f_cnt * dpll_clk) / 192;
+
+ /* Clamp PCI clock to bands. */
+ if (pci_clk < 40)
+ pci_clk = 33;
+ else if(pci_clk < 45)
+ pci_clk = 40;
+ else if(pci_clk < 55)
+ pci_clk = 50;
+ else
+ pci_clk = 66;
+
+ printk(KERN_INFO "%s %s: DPLL base: %d MHz, f_CNT: %d, "
+ "assuming %d MHz PCI\n", name, pci_name(dev),
+ dpll_clk, f_cnt, pci_clk);
+ } else {
+ u32 itr1 = 0;
+
+ pci_read_config_dword(dev, 0x40, &itr1);
+
+ /* Detect PCI clock by looking at cmd_high_time. */
+ switch((itr1 >> 8) & 0x07) {
+ case 0x09:
+ pci_clk = 40;
+ break;
+ case 0x05:
+ pci_clk = 25;
+ break;
+ case 0x07:
+ default:
+ pci_clk = 33;
+ break;
+ }
+ }
+
+ /* Let's assume we'll use PCI clock for the ATA clock... */
+ switch (pci_clk) {
+ case 25:
+ clock = ATA_CLOCK_25MHZ;
+ break;
+ case 33:
+ default:
+ clock = ATA_CLOCK_33MHZ;
+ break;
+ case 40:
+ clock = ATA_CLOCK_40MHZ;
+ break;
+ case 50:
+ clock = ATA_CLOCK_50MHZ;
+ break;
+ case 66:
+ clock = ATA_CLOCK_66MHZ;
+ break;
+ }
+
+ /*
+ * Only try the DPLL if we don't have a table for the PCI clock that
+ * we are running at for HPT370/A, always use it for anything newer...
+ *
+ * NOTE: Using the internal DPLL results in slow reads on 33 MHz PCI.
+ * We also don't like using the DPLL because this causes glitches
+ * on PRST-/SRST- when the state engine gets reset...
+ */
+ if (chip_type >= HPT374 || info->timings->clock_table[clock] == NULL) {
+ u16 f_low, delta = pci_clk < 50 ? 2 : 4;
+ int adjust;
+
+ /*
+ * Select 66 MHz DPLL clock only if UltraATA/133 mode is
+ * supported/enabled, use 50 MHz DPLL clock otherwise...
+ */
+ if (info->udma_mask == ATA_UDMA6) {
+ dpll_clk = 66;
+ clock = ATA_CLOCK_66MHZ;
+ } else if (dpll_clk) { /* HPT36x chips don't have DPLL */
+ dpll_clk = 50;
+ clock = ATA_CLOCK_50MHZ;
+ }
+
+ if (info->timings->clock_table[clock] == NULL) {
+ printk(KERN_ERR "%s %s: unknown bus timing!\n",
+ name, pci_name(dev));
+ return -EIO;
+ }
+
+ /* Select the DPLL clock. */
+ pci_write_config_byte(dev, 0x5b, 0x21);
+
+ /*
+ * Adjust the DPLL based upon PCI clock, enable it,
+ * and wait for stabilization...
+ */
+ f_low = (pci_clk * 48) / dpll_clk;
+
+ for (adjust = 0; adjust < 8; adjust++) {
+ if(hpt37x_calibrate_dpll(dev, f_low, f_low + delta))
+ break;
+
+ /*
+ * See if it'll settle at a fractionally different clock
+ */
+ if (adjust & 1)
+ f_low -= adjust >> 1;
+ else
+ f_low += adjust >> 1;
+ }
+ if (adjust == 8) {
+ printk(KERN_ERR "%s %s: DPLL did not stabilize!\n",
+ name, pci_name(dev));
+ return -EIO;
+ }
+
+ printk(KERN_INFO "%s %s: using %d MHz DPLL clock\n",
+ name, pci_name(dev), dpll_clk);
+ } else {
+ /* Mark the fact that we're not using the DPLL. */
+ dpll_clk = 0;
+
+ printk(KERN_INFO "%s %s: using %d MHz PCI clock\n",
+ name, pci_name(dev), pci_clk);
+ }
+
+ /* Store the clock frequencies. */
+ info->dpll_clk = dpll_clk;
+ info->pci_clk = pci_clk;
+ info->clock = clock;
+
+ if (chip_type >= HPT370) {
+ u8 mcr1, mcr4;
+
+ /*
+ * Reset the state engines.
+ * NOTE: Avoid accidentally enabling the disabled channels.
+ */
+ pci_read_config_byte (dev, 0x50, &mcr1);
+ pci_read_config_byte (dev, 0x54, &mcr4);
+ pci_write_config_byte(dev, 0x50, (mcr1 | 0x32));
+ pci_write_config_byte(dev, 0x54, (mcr4 | 0x32));
+ udelay(100);
+ }
+
+ /*
+ * On HPT371N, if ATA clock is 66 MHz we must set bit 2 in
+ * the MISC. register to stretch the UltraDMA Tss timing.
+ * NOTE: This register is only writeable via I/O space.
+ */
+ if (chip_type == HPT371N && clock == ATA_CLOCK_66MHZ)
+ outb(inb(io_base + 0x9c) | 0x04, io_base + 0x9c);
+
+ hpt3xx_disable_fast_irq(dev, 0x50);
+ hpt3xx_disable_fast_irq(dev, 0x54);
+
+ return dev->irq;
+}
+
+static u8 hpt3xx_cable_detect(ide_hwif_t *hwif)
+{
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+ struct hpt_info *info = hpt3xx_get_info(hwif->dev);
+ u8 chip_type = info->chip_type;
+ u8 scr1 = 0, ata66 = hwif->channel ? 0x01 : 0x02;
+
+ /*
+ * The HPT37x uses the CBLID pins as outputs for MA15/MA16
+ * address lines to access an external EEPROM. To read valid
+ * cable detect state the pins must be enabled as inputs.
+ */
+ if (chip_type == HPT374 && (PCI_FUNC(dev->devfn) & 1)) {
+ /*
+ * HPT374 PCI function 1
+ * - set bit 15 of reg 0x52 to enable TCBLID as input
+ * - set bit 15 of reg 0x56 to enable FCBLID as input
+ */
+ u8 mcr_addr = hwif->select_data + 2;
+ u16 mcr;
+
+ pci_read_config_word(dev, mcr_addr, &mcr);
+ pci_write_config_word(dev, mcr_addr, (mcr | 0x8000));
+ /* now read cable id register */
+ pci_read_config_byte(dev, 0x5a, &scr1);
+ pci_write_config_word(dev, mcr_addr, mcr);
+ } else if (chip_type >= HPT370) {
+ /*
+ * HPT370/372 and 374 pcifn 0
+ * - clear bit 0 of reg 0x5b to enable P/SCBLID as inputs
+ */
+ u8 scr2 = 0;
+
+ pci_read_config_byte(dev, 0x5b, &scr2);
+ pci_write_config_byte(dev, 0x5b, (scr2 & ~1));
+ /* now read cable id register */
+ pci_read_config_byte(dev, 0x5a, &scr1);
+ pci_write_config_byte(dev, 0x5b, scr2);
+ } else
+ pci_read_config_byte(dev, 0x5a, &scr1);
+
+ return (scr1 & ata66) ? ATA_CBL_PATA40 : ATA_CBL_PATA80;
+}
+
+static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
+{
+ struct hpt_info *info = hpt3xx_get_info(hwif->dev);
+ int serialize = HPT_SERIALIZE_IO;
+ u8 chip_type = info->chip_type;
+
+ /* Cache the channel's MISC. control registers' offset */
+ hwif->select_data = hwif->channel ? 0x54 : 0x50;
+
+ /*
+ * HPT3xxN chips have some complications:
+ *
+ * - on 33 MHz PCI we must clock switch
+ * - on 66 MHz PCI we must NOT use the PCI clock
+ */
+ if (chip_type >= HPT372N && info->dpll_clk && info->pci_clk < 66) {
+ /*
+ * Clock is shared between the channels,
+ * so we'll have to serialize them... :-(
+ */
+ serialize = 1;
+ hwif->rw_disk = &hpt3xxn_rw_disk;
+ }
+
+ /* Serialize access to this device if needed */
+ if (serialize && hwif->mate)
+ hwif->serialized = hwif->mate->serialized = 1;
+}
+
+static int __devinit init_dma_hpt366(ide_hwif_t *hwif,
+ const struct ide_port_info *d)
+{
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+ unsigned long flags, base = ide_pci_dma_base(hwif, d);
+ u8 dma_old, dma_new, masterdma = 0, slavedma = 0;
+
+ if (base == 0)
+ return -1;
+
+ hwif->dma_base = base;
+
+ if (ide_pci_check_simplex(hwif, d) < 0)
+ return -1;
+
+ if (ide_pci_set_master(dev, d->name) < 0)
+ return -1;
+
+ dma_old = inb(base + 2);
+
+ local_irq_save(flags);
+
+ dma_new = dma_old;
+ pci_read_config_byte(dev, hwif->channel ? 0x4b : 0x43, &masterdma);
+ pci_read_config_byte(dev, hwif->channel ? 0x4f : 0x47, &slavedma);
+
+ if (masterdma & 0x30) dma_new |= 0x20;
+ if ( slavedma & 0x30) dma_new |= 0x40;
+ if (dma_new != dma_old)
+ outb(dma_new, base + 2);
+
+ local_irq_restore(flags);
+
+ printk(KERN_INFO " %s: BM-DMA at 0x%04lx-0x%04lx\n",
+ hwif->name, base, base + 7);
+
+ hwif->extra_base = base + (hwif->channel ? 8 : 16);
+
+ if (ide_allocate_dma_engine(hwif))
+ return -1;
+
+ hwif->dma_ops = &sff_dma_ops;
+
+ return 0;
+}
+
+static void __devinit hpt374_init(struct pci_dev *dev, struct pci_dev *dev2)
+{
+ if (dev2->irq != dev->irq) {
+ /* FIXME: we need a core pci_set_interrupt() */
+ dev2->irq = dev->irq;
+ printk(KERN_INFO DRV_NAME " %s: PCI config space interrupt "
+ "fixed\n", pci_name(dev2));
+ }
+}
+
+static void __devinit hpt371_init(struct pci_dev *dev)
+{
+ u8 mcr1 = 0;
+
+ /*
+ * HPT371 chips physically have only one channel, the secondary one,
+ * but the primary channel registers do exist! Go figure...
+ * So, we manually disable the non-existing channel here
+ * (if the BIOS hasn't done this already).
+ */
+ pci_read_config_byte(dev, 0x50, &mcr1);
+ if (mcr1 & 0x04)
+ pci_write_config_byte(dev, 0x50, mcr1 & ~0x04);
+}
+
+static int __devinit hpt36x_init(struct pci_dev *dev, struct pci_dev *dev2)
+{
+ u8 mcr1 = 0, pin1 = 0, pin2 = 0;
+
+ /*
+ * Now we'll have to force both channels enabled if
+ * at least one of them has been enabled by BIOS...
+ */
+ pci_read_config_byte(dev, 0x50, &mcr1);
+ if (mcr1 & 0x30)
+ pci_write_config_byte(dev, 0x50, mcr1 | 0x30);
+
+ pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin1);
+ pci_read_config_byte(dev2, PCI_INTERRUPT_PIN, &pin2);
+
+ if (pin1 != pin2 && dev->irq == dev2->irq) {
+ printk(KERN_INFO DRV_NAME " %s: onboard version of chipset, "
+ "pin1=%d pin2=%d\n", pci_name(dev), pin1, pin2);
+ return 1;
+ }
+
+ return 0;
+}
+
+#define IDE_HFLAGS_HPT3XX \
+ (IDE_HFLAG_NO_ATAPI_DMA | \
+ IDE_HFLAG_OFF_BOARD)
+
+static const struct ide_port_ops hpt3xx_port_ops = {
+ .set_pio_mode = hpt3xx_set_pio_mode,
+ .set_dma_mode = hpt3xx_set_mode,
+ .quirkproc = hpt3xx_quirkproc,
+ .maskproc = hpt3xx_maskproc,
+ .mdma_filter = hpt3xx_mdma_filter,
+ .udma_filter = hpt3xx_udma_filter,
+ .cable_detect = hpt3xx_cable_detect,
+};
+
+static const struct ide_dma_ops hpt37x_dma_ops = {
+ .dma_host_set = ide_dma_host_set,
+ .dma_setup = ide_dma_setup,
+ .dma_exec_cmd = ide_dma_exec_cmd,
+ .dma_start = ide_dma_start,
+ .dma_end = hpt374_dma_end,
+ .dma_test_irq = hpt374_dma_test_irq,
+ .dma_lost_irq = ide_dma_lost_irq,
+ .dma_timeout = ide_dma_timeout,
+};
+
+static const struct ide_dma_ops hpt370_dma_ops = {
+ .dma_host_set = ide_dma_host_set,
+ .dma_setup = ide_dma_setup,
+ .dma_exec_cmd = ide_dma_exec_cmd,
+ .dma_start = hpt370_dma_start,
+ .dma_end = hpt370_dma_end,
+ .dma_test_irq = ide_dma_test_irq,
+ .dma_lost_irq = ide_dma_lost_irq,
+ .dma_timeout = hpt370_dma_timeout,
+};
+
+static const struct ide_dma_ops hpt36x_dma_ops = {
+ .dma_host_set = ide_dma_host_set,
+ .dma_setup = ide_dma_setup,
+ .dma_exec_cmd = ide_dma_exec_cmd,
+ .dma_start = ide_dma_start,
+ .dma_end = ide_dma_end,
+ .dma_test_irq = ide_dma_test_irq,
+ .dma_lost_irq = hpt366_dma_lost_irq,
+ .dma_timeout = ide_dma_timeout,
+};
+
+static const struct ide_port_info hpt366_chipsets[] __devinitdata = {
+ { /* 0: HPT36x */
+ .name = DRV_NAME,
+ .init_chipset = init_chipset_hpt366,
+ .init_hwif = init_hwif_hpt366,
+ .init_dma = init_dma_hpt366,
+ /*
+ * HPT36x chips have one channel per function and have
+ * both channel enable bits located differently and visible
+ * to both functions -- really stupid design decision... :-(
+ * Bit 4 is for the primary channel, bit 5 for the secondary.
+ */
+ .enablebits = {{0x50,0x10,0x10}, {0x54,0x04,0x04}},
+ .port_ops = &hpt3xx_port_ops,
+ .dma_ops = &hpt36x_dma_ops,
+ .host_flags = IDE_HFLAGS_HPT3XX | IDE_HFLAG_SINGLE,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ },
+ { /* 1: HPT3xx */
+ .name = DRV_NAME,
+ .init_chipset = init_chipset_hpt366,
+ .init_hwif = init_hwif_hpt366,
+ .init_dma = init_dma_hpt366,
+ .enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
+ .port_ops = &hpt3xx_port_ops,
+ .dma_ops = &hpt37x_dma_ops,
+ .host_flags = IDE_HFLAGS_HPT3XX,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ }
+};
+
+/**
+ * hpt366_init_one - called when an HPT366 is found
+ * @dev: the hpt366 device
+ * @id: the matching pci id
+ *
+ * Called when the PCI registration layer (or the IDE initialization)
+ * finds a device matching our IDE device tables.
+ */
+static int __devinit hpt366_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ const struct hpt_info *info = NULL;
+ struct hpt_info *dyn_info;
+ struct pci_dev *dev2 = NULL;
+ struct ide_port_info d;
+ u8 idx = id->driver_data;
+ u8 rev = dev->revision;
+ int ret;
+
+ if ((idx == 0 || idx == 4) && (PCI_FUNC(dev->devfn) & 1))
+ return -ENODEV;
+
+ switch (idx) {
+ case 0:
+ if (rev < 3)
+ info = &hpt36x;
+ else {
+ switch (min_t(u8, rev, 6)) {
+ case 3: info = &hpt370; break;
+ case 4: info = &hpt370a; break;
+ case 5: info = &hpt372; break;
+ case 6: info = &hpt372n; break;
+ }
+ idx++;
+ }
+ break;
+ case 1:
+ info = (rev > 1) ? &hpt372n : &hpt372a;
+ break;
+ case 2:
+ info = (rev > 1) ? &hpt302n : &hpt302;
+ break;
+ case 3:
+ hpt371_init(dev);
+ info = (rev > 1) ? &hpt371n : &hpt371;
+ break;
+ case 4:
+ info = &hpt374;
+ break;
+ case 5:
+ info = &hpt372n;
+ break;
+ }
+
+ printk(KERN_INFO DRV_NAME ": %s chipset detected\n", info->chip_name);
+
+ d = hpt366_chipsets[min_t(u8, idx, 1)];
+
+ d.udma_mask = info->udma_mask;
+
+ /* fixup ->dma_ops for HPT370/HPT370A */
+ if (info == &hpt370 || info == &hpt370a)
+ d.dma_ops = &hpt370_dma_ops;
+
+ if (info == &hpt36x || info == &hpt374)
+ dev2 = pci_get_slot(dev->bus, dev->devfn + 1);
+
+ dyn_info = kzalloc(sizeof(*dyn_info) * (dev2 ? 2 : 1), GFP_KERNEL);
+ if (dyn_info == NULL) {
+ printk(KERN_ERR "%s %s: out of memory!\n",
+ d.name, pci_name(dev));
+ pci_dev_put(dev2);
+ return -ENOMEM;
+ }
+
+ /*
+ * Copy everything from a static "template" structure
+ * to just allocated per-chip hpt_info structure.
+ */
+ memcpy(dyn_info, info, sizeof(*dyn_info));
+
+ if (dev2) {
+ memcpy(dyn_info + 1, info, sizeof(*dyn_info));
+
+ if (info == &hpt374)
+ hpt374_init(dev, dev2);
+ else {
+ if (hpt36x_init(dev, dev2))
+ d.host_flags &= ~IDE_HFLAG_NON_BOOTABLE;
+ }
+
+ ret = ide_pci_init_two(dev, dev2, &d, dyn_info);
+ if (ret < 0) {
+ pci_dev_put(dev2);
+ kfree(dyn_info);
+ }
+ return ret;
+ }
+
+ ret = ide_pci_init_one(dev, &d, dyn_info);
+ if (ret < 0)
+ kfree(dyn_info);
+
+ return ret;
+}
+
+static void __devexit hpt366_remove(struct pci_dev *dev)
+{
+ struct ide_host *host = pci_get_drvdata(dev);
+ struct ide_info *info = host->host_priv;
+ struct pci_dev *dev2 = host->dev[1] ? to_pci_dev(host->dev[1]) : NULL;
+
+ ide_pci_remove(dev);
+ pci_dev_put(dev2);
+ kfree(info);
+}
+
+static const struct pci_device_id hpt366_pci_tbl[] __devinitconst = {
+ { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT366), 0 },
+ { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT372), 1 },
+ { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT302), 2 },
+ { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT371), 3 },
+ { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT374), 4 },
+ { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT372N), 5 },
+ { 0, },
+};
+MODULE_DEVICE_TABLE(pci, hpt366_pci_tbl);
+
+static struct pci_driver hpt366_pci_driver = {
+ .name = "HPT366_IDE",
+ .id_table = hpt366_pci_tbl,
+ .probe = hpt366_init_one,
+ .remove = __devexit_p(hpt366_remove),
+ .suspend = ide_pci_suspend,
+ .resume = ide_pci_resume,
+};
+
+static int __init hpt366_ide_init(void)
+{
+ return ide_pci_register_driver(&hpt366_pci_driver);
+}
+
+static void __exit hpt366_ide_exit(void)
+{
+ pci_unregister_driver(&hpt366_pci_driver);
+}
+
+module_init(hpt366_ide_init);
+module_exit(hpt366_ide_exit);
+
+MODULE_AUTHOR("Andre Hedrick");
+MODULE_DESCRIPTION("PCI driver module for Highpoint HPT366 IDE");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/ht6560b.c b/drivers/ide/ht6560b.c
new file mode 100644
index 0000000..c7e5c22
--- /dev/null
+++ b/drivers/ide/ht6560b.c
@@ -0,0 +1,351 @@
+/*
+ * Copyright (C) 1995-2000 Linus Torvalds & author (see below)
+ */
+
+/*
+ * HT-6560B EIDE-controller support
+ * To activate controller support use kernel parameter "ide0=ht6560b".
+ * Use hdparm utility to enable PIO mode support.
+ *
+ * Author: Mikko Ala-Fossi <maf@iki.fi>
+ * Jan Evert van Grootheest <j.e.van.grootheest@caiway.nl>
+ *
+ * Try: http://www.maf.iki.fi/~maf/ht6560b/
+ */
+
+#define DRV_NAME "ht6560b"
+#define HT6560B_VERSION "v0.08"
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+/* #define DEBUG */ /* remove comments for DEBUG messages */
+
+/*
+ * The special i/o-port that HT-6560B uses to configuration:
+ * bit0 (0x01): "1" selects secondary interface
+ * bit2 (0x04): "1" enables FIFO function
+ * bit5 (0x20): "1" enables prefetched data read function (???)
+ *
+ * The special i/o-port that HT-6560A uses to configuration:
+ * bit0 (0x01): "1" selects secondary interface
+ * bit1 (0x02): "1" enables prefetched data read function
+ * bit2 (0x04): "0" enables multi-master system (?)
+ * bit3 (0x08): "1" 3 cycle time, "0" 2 cycle time (?)
+ */
+#define HT_CONFIG_PORT 0x3e6
+#define HT_CONFIG(drivea) (u8)(((drivea)->drive_data & 0xff00) >> 8)
+/*
+ * FIFO + PREFETCH (both a/b-model)
+ */
+#define HT_CONFIG_DEFAULT 0x1c /* no prefetch */
+/* #define HT_CONFIG_DEFAULT 0x3c */ /* with prefetch */
+#define HT_SECONDARY_IF 0x01
+#define HT_PREFETCH_MODE 0x20
+
+/*
+ * ht6560b Timing values:
+ *
+ * I reviewed some assembler source listings of htide drivers and found
+ * out how they setup those cycle time interfacing values, as they at Holtek
+ * call them. IDESETUP.COM that is supplied with the drivers figures out
+ * optimal values and fetches those values to drivers. I found out that
+ * they use Select register to fetch timings to the ide board right after
+ * interface switching. After that it was quite easy to add code to
+ * ht6560b.c.
+ *
+ * IDESETUP.COM gave me values 0x24, 0x45, 0xaa, 0xff that worked fine
+ * for hda and hdc. But hdb needed higher values to work, so I guess
+ * that sometimes it is necessary to give higher value than IDESETUP
+ * gives. [see cmd640.c for an extreme example of this. -ml]
+ *
+ * Perhaps I should explain something about these timing values:
+ * The higher nibble of value is the Recovery Time (rt) and the lower nibble
+ * of the value is the Active Time (at). Minimum value 2 is the fastest and
+ * the maximum value 15 is the slowest. Default values should be 15 for both.
+ * So 0x24 means 2 for rt and 4 for at. Each of the drives should have
+ * both values, and IDESETUP gives automatically rt=15 st=15 for CDROMs or
+ * similar. If value is too small there will be all sorts of failures.
+ *
+ * Timing byte consists of
+ * High nibble: Recovery Cycle Time (rt)
+ * The valid values range from 2 to 15. The default is 15.
+ *
+ * Low nibble: Active Cycle Time (at)
+ * The valid values range from 2 to 15. The default is 15.
+ *
+ * You can obtain optimized timing values by running Holtek IDESETUP.COM
+ * for DOS. DOS drivers get their timing values from command line, where
+ * the first value is the Recovery Time and the second value is the
+ * Active Time for each drive. Smaller value gives higher speed.
+ * In case of failures you should probably fall back to a higher value.
+ */
+#define HT_TIMING(drivea) (u8)((drivea)->drive_data & 0x00ff)
+#define HT_TIMING_DEFAULT 0xff
+
+/*
+ * This routine handles interface switching for the peculiar hardware design
+ * on the F.G.I./Holtek HT-6560B VLB IDE interface.
+ * The HT-6560B can only enable one IDE port at a time, and requires a
+ * silly sequence (below) whenever we switch between primary and secondary.
+ */
+
+/*
+ * This routine is invoked from ide.c to prepare for access to a given drive.
+ */
+static void ht6560b_selectproc (ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ unsigned long flags;
+ static u8 current_select = 0;
+ static u8 current_timing = 0;
+ u8 select, timing;
+
+ local_irq_save(flags);
+
+ select = HT_CONFIG(drive);
+ timing = HT_TIMING(drive);
+
+ /*
+ * Need to enforce prefetch sometimes because otherwise
+ * it'll hang (hard).
+ */
+ if (drive->media != ide_disk ||
+ (drive->dev_flags & IDE_DFLAG_PRESENT) == 0)
+ select |= HT_PREFETCH_MODE;
+
+ if (select != current_select || timing != current_timing) {
+ current_select = select;
+ current_timing = timing;
+ (void)inb(HT_CONFIG_PORT);
+ (void)inb(HT_CONFIG_PORT);
+ (void)inb(HT_CONFIG_PORT);
+ (void)inb(HT_CONFIG_PORT);
+ outb(select, HT_CONFIG_PORT);
+ /*
+ * Set timing for this drive:
+ */
+ outb(timing, hwif->io_ports.device_addr);
+ (void)inb(hwif->io_ports.status_addr);
+#ifdef DEBUG
+ printk("ht6560b: %s: select=%#x timing=%#x\n",
+ drive->name, select, timing);
+#endif
+ }
+ local_irq_restore(flags);
+}
+
+/*
+ * Autodetection and initialization of ht6560b
+ */
+static int __init try_to_init_ht6560b(void)
+{
+ u8 orig_value;
+ int i;
+
+ /* Autodetect ht6560b */
+ if ((orig_value = inb(HT_CONFIG_PORT)) == 0xff)
+ return 0;
+
+ for (i=3;i>0;i--) {
+ outb(0x00, HT_CONFIG_PORT);
+ if (!( (~inb(HT_CONFIG_PORT)) & 0x3f )) {
+ outb(orig_value, HT_CONFIG_PORT);
+ return 0;
+ }
+ }
+ outb(0x00, HT_CONFIG_PORT);
+ if ((~inb(HT_CONFIG_PORT))& 0x3f) {
+ outb(orig_value, HT_CONFIG_PORT);
+ return 0;
+ }
+ /*
+ * Ht6560b autodetected
+ */
+ outb(HT_CONFIG_DEFAULT, HT_CONFIG_PORT);
+ outb(HT_TIMING_DEFAULT, 0x1f6); /* Select register */
+ (void)inb(0x1f7); /* Status register */
+
+ printk("ht6560b " HT6560B_VERSION
+ ": chipset detected and initialized"
+#ifdef DEBUG
+ " with debug enabled"
+#endif
+ "\n"
+ );
+ return 1;
+}
+
+static u8 ht_pio2timings(ide_drive_t *drive, const u8 pio)
+{
+ int active_time, recovery_time;
+ int active_cycles, recovery_cycles;
+ int bus_speed = ide_vlb_clk ? ide_vlb_clk : 50;
+
+ if (pio) {
+ unsigned int cycle_time;
+ struct ide_timing *t = ide_timing_find_mode(XFER_PIO_0 + pio);
+
+ cycle_time = ide_pio_cycle_time(drive, pio);
+
+ /*
+ * Just like opti621.c we try to calculate the
+ * actual cycle time for recovery and activity
+ * according system bus speed.
+ */
+ active_time = t->active;
+ recovery_time = cycle_time - active_time - t->setup;
+ /*
+ * Cycle times should be Vesa bus cycles
+ */
+ active_cycles = (active_time * bus_speed + 999) / 1000;
+ recovery_cycles = (recovery_time * bus_speed + 999) / 1000;
+ /*
+ * Upper and lower limits
+ */
+ if (active_cycles < 2) active_cycles = 2;
+ if (recovery_cycles < 2) recovery_cycles = 2;
+ if (active_cycles > 15) active_cycles = 15;
+ if (recovery_cycles > 15) recovery_cycles = 0; /* 0==16 */
+
+#ifdef DEBUG
+ printk("ht6560b: drive %s setting pio=%d recovery=%d (%dns) active=%d (%dns)\n", drive->name, pio, recovery_cycles, recovery_time, active_cycles, active_time);
+#endif
+
+ return (u8)((recovery_cycles << 4) | active_cycles);
+ } else {
+
+#ifdef DEBUG
+ printk("ht6560b: drive %s setting pio=0\n", drive->name);
+#endif
+
+ return HT_TIMING_DEFAULT; /* default setting */
+ }
+}
+
+static DEFINE_SPINLOCK(ht6560b_lock);
+
+/*
+ * Enable/Disable so called prefetch mode
+ */
+static void ht_set_prefetch(ide_drive_t *drive, u8 state)
+{
+ unsigned long flags;
+ int t = HT_PREFETCH_MODE << 8;
+
+ spin_lock_irqsave(&ht6560b_lock, flags);
+
+ /*
+ * Prefetch mode and unmask irq seems to conflict
+ */
+ if (state) {
+ drive->drive_data |= t; /* enable prefetch mode */
+ drive->dev_flags |= IDE_DFLAG_NO_UNMASK;
+ drive->dev_flags &= ~IDE_DFLAG_UNMASK;
+ } else {
+ drive->drive_data &= ~t; /* disable prefetch mode */
+ drive->dev_flags &= ~IDE_DFLAG_NO_UNMASK;
+ }
+
+ spin_unlock_irqrestore(&ht6560b_lock, flags);
+
+#ifdef DEBUG
+ printk("ht6560b: drive %s prefetch mode %sabled\n", drive->name, (state ? "en" : "dis"));
+#endif
+}
+
+static void ht6560b_set_pio_mode(ide_drive_t *drive, const u8 pio)
+{
+ unsigned long flags;
+ u8 timing;
+
+ switch (pio) {
+ case 8: /* set prefetch off */
+ case 9: /* set prefetch on */
+ ht_set_prefetch(drive, pio & 1);
+ return;
+ }
+
+ timing = ht_pio2timings(drive, pio);
+
+ spin_lock_irqsave(&ht6560b_lock, flags);
+ drive->drive_data &= 0xff00;
+ drive->drive_data |= timing;
+ spin_unlock_irqrestore(&ht6560b_lock, flags);
+
+#ifdef DEBUG
+ printk("ht6560b: drive %s tuned to pio mode %#x timing=%#x\n", drive->name, pio, timing);
+#endif
+}
+
+static void __init ht6560b_init_dev(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ /* Setting default configurations for drives. */
+ int t = (HT_CONFIG_DEFAULT << 8) | HT_TIMING_DEFAULT;
+
+ if (hwif->channel)
+ t |= (HT_SECONDARY_IF << 8);
+
+ drive->drive_data = t;
+}
+
+static int probe_ht6560b;
+
+module_param_named(probe, probe_ht6560b, bool, 0);
+MODULE_PARM_DESC(probe, "probe for HT6560B chipset");
+
+static const struct ide_port_ops ht6560b_port_ops = {
+ .init_dev = ht6560b_init_dev,
+ .set_pio_mode = ht6560b_set_pio_mode,
+ .selectproc = ht6560b_selectproc,
+};
+
+static const struct ide_port_info ht6560b_port_info __initdata = {
+ .name = DRV_NAME,
+ .chipset = ide_ht6560b,
+ .port_ops = &ht6560b_port_ops,
+ .host_flags = IDE_HFLAG_SERIALIZE | /* is this needed? */
+ IDE_HFLAG_NO_DMA |
+ IDE_HFLAG_ABUSE_PREFETCH,
+ .pio_mask = ATA_PIO4,
+};
+
+static int __init ht6560b_init(void)
+{
+ if (probe_ht6560b == 0)
+ return -ENODEV;
+
+ if (!request_region(HT_CONFIG_PORT, 1, DRV_NAME)) {
+ printk(KERN_NOTICE "%s: HT_CONFIG_PORT not found\n",
+ __func__);
+ return -ENODEV;
+ }
+
+ if (!try_to_init_ht6560b()) {
+ printk(KERN_NOTICE "%s: HBA not found\n", __func__);
+ goto release_region;
+ }
+
+ return ide_legacy_device_add(&ht6560b_port_info, 0);
+
+release_region:
+ release_region(HT_CONFIG_PORT, 1);
+ return -ENODEV;
+}
+
+module_init(ht6560b_init);
+
+MODULE_AUTHOR("See Local File");
+MODULE_DESCRIPTION("HT-6560B EIDE-controller support");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/icside.c b/drivers/ide/icside.c
new file mode 100644
index 0000000..81f70ca
--- /dev/null
+++ b/drivers/ide/icside.c
@@ -0,0 +1,703 @@
+/*
+ * Copyright (c) 1996-2004 Russell King.
+ *
+ * Please note that this platform does not support 32-bit IDE IO.
+ */
+
+#include <linux/string.h>
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/blkdev.h>
+#include <linux/errno.h>
+#include <linux/ide.h>
+#include <linux/dma-mapping.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/scatterlist.h>
+#include <linux/io.h>
+
+#include <asm/dma.h>
+#include <asm/ecard.h>
+
+#define DRV_NAME "icside"
+
+#define ICS_IDENT_OFFSET 0x2280
+
+#define ICS_ARCIN_V5_INTRSTAT 0x0000
+#define ICS_ARCIN_V5_INTROFFSET 0x0004
+#define ICS_ARCIN_V5_IDEOFFSET 0x2800
+#define ICS_ARCIN_V5_IDEALTOFFSET 0x2b80
+#define ICS_ARCIN_V5_IDESTEPPING 6
+
+#define ICS_ARCIN_V6_IDEOFFSET_1 0x2000
+#define ICS_ARCIN_V6_INTROFFSET_1 0x2200
+#define ICS_ARCIN_V6_INTRSTAT_1 0x2290
+#define ICS_ARCIN_V6_IDEALTOFFSET_1 0x2380
+#define ICS_ARCIN_V6_IDEOFFSET_2 0x3000
+#define ICS_ARCIN_V6_INTROFFSET_2 0x3200
+#define ICS_ARCIN_V6_INTRSTAT_2 0x3290
+#define ICS_ARCIN_V6_IDEALTOFFSET_2 0x3380
+#define ICS_ARCIN_V6_IDESTEPPING 6
+
+struct cardinfo {
+ unsigned int dataoffset;
+ unsigned int ctrloffset;
+ unsigned int stepping;
+};
+
+static struct cardinfo icside_cardinfo_v5 = {
+ .dataoffset = ICS_ARCIN_V5_IDEOFFSET,
+ .ctrloffset = ICS_ARCIN_V5_IDEALTOFFSET,
+ .stepping = ICS_ARCIN_V5_IDESTEPPING,
+};
+
+static struct cardinfo icside_cardinfo_v6_1 = {
+ .dataoffset = ICS_ARCIN_V6_IDEOFFSET_1,
+ .ctrloffset = ICS_ARCIN_V6_IDEALTOFFSET_1,
+ .stepping = ICS_ARCIN_V6_IDESTEPPING,
+};
+
+static struct cardinfo icside_cardinfo_v6_2 = {
+ .dataoffset = ICS_ARCIN_V6_IDEOFFSET_2,
+ .ctrloffset = ICS_ARCIN_V6_IDEALTOFFSET_2,
+ .stepping = ICS_ARCIN_V6_IDESTEPPING,
+};
+
+struct icside_state {
+ unsigned int channel;
+ unsigned int enabled;
+ void __iomem *irq_port;
+ void __iomem *ioc_base;
+ unsigned int sel;
+ unsigned int type;
+ struct ide_host *host;
+};
+
+#define ICS_TYPE_A3IN 0
+#define ICS_TYPE_A3USER 1
+#define ICS_TYPE_V6 3
+#define ICS_TYPE_V5 15
+#define ICS_TYPE_NOTYPE ((unsigned int)-1)
+
+/* ---------------- Version 5 PCB Support Functions --------------------- */
+/* Prototype: icside_irqenable_arcin_v5 (struct expansion_card *ec, int irqnr)
+ * Purpose : enable interrupts from card
+ */
+static void icside_irqenable_arcin_v5 (struct expansion_card *ec, int irqnr)
+{
+ struct icside_state *state = ec->irq_data;
+
+ writeb(0, state->irq_port + ICS_ARCIN_V5_INTROFFSET);
+}
+
+/* Prototype: icside_irqdisable_arcin_v5 (struct expansion_card *ec, int irqnr)
+ * Purpose : disable interrupts from card
+ */
+static void icside_irqdisable_arcin_v5 (struct expansion_card *ec, int irqnr)
+{
+ struct icside_state *state = ec->irq_data;
+
+ readb(state->irq_port + ICS_ARCIN_V5_INTROFFSET);
+}
+
+static const expansioncard_ops_t icside_ops_arcin_v5 = {
+ .irqenable = icside_irqenable_arcin_v5,
+ .irqdisable = icside_irqdisable_arcin_v5,
+};
+
+
+/* ---------------- Version 6 PCB Support Functions --------------------- */
+/* Prototype: icside_irqenable_arcin_v6 (struct expansion_card *ec, int irqnr)
+ * Purpose : enable interrupts from card
+ */
+static void icside_irqenable_arcin_v6 (struct expansion_card *ec, int irqnr)
+{
+ struct icside_state *state = ec->irq_data;
+ void __iomem *base = state->irq_port;
+
+ state->enabled = 1;
+
+ switch (state->channel) {
+ case 0:
+ writeb(0, base + ICS_ARCIN_V6_INTROFFSET_1);
+ readb(base + ICS_ARCIN_V6_INTROFFSET_2);
+ break;
+ case 1:
+ writeb(0, base + ICS_ARCIN_V6_INTROFFSET_2);
+ readb(base + ICS_ARCIN_V6_INTROFFSET_1);
+ break;
+ }
+}
+
+/* Prototype: icside_irqdisable_arcin_v6 (struct expansion_card *ec, int irqnr)
+ * Purpose : disable interrupts from card
+ */
+static void icside_irqdisable_arcin_v6 (struct expansion_card *ec, int irqnr)
+{
+ struct icside_state *state = ec->irq_data;
+
+ state->enabled = 0;
+
+ readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_1);
+ readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_2);
+}
+
+/* Prototype: icside_irqprobe(struct expansion_card *ec)
+ * Purpose : detect an active interrupt from card
+ */
+static int icside_irqpending_arcin_v6(struct expansion_card *ec)
+{
+ struct icside_state *state = ec->irq_data;
+
+ return readb(state->irq_port + ICS_ARCIN_V6_INTRSTAT_1) & 1 ||
+ readb(state->irq_port + ICS_ARCIN_V6_INTRSTAT_2) & 1;
+}
+
+static const expansioncard_ops_t icside_ops_arcin_v6 = {
+ .irqenable = icside_irqenable_arcin_v6,
+ .irqdisable = icside_irqdisable_arcin_v6,
+ .irqpending = icside_irqpending_arcin_v6,
+};
+
+/*
+ * Handle routing of interrupts. This is called before
+ * we write the command to the drive.
+ */
+static void icside_maskproc(ide_drive_t *drive, int mask)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct expansion_card *ec = ECARD_DEV(hwif->dev);
+ struct icside_state *state = ecard_get_drvdata(ec);
+ unsigned long flags;
+
+ local_irq_save(flags);
+
+ state->channel = hwif->channel;
+
+ if (state->enabled && !mask) {
+ switch (hwif->channel) {
+ case 0:
+ writeb(0, state->irq_port + ICS_ARCIN_V6_INTROFFSET_1);
+ readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_2);
+ break;
+ case 1:
+ writeb(0, state->irq_port + ICS_ARCIN_V6_INTROFFSET_2);
+ readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_1);
+ break;
+ }
+ } else {
+ readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_2);
+ readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_1);
+ }
+
+ local_irq_restore(flags);
+}
+
+static const struct ide_port_ops icside_v6_no_dma_port_ops = {
+ .maskproc = icside_maskproc,
+};
+
+#ifdef CONFIG_BLK_DEV_IDEDMA_ICS
+/*
+ * SG-DMA support.
+ *
+ * Similar to the BM-DMA, but we use the RiscPCs IOMD DMA controllers.
+ * There is only one DMA controller per card, which means that only
+ * one drive can be accessed at one time. NOTE! We do not enforce that
+ * here, but we rely on the main IDE driver spotting that both
+ * interfaces use the same IRQ, which should guarantee this.
+ */
+
+/*
+ * Configure the IOMD to give the appropriate timings for the transfer
+ * mode being requested. We take the advice of the ATA standards, and
+ * calculate the cycle time based on the transfer mode, and the EIDE
+ * MW DMA specs that the drive provides in the IDENTIFY command.
+ *
+ * We have the following IOMD DMA modes to choose from:
+ *
+ * Type Active Recovery Cycle
+ * A 250 (250) 312 (550) 562 (800)
+ * B 187 250 437
+ * C 125 (125) 125 (375) 250 (500)
+ * D 62 125 187
+ *
+ * (figures in brackets are actual measured timings)
+ *
+ * However, we also need to take care of the read/write active and
+ * recovery timings:
+ *
+ * Read Write
+ * Mode Active -- Recovery -- Cycle IOMD type
+ * MW0 215 50 215 480 A
+ * MW1 80 50 50 150 C
+ * MW2 70 25 25 120 C
+ */
+static void icside_set_dma_mode(ide_drive_t *drive, const u8 xfer_mode)
+{
+ int cycle_time, use_dma_info = 0;
+
+ switch (xfer_mode) {
+ case XFER_MW_DMA_2:
+ cycle_time = 250;
+ use_dma_info = 1;
+ break;
+
+ case XFER_MW_DMA_1:
+ cycle_time = 250;
+ use_dma_info = 1;
+ break;
+
+ case XFER_MW_DMA_0:
+ cycle_time = 480;
+ break;
+
+ case XFER_SW_DMA_2:
+ case XFER_SW_DMA_1:
+ case XFER_SW_DMA_0:
+ cycle_time = 480;
+ break;
+ }
+
+ /*
+ * If we're going to be doing MW_DMA_1 or MW_DMA_2, we should
+ * take care to note the values in the ID...
+ */
+ if (use_dma_info && drive->id[ATA_ID_EIDE_DMA_TIME] > cycle_time)
+ cycle_time = drive->id[ATA_ID_EIDE_DMA_TIME];
+
+ drive->drive_data = cycle_time;
+
+ printk("%s: %s selected (peak %dMB/s)\n", drive->name,
+ ide_xfer_verbose(xfer_mode), 2000 / drive->drive_data);
+}
+
+static const struct ide_port_ops icside_v6_port_ops = {
+ .set_dma_mode = icside_set_dma_mode,
+ .maskproc = icside_maskproc,
+};
+
+static void icside_dma_host_set(ide_drive_t *drive, int on)
+{
+}
+
+static int icside_dma_end(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct expansion_card *ec = ECARD_DEV(hwif->dev);
+
+ drive->waiting_for_dma = 0;
+
+ disable_dma(ec->dma);
+
+ /* Teardown mappings after DMA has completed. */
+ ide_destroy_dmatable(drive);
+
+ return get_dma_residue(ec->dma) != 0;
+}
+
+static void icside_dma_start(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct expansion_card *ec = ECARD_DEV(hwif->dev);
+
+ /* We can not enable DMA on both channels simultaneously. */
+ BUG_ON(dma_channel_active(ec->dma));
+ enable_dma(ec->dma);
+}
+
+static int icside_dma_setup(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct expansion_card *ec = ECARD_DEV(hwif->dev);
+ struct icside_state *state = ecard_get_drvdata(ec);
+ struct request *rq = hwif->hwgroup->rq;
+ unsigned int dma_mode;
+
+ if (rq_data_dir(rq))
+ dma_mode = DMA_MODE_WRITE;
+ else
+ dma_mode = DMA_MODE_READ;
+
+ /*
+ * We can not enable DMA on both channels.
+ */
+ BUG_ON(dma_channel_active(ec->dma));
+
+ hwif->sg_nents = ide_build_sglist(drive, rq);
+
+ /*
+ * Ensure that we have the right interrupt routed.
+ */
+ icside_maskproc(drive, 0);
+
+ /*
+ * Route the DMA signals to the correct interface.
+ */
+ writeb(state->sel | hwif->channel, state->ioc_base);
+
+ /*
+ * Select the correct timing for this drive.
+ */
+ set_dma_speed(ec->dma, drive->drive_data);
+
+ /*
+ * Tell the DMA engine about the SG table and
+ * data direction.
+ */
+ set_dma_sg(ec->dma, hwif->sg_table, hwif->sg_nents);
+ set_dma_mode(ec->dma, dma_mode);
+
+ drive->waiting_for_dma = 1;
+
+ return 0;
+}
+
+static void icside_dma_exec_cmd(ide_drive_t *drive, u8 cmd)
+{
+ /* issue cmd to drive */
+ ide_execute_command(drive, cmd, ide_dma_intr, 2 * WAIT_CMD, NULL);
+}
+
+static int icside_dma_test_irq(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct expansion_card *ec = ECARD_DEV(hwif->dev);
+ struct icside_state *state = ecard_get_drvdata(ec);
+
+ return readb(state->irq_port +
+ (hwif->channel ?
+ ICS_ARCIN_V6_INTRSTAT_2 :
+ ICS_ARCIN_V6_INTRSTAT_1)) & 1;
+}
+
+static int icside_dma_init(ide_hwif_t *hwif, const struct ide_port_info *d)
+{
+ hwif->dmatable_cpu = NULL;
+ hwif->dmatable_dma = 0;
+
+ return 0;
+}
+
+static const struct ide_dma_ops icside_v6_dma_ops = {
+ .dma_host_set = icside_dma_host_set,
+ .dma_setup = icside_dma_setup,
+ .dma_exec_cmd = icside_dma_exec_cmd,
+ .dma_start = icside_dma_start,
+ .dma_end = icside_dma_end,
+ .dma_test_irq = icside_dma_test_irq,
+ .dma_timeout = ide_dma_timeout,
+ .dma_lost_irq = ide_dma_lost_irq,
+};
+#else
+#define icside_v6_dma_ops NULL
+#endif
+
+static int icside_dma_off_init(ide_hwif_t *hwif, const struct ide_port_info *d)
+{
+ return -EOPNOTSUPP;
+}
+
+static void icside_setup_ports(hw_regs_t *hw, void __iomem *base,
+ struct cardinfo *info, struct expansion_card *ec)
+{
+ unsigned long port = (unsigned long)base + info->dataoffset;
+
+ hw->io_ports.data_addr = port;
+ hw->io_ports.error_addr = port + (1 << info->stepping);
+ hw->io_ports.nsect_addr = port + (2 << info->stepping);
+ hw->io_ports.lbal_addr = port + (3 << info->stepping);
+ hw->io_ports.lbam_addr = port + (4 << info->stepping);
+ hw->io_ports.lbah_addr = port + (5 << info->stepping);
+ hw->io_ports.device_addr = port + (6 << info->stepping);
+ hw->io_ports.status_addr = port + (7 << info->stepping);
+ hw->io_ports.ctl_addr = (unsigned long)base + info->ctrloffset;
+
+ hw->irq = ec->irq;
+ hw->dev = &ec->dev;
+ hw->chipset = ide_acorn;
+}
+
+static int __devinit
+icside_register_v5(struct icside_state *state, struct expansion_card *ec)
+{
+ void __iomem *base;
+ struct ide_host *host;
+ hw_regs_t hw, *hws[] = { &hw, NULL, NULL, NULL };
+ int ret;
+
+ base = ecardm_iomap(ec, ECARD_RES_MEMC, 0, 0);
+ if (!base)
+ return -ENOMEM;
+
+ state->irq_port = base;
+
+ ec->irqaddr = base + ICS_ARCIN_V5_INTRSTAT;
+ ec->irqmask = 1;
+
+ ecard_setirq(ec, &icside_ops_arcin_v5, state);
+
+ /*
+ * Be on the safe side - disable interrupts
+ */
+ icside_irqdisable_arcin_v5(ec, 0);
+
+ icside_setup_ports(&hw, base, &icside_cardinfo_v5, ec);
+
+ host = ide_host_alloc(NULL, hws);
+ if (host == NULL)
+ return -ENODEV;
+
+ state->host = host;
+
+ ecard_set_drvdata(ec, state);
+
+ ret = ide_host_register(host, NULL, hws);
+ if (ret)
+ goto err_free;
+
+ return 0;
+err_free:
+ ide_host_free(host);
+ ecard_set_drvdata(ec, NULL);
+ return ret;
+}
+
+static const struct ide_port_info icside_v6_port_info __initdata = {
+ .init_dma = icside_dma_off_init,
+ .port_ops = &icside_v6_no_dma_port_ops,
+ .dma_ops = &icside_v6_dma_ops,
+ .host_flags = IDE_HFLAG_SERIALIZE | IDE_HFLAG_MMIO,
+ .mwdma_mask = ATA_MWDMA2,
+ .swdma_mask = ATA_SWDMA2,
+};
+
+static int __devinit
+icside_register_v6(struct icside_state *state, struct expansion_card *ec)
+{
+ void __iomem *ioc_base, *easi_base;
+ struct ide_host *host;
+ unsigned int sel = 0;
+ int ret;
+ hw_regs_t hw[2], *hws[] = { &hw[0], NULL, NULL, NULL };
+ struct ide_port_info d = icside_v6_port_info;
+
+ ioc_base = ecardm_iomap(ec, ECARD_RES_IOCFAST, 0, 0);
+ if (!ioc_base) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ easi_base = ioc_base;
+
+ if (ecard_resource_flags(ec, ECARD_RES_EASI)) {
+ easi_base = ecardm_iomap(ec, ECARD_RES_EASI, 0, 0);
+ if (!easi_base) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /*
+ * Enable access to the EASI region.
+ */
+ sel = 1 << 5;
+ }
+
+ writeb(sel, ioc_base);
+
+ ecard_setirq(ec, &icside_ops_arcin_v6, state);
+
+ state->irq_port = easi_base;
+ state->ioc_base = ioc_base;
+ state->sel = sel;
+
+ /*
+ * Be on the safe side - disable interrupts
+ */
+ icside_irqdisable_arcin_v6(ec, 0);
+
+ icside_setup_ports(&hw[0], easi_base, &icside_cardinfo_v6_1, ec);
+ icside_setup_ports(&hw[1], easi_base, &icside_cardinfo_v6_2, ec);
+
+ host = ide_host_alloc(&d, hws);
+ if (host == NULL)
+ return -ENODEV;
+
+ state->host = host;
+
+ ecard_set_drvdata(ec, state);
+
+ if (ec->dma != NO_DMA && !request_dma(ec->dma, DRV_NAME)) {
+ d.init_dma = icside_dma_init;
+ d.port_ops = &icside_v6_port_ops;
+ d.dma_ops = NULL;
+ }
+
+ ret = ide_host_register(host, NULL, hws);
+ if (ret)
+ goto err_free;
+
+ return 0;
+err_free:
+ ide_host_free(host);
+ if (d.dma_ops)
+ free_dma(ec->dma);
+ ecard_set_drvdata(ec, NULL);
+out:
+ return ret;
+}
+
+static int __devinit
+icside_probe(struct expansion_card *ec, const struct ecard_id *id)
+{
+ struct icside_state *state;
+ void __iomem *idmem;
+ int ret;
+
+ ret = ecard_request_resources(ec);
+ if (ret)
+ goto out;
+
+ state = kzalloc(sizeof(struct icside_state), GFP_KERNEL);
+ if (!state) {
+ ret = -ENOMEM;
+ goto release;
+ }
+
+ state->type = ICS_TYPE_NOTYPE;
+
+ idmem = ecardm_iomap(ec, ECARD_RES_IOCFAST, 0, 0);
+ if (idmem) {
+ unsigned int type;
+
+ type = readb(idmem + ICS_IDENT_OFFSET) & 1;
+ type |= (readb(idmem + ICS_IDENT_OFFSET + 4) & 1) << 1;
+ type |= (readb(idmem + ICS_IDENT_OFFSET + 8) & 1) << 2;
+ type |= (readb(idmem + ICS_IDENT_OFFSET + 12) & 1) << 3;
+ ecardm_iounmap(ec, idmem);
+
+ state->type = type;
+ }
+
+ switch (state->type) {
+ case ICS_TYPE_A3IN:
+ dev_warn(&ec->dev, "A3IN unsupported\n");
+ ret = -ENODEV;
+ break;
+
+ case ICS_TYPE_A3USER:
+ dev_warn(&ec->dev, "A3USER unsupported\n");
+ ret = -ENODEV;
+ break;
+
+ case ICS_TYPE_V5:
+ ret = icside_register_v5(state, ec);
+ break;
+
+ case ICS_TYPE_V6:
+ ret = icside_register_v6(state, ec);
+ break;
+
+ default:
+ dev_warn(&ec->dev, "unknown interface type\n");
+ ret = -ENODEV;
+ break;
+ }
+
+ if (ret == 0)
+ goto out;
+
+ kfree(state);
+ release:
+ ecard_release_resources(ec);
+ out:
+ return ret;
+}
+
+static void __devexit icside_remove(struct expansion_card *ec)
+{
+ struct icside_state *state = ecard_get_drvdata(ec);
+
+ switch (state->type) {
+ case ICS_TYPE_V5:
+ /* FIXME: tell IDE to stop using the interface */
+
+ /* Disable interrupts */
+ icside_irqdisable_arcin_v5(ec, 0);
+ break;
+
+ case ICS_TYPE_V6:
+ /* FIXME: tell IDE to stop using the interface */
+ if (ec->dma != NO_DMA)
+ free_dma(ec->dma);
+
+ /* Disable interrupts */
+ icside_irqdisable_arcin_v6(ec, 0);
+
+ /* Reset the ROM pointer/EASI selection */
+ writeb(0, state->ioc_base);
+ break;
+ }
+
+ ecard_set_drvdata(ec, NULL);
+
+ kfree(state);
+ ecard_release_resources(ec);
+}
+
+static void icside_shutdown(struct expansion_card *ec)
+{
+ struct icside_state *state = ecard_get_drvdata(ec);
+ unsigned long flags;
+
+ /*
+ * Disable interrupts from this card. We need to do
+ * this before disabling EASI since we may be accessing
+ * this register via that region.
+ */
+ local_irq_save(flags);
+ ec->ops->irqdisable(ec, 0);
+ local_irq_restore(flags);
+
+ /*
+ * Reset the ROM pointer so that we can read the ROM
+ * after a soft reboot. This also disables access to
+ * the IDE taskfile via the EASI region.
+ */
+ if (state->ioc_base)
+ writeb(0, state->ioc_base);
+}
+
+static const struct ecard_id icside_ids[] = {
+ { MANU_ICS, PROD_ICS_IDE },
+ { MANU_ICS2, PROD_ICS2_IDE },
+ { 0xffff, 0xffff }
+};
+
+static struct ecard_driver icside_driver = {
+ .probe = icside_probe,
+ .remove = __devexit_p(icside_remove),
+ .shutdown = icside_shutdown,
+ .id_table = icside_ids,
+ .drv = {
+ .name = "icside",
+ },
+};
+
+static int __init icside_init(void)
+{
+ return ecard_register_driver(&icside_driver);
+}
+
+static void __exit icside_exit(void)
+{
+ ecard_remove_driver(&icside_driver);
+}
+
+MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("ICS IDE driver");
+
+module_init(icside_init);
+module_exit(icside_exit);
diff --git a/drivers/ide/ide-4drives.c b/drivers/ide/ide-4drives.c
new file mode 100644
index 0000000..9e85b1e
--- /dev/null
+++ b/drivers/ide/ide-4drives.c
@@ -0,0 +1,63 @@
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/ide.h>
+
+#define DRV_NAME "ide-4drives"
+
+static int probe_4drives;
+
+module_param_named(probe, probe_4drives, bool, 0);
+MODULE_PARM_DESC(probe, "probe for generic IDE chipset with 4 drives/port");
+
+static void ide_4drives_init_dev(ide_drive_t *drive)
+{
+ if (drive->hwif->channel)
+ drive->select ^= 0x20;
+}
+
+static const struct ide_port_ops ide_4drives_port_ops = {
+ .init_dev = ide_4drives_init_dev,
+};
+
+static const struct ide_port_info ide_4drives_port_info = {
+ .port_ops = &ide_4drives_port_ops,
+ .host_flags = IDE_HFLAG_SERIALIZE | IDE_HFLAG_NO_DMA,
+};
+
+static int __init ide_4drives_init(void)
+{
+ unsigned long base = 0x1f0, ctl = 0x3f6;
+ hw_regs_t hw, *hws[] = { &hw, &hw, NULL, NULL };
+
+ if (probe_4drives == 0)
+ return -ENODEV;
+
+ if (!request_region(base, 8, DRV_NAME)) {
+ printk(KERN_ERR "%s: I/O resource 0x%lX-0x%lX not free.\n",
+ DRV_NAME, base, base + 7);
+ return -EBUSY;
+ }
+
+ if (!request_region(ctl, 1, DRV_NAME)) {
+ printk(KERN_ERR "%s: I/O resource 0x%lX not free.\n",
+ DRV_NAME, ctl);
+ release_region(base, 8);
+ return -EBUSY;
+ }
+
+ memset(&hw, 0, sizeof(hw));
+
+ ide_std_init_ports(&hw, base, ctl);
+ hw.irq = 14;
+ hw.chipset = ide_4drives;
+
+ return ide_host_add(&ide_4drives_port_info, hws, NULL);
+}
+
+module_init(ide_4drives_init);
+
+MODULE_AUTHOR("Bartlomiej Zolnierkiewicz");
+MODULE_DESCRIPTION("generic IDE chipset with 4 drives/port support");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/ide-acpi.c b/drivers/ide/ide-acpi.c
new file mode 100644
index 0000000..244a8a0
--- /dev/null
+++ b/drivers/ide/ide-acpi.c
@@ -0,0 +1,754 @@
+/*
+ * Provides ACPI support for IDE drives.
+ *
+ * Copyright (C) 2005 Intel Corp.
+ * Copyright (C) 2005 Randy Dunlap
+ * Copyright (C) 2006 SUSE Linux Products GmbH
+ * Copyright (C) 2006 Hannes Reinecke
+ */
+
+#include <linux/ata.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <acpi/acpi.h>
+#include <linux/ide.h>
+#include <linux/pci.h>
+#include <linux/dmi.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 REGS_PER_GTF 7
+struct taskfile_array {
+ u8 tfa[REGS_PER_GTF]; /* regs. 0x1f1 - 0x1f7 */
+};
+
+struct GTM_buffer {
+ u32 PIO_speed0;
+ u32 DMA_speed0;
+ u32 PIO_speed1;
+ u32 DMA_speed1;
+ u32 GTM_flags;
+};
+
+struct ide_acpi_drive_link {
+ acpi_handle obj_handle;
+ u8 idbuff[512];
+};
+
+struct ide_acpi_hwif_link {
+ ide_hwif_t *hwif;
+ acpi_handle obj_handle;
+ struct GTM_buffer gtm;
+ struct ide_acpi_drive_link master;
+ struct ide_acpi_drive_link slave;
+};
+
+#undef DEBUGGING
+/* note: adds function name and KERN_DEBUG */
+#ifdef DEBUGGING
+#define DEBPRINT(fmt, args...) \
+ printk(KERN_DEBUG "%s: " fmt, __func__, ## args)
+#else
+#define DEBPRINT(fmt, args...) do {} while (0)
+#endif /* DEBUGGING */
+
+static int ide_noacpi;
+module_param_named(noacpi, ide_noacpi, bool, 0);
+MODULE_PARM_DESC(noacpi, "disable IDE ACPI support");
+
+static int ide_acpigtf;
+module_param_named(acpigtf, ide_acpigtf, bool, 0);
+MODULE_PARM_DESC(acpigtf, "enable IDE ACPI _GTF support");
+
+static int ide_acpionboot;
+module_param_named(acpionboot, ide_acpionboot, bool, 0);
+MODULE_PARM_DESC(acpionboot, "call IDE ACPI methods on boot");
+
+static bool ide_noacpi_psx;
+static int no_acpi_psx(const struct dmi_system_id *id)
+{
+ ide_noacpi_psx = true;
+ printk(KERN_NOTICE"%s detected - disable ACPI _PSx.\n", id->ident);
+ return 0;
+}
+
+static const struct dmi_system_id ide_acpi_dmi_table[] = {
+ /* Bug 9673. */
+ /* We should check if this is because ACPI NVS isn't save/restored. */
+ {
+ .callback = no_acpi_psx,
+ .ident = "HP nx9005",
+ .matches = {
+ DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies Ltd."),
+ DMI_MATCH(DMI_BIOS_VERSION, "KAM1.60")
+ },
+ },
+
+ { } /* terminate list */
+};
+
+static int ide_acpi_blacklist(void)
+{
+ static int done;
+ if (done)
+ return 0;
+ done = 1;
+ dmi_check_system(ide_acpi_dmi_table);
+ return 0;
+}
+
+/**
+ * ide_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
+ *
+ * Returns the ACPI object handle to the corresponding PCI device.
+ *
+ * Returns 0 on success, <0 on error.
+ */
+static int ide_get_dev_handle(struct device *dev, acpi_handle *handle,
+ acpi_integer *pcidevfn)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ unsigned int bus, devnum, func;
+ acpi_integer addr;
+ acpi_handle dev_handle;
+ struct acpi_buffer buffer = {.length = ACPI_ALLOCATE_BUFFER,
+ .pointer = NULL};
+ acpi_status status;
+ struct acpi_device_info *dinfo = NULL;
+ int ret = -ENODEV;
+
+ bus = pdev->bus->number;
+ devnum = PCI_SLOT(pdev->devfn);
+ func = PCI_FUNC(pdev->devfn);
+ /* ACPI _ADR encoding for PCI bus: */
+ addr = (acpi_integer)(devnum << 16 | func);
+
+ DEBPRINT("ENTER: pci %02x:%02x.%01x\n", bus, devnum, func);
+
+ dev_handle = DEVICE_ACPI_HANDLE(dev);
+ if (!dev_handle) {
+ DEBPRINT("no acpi handle for device\n");
+ goto err;
+ }
+
+ status = acpi_get_object_info(dev_handle, &buffer);
+ if (ACPI_FAILURE(status)) {
+ DEBPRINT("get_object_info for device failed\n");
+ goto err;
+ }
+ dinfo = buffer.pointer;
+ if (dinfo && (dinfo->valid & ACPI_VALID_ADR) &&
+ dinfo->address == addr) {
+ *pcidevfn = addr;
+ *handle = dev_handle;
+ } else {
+ DEBPRINT("get_object_info for device has wrong "
+ " address: %llu, should be %u\n",
+ dinfo ? (unsigned long long)dinfo->address : -1ULL,
+ (unsigned int)addr);
+ goto err;
+ }
+
+ DEBPRINT("for dev=0x%x.%x, addr=0x%llx, *handle=0x%p\n",
+ devnum, func, (unsigned long long)addr, *handle);
+ ret = 0;
+err:
+ kfree(dinfo);
+ return ret;
+}
+
+/**
+ * ide_acpi_hwif_get_handle - Get ACPI object handle for a given hwif
+ * @hwif: device to locate
+ *
+ * Retrieves the object handle for a given hwif.
+ *
+ * Returns handle on success, 0 on error.
+ */
+static acpi_handle ide_acpi_hwif_get_handle(ide_hwif_t *hwif)
+{
+ struct device *dev = hwif->gendev.parent;
+ acpi_handle uninitialized_var(dev_handle);
+ acpi_integer pcidevfn;
+ acpi_handle chan_handle;
+ int err;
+
+ DEBPRINT("ENTER: device %s\n", hwif->name);
+
+ if (!dev) {
+ DEBPRINT("no PCI device for %s\n", hwif->name);
+ return NULL;
+ }
+
+ err = ide_get_dev_handle(dev, &dev_handle, &pcidevfn);
+ if (err < 0) {
+ DEBPRINT("ide_get_dev_handle failed (%d)\n", err);
+ return NULL;
+ }
+
+ /* get child objects of dev_handle == channel objects,
+ * + _their_ children == drive objects */
+ /* channel is hwif->channel */
+ chan_handle = acpi_get_child(dev_handle, hwif->channel);
+ DEBPRINT("chan adr=%d: handle=0x%p\n",
+ hwif->channel, chan_handle);
+
+ return chan_handle;
+}
+
+/**
+ * ide_acpi_drive_get_handle - Get ACPI object handle for a given drive
+ * @drive: device to locate
+ *
+ * Retrieves the object handle of a given drive. According to the ACPI
+ * spec the drive is a child of the hwif.
+ *
+ * Returns handle on success, 0 on error.
+ */
+static acpi_handle ide_acpi_drive_get_handle(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ int port;
+ acpi_handle drive_handle;
+
+ if (!hwif->acpidata)
+ return NULL;
+
+ if (!hwif->acpidata->obj_handle)
+ return NULL;
+
+ port = hwif->channel ? drive->dn - 2: drive->dn;
+
+ DEBPRINT("ENTER: %s at channel#: %d port#: %d\n",
+ drive->name, hwif->channel, port);
+
+
+ /* TBD: could also check ACPI object VALID bits */
+ drive_handle = acpi_get_child(hwif->acpidata->obj_handle, port);
+ DEBPRINT("drive %s handle 0x%p\n", drive->name, drive_handle);
+
+ return drive_handle;
+}
+
+/**
+ * do_drive_get_GTF - get the drive bootup default taskfile settings
+ * @drive: the drive for which the taskfile settings should be retrieved
+ * @gtf_length: number of bytes of _GTF data returned at @gtf_address
+ * @gtf_address: buffer containing _GTF taskfile arrays
+ *
+ * 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(ide_drive_t *drive,
+ unsigned int *gtf_length, unsigned long *gtf_address,
+ unsigned long *obj_loc)
+{
+ acpi_status status;
+ struct acpi_buffer output;
+ union acpi_object *out_obj;
+ ide_hwif_t *hwif = HWIF(drive);
+ struct device *dev = hwif->gendev.parent;
+ int err = -ENODEV;
+ int port;
+
+ *gtf_length = 0;
+ *gtf_address = 0UL;
+ *obj_loc = 0UL;
+
+ if (ide_noacpi)
+ return 0;
+
+ if (!dev) {
+ DEBPRINT("no PCI device for %s\n", hwif->name);
+ goto out;
+ }
+
+ if (!hwif->acpidata) {
+ DEBPRINT("no ACPI data for %s\n", hwif->name);
+ goto out;
+ }
+
+ port = hwif->channel ? drive->dn - 2: drive->dn;
+
+ DEBPRINT("ENTER: %s at %s, port#: %d, hard_port#: %d\n",
+ hwif->name, dev->bus_id, port, hwif->channel);
+
+ if ((drive->dev_flags & IDE_DFLAG_PRESENT) == 0) {
+ DEBPRINT("%s drive %d:%d not present\n",
+ hwif->name, hwif->channel, port);
+ goto out;
+ }
+
+ /* Get this drive's _ADR info. if not already known. */
+ if (!drive->acpidata->obj_handle) {
+ drive->acpidata->obj_handle = ide_acpi_drive_get_handle(drive);
+ if (!drive->acpidata->obj_handle) {
+ DEBPRINT("No ACPI object found for %s\n",
+ drive->name);
+ 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(drive->acpidata->obj_handle, "_GTF",
+ NULL, &output);
+ if (ACPI_FAILURE(status)) {
+ printk(KERN_DEBUG
+ "%s: Run _GTF error: status = 0x%x\n",
+ __func__, status);
+ goto out;
+ }
+
+ if (!output.length || !output.pointer) {
+ DEBPRINT("Run _GTF: "
+ "length or ptr is NULL (0x%llx, 0x%p)\n",
+ (unsigned long long)output.length,
+ output.pointer);
+ goto out;
+ }
+
+ out_obj = output.pointer;
+ if (out_obj->type != ACPI_TYPE_BUFFER) {
+ DEBPRINT("Run _GTF: error: "
+ "expected object type of ACPI_TYPE_BUFFER, "
+ "got 0x%x\n", out_obj->type);
+ err = -ENOENT;
+ kfree(output.pointer);
+ goto out;
+ }
+
+ if (!out_obj->buffer.length || !out_obj->buffer.pointer ||
+ out_obj->buffer.length % REGS_PER_GTF) {
+ printk(KERN_ERR
+ "%s: unexpected GTF length (%d) or addr (0x%p)\n",
+ __func__, out_obj->buffer.length,
+ out_obj->buffer.pointer);
+ err = -ENOENT;
+ kfree(output.pointer);
+ goto out;
+ }
+
+ *gtf_length = out_obj->buffer.length;
+ *gtf_address = (unsigned long)out_obj->buffer.pointer;
+ *obj_loc = (unsigned long)out_obj;
+ DEBPRINT("returning gtf_length=%d, gtf_address=0x%lx, obj_loc=0x%lx\n",
+ *gtf_length, *gtf_address, *obj_loc);
+ err = 0;
+out:
+ return err;
+}
+
+/**
+ * taskfile_load_raw - send taskfile registers to drive
+ * @drive: drive to which output is sent
+ * @gtf: raw ATA taskfile register set (0x1f1 - 0x1f7)
+ *
+ * Outputs IDE taskfile to the drive.
+ */
+static int taskfile_load_raw(ide_drive_t *drive,
+ const struct taskfile_array *gtf)
+{
+ ide_task_t args;
+ int err = 0;
+
+ DEBPRINT("(0x1f1-1f7): hex: "
+ "%02x %02x %02x %02x %02x %02x %02x\n",
+ gtf->tfa[0], gtf->tfa[1], gtf->tfa[2],
+ gtf->tfa[3], gtf->tfa[4], gtf->tfa[5], gtf->tfa[6]);
+
+ memset(&args, 0, sizeof(ide_task_t));
+
+ /* convert gtf to IDE Taskfile */
+ memcpy(&args.tf_array[7], &gtf->tfa, 7);
+ args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
+
+ if (!ide_acpigtf) {
+ DEBPRINT("_GTF execution disabled\n");
+ return err;
+ }
+
+ err = ide_no_data_taskfile(drive, &args);
+ if (err)
+ printk(KERN_ERR "%s: ide_no_data_taskfile failed: %u\n",
+ __func__, err);
+
+ return err;
+}
+
+/**
+ * do_drive_set_taskfiles - write the drive taskfile settings from _GTF
+ * @drive: the drive to which the taskfile command should be sent
+ * @gtf_length: total number of bytes of _GTF taskfiles
+ * @gtf_address: location of _GTF taskfile arrays
+ *
+ * Write {gtf_address, length gtf_length} in groups of
+ * REGS_PER_GTF bytes.
+ */
+static int do_drive_set_taskfiles(ide_drive_t *drive,
+ unsigned int gtf_length,
+ unsigned long gtf_address)
+{
+ int rc = -ENODEV, err;
+ int gtf_count = gtf_length / REGS_PER_GTF;
+ int ix;
+ struct taskfile_array *gtf;
+
+ if (ide_noacpi)
+ return 0;
+
+ DEBPRINT("ENTER: %s, hard_port#: %d\n", drive->name, drive->dn);
+
+ if ((drive->dev_flags & IDE_DFLAG_PRESENT) == 0)
+ goto out;
+
+ if (!gtf_count) /* shouldn't be here */
+ goto out;
+
+ DEBPRINT("total GTF bytes=%u (0x%x), gtf_count=%d, addr=0x%lx\n",
+ gtf_length, gtf_length, gtf_count, gtf_address);
+
+ if (gtf_length % REGS_PER_GTF) {
+ printk(KERN_ERR "%s: unexpected GTF length (%d)\n",
+ __func__, gtf_length);
+ goto out;
+ }
+
+ rc = 0;
+ 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* */
+ err = taskfile_load_raw(drive, gtf);
+ if (err)
+ rc = err;
+ }
+
+out:
+ return rc;
+}
+
+/**
+ * ide_acpi_exec_tfs - get then write drive taskfile settings
+ * @drive: the drive for which the taskfile settings should be
+ * written.
+ *
+ * According to the ACPI spec this should be called after _STM
+ * has been evaluated for the interface. Some ACPI vendors interpret
+ * that as a hard requirement and modify the taskfile according
+ * to the Identify Drive information passed down with _STM.
+ * So one should really make sure to call this only after _STM has
+ * been executed.
+ */
+int ide_acpi_exec_tfs(ide_drive_t *drive)
+{
+ int ret;
+ unsigned int gtf_length;
+ unsigned long gtf_address;
+ unsigned long obj_loc;
+
+ if (ide_noacpi)
+ return 0;
+
+ DEBPRINT("call get_GTF, drive=%s port=%d\n", drive->name, drive->dn);
+
+ ret = do_drive_get_GTF(drive, &gtf_length, &gtf_address, &obj_loc);
+ if (ret < 0) {
+ DEBPRINT("get_GTF error (%d)\n", ret);
+ return ret;
+ }
+
+ DEBPRINT("call set_taskfiles, drive=%s\n", drive->name);
+
+ ret = do_drive_set_taskfiles(drive, gtf_length, gtf_address);
+ kfree((void *)obj_loc);
+ if (ret < 0) {
+ DEBPRINT("set_taskfiles error (%d)\n", ret);
+ }
+
+ DEBPRINT("ret=%d\n", ret);
+
+ return ret;
+}
+
+/**
+ * ide_acpi_get_timing - get the channel (controller) timings
+ * @hwif: target IDE interface (channel)
+ *
+ * This function executes the _GTM ACPI method for the target channel.
+ *
+ */
+void ide_acpi_get_timing(ide_hwif_t *hwif)
+{
+ acpi_status status;
+ struct acpi_buffer output;
+ union acpi_object *out_obj;
+
+ if (ide_noacpi)
+ return;
+
+ DEBPRINT("ENTER:\n");
+
+ if (!hwif->acpidata) {
+ DEBPRINT("no ACPI data for %s\n", hwif->name);
+ return;
+ }
+
+ /* Setting up output buffer for _GTM */
+ output.length = ACPI_ALLOCATE_BUFFER;
+ output.pointer = NULL; /* ACPI-CA sets this; save/free it later */
+
+ /* _GTM has no input parameters */
+ status = acpi_evaluate_object(hwif->acpidata->obj_handle, "_GTM",
+ NULL, &output);
+
+ DEBPRINT("_GTM status: %d, outptr: 0x%p, outlen: 0x%llx\n",
+ status, output.pointer,
+ (unsigned long long)output.length);
+
+ if (ACPI_FAILURE(status)) {
+ DEBPRINT("Run _GTM error: status = 0x%x\n", status);
+ return;
+ }
+
+ if (!output.length || !output.pointer) {
+ DEBPRINT("Run _GTM: length or ptr is NULL (0x%llx, 0x%p)\n",
+ (unsigned long long)output.length,
+ output.pointer);
+ kfree(output.pointer);
+ return;
+ }
+
+ out_obj = output.pointer;
+ if (out_obj->type != ACPI_TYPE_BUFFER) {
+ kfree(output.pointer);
+ DEBPRINT("Run _GTM: error: "
+ "expected object type of ACPI_TYPE_BUFFER, "
+ "got 0x%x\n", out_obj->type);
+ return;
+ }
+
+ if (!out_obj->buffer.length || !out_obj->buffer.pointer ||
+ out_obj->buffer.length != sizeof(struct GTM_buffer)) {
+ kfree(output.pointer);
+ printk(KERN_ERR
+ "%s: unexpected _GTM length (0x%x)[should be 0x%zx] or "
+ "addr (0x%p)\n",
+ __func__, out_obj->buffer.length,
+ sizeof(struct GTM_buffer), out_obj->buffer.pointer);
+ return;
+ }
+
+ memcpy(&hwif->acpidata->gtm, out_obj->buffer.pointer,
+ sizeof(struct GTM_buffer));
+
+ DEBPRINT("_GTM info: ptr: 0x%p, len: 0x%x, exp.len: 0x%Zx\n",
+ out_obj->buffer.pointer, out_obj->buffer.length,
+ sizeof(struct GTM_buffer));
+
+ DEBPRINT("_GTM fields: 0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n",
+ hwif->acpidata->gtm.PIO_speed0,
+ hwif->acpidata->gtm.DMA_speed0,
+ hwif->acpidata->gtm.PIO_speed1,
+ hwif->acpidata->gtm.DMA_speed1,
+ hwif->acpidata->gtm.GTM_flags);
+
+ kfree(output.pointer);
+}
+
+/**
+ * ide_acpi_push_timing - set the channel (controller) timings
+ * @hwif: target IDE interface (channel)
+ *
+ * This function executes the _STM ACPI method for the target channel.
+ *
+ * _STM requires Identify Drive data, which has to passed as an argument.
+ * Unfortunately drive->id is a mangled version which we can't readily
+ * use; hence we'll get the information afresh.
+ */
+void ide_acpi_push_timing(ide_hwif_t *hwif)
+{
+ acpi_status status;
+ struct acpi_object_list input;
+ union acpi_object in_params[3];
+ struct ide_acpi_drive_link *master = &hwif->acpidata->master;
+ struct ide_acpi_drive_link *slave = &hwif->acpidata->slave;
+
+ if (ide_noacpi)
+ return;
+
+ DEBPRINT("ENTER:\n");
+
+ if (!hwif->acpidata) {
+ DEBPRINT("no ACPI data for %s\n", hwif->name);
+ return;
+ }
+
+ /* Give the GTM buffer + drive Identify data to the channel via the
+ * _STM method: */
+ /* setup input parameters buffer for _STM */
+ input.count = 3;
+ input.pointer = in_params;
+ in_params[0].type = ACPI_TYPE_BUFFER;
+ in_params[0].buffer.length = sizeof(struct GTM_buffer);
+ in_params[0].buffer.pointer = (u8 *)&hwif->acpidata->gtm;
+ in_params[1].type = ACPI_TYPE_BUFFER;
+ in_params[1].buffer.length = sizeof(ATA_ID_WORDS * 2);
+ in_params[1].buffer.pointer = (u8 *)&master->idbuff;
+ in_params[2].type = ACPI_TYPE_BUFFER;
+ in_params[2].buffer.length = sizeof(ATA_ID_WORDS * 2);
+ in_params[2].buffer.pointer = (u8 *)&slave->idbuff;
+ /* Output buffer: _STM has no output */
+
+ status = acpi_evaluate_object(hwif->acpidata->obj_handle, "_STM",
+ &input, NULL);
+
+ if (ACPI_FAILURE(status)) {
+ DEBPRINT("Run _STM error: status = 0x%x\n", status);
+ }
+ DEBPRINT("_STM status: %d\n", status);
+}
+
+/**
+ * ide_acpi_set_state - set the channel power state
+ * @hwif: target IDE interface
+ * @on: state, on/off
+ *
+ * This function executes the _PS0/_PS3 ACPI method to set the power state.
+ * ACPI spec requires _PS0 when IDE power on and _PS3 when power off
+ */
+void ide_acpi_set_state(ide_hwif_t *hwif, int on)
+{
+ int unit;
+
+ if (ide_noacpi || ide_noacpi_psx)
+ return;
+
+ DEBPRINT("ENTER:\n");
+
+ if (!hwif->acpidata) {
+ DEBPRINT("no ACPI data for %s\n", hwif->name);
+ return;
+ }
+ /* channel first and then drives for power on and verse versa for power off */
+ if (on)
+ acpi_bus_set_power(hwif->acpidata->obj_handle, ACPI_STATE_D0);
+ for (unit = 0; unit < MAX_DRIVES; ++unit) {
+ ide_drive_t *drive = &hwif->drives[unit];
+
+ if (!drive->acpidata->obj_handle)
+ drive->acpidata->obj_handle = ide_acpi_drive_get_handle(drive);
+
+ if (drive->acpidata->obj_handle &&
+ (drive->dev_flags & IDE_DFLAG_PRESENT)) {
+ acpi_bus_set_power(drive->acpidata->obj_handle,
+ on? ACPI_STATE_D0: ACPI_STATE_D3);
+ }
+ }
+ if (!on)
+ acpi_bus_set_power(hwif->acpidata->obj_handle, ACPI_STATE_D3);
+}
+
+/**
+ * ide_acpi_init - initialize the ACPI link for an IDE interface
+ * @hwif: target IDE interface (channel)
+ *
+ * The ACPI spec is not quite clear when the drive identify buffer
+ * should be obtained. Calling IDENTIFY DEVICE during shutdown
+ * is not the best of ideas as the drive might already being put to
+ * sleep. And obviously we can't call it during resume.
+ * So we get the information during startup; but this means that
+ * any changes during run-time will be lost after resume.
+ */
+void ide_acpi_init(ide_hwif_t *hwif)
+{
+ ide_acpi_blacklist();
+
+ hwif->acpidata = kzalloc(sizeof(struct ide_acpi_hwif_link), GFP_KERNEL);
+ if (!hwif->acpidata)
+ return;
+
+ hwif->acpidata->obj_handle = ide_acpi_hwif_get_handle(hwif);
+ if (!hwif->acpidata->obj_handle) {
+ DEBPRINT("no ACPI object for %s found\n", hwif->name);
+ kfree(hwif->acpidata);
+ hwif->acpidata = NULL;
+ }
+}
+
+void ide_acpi_port_init_devices(ide_hwif_t *hwif)
+{
+ ide_drive_t *drive;
+ int i, err;
+
+ if (hwif->acpidata == NULL)
+ return;
+
+ /*
+ * The ACPI spec mandates that we send information
+ * for both drives, regardless whether they are connected
+ * or not.
+ */
+ hwif->drives[0].acpidata = &hwif->acpidata->master;
+ hwif->drives[1].acpidata = &hwif->acpidata->slave;
+
+ /*
+ * Send IDENTIFY for each drive
+ */
+ for (i = 0; i < MAX_DRIVES; i++) {
+ drive = &hwif->drives[i];
+
+ memset(drive->acpidata, 0, sizeof(*drive->acpidata));
+
+ if ((drive->dev_flags & IDE_DFLAG_PRESENT) == 0)
+ continue;
+
+ err = taskfile_lib_get_identify(drive, drive->acpidata->idbuff);
+ if (err)
+ DEBPRINT("identify device %s failed (%d)\n",
+ drive->name, err);
+ }
+
+ if (!ide_acpionboot) {
+ DEBPRINT("ACPI methods disabled on boot\n");
+ return;
+ }
+
+ /* ACPI _PS0 before _STM */
+ ide_acpi_set_state(hwif, 1);
+ /*
+ * ACPI requires us to call _STM on startup
+ */
+ ide_acpi_get_timing(hwif);
+ ide_acpi_push_timing(hwif);
+
+ for (i = 0; i < MAX_DRIVES; i++) {
+ drive = &hwif->drives[i];
+
+ if (drive->dev_flags & IDE_DFLAG_PRESENT)
+ /* Execute ACPI startup code */
+ ide_acpi_exec_tfs(drive);
+ }
+}
diff --git a/drivers/ide/ide-atapi.c b/drivers/ide/ide-atapi.c
new file mode 100644
index 0000000..4e58b9e
--- /dev/null
+++ b/drivers/ide/ide-atapi.c
@@ -0,0 +1,597 @@
+/*
+ * ATAPI support.
+ */
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/ide.h>
+#include <scsi/scsi.h>
+
+#ifdef DEBUG
+#define debug_log(fmt, args...) \
+ printk(KERN_INFO "ide: " fmt, ## args)
+#else
+#define debug_log(fmt, args...) do {} while (0)
+#endif
+
+/*
+ * Check whether we can support a device,
+ * based on the ATAPI IDENTIFY command results.
+ */
+int ide_check_atapi_device(ide_drive_t *drive, const char *s)
+{
+ u16 *id = drive->id;
+ u8 gcw[2], protocol, device_type, removable, drq_type, packet_size;
+
+ *((u16 *)&gcw) = id[ATA_ID_CONFIG];
+
+ protocol = (gcw[1] & 0xC0) >> 6;
+ device_type = gcw[1] & 0x1F;
+ removable = (gcw[0] & 0x80) >> 7;
+ drq_type = (gcw[0] & 0x60) >> 5;
+ packet_size = gcw[0] & 0x03;
+
+#ifdef CONFIG_PPC
+ /* kludge for Apple PowerBook internal zip */
+ if (drive->media == ide_floppy && device_type == 5 &&
+ !strstr((char *)&id[ATA_ID_PROD], "CD-ROM") &&
+ strstr((char *)&id[ATA_ID_PROD], "ZIP"))
+ device_type = 0;
+#endif
+
+ if (protocol != 2)
+ printk(KERN_ERR "%s: %s: protocol (0x%02x) is not ATAPI\n",
+ s, drive->name, protocol);
+ else if ((drive->media == ide_floppy && device_type != 0) ||
+ (drive->media == ide_tape && device_type != 1))
+ printk(KERN_ERR "%s: %s: invalid device type (0x%02x)\n",
+ s, drive->name, device_type);
+ else if (removable == 0)
+ printk(KERN_ERR "%s: %s: the removable flag is not set\n",
+ s, drive->name);
+ else if (drive->media == ide_floppy && drq_type == 3)
+ printk(KERN_ERR "%s: %s: sorry, DRQ type (0x%02x) not "
+ "supported\n", s, drive->name, drq_type);
+ else if (packet_size != 0)
+ printk(KERN_ERR "%s: %s: packet size (0x%02x) is not 12 "
+ "bytes\n", s, drive->name, packet_size);
+ else
+ return 1;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ide_check_atapi_device);
+
+/* PIO data transfer routine using the scatter gather table. */
+int ide_io_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc,
+ unsigned int bcount, int write)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ const struct ide_tp_ops *tp_ops = hwif->tp_ops;
+ xfer_func_t *xf = write ? tp_ops->output_data : tp_ops->input_data;
+ struct scatterlist *sg = pc->sg;
+ char *buf;
+ int count, done = 0;
+
+ while (bcount) {
+ count = min(sg->length - pc->b_count, bcount);
+
+ if (PageHighMem(sg_page(sg))) {
+ unsigned long flags;
+
+ local_irq_save(flags);
+ buf = kmap_atomic(sg_page(sg), KM_IRQ0) + sg->offset;
+ xf(drive, NULL, buf + pc->b_count, count);
+ kunmap_atomic(buf - sg->offset, KM_IRQ0);
+ local_irq_restore(flags);
+ } else {
+ buf = sg_virt(sg);
+ xf(drive, NULL, buf + pc->b_count, count);
+ }
+
+ bcount -= count;
+ pc->b_count += count;
+ done += count;
+
+ if (pc->b_count == sg->length) {
+ if (!--pc->sg_cnt)
+ break;
+ pc->sg = sg = sg_next(sg);
+ pc->b_count = 0;
+ }
+ }
+
+ if (bcount) {
+ printk(KERN_ERR "%s: %d leftover bytes, %s\n", drive->name,
+ bcount, write ? "padding with zeros"
+ : "discarding data");
+ ide_pad_transfer(drive, write, bcount);
+ }
+
+ return done;
+}
+EXPORT_SYMBOL_GPL(ide_io_buffers);
+
+void ide_init_pc(struct ide_atapi_pc *pc)
+{
+ memset(pc, 0, sizeof(*pc));
+ pc->buf = pc->pc_buf;
+ pc->buf_size = IDE_PC_BUFFER_SIZE;
+}
+EXPORT_SYMBOL_GPL(ide_init_pc);
+
+/*
+ * Generate a new packet command request in front of the request queue, before
+ * the current request, so that it will be processed immediately, on the next
+ * pass through the driver.
+ */
+static void ide_queue_pc_head(ide_drive_t *drive, struct gendisk *disk,
+ struct ide_atapi_pc *pc, struct request *rq)
+{
+ blk_rq_init(NULL, rq);
+ rq->cmd_type = REQ_TYPE_SPECIAL;
+ rq->cmd_flags |= REQ_PREEMPT;
+ rq->buffer = (char *)pc;
+ rq->rq_disk = disk;
+ memcpy(rq->cmd, pc->c, 12);
+ if (drive->media == ide_tape)
+ rq->cmd[13] = REQ_IDETAPE_PC1;
+ ide_do_drive_cmd(drive, rq);
+}
+
+/*
+ * Add a special packet command request to the tail of the request queue,
+ * and wait for it to be serviced.
+ */
+int ide_queue_pc_tail(ide_drive_t *drive, struct gendisk *disk,
+ struct ide_atapi_pc *pc)
+{
+ struct request *rq;
+ int error;
+
+ rq = blk_get_request(drive->queue, READ, __GFP_WAIT);
+ rq->cmd_type = REQ_TYPE_SPECIAL;
+ rq->buffer = (char *)pc;
+ memcpy(rq->cmd, pc->c, 12);
+ if (drive->media == ide_tape)
+ rq->cmd[13] = REQ_IDETAPE_PC1;
+ error = blk_execute_rq(drive->queue, disk, rq, 0);
+ blk_put_request(rq);
+
+ return error;
+}
+EXPORT_SYMBOL_GPL(ide_queue_pc_tail);
+
+int ide_do_test_unit_ready(ide_drive_t *drive, struct gendisk *disk)
+{
+ struct ide_atapi_pc pc;
+
+ ide_init_pc(&pc);
+ pc.c[0] = TEST_UNIT_READY;
+
+ return ide_queue_pc_tail(drive, disk, &pc);
+}
+EXPORT_SYMBOL_GPL(ide_do_test_unit_ready);
+
+int ide_do_start_stop(ide_drive_t *drive, struct gendisk *disk, int start)
+{
+ struct ide_atapi_pc pc;
+
+ ide_init_pc(&pc);
+ pc.c[0] = START_STOP;
+ pc.c[4] = start;
+
+ if (drive->media == ide_tape)
+ pc.flags |= PC_FLAG_WAIT_FOR_DSC;
+
+ return ide_queue_pc_tail(drive, disk, &pc);
+}
+EXPORT_SYMBOL_GPL(ide_do_start_stop);
+
+int ide_set_media_lock(ide_drive_t *drive, struct gendisk *disk, int on)
+{
+ struct ide_atapi_pc pc;
+
+ if ((drive->dev_flags & IDE_DFLAG_DOORLOCKING) == 0)
+ return 0;
+
+ ide_init_pc(&pc);
+ pc.c[0] = ALLOW_MEDIUM_REMOVAL;
+ pc.c[4] = on;
+
+ return ide_queue_pc_tail(drive, disk, &pc);
+}
+EXPORT_SYMBOL_GPL(ide_set_media_lock);
+
+void ide_create_request_sense_cmd(ide_drive_t *drive, struct ide_atapi_pc *pc)
+{
+ ide_init_pc(pc);
+ pc->c[0] = REQUEST_SENSE;
+ if (drive->media == ide_floppy) {
+ pc->c[4] = 255;
+ pc->req_xfer = 18;
+ } else {
+ pc->c[4] = 20;
+ pc->req_xfer = 20;
+ }
+}
+EXPORT_SYMBOL_GPL(ide_create_request_sense_cmd);
+
+/*
+ * Called when an error was detected during the last packet command.
+ * We queue a request sense packet command in the head of the request list.
+ */
+void ide_retry_pc(ide_drive_t *drive, struct gendisk *disk)
+{
+ struct request *rq = &drive->request_sense_rq;
+ struct ide_atapi_pc *pc = &drive->request_sense_pc;
+
+ (void)ide_read_error(drive);
+ ide_create_request_sense_cmd(drive, pc);
+ if (drive->media == ide_tape)
+ set_bit(IDE_AFLAG_IGNORE_DSC, &drive->atapi_flags);
+ ide_queue_pc_head(drive, disk, pc, rq);
+}
+EXPORT_SYMBOL_GPL(ide_retry_pc);
+
+int ide_scsi_expiry(ide_drive_t *drive)
+{
+ struct ide_atapi_pc *pc = drive->pc;
+
+ debug_log("%s called for %lu at %lu\n", __func__,
+ pc->scsi_cmd->serial_number, jiffies);
+
+ pc->flags |= PC_FLAG_TIMEDOUT;
+
+ return 0; /* we do not want the IDE subsystem to retry */
+}
+EXPORT_SYMBOL_GPL(ide_scsi_expiry);
+
+/*
+ * This is the usual interrupt handler which will be called during a packet
+ * command. We will transfer some of the data (as requested by the drive)
+ * and will re-point interrupt handler to us.
+ */
+static ide_startstop_t ide_pc_intr(ide_drive_t *drive)
+{
+ struct ide_atapi_pc *pc = drive->pc;
+ ide_hwif_t *hwif = drive->hwif;
+ struct request *rq = hwif->hwgroup->rq;
+ const struct ide_tp_ops *tp_ops = hwif->tp_ops;
+ xfer_func_t *xferfunc;
+ ide_expiry_t *expiry;
+ unsigned int timeout, temp;
+ u16 bcount;
+ u8 stat, ireason, scsi = !!(drive->dev_flags & IDE_DFLAG_SCSI), dsc = 0;
+
+ debug_log("Enter %s - interrupt handler\n", __func__);
+
+ if (scsi) {
+ timeout = ide_scsi_get_timeout(pc);
+ expiry = ide_scsi_expiry;
+ } else {
+ timeout = (drive->media == ide_floppy) ? WAIT_FLOPPY_CMD
+ : WAIT_TAPE_CMD;
+ expiry = NULL;
+ }
+
+ if (pc->flags & PC_FLAG_TIMEDOUT) {
+ drive->pc_callback(drive, 0);
+ return ide_stopped;
+ }
+
+ /* Clear the interrupt */
+ stat = tp_ops->read_status(hwif);
+
+ if (pc->flags & PC_FLAG_DMA_IN_PROGRESS) {
+ if (hwif->dma_ops->dma_end(drive) ||
+ (drive->media == ide_tape && !scsi && (stat & ATA_ERR))) {
+ if (drive->media == ide_floppy && !scsi)
+ printk(KERN_ERR "%s: DMA %s error\n",
+ drive->name, rq_data_dir(pc->rq)
+ ? "write" : "read");
+ pc->flags |= PC_FLAG_DMA_ERROR;
+ } else {
+ pc->xferred = pc->req_xfer;
+ if (drive->pc_update_buffers)
+ drive->pc_update_buffers(drive, pc);
+ }
+ debug_log("%s: DMA finished\n", drive->name);
+ }
+
+ /* No more interrupts */
+ if ((stat & ATA_DRQ) == 0) {
+ debug_log("Packet command completed, %d bytes transferred\n",
+ pc->xferred);
+
+ pc->flags &= ~PC_FLAG_DMA_IN_PROGRESS;
+
+ local_irq_enable_in_hardirq();
+
+ if (drive->media == ide_tape && !scsi &&
+ (stat & ATA_ERR) && rq->cmd[0] == REQUEST_SENSE)
+ stat &= ~ATA_ERR;
+
+ if ((stat & ATA_ERR) || (pc->flags & PC_FLAG_DMA_ERROR)) {
+ /* Error detected */
+ debug_log("%s: I/O error\n", drive->name);
+
+ if (drive->media != ide_tape || scsi) {
+ pc->rq->errors++;
+ if (scsi)
+ goto cmd_finished;
+ }
+
+ if (rq->cmd[0] == REQUEST_SENSE) {
+ printk(KERN_ERR "%s: I/O error in request sense"
+ " command\n", drive->name);
+ return ide_do_reset(drive);
+ }
+
+ debug_log("[cmd %x]: check condition\n", rq->cmd[0]);
+
+ /* Retry operation */
+ ide_retry_pc(drive, rq->rq_disk);
+
+ /* queued, but not started */
+ return ide_stopped;
+ }
+cmd_finished:
+ pc->error = 0;
+
+ if ((pc->flags & PC_FLAG_WAIT_FOR_DSC) && (stat & ATA_DSC) == 0)
+ dsc = 1;
+
+ /* Command finished - Call the callback function */
+ drive->pc_callback(drive, dsc);
+
+ return ide_stopped;
+ }
+
+ if (pc->flags & PC_FLAG_DMA_IN_PROGRESS) {
+ pc->flags &= ~PC_FLAG_DMA_IN_PROGRESS;
+ printk(KERN_ERR "%s: The device wants to issue more interrupts "
+ "in DMA mode\n", drive->name);
+ ide_dma_off(drive);
+ return ide_do_reset(drive);
+ }
+
+ /* Get the number of bytes to transfer on this interrupt. */
+ ide_read_bcount_and_ireason(drive, &bcount, &ireason);
+
+ if (ireason & ATAPI_COD) {
+ printk(KERN_ERR "%s: CoD != 0 in %s\n", drive->name, __func__);
+ return ide_do_reset(drive);
+ }
+
+ if (((ireason & ATAPI_IO) == ATAPI_IO) ==
+ !!(pc->flags & PC_FLAG_WRITING)) {
+ /* Hopefully, we will never get here */
+ printk(KERN_ERR "%s: We wanted to %s, but the device wants us "
+ "to %s!\n", drive->name,
+ (ireason & ATAPI_IO) ? "Write" : "Read",
+ (ireason & ATAPI_IO) ? "Read" : "Write");
+ return ide_do_reset(drive);
+ }
+
+ if (!(pc->flags & PC_FLAG_WRITING)) {
+ /* Reading - Check that we have enough space */
+ temp = pc->xferred + bcount;
+ if (temp > pc->req_xfer) {
+ if (temp > pc->buf_size) {
+ printk(KERN_ERR "%s: The device wants to send "
+ "us more data than expected - "
+ "discarding data\n",
+ drive->name);
+ if (scsi)
+ temp = pc->buf_size - pc->xferred;
+ else
+ temp = 0;
+ if (temp) {
+ if (pc->sg)
+ drive->pc_io_buffers(drive, pc,
+ temp, 0);
+ else
+ tp_ops->input_data(drive, NULL,
+ pc->cur_pos, temp);
+ printk(KERN_ERR "%s: transferred %d of "
+ "%d bytes\n",
+ drive->name,
+ temp, bcount);
+ }
+ pc->xferred += temp;
+ pc->cur_pos += temp;
+ ide_pad_transfer(drive, 0, bcount - temp);
+ goto next_irq;
+ }
+ debug_log("The device wants to send us more data than "
+ "expected - allowing transfer\n");
+ }
+ xferfunc = tp_ops->input_data;
+ } else
+ xferfunc = tp_ops->output_data;
+
+ if ((drive->media == ide_floppy && !scsi && !pc->buf) ||
+ (drive->media == ide_tape && !scsi && pc->bh) ||
+ (scsi && pc->sg)) {
+ int done = drive->pc_io_buffers(drive, pc, bcount,
+ !!(pc->flags & PC_FLAG_WRITING));
+
+ /* FIXME: don't do partial completions */
+ if (drive->media == ide_floppy && !scsi)
+ ide_end_request(drive, 1, done >> 9);
+ } else
+ xferfunc(drive, NULL, pc->cur_pos, bcount);
+
+ /* Update the current position */
+ pc->xferred += bcount;
+ pc->cur_pos += bcount;
+
+ debug_log("[cmd %x] transferred %d bytes on that intr.\n",
+ rq->cmd[0], bcount);
+next_irq:
+ /* And set the interrupt handler again */
+ ide_set_handler(drive, ide_pc_intr, timeout, expiry);
+ return ide_started;
+}
+
+static u8 ide_read_ireason(ide_drive_t *drive)
+{
+ ide_task_t task;
+
+ memset(&task, 0, sizeof(task));
+ task.tf_flags = IDE_TFLAG_IN_NSECT;
+
+ drive->hwif->tp_ops->tf_read(drive, &task);
+
+ return task.tf.nsect & 3;
+}
+
+static u8 ide_wait_ireason(ide_drive_t *drive, u8 ireason)
+{
+ int retries = 100;
+
+ while (retries-- && ((ireason & ATAPI_COD) == 0 ||
+ (ireason & ATAPI_IO))) {
+ printk(KERN_ERR "%s: (IO,CoD != (0,1) while issuing "
+ "a packet command, retrying\n", drive->name);
+ udelay(100);
+ ireason = ide_read_ireason(drive);
+ if (retries == 0) {
+ printk(KERN_ERR "%s: (IO,CoD != (0,1) while issuing "
+ "a packet command, ignoring\n",
+ drive->name);
+ ireason |= ATAPI_COD;
+ ireason &= ~ATAPI_IO;
+ }
+ }
+
+ return ireason;
+}
+
+static int ide_delayed_transfer_pc(ide_drive_t *drive)
+{
+ /* Send the actual packet */
+ drive->hwif->tp_ops->output_data(drive, NULL, drive->pc->c, 12);
+
+ /* Timeout for the packet command */
+ return WAIT_FLOPPY_CMD;
+}
+
+static ide_startstop_t ide_transfer_pc(ide_drive_t *drive)
+{
+ struct ide_atapi_pc *pc = drive->pc;
+ ide_hwif_t *hwif = drive->hwif;
+ struct request *rq = hwif->hwgroup->rq;
+ ide_expiry_t *expiry;
+ unsigned int timeout;
+ ide_startstop_t startstop;
+ u8 ireason;
+
+ if (ide_wait_stat(&startstop, drive, ATA_DRQ, ATA_BUSY, WAIT_READY)) {
+ printk(KERN_ERR "%s: Strange, packet command initiated yet "
+ "DRQ isn't asserted\n", drive->name);
+ return startstop;
+ }
+
+ ireason = ide_read_ireason(drive);
+ if (drive->media == ide_tape &&
+ (drive->dev_flags & IDE_DFLAG_SCSI) == 0)
+ ireason = ide_wait_ireason(drive, ireason);
+
+ if ((ireason & ATAPI_COD) == 0 || (ireason & ATAPI_IO)) {
+ printk(KERN_ERR "%s: (IO,CoD) != (0,1) while issuing "
+ "a packet command\n", drive->name);
+ return ide_do_reset(drive);
+ }
+
+ /*
+ * If necessary schedule the packet transfer to occur 'timeout'
+ * miliseconds later in ide_delayed_transfer_pc() after the device
+ * says it's ready for a packet.
+ */
+ if (drive->atapi_flags & IDE_AFLAG_ZIP_DRIVE) {
+ timeout = drive->pc_delay;
+ expiry = &ide_delayed_transfer_pc;
+ } else {
+ if (drive->dev_flags & IDE_DFLAG_SCSI) {
+ timeout = ide_scsi_get_timeout(pc);
+ expiry = ide_scsi_expiry;
+ } else {
+ timeout = (drive->media == ide_floppy) ? WAIT_FLOPPY_CMD
+ : WAIT_TAPE_CMD;
+ expiry = NULL;
+ }
+ }
+
+ /* Set the interrupt routine */
+ ide_set_handler(drive, ide_pc_intr, timeout, expiry);
+
+ /* Begin DMA, if necessary */
+ if (pc->flags & PC_FLAG_DMA_OK) {
+ pc->flags |= PC_FLAG_DMA_IN_PROGRESS;
+ hwif->dma_ops->dma_start(drive);
+ }
+
+ /* Send the actual packet */
+ if ((drive->atapi_flags & IDE_AFLAG_ZIP_DRIVE) == 0)
+ hwif->tp_ops->output_data(drive, NULL, rq->cmd, 12);
+
+ return ide_started;
+}
+
+ide_startstop_t ide_issue_pc(ide_drive_t *drive, unsigned int timeout,
+ ide_expiry_t *expiry)
+{
+ struct ide_atapi_pc *pc = drive->pc;
+ ide_hwif_t *hwif = drive->hwif;
+ u32 tf_flags;
+ u16 bcount;
+ u8 scsi = !!(drive->dev_flags & IDE_DFLAG_SCSI);
+
+ /* We haven't transferred any data yet */
+ pc->xferred = 0;
+ pc->cur_pos = pc->buf;
+
+ /* Request to transfer the entire buffer at once */
+ if (drive->media == ide_tape && scsi == 0)
+ bcount = pc->req_xfer;
+ else
+ bcount = min(pc->req_xfer, 63 * 1024);
+
+ if (pc->flags & PC_FLAG_DMA_ERROR) {
+ pc->flags &= ~PC_FLAG_DMA_ERROR;
+ ide_dma_off(drive);
+ }
+
+ if ((pc->flags & PC_FLAG_DMA_OK) &&
+ (drive->dev_flags & IDE_DFLAG_USING_DMA)) {
+ if (scsi)
+ hwif->sg_mapped = 1;
+ drive->dma = !hwif->dma_ops->dma_setup(drive);
+ if (scsi)
+ hwif->sg_mapped = 0;
+ }
+
+ if (!drive->dma)
+ pc->flags &= ~PC_FLAG_DMA_OK;
+
+ if (scsi)
+ tf_flags = 0;
+ else if (drive->media == ide_cdrom || drive->media == ide_optical)
+ tf_flags = IDE_TFLAG_OUT_NSECT | IDE_TFLAG_OUT_LBAL;
+ else
+ tf_flags = IDE_TFLAG_OUT_DEVICE;
+
+ ide_pktcmd_tf_load(drive, tf_flags, bcount, drive->dma);
+
+ /* Issue the packet command */
+ if (drive->atapi_flags & IDE_AFLAG_DRQ_INTERRUPT) {
+ ide_execute_command(drive, ATA_CMD_PACKET, ide_transfer_pc,
+ timeout, NULL);
+ return ide_started;
+ } else {
+ ide_execute_pkt_cmd(drive);
+ return ide_transfer_pc(drive);
+ }
+}
+EXPORT_SYMBOL_GPL(ide_issue_pc);
diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c
new file mode 100644
index 0000000..65f02b2
--- /dev/null
+++ b/drivers/ide/ide-cd.c
@@ -0,0 +1,2304 @@
+/*
+ * ATAPI CD-ROM driver.
+ *
+ * Copyright (C) 1994-1996 Scott Snyder <snyder@fnald0.fnal.gov>
+ * Copyright (C) 1996-1998 Erik Andersen <andersee@debian.org>
+ * Copyright (C) 1998-2000 Jens Axboe <axboe@suse.de>
+ * Copyright (C) 2005, 2007 Bartlomiej Zolnierkiewicz
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See linux/COPYING for more information.
+ *
+ * See Documentation/cdrom/ide-cd for usage information.
+ *
+ * Suggestions are welcome. Patches that work are more welcome though. ;-)
+ * For those wishing to work on this driver, please be sure you download
+ * and comply with the latest Mt. Fuji (SFF8090 version 4) and ATAPI
+ * (SFF-8020i rev 2.6) standards. These documents can be obtained by
+ * anonymous ftp from:
+ * ftp://fission.dt.wdc.com/pub/standards/SFF_atapi/spec/SFF8020-r2.6/PS/8020r26.ps
+ * ftp://ftp.avc-pioneer.com/Mtfuji4/Spec/Fuji4r10.pdf
+ *
+ * For historical changelog please see:
+ * Documentation/ide/ChangeLog.ide-cd.1994-2004
+ */
+
+#define DRV_NAME "ide-cd"
+#define PFX DRV_NAME ": "
+
+#define IDECD_VERSION "5.00"
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/errno.h>
+#include <linux/cdrom.h>
+#include <linux/ide.h>
+#include <linux/completion.h>
+#include <linux/mutex.h>
+#include <linux/bcd.h>
+
+/* For SCSI -> ATAPI command conversion */
+#include <scsi/scsi.h>
+
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <asm/byteorder.h>
+#include <linux/uaccess.h>
+#include <asm/unaligned.h>
+
+#include "ide-cd.h"
+
+#define IDECD_DEBUG_LOG 1
+
+#if IDECD_DEBUG_LOG
+#define ide_debug_log(lvl, fmt, args...) __ide_debug_log(lvl, fmt, args)
+#else
+#define ide_debug_log(lvl, fmt, args...) do {} while (0)
+#endif
+
+static DEFINE_MUTEX(idecd_ref_mutex);
+
+static void ide_cd_release(struct kref *);
+
+static struct cdrom_info *ide_cd_get(struct gendisk *disk)
+{
+ struct cdrom_info *cd = NULL;
+
+ mutex_lock(&idecd_ref_mutex);
+ cd = ide_drv_g(disk, cdrom_info);
+ if (cd) {
+ if (ide_device_get(cd->drive))
+ cd = NULL;
+ else
+ kref_get(&cd->kref);
+
+ }
+ mutex_unlock(&idecd_ref_mutex);
+ return cd;
+}
+
+static void ide_cd_put(struct cdrom_info *cd)
+{
+ ide_drive_t *drive = cd->drive;
+
+ mutex_lock(&idecd_ref_mutex);
+ kref_put(&cd->kref, ide_cd_release);
+ ide_device_put(drive);
+ mutex_unlock(&idecd_ref_mutex);
+}
+
+/*
+ * Generic packet command support and error handling routines.
+ */
+
+/* Mark that we've seen a media change and invalidate our internal buffers. */
+static void cdrom_saw_media_change(ide_drive_t *drive)
+{
+ drive->dev_flags |= IDE_DFLAG_MEDIA_CHANGED;
+ drive->atapi_flags &= ~IDE_AFLAG_TOC_VALID;
+}
+
+static int cdrom_log_sense(ide_drive_t *drive, struct request *rq,
+ struct request_sense *sense)
+{
+ int log = 0;
+
+ ide_debug_log(IDE_DBG_SENSE, "Call %s, sense_key: 0x%x\n", __func__,
+ sense->sense_key);
+
+ if (!sense || !rq || (rq->cmd_flags & REQ_QUIET))
+ return 0;
+
+ switch (sense->sense_key) {
+ case NO_SENSE:
+ case RECOVERED_ERROR:
+ break;
+ case NOT_READY:
+ /*
+ * don't care about tray state messages for e.g. capacity
+ * commands or in-progress or becoming ready
+ */
+ if (sense->asc == 0x3a || sense->asc == 0x04)
+ break;
+ log = 1;
+ break;
+ case ILLEGAL_REQUEST:
+ /*
+ * don't log START_STOP unit with LoEj set, since we cannot
+ * reliably check if drive can auto-close
+ */
+ if (rq->cmd[0] == GPCMD_START_STOP_UNIT && sense->asc == 0x24)
+ break;
+ log = 1;
+ break;
+ case UNIT_ATTENTION:
+ /*
+ * Make good and sure we've seen this potential media change.
+ * Some drives (i.e. Creative) fail to present the correct sense
+ * key in the error register.
+ */
+ cdrom_saw_media_change(drive);
+ break;
+ default:
+ log = 1;
+ break;
+ }
+ return log;
+}
+
+static void cdrom_analyze_sense_data(ide_drive_t *drive,
+ struct request *failed_command,
+ struct request_sense *sense)
+{
+ unsigned long sector;
+ unsigned long bio_sectors;
+ struct cdrom_info *info = drive->driver_data;
+
+ ide_debug_log(IDE_DBG_SENSE, "Call %s, error_code: 0x%x, "
+ "sense_key: 0x%x\n", __func__, sense->error_code,
+ sense->sense_key);
+
+ if (failed_command)
+ ide_debug_log(IDE_DBG_SENSE, "%s: failed cmd: 0x%x\n",
+ __func__, failed_command->cmd[0]);
+
+ if (!cdrom_log_sense(drive, failed_command, sense))
+ return;
+
+ /*
+ * If a read toc is executed for a CD-R or CD-RW medium where the first
+ * toc has not been recorded yet, it will fail with 05/24/00 (which is a
+ * confusing error)
+ */
+ if (failed_command && failed_command->cmd[0] == GPCMD_READ_TOC_PMA_ATIP)
+ if (sense->sense_key == 0x05 && sense->asc == 0x24)
+ return;
+
+ /* current error */
+ if (sense->error_code == 0x70) {
+ switch (sense->sense_key) {
+ case MEDIUM_ERROR:
+ case VOLUME_OVERFLOW:
+ case ILLEGAL_REQUEST:
+ if (!sense->valid)
+ break;
+ if (failed_command == NULL ||
+ !blk_fs_request(failed_command))
+ break;
+ sector = (sense->information[0] << 24) |
+ (sense->information[1] << 16) |
+ (sense->information[2] << 8) |
+ (sense->information[3]);
+
+ if (drive->queue->hardsect_size == 2048)
+ /* device sector size is 2K */
+ sector <<= 2;
+
+ bio_sectors = max(bio_sectors(failed_command->bio), 4U);
+ sector &= ~(bio_sectors - 1);
+
+ if (sector < get_capacity(info->disk) &&
+ drive->probed_capacity - sector < 4 * 75)
+ set_capacity(info->disk, sector);
+ }
+ }
+
+ ide_cd_log_error(drive->name, failed_command, sense);
+}
+
+static void cdrom_queue_request_sense(ide_drive_t *drive, void *sense,
+ struct request *failed_command)
+{
+ struct cdrom_info *info = drive->driver_data;
+ struct request *rq = &info->request_sense_request;
+
+ ide_debug_log(IDE_DBG_SENSE, "Call %s\n", __func__);
+
+ if (sense == NULL)
+ sense = &info->sense_data;
+
+ /* stuff the sense request in front of our current request */
+ blk_rq_init(NULL, rq);
+ rq->cmd_type = REQ_TYPE_ATA_PC;
+ rq->rq_disk = info->disk;
+
+ rq->data = sense;
+ rq->cmd[0] = GPCMD_REQUEST_SENSE;
+ rq->cmd[4] = 18;
+ rq->data_len = 18;
+
+ rq->cmd_type = REQ_TYPE_SENSE;
+ rq->cmd_flags |= REQ_PREEMPT;
+
+ /* NOTE! Save the failed command in "rq->buffer" */
+ rq->buffer = (void *) failed_command;
+
+ if (failed_command)
+ ide_debug_log(IDE_DBG_SENSE, "failed_cmd: 0x%x\n",
+ failed_command->cmd[0]);
+
+ ide_do_drive_cmd(drive, rq);
+}
+
+static void cdrom_end_request(ide_drive_t *drive, int uptodate)
+{
+ struct request *rq = HWGROUP(drive)->rq;
+ int nsectors = rq->hard_cur_sectors;
+
+ ide_debug_log(IDE_DBG_FUNC, "Call %s, cmd: 0x%x, uptodate: 0x%x, "
+ "nsectors: %d\n", __func__, rq->cmd[0], uptodate,
+ nsectors);
+
+ if (blk_sense_request(rq) && uptodate) {
+ /*
+ * For REQ_TYPE_SENSE, "rq->buffer" points to the original
+ * failed request
+ */
+ struct request *failed = (struct request *) rq->buffer;
+ struct cdrom_info *info = drive->driver_data;
+ void *sense = &info->sense_data;
+ unsigned long flags;
+
+ if (failed) {
+ if (failed->sense) {
+ sense = failed->sense;
+ failed->sense_len = rq->sense_len;
+ }
+ cdrom_analyze_sense_data(drive, failed, sense);
+ /*
+ * now end the failed request
+ */
+ if (blk_fs_request(failed)) {
+ if (ide_end_dequeued_request(drive, failed, 0,
+ failed->hard_nr_sectors))
+ BUG();
+ } else {
+ spin_lock_irqsave(&ide_lock, flags);
+ if (__blk_end_request(failed, -EIO,
+ failed->data_len))
+ BUG();
+ spin_unlock_irqrestore(&ide_lock, flags);
+ }
+ } else
+ cdrom_analyze_sense_data(drive, NULL, sense);
+ }
+
+ if (!rq->current_nr_sectors && blk_fs_request(rq))
+ uptodate = 1;
+ /* make sure it's fully ended */
+ if (blk_pc_request(rq))
+ nsectors = (rq->data_len + 511) >> 9;
+ if (!nsectors)
+ nsectors = 1;
+
+ ide_debug_log(IDE_DBG_FUNC, "Exit %s, uptodate: 0x%x, nsectors: %d\n",
+ __func__, uptodate, nsectors);
+
+ ide_end_request(drive, uptodate, nsectors);
+}
+
+static void ide_dump_status_no_sense(ide_drive_t *drive, const char *msg, u8 st)
+{
+ if (st & 0x80)
+ return;
+ ide_dump_status(drive, msg, st);
+}
+
+/*
+ * Returns:
+ * 0: if the request should be continued.
+ * 1: if the request was ended.
+ */
+static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ struct request *rq = hwif->hwgroup->rq;
+ int stat, err, sense_key;
+
+ /* check for errors */
+ stat = hwif->tp_ops->read_status(hwif);
+
+ if (stat_ret)
+ *stat_ret = stat;
+
+ if (OK_STAT(stat, good_stat, BAD_R_STAT))
+ return 0;
+
+ /* get the IDE error register */
+ err = ide_read_error(drive);
+ sense_key = err >> 4;
+
+ if (rq == NULL) {
+ printk(KERN_ERR PFX "%s: missing rq in %s\n",
+ drive->name, __func__);
+ return 1;
+ }
+
+ ide_debug_log(IDE_DBG_RQ, "%s: stat: 0x%x, good_stat: 0x%x, "
+ "rq->cmd[0]: 0x%x, rq->cmd_type: 0x%x, err: 0x%x\n",
+ __func__, stat, good_stat, rq->cmd[0], rq->cmd_type, err);
+
+ if (blk_sense_request(rq)) {
+ /*
+ * We got an error trying to get sense info from the drive
+ * (probably while trying to recover from a former error).
+ * Just give up.
+ */
+ rq->cmd_flags |= REQ_FAILED;
+ cdrom_end_request(drive, 0);
+ ide_error(drive, "request sense failure", stat);
+ return 1;
+
+ } else if (blk_pc_request(rq) || rq->cmd_type == REQ_TYPE_ATA_PC) {
+ /* All other functions, except for READ. */
+
+ /*
+ * if we have an error, pass back CHECK_CONDITION as the
+ * scsi status byte
+ */
+ if (blk_pc_request(rq) && !rq->errors)
+ rq->errors = SAM_STAT_CHECK_CONDITION;
+
+ /* check for tray open */
+ if (sense_key == NOT_READY) {
+ cdrom_saw_media_change(drive);
+ } else if (sense_key == UNIT_ATTENTION) {
+ /* check for media change */
+ cdrom_saw_media_change(drive);
+ return 0;
+ } else if (sense_key == ILLEGAL_REQUEST &&
+ rq->cmd[0] == GPCMD_START_STOP_UNIT) {
+ /*
+ * Don't print error message for this condition--
+ * SFF8090i indicates that 5/24/00 is the correct
+ * response to a request to close the tray if the
+ * drive doesn't have that capability.
+ * cdrom_log_sense() knows this!
+ */
+ } else if (!(rq->cmd_flags & REQ_QUIET)) {
+ /* otherwise, print an error */
+ ide_dump_status(drive, "packet command error", stat);
+ }
+
+ rq->cmd_flags |= REQ_FAILED;
+
+ /*
+ * instead of playing games with moving completions around,
+ * remove failed request completely and end it when the
+ * request sense has completed
+ */
+ goto end_request;
+
+ } else if (blk_fs_request(rq)) {
+ int do_end_request = 0;
+
+ /* handle errors from READ and WRITE requests */
+
+ if (blk_noretry_request(rq))
+ do_end_request = 1;
+
+ if (sense_key == NOT_READY) {
+ /* tray open */
+ if (rq_data_dir(rq) == READ) {
+ cdrom_saw_media_change(drive);
+
+ /* fail the request */
+ printk(KERN_ERR PFX "%s: tray open\n",
+ drive->name);
+ do_end_request = 1;
+ } else {
+ struct cdrom_info *info = drive->driver_data;
+
+ /*
+ * Allow the drive 5 seconds to recover, some
+ * devices will return this error while flushing
+ * data from cache.
+ */
+ if (!rq->errors)
+ info->write_timeout = jiffies +
+ ATAPI_WAIT_WRITE_BUSY;
+ rq->errors = 1;
+ if (time_after(jiffies, info->write_timeout))
+ do_end_request = 1;
+ else {
+ unsigned long flags;
+
+ /*
+ * take a breather relying on the unplug
+ * timer to kick us again
+ */
+ spin_lock_irqsave(&ide_lock, flags);
+ blk_plug_device(drive->queue);
+ spin_unlock_irqrestore(&ide_lock,
+ flags);
+ return 1;
+ }
+ }
+ } else if (sense_key == UNIT_ATTENTION) {
+ /* media change */
+ cdrom_saw_media_change(drive);
+
+ /*
+ * Arrange to retry the request but be sure to give up
+ * if we've retried too many times.
+ */
+ if (++rq->errors > ERROR_MAX)
+ do_end_request = 1;
+ } else if (sense_key == ILLEGAL_REQUEST ||
+ sense_key == DATA_PROTECT) {
+ /*
+ * No point in retrying after an illegal request or data
+ * protect error.
+ */
+ ide_dump_status_no_sense(drive, "command error", stat);
+ do_end_request = 1;
+ } else if (sense_key == MEDIUM_ERROR) {
+ /*
+ * No point in re-trying a zillion times on a bad
+ * sector. If we got here the error is not correctable.
+ */
+ ide_dump_status_no_sense(drive,
+ "media error (bad sector)",
+ stat);
+ do_end_request = 1;
+ } else if (sense_key == BLANK_CHECK) {
+ /* disk appears blank ?? */
+ ide_dump_status_no_sense(drive, "media error (blank)",
+ stat);
+ do_end_request = 1;
+ } else if ((err & ~ATA_ABORTED) != 0) {
+ /* go to the default handler for other errors */
+ ide_error(drive, "cdrom_decode_status", stat);
+ return 1;
+ } else if ((++rq->errors > ERROR_MAX)) {
+ /* we've racked up too many retries, abort */
+ do_end_request = 1;
+ }
+
+ /*
+ * End a request through request sense analysis when we have
+ * sense data. We need this in order to perform end of media
+ * processing.
+ */
+ if (do_end_request)
+ goto end_request;
+
+ /*
+ * If we got a CHECK_CONDITION status, queue
+ * a request sense command.
+ */
+ if (stat & ATA_ERR)
+ cdrom_queue_request_sense(drive, NULL, NULL);
+ } else {
+ blk_dump_rq_flags(rq, PFX "bad rq");
+ cdrom_end_request(drive, 0);
+ }
+
+ /* retry, or handle the next request */
+ return 1;
+
+end_request:
+ if (stat & ATA_ERR) {
+ unsigned long flags;
+
+ spin_lock_irqsave(&ide_lock, flags);
+ blkdev_dequeue_request(rq);
+ HWGROUP(drive)->rq = NULL;
+ spin_unlock_irqrestore(&ide_lock, flags);
+
+ cdrom_queue_request_sense(drive, rq->sense, rq);
+ } else
+ cdrom_end_request(drive, 0);
+
+ return 1;
+}
+
+static int cdrom_timer_expiry(ide_drive_t *drive)
+{
+ struct request *rq = HWGROUP(drive)->rq;
+ unsigned long wait = 0;
+
+ ide_debug_log(IDE_DBG_RQ, "Call %s: rq->cmd[0]: 0x%x\n", __func__,
+ rq->cmd[0]);
+
+ /*
+ * Some commands are *slow* and normally take a long time to complete.
+ * Usually we can use the ATAPI "disconnect" to bypass this, but not all
+ * commands/drives support that. Let ide_timer_expiry keep polling us
+ * for these.
+ */
+ switch (rq->cmd[0]) {
+ case GPCMD_BLANK:
+ case GPCMD_FORMAT_UNIT:
+ case GPCMD_RESERVE_RZONE_TRACK:
+ case GPCMD_CLOSE_TRACK:
+ case GPCMD_FLUSH_CACHE:
+ wait = ATAPI_WAIT_PC;
+ break;
+ default:
+ if (!(rq->cmd_flags & REQ_QUIET))
+ printk(KERN_INFO PFX "cmd 0x%x timed out\n",
+ rq->cmd[0]);
+ wait = 0;
+ break;
+ }
+ return wait;
+}
+
+/*
+ * Set up the device registers for transferring a packet command on DEV,
+ * expecting to later transfer XFERLEN bytes. HANDLER is the routine
+ * which actually transfers the command to the drive. If this is a
+ * drq_interrupt device, this routine will arrange for HANDLER to be
+ * called when the interrupt from the drive arrives. Otherwise, HANDLER
+ * will be called immediately after the drive is prepared for the transfer.
+ */
+static ide_startstop_t cdrom_start_packet_command(ide_drive_t *drive,
+ int xferlen,
+ ide_handler_t *handler)
+{
+ ide_hwif_t *hwif = drive->hwif;
+
+ ide_debug_log(IDE_DBG_PC, "Call %s, xferlen: %d\n", __func__, xferlen);
+
+ /* FIXME: for Virtual DMA we must check harder */
+ if (drive->dma)
+ drive->dma = !hwif->dma_ops->dma_setup(drive);
+
+ /* set up the controller registers */
+ ide_pktcmd_tf_load(drive, IDE_TFLAG_OUT_NSECT | IDE_TFLAG_OUT_LBAL,
+ xferlen, drive->dma);
+
+ if (drive->atapi_flags & IDE_AFLAG_DRQ_INTERRUPT) {
+ /* waiting for CDB interrupt, not DMA yet. */
+ if (drive->dma)
+ drive->waiting_for_dma = 0;
+
+ /* packet command */
+ ide_execute_command(drive, ATA_CMD_PACKET, handler,
+ ATAPI_WAIT_PC, cdrom_timer_expiry);
+ return ide_started;
+ } else {
+ ide_execute_pkt_cmd(drive);
+
+ return (*handler) (drive);
+ }
+}
+
+/*
+ * Send a packet command to DRIVE described by CMD_BUF and CMD_LEN. The device
+ * registers must have already been prepared by cdrom_start_packet_command.
+ * HANDLER is the interrupt handler to call when the command completes or
+ * there's data ready.
+ */
+#define ATAPI_MIN_CDB_BYTES 12
+static ide_startstop_t cdrom_transfer_packet_command(ide_drive_t *drive,
+ struct request *rq,
+ ide_handler_t *handler)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ int cmd_len;
+ ide_startstop_t startstop;
+
+ ide_debug_log(IDE_DBG_PC, "Call %s\n", __func__);
+
+ if (drive->atapi_flags & IDE_AFLAG_DRQ_INTERRUPT) {
+ /*
+ * Here we should have been called after receiving an interrupt
+ * from the device. DRQ should how be set.
+ */
+
+ /* check for errors */
+ if (cdrom_decode_status(drive, ATA_DRQ, NULL))
+ return ide_stopped;
+
+ /* ok, next interrupt will be DMA interrupt */
+ if (drive->dma)
+ drive->waiting_for_dma = 1;
+ } else {
+ /* otherwise, we must wait for DRQ to get set */
+ if (ide_wait_stat(&startstop, drive, ATA_DRQ,
+ ATA_BUSY, WAIT_READY))
+ return startstop;
+ }
+
+ /* arm the interrupt handler */
+ ide_set_handler(drive, handler, rq->timeout, cdrom_timer_expiry);
+
+ /* ATAPI commands get padded out to 12 bytes minimum */
+ cmd_len = COMMAND_SIZE(rq->cmd[0]);
+ if (cmd_len < ATAPI_MIN_CDB_BYTES)
+ cmd_len = ATAPI_MIN_CDB_BYTES;
+
+ /* send the command to the device */
+ hwif->tp_ops->output_data(drive, NULL, rq->cmd, cmd_len);
+
+ /* start the DMA if need be */
+ if (drive->dma)
+ hwif->dma_ops->dma_start(drive);
+
+ return ide_started;
+}
+
+/*
+ * Check the contents of the interrupt reason register from the cdrom
+ * and attempt to recover if there are problems. Returns 0 if everything's
+ * ok; nonzero if the request has been terminated.
+ */
+static int ide_cd_check_ireason(ide_drive_t *drive, struct request *rq,
+ int len, int ireason, int rw)
+{
+ ide_hwif_t *hwif = drive->hwif;
+
+ ide_debug_log(IDE_DBG_FUNC, "Call %s, ireason: 0x%x, rw: 0x%x\n",
+ __func__, ireason, rw);
+
+ /*
+ * ireason == 0: the drive wants to receive data from us
+ * ireason == 2: the drive is expecting to transfer data to us
+ */
+ if (ireason == (!rw << 1))
+ return 0;
+ else if (ireason == (rw << 1)) {
+
+ /* whoops... */
+ printk(KERN_ERR PFX "%s: %s: wrong transfer direction!\n",
+ drive->name, __func__);
+
+ ide_pad_transfer(drive, rw, len);
+ } else if (rw == 0 && ireason == 1) {
+ /*
+ * Some drives (ASUS) seem to tell us that status info is
+ * available. Just get it and ignore.
+ */
+ (void)hwif->tp_ops->read_status(hwif);
+ return 0;
+ } else {
+ /* drive wants a command packet, or invalid ireason... */
+ printk(KERN_ERR PFX "%s: %s: bad interrupt reason 0x%02x\n",
+ drive->name, __func__, ireason);
+ }
+
+ if (rq->cmd_type == REQ_TYPE_ATA_PC)
+ rq->cmd_flags |= REQ_FAILED;
+
+ cdrom_end_request(drive, 0);
+ return -1;
+}
+
+/*
+ * Assume that the drive will always provide data in multiples of at least
+ * SECTOR_SIZE, as it gets hairy to keep track of the transfers otherwise.
+ */
+static int ide_cd_check_transfer_size(ide_drive_t *drive, int len)
+{
+ ide_debug_log(IDE_DBG_FUNC, "Call %s, len: %d\n", __func__, len);
+
+ if ((len % SECTOR_SIZE) == 0)
+ return 0;
+
+ printk(KERN_ERR PFX "%s: %s: Bad transfer size %d\n", drive->name,
+ __func__, len);
+
+ if (drive->atapi_flags & IDE_AFLAG_LIMIT_NFRAMES)
+ printk(KERN_ERR PFX "This drive is not supported by this "
+ "version of the driver\n");
+ else {
+ printk(KERN_ERR PFX "Trying to limit transfer sizes\n");
+ drive->atapi_flags |= IDE_AFLAG_LIMIT_NFRAMES;
+ }
+
+ return 1;
+}
+
+static ide_startstop_t cdrom_newpc_intr(ide_drive_t *);
+
+static ide_startstop_t ide_cd_prepare_rw_request(ide_drive_t *drive,
+ struct request *rq)
+{
+ ide_debug_log(IDE_DBG_RQ, "Call %s: rq->cmd_flags: 0x%x\n", __func__,
+ rq->cmd_flags);
+
+ if (rq_data_dir(rq) == READ) {
+ unsigned short sectors_per_frame =
+ queue_hardsect_size(drive->queue) >> SECTOR_BITS;
+ int nskip = rq->sector & (sectors_per_frame - 1);
+
+ /*
+ * If the requested sector doesn't start on a frame boundary,
+ * we must adjust the start of the transfer so that it does,
+ * and remember to skip the first few sectors.
+ *
+ * If the rq->current_nr_sectors field is larger than the size
+ * of the buffer, it will mean that we're to skip a number of
+ * sectors equal to the amount by which rq->current_nr_sectors
+ * is larger than the buffer size.
+ */
+ if (nskip > 0) {
+ /* sanity check... */
+ if (rq->current_nr_sectors !=
+ bio_cur_sectors(rq->bio)) {
+ printk(KERN_ERR PFX "%s: %s: buffer botch (%u)\n",
+ drive->name, __func__,
+ rq->current_nr_sectors);
+ cdrom_end_request(drive, 0);
+ return ide_stopped;
+ }
+ rq->current_nr_sectors += nskip;
+ }
+ }
+
+ /* set up the command */
+ rq->timeout = ATAPI_WAIT_PC;
+
+ return ide_started;
+}
+
+/*
+ * Routine to send a read/write packet command to the drive. This is usually
+ * called directly from cdrom_start_{read,write}(). However, for drq_interrupt
+ * devices, it is called from an interrupt when the drive is ready to accept
+ * the command.
+ */
+static ide_startstop_t cdrom_start_rw_cont(ide_drive_t *drive)
+{
+ struct request *rq = drive->hwif->hwgroup->rq;
+
+ /* send the command to the drive and return */
+ return cdrom_transfer_packet_command(drive, rq, cdrom_newpc_intr);
+}
+
+#define IDECD_SEEK_THRESHOLD (1000) /* 1000 blocks */
+#define IDECD_SEEK_TIMER (5 * WAIT_MIN_SLEEP) /* 100 ms */
+#define IDECD_SEEK_TIMEOUT (2 * WAIT_CMD) /* 20 sec */
+
+static ide_startstop_t cdrom_seek_intr(ide_drive_t *drive)
+{
+ struct cdrom_info *info = drive->driver_data;
+ int stat;
+ static int retry = 10;
+
+ ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__);
+
+ if (cdrom_decode_status(drive, 0, &stat))
+ return ide_stopped;
+
+ drive->atapi_flags |= IDE_AFLAG_SEEKING;
+
+ if (retry && time_after(jiffies, info->start_seek + IDECD_SEEK_TIMER)) {
+ if (--retry == 0)
+ drive->dev_flags &= ~IDE_DFLAG_DSC_OVERLAP;
+ }
+ return ide_stopped;
+}
+
+static void ide_cd_prepare_seek_request(ide_drive_t *drive, struct request *rq)
+{
+ sector_t frame = rq->sector;
+
+ ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__);
+
+ sector_div(frame, queue_hardsect_size(drive->queue) >> SECTOR_BITS);
+
+ memset(rq->cmd, 0, BLK_MAX_CDB);
+ rq->cmd[0] = GPCMD_SEEK;
+ put_unaligned(cpu_to_be32(frame), (unsigned int *) &rq->cmd[2]);
+
+ rq->timeout = ATAPI_WAIT_PC;
+}
+
+static ide_startstop_t cdrom_start_seek_continuation(ide_drive_t *drive)
+{
+ struct request *rq = drive->hwif->hwgroup->rq;
+
+ return cdrom_transfer_packet_command(drive, rq, &cdrom_seek_intr);
+}
+
+/*
+ * Fix up a possibly partially-processed request so that we can start it over
+ * entirely, or even put it back on the request queue.
+ */
+static void ide_cd_restore_request(ide_drive_t *drive, struct request *rq)
+{
+
+ ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__);
+
+ if (rq->buffer != bio_data(rq->bio)) {
+ sector_t n =
+ (rq->buffer - (char *)bio_data(rq->bio)) / SECTOR_SIZE;
+
+ rq->buffer = bio_data(rq->bio);
+ rq->nr_sectors += n;
+ rq->sector -= n;
+ }
+ rq->current_nr_sectors = bio_cur_sectors(rq->bio);
+ rq->hard_cur_sectors = rq->current_nr_sectors;
+ rq->hard_nr_sectors = rq->nr_sectors;
+ rq->hard_sector = rq->sector;
+ rq->q->prep_rq_fn(rq->q, rq);
+}
+
+static void ide_cd_request_sense_fixup(ide_drive_t *drive, struct request *rq)
+{
+ ide_debug_log(IDE_DBG_FUNC, "Call %s, rq->cmd[0]: 0x%x\n",
+ __func__, rq->cmd[0]);
+
+ /*
+ * Some of the trailing request sense fields are optional,
+ * and some drives don't send them. Sigh.
+ */
+ if (rq->cmd[0] == GPCMD_REQUEST_SENSE &&
+ rq->data_len > 0 && rq->data_len <= 5)
+ while (rq->data_len > 0) {
+ *(u8 *)rq->data++ = 0;
+ --rq->data_len;
+ }
+}
+
+int ide_cd_queue_pc(ide_drive_t *drive, const unsigned char *cmd,
+ int write, void *buffer, unsigned *bufflen,
+ struct request_sense *sense, int timeout,
+ unsigned int cmd_flags)
+{
+ struct cdrom_info *info = drive->driver_data;
+ struct request_sense local_sense;
+ int retries = 10;
+ unsigned int flags = 0;
+
+ if (!sense)
+ sense = &local_sense;
+
+ ide_debug_log(IDE_DBG_PC, "Call %s, cmd[0]: 0x%x, write: 0x%x, "
+ "timeout: %d, cmd_flags: 0x%x\n", __func__, cmd[0], write,
+ timeout, cmd_flags);
+
+ /* start of retry loop */
+ do {
+ struct request *rq;
+ int error;
+
+ rq = blk_get_request(drive->queue, write, __GFP_WAIT);
+
+ memcpy(rq->cmd, cmd, BLK_MAX_CDB);
+ rq->cmd_type = REQ_TYPE_ATA_PC;
+ rq->sense = sense;
+ rq->cmd_flags |= cmd_flags;
+ rq->timeout = timeout;
+ if (buffer) {
+ rq->data = buffer;
+ rq->data_len = *bufflen;
+ }
+
+ error = blk_execute_rq(drive->queue, info->disk, rq, 0);
+
+ if (buffer)
+ *bufflen = rq->data_len;
+
+ flags = rq->cmd_flags;
+ blk_put_request(rq);
+
+ /*
+ * FIXME: we should probably abort/retry or something in case of
+ * failure.
+ */
+ if (flags & REQ_FAILED) {
+ /*
+ * The request failed. Retry if it was due to a unit
+ * attention status (usually means media was changed).
+ */
+ struct request_sense *reqbuf = sense;
+
+ if (reqbuf->sense_key == UNIT_ATTENTION)
+ cdrom_saw_media_change(drive);
+ else if (reqbuf->sense_key == NOT_READY &&
+ reqbuf->asc == 4 && reqbuf->ascq != 4) {
+ /*
+ * The drive is in the process of loading
+ * a disk. Retry, but wait a little to give
+ * the drive time to complete the load.
+ */
+ ssleep(2);
+ } else {
+ /* otherwise, don't retry */
+ retries = 0;
+ }
+ --retries;
+ }
+
+ /* end of retry loop */
+ } while ((flags & REQ_FAILED) && retries >= 0);
+
+ /* return an error if the command failed */
+ return (flags & REQ_FAILED) ? -EIO : 0;
+}
+
+/*
+ * Called from blk_end_request_callback() after the data of the request is
+ * completed and before the request itself is completed. By returning value '1',
+ * blk_end_request_callback() returns immediately without completing it.
+ */
+static int cdrom_newpc_intr_dummy_cb(struct request *rq)
+{
+ return 1;
+}
+
+static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ struct request *rq = HWGROUP(drive)->rq;
+ xfer_func_t *xferfunc;
+ ide_expiry_t *expiry = NULL;
+ int dma_error = 0, dma, stat, thislen, uptodate = 0;
+ int write = (rq_data_dir(rq) == WRITE) ? 1 : 0;
+ unsigned int timeout;
+ u16 len;
+ u8 ireason;
+
+ ide_debug_log(IDE_DBG_PC, "Call %s, rq->cmd[0]: 0x%x, write: 0x%x\n",
+ __func__, rq->cmd[0], write);
+
+ /* check for errors */
+ dma = drive->dma;
+ if (dma) {
+ drive->dma = 0;
+ dma_error = hwif->dma_ops->dma_end(drive);
+ if (dma_error) {
+ printk(KERN_ERR PFX "%s: DMA %s error\n", drive->name,
+ write ? "write" : "read");
+ ide_dma_off(drive);
+ }
+ }
+
+ if (cdrom_decode_status(drive, 0, &stat))
+ return ide_stopped;
+
+ /* using dma, transfer is complete now */
+ if (dma) {
+ if (dma_error)
+ return ide_error(drive, "dma error", stat);
+ if (blk_fs_request(rq)) {
+ ide_end_request(drive, 1, rq->nr_sectors);
+ return ide_stopped;
+ } else if (rq->cmd_type == REQ_TYPE_ATA_PC && !rq->bio) {
+ ide_end_request(drive, 1, 1);
+ return ide_stopped;
+ }
+ goto end_request;
+ }
+
+ ide_read_bcount_and_ireason(drive, &len, &ireason);
+
+ thislen = blk_fs_request(rq) ? len : rq->data_len;
+ if (thislen > len)
+ thislen = len;
+
+ ide_debug_log(IDE_DBG_PC, "%s: DRQ: stat: 0x%x, thislen: %d\n",
+ __func__, stat, thislen);
+
+ /* If DRQ is clear, the command has completed. */
+ if ((stat & ATA_DRQ) == 0) {
+ if (blk_fs_request(rq)) {
+ /*
+ * If we're not done reading/writing, complain.
+ * Otherwise, complete the command normally.
+ */
+ uptodate = 1;
+ if (rq->current_nr_sectors > 0) {
+ printk(KERN_ERR PFX "%s: %s: data underrun "
+ "(%d blocks)\n",
+ drive->name, __func__,
+ rq->current_nr_sectors);
+ if (!write)
+ rq->cmd_flags |= REQ_FAILED;
+ uptodate = 0;
+ }
+ cdrom_end_request(drive, uptodate);
+ return ide_stopped;
+ } else if (!blk_pc_request(rq)) {
+ ide_cd_request_sense_fixup(drive, rq);
+ /* complain if we still have data left to transfer */
+ uptodate = rq->data_len ? 0 : 1;
+ }
+ goto end_request;
+ }
+
+ /* check which way to transfer data */
+ if (ide_cd_check_ireason(drive, rq, len, ireason, write))
+ return ide_stopped;
+
+ if (blk_fs_request(rq)) {
+ if (write == 0) {
+ int nskip;
+
+ if (ide_cd_check_transfer_size(drive, len)) {
+ cdrom_end_request(drive, 0);
+ return ide_stopped;
+ }
+
+ /*
+ * First, figure out if we need to bit-bucket
+ * any of the leading sectors.
+ */
+ nskip = min_t(int, rq->current_nr_sectors
+ - bio_cur_sectors(rq->bio),
+ thislen >> 9);
+ if (nskip > 0) {
+ ide_pad_transfer(drive, write, nskip << 9);
+ rq->current_nr_sectors -= nskip;
+ thislen -= (nskip << 9);
+ }
+ }
+ }
+
+ if (ireason == 0) {
+ write = 1;
+ xferfunc = hwif->tp_ops->output_data;
+ } else {
+ write = 0;
+ xferfunc = hwif->tp_ops->input_data;
+ }
+
+ ide_debug_log(IDE_DBG_PC, "%s: data transfer, rq->cmd_type: 0x%x, "
+ "ireason: 0x%x\n", __func__, rq->cmd_type, ireason);
+
+ /* transfer data */
+ while (thislen > 0) {
+ u8 *ptr = blk_fs_request(rq) ? NULL : rq->data;
+ int blen = rq->data_len;
+
+ /* bio backed? */
+ if (rq->bio) {
+ if (blk_fs_request(rq)) {
+ ptr = rq->buffer;
+ blen = rq->current_nr_sectors << 9;
+ } else {
+ ptr = bio_data(rq->bio);
+ blen = bio_iovec(rq->bio)->bv_len;
+ }
+ }
+
+ if (!ptr) {
+ if (blk_fs_request(rq) && !write)
+ /*
+ * If the buffers are full, pipe the rest into
+ * oblivion.
+ */
+ ide_pad_transfer(drive, 0, thislen);
+ else {
+ printk(KERN_ERR PFX "%s: confused, missing data\n",
+ drive->name);
+ blk_dump_rq_flags(rq, rq_data_dir(rq)
+ ? "cdrom_newpc_intr, write"
+ : "cdrom_newpc_intr, read");
+ }
+ break;
+ }
+
+ if (blen > thislen)
+ blen = thislen;
+
+ xferfunc(drive, NULL, ptr, blen);
+
+ thislen -= blen;
+ len -= blen;
+
+ if (blk_fs_request(rq)) {
+ rq->buffer += blen;
+ rq->nr_sectors -= (blen >> 9);
+ rq->current_nr_sectors -= (blen >> 9);
+ rq->sector += (blen >> 9);
+
+ if (rq->current_nr_sectors == 0 && rq->nr_sectors)
+ cdrom_end_request(drive, 1);
+ } else {
+ rq->data_len -= blen;
+
+ /*
+ * The request can't be completed until DRQ is cleared.
+ * So complete the data, but don't complete the request
+ * using the dummy function for the callback feature
+ * of blk_end_request_callback().
+ */
+ if (rq->bio)
+ blk_end_request_callback(rq, 0, blen,
+ cdrom_newpc_intr_dummy_cb);
+ else
+ rq->data += blen;
+ }
+ if (!write && blk_sense_request(rq))
+ rq->sense_len += blen;
+ }
+
+ /* pad, if necessary */
+ if (!blk_fs_request(rq) && len > 0)
+ ide_pad_transfer(drive, write, len);
+
+ if (blk_pc_request(rq)) {
+ timeout = rq->timeout;
+ } else {
+ timeout = ATAPI_WAIT_PC;
+ if (!blk_fs_request(rq))
+ expiry = cdrom_timer_expiry;
+ }
+
+ ide_set_handler(drive, cdrom_newpc_intr, timeout, expiry);
+ return ide_started;
+
+end_request:
+ if (blk_pc_request(rq)) {
+ unsigned long flags;
+ unsigned int dlen = rq->data_len;
+
+ if (dma)
+ rq->data_len = 0;
+
+ spin_lock_irqsave(&ide_lock, flags);
+ if (__blk_end_request(rq, 0, dlen))
+ BUG();
+ HWGROUP(drive)->rq = NULL;
+ spin_unlock_irqrestore(&ide_lock, flags);
+ } else {
+ if (!uptodate)
+ rq->cmd_flags |= REQ_FAILED;
+ cdrom_end_request(drive, uptodate);
+ }
+ return ide_stopped;
+}
+
+static ide_startstop_t cdrom_start_rw(ide_drive_t *drive, struct request *rq)
+{
+ struct cdrom_info *cd = drive->driver_data;
+ int write = rq_data_dir(rq) == WRITE;
+ unsigned short sectors_per_frame =
+ queue_hardsect_size(drive->queue) >> SECTOR_BITS;
+
+ ide_debug_log(IDE_DBG_RQ, "Call %s, rq->cmd[0]: 0x%x, write: 0x%x, "
+ "secs_per_frame: %u\n",
+ __func__, rq->cmd[0], write, sectors_per_frame);
+
+ if (write) {
+ /* disk has become write protected */
+ if (get_disk_ro(cd->disk)) {
+ cdrom_end_request(drive, 0);
+ return ide_stopped;
+ }
+ } else {
+ /*
+ * We may be retrying this request after an error. Fix up any
+ * weirdness which might be present in the request packet.
+ */
+ ide_cd_restore_request(drive, rq);
+ }
+
+ /* use DMA, if possible / writes *must* be hardware frame aligned */
+ if ((rq->nr_sectors & (sectors_per_frame - 1)) ||
+ (rq->sector & (sectors_per_frame - 1))) {
+ if (write) {
+ cdrom_end_request(drive, 0);
+ return ide_stopped;
+ }
+ drive->dma = 0;
+ } else
+ drive->dma = !!(drive->dev_flags & IDE_DFLAG_USING_DMA);
+
+ if (write)
+ cd->devinfo.media_written = 1;
+
+ return ide_started;
+}
+
+static ide_startstop_t cdrom_do_newpc_cont(ide_drive_t *drive)
+{
+ struct request *rq = HWGROUP(drive)->rq;
+
+ return cdrom_transfer_packet_command(drive, rq, cdrom_newpc_intr);
+}
+
+static void cdrom_do_block_pc(ide_drive_t *drive, struct request *rq)
+{
+
+ ide_debug_log(IDE_DBG_PC, "Call %s, rq->cmd[0]: 0x%x, "
+ "rq->cmd_type: 0x%x\n", __func__, rq->cmd[0],
+ rq->cmd_type);
+
+ if (blk_pc_request(rq))
+ rq->cmd_flags |= REQ_QUIET;
+ else
+ rq->cmd_flags &= ~REQ_FAILED;
+
+ drive->dma = 0;
+
+ /* sg request */
+ if (rq->bio || ((rq->cmd_type == REQ_TYPE_ATA_PC) && rq->data_len)) {
+ struct request_queue *q = drive->queue;
+ unsigned int alignment;
+ char *buf;
+
+ if (rq->bio)
+ buf = bio_data(rq->bio);
+ else
+ buf = rq->data;
+
+ drive->dma = !!(drive->dev_flags & IDE_DFLAG_USING_DMA);
+
+ /*
+ * check if dma is safe
+ *
+ * NOTE! The "len" and "addr" checks should possibly have
+ * separate masks.
+ */
+ alignment = queue_dma_alignment(q) | q->dma_pad_mask;
+ if ((unsigned long)buf & alignment
+ || rq->data_len & q->dma_pad_mask
+ || object_is_on_stack(buf))
+ drive->dma = 0;
+ }
+}
+
+static ide_startstop_t ide_cd_do_request(ide_drive_t *drive, struct request *rq,
+ sector_t block)
+{
+ struct cdrom_info *info = drive->driver_data;
+ ide_handler_t *fn;
+ int xferlen;
+
+ ide_debug_log(IDE_DBG_RQ, "Call %s, rq->cmd[0]: 0x%x, "
+ "rq->cmd_type: 0x%x, block: %llu\n",
+ __func__, rq->cmd[0], rq->cmd_type,
+ (unsigned long long)block);
+
+ if (blk_fs_request(rq)) {
+ if (drive->atapi_flags & IDE_AFLAG_SEEKING) {
+ ide_hwif_t *hwif = drive->hwif;
+ unsigned long elapsed = jiffies - info->start_seek;
+ int stat = hwif->tp_ops->read_status(hwif);
+
+ if ((stat & ATA_DSC) != ATA_DSC) {
+ if (elapsed < IDECD_SEEK_TIMEOUT) {
+ ide_stall_queue(drive,
+ IDECD_SEEK_TIMER);
+ return ide_stopped;
+ }
+ printk(KERN_ERR PFX "%s: DSC timeout\n",
+ drive->name);
+ }
+ drive->atapi_flags &= ~IDE_AFLAG_SEEKING;
+ }
+ if (rq_data_dir(rq) == READ &&
+ IDE_LARGE_SEEK(info->last_block, block,
+ IDECD_SEEK_THRESHOLD) &&
+ (drive->dev_flags & IDE_DFLAG_DSC_OVERLAP)) {
+ xferlen = 0;
+ fn = cdrom_start_seek_continuation;
+
+ drive->dma = 0;
+ info->start_seek = jiffies;
+
+ ide_cd_prepare_seek_request(drive, rq);
+ } else {
+ xferlen = 32768;
+ fn = cdrom_start_rw_cont;
+
+ if (cdrom_start_rw(drive, rq) == ide_stopped)
+ return ide_stopped;
+
+ if (ide_cd_prepare_rw_request(drive, rq) == ide_stopped)
+ return ide_stopped;
+ }
+ info->last_block = block;
+ } else if (blk_sense_request(rq) || blk_pc_request(rq) ||
+ rq->cmd_type == REQ_TYPE_ATA_PC) {
+ xferlen = rq->data_len;
+ fn = cdrom_do_newpc_cont;
+
+ if (!rq->timeout)
+ rq->timeout = ATAPI_WAIT_PC;
+
+ cdrom_do_block_pc(drive, rq);
+ } else if (blk_special_request(rq)) {
+ /* right now this can only be a reset... */
+ cdrom_end_request(drive, 1);
+ return ide_stopped;
+ } else {
+ blk_dump_rq_flags(rq, DRV_NAME " bad flags");
+ cdrom_end_request(drive, 0);
+ return ide_stopped;
+ }
+
+ return cdrom_start_packet_command(drive, xferlen, fn);
+}
+
+/*
+ * Ioctl handling.
+ *
+ * Routines which queue packet commands take as a final argument a pointer to a
+ * request_sense struct. If execution of the command results in an error with a
+ * CHECK CONDITION status, this structure will be filled with the results of the
+ * subsequent request sense command. The pointer can also be NULL, in which case
+ * no sense information is returned.
+ */
+static void msf_from_bcd(struct atapi_msf *msf)
+{
+ msf->minute = bcd2bin(msf->minute);
+ msf->second = bcd2bin(msf->second);
+ msf->frame = bcd2bin(msf->frame);
+}
+
+int cdrom_check_status(ide_drive_t *drive, struct request_sense *sense)
+{
+ struct cdrom_info *info = drive->driver_data;
+ struct cdrom_device_info *cdi = &info->devinfo;
+ unsigned char cmd[BLK_MAX_CDB];
+
+ ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__);
+
+ memset(cmd, 0, BLK_MAX_CDB);
+ cmd[0] = GPCMD_TEST_UNIT_READY;
+
+ /*
+ * Sanyo 3 CD changer uses byte 7 of TEST_UNIT_READY to switch CDs
+ * instead of supporting the LOAD_UNLOAD opcode.
+ */
+ cmd[7] = cdi->sanyo_slot % 3;
+
+ return ide_cd_queue_pc(drive, cmd, 0, NULL, NULL, sense, 0, REQ_QUIET);
+}
+
+static int cdrom_read_capacity(ide_drive_t *drive, unsigned long *capacity,
+ unsigned long *sectors_per_frame,
+ struct request_sense *sense)
+{
+ struct {
+ __be32 lba;
+ __be32 blocklen;
+ } capbuf;
+
+ int stat;
+ unsigned char cmd[BLK_MAX_CDB];
+ unsigned len = sizeof(capbuf);
+ u32 blocklen;
+
+ ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__);
+
+ memset(cmd, 0, BLK_MAX_CDB);
+ cmd[0] = GPCMD_READ_CDVD_CAPACITY;
+
+ stat = ide_cd_queue_pc(drive, cmd, 0, &capbuf, &len, sense, 0,
+ REQ_QUIET);
+ if (stat)
+ return stat;
+
+ /*
+ * Sanity check the given block size
+ */
+ blocklen = be32_to_cpu(capbuf.blocklen);
+ switch (blocklen) {
+ case 512:
+ case 1024:
+ case 2048:
+ case 4096:
+ break;
+ default:
+ printk(KERN_ERR PFX "%s: weird block size %u\n",
+ drive->name, blocklen);
+ printk(KERN_ERR PFX "%s: default to 2kb block size\n",
+ drive->name);
+ blocklen = 2048;
+ break;
+ }
+
+ *capacity = 1 + be32_to_cpu(capbuf.lba);
+ *sectors_per_frame = blocklen >> SECTOR_BITS;
+
+ ide_debug_log(IDE_DBG_PROBE, "%s: cap: %lu, sectors_per_frame: %lu\n",
+ __func__, *capacity, *sectors_per_frame);
+
+ return 0;
+}
+
+static int cdrom_read_tocentry(ide_drive_t *drive, int trackno, int msf_flag,
+ int format, char *buf, int buflen,
+ struct request_sense *sense)
+{
+ unsigned char cmd[BLK_MAX_CDB];
+
+ ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__);
+
+ memset(cmd, 0, BLK_MAX_CDB);
+
+ cmd[0] = GPCMD_READ_TOC_PMA_ATIP;
+ cmd[6] = trackno;
+ cmd[7] = (buflen >> 8);
+ cmd[8] = (buflen & 0xff);
+ cmd[9] = (format << 6);
+
+ if (msf_flag)
+ cmd[1] = 2;
+
+ return ide_cd_queue_pc(drive, cmd, 0, buf, &buflen, sense, 0, REQ_QUIET);
+}
+
+/* Try to read the entire TOC for the disk into our internal buffer. */
+int ide_cd_read_toc(ide_drive_t *drive, struct request_sense *sense)
+{
+ int stat, ntracks, i;
+ struct cdrom_info *info = drive->driver_data;
+ struct cdrom_device_info *cdi = &info->devinfo;
+ struct atapi_toc *toc = info->toc;
+ struct {
+ struct atapi_toc_header hdr;
+ struct atapi_toc_entry ent;
+ } ms_tmp;
+ long last_written;
+ unsigned long sectors_per_frame = SECTORS_PER_FRAME;
+
+ ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__);
+
+ if (toc == NULL) {
+ /* try to allocate space */
+ toc = kmalloc(sizeof(struct atapi_toc), GFP_KERNEL);
+ if (toc == NULL) {
+ printk(KERN_ERR PFX "%s: No cdrom TOC buffer!\n",
+ drive->name);
+ return -ENOMEM;
+ }
+ info->toc = toc;
+ }
+
+ /*
+ * Check to see if the existing data is still valid. If it is,
+ * just return.
+ */
+ (void) cdrom_check_status(drive, sense);
+
+ if (drive->atapi_flags & IDE_AFLAG_TOC_VALID)
+ return 0;
+
+ /* try to get the total cdrom capacity and sector size */
+ stat = cdrom_read_capacity(drive, &toc->capacity, &sectors_per_frame,
+ sense);
+ if (stat)
+ toc->capacity = 0x1fffff;
+
+ set_capacity(info->disk, toc->capacity * sectors_per_frame);
+ /* save a private copy of the TOC capacity for error handling */
+ drive->probed_capacity = toc->capacity * sectors_per_frame;
+
+ blk_queue_hardsect_size(drive->queue,
+ sectors_per_frame << SECTOR_BITS);
+
+ /* first read just the header, so we know how long the TOC is */
+ stat = cdrom_read_tocentry(drive, 0, 1, 0, (char *) &toc->hdr,
+ sizeof(struct atapi_toc_header), sense);
+ if (stat)
+ return stat;
+
+ if (drive->atapi_flags & IDE_AFLAG_TOCTRACKS_AS_BCD) {
+ toc->hdr.first_track = bcd2bin(toc->hdr.first_track);
+ toc->hdr.last_track = bcd2bin(toc->hdr.last_track);
+ }
+
+ ntracks = toc->hdr.last_track - toc->hdr.first_track + 1;
+ if (ntracks <= 0)
+ return -EIO;
+ if (ntracks > MAX_TRACKS)
+ ntracks = MAX_TRACKS;
+
+ /* now read the whole schmeer */
+ stat = cdrom_read_tocentry(drive, toc->hdr.first_track, 1, 0,
+ (char *)&toc->hdr,
+ sizeof(struct atapi_toc_header) +
+ (ntracks + 1) *
+ sizeof(struct atapi_toc_entry), sense);
+
+ if (stat && toc->hdr.first_track > 1) {
+ /*
+ * Cds with CDI tracks only don't have any TOC entries, despite
+ * of this the returned values are
+ * first_track == last_track = number of CDI tracks + 1,
+ * so that this case is indistinguishable from the same layout
+ * plus an additional audio track. If we get an error for the
+ * regular case, we assume a CDI without additional audio
+ * tracks. In this case the readable TOC is empty (CDI tracks
+ * are not included) and only holds the Leadout entry.
+ *
+ * Heiko Eißfeldt.
+ */
+ ntracks = 0;
+ stat = cdrom_read_tocentry(drive, CDROM_LEADOUT, 1, 0,
+ (char *)&toc->hdr,
+ sizeof(struct atapi_toc_header) +
+ (ntracks + 1) *
+ sizeof(struct atapi_toc_entry),
+ sense);
+ if (stat)
+ return stat;
+
+ if (drive->atapi_flags & IDE_AFLAG_TOCTRACKS_AS_BCD) {
+ toc->hdr.first_track = (u8)bin2bcd(CDROM_LEADOUT);
+ toc->hdr.last_track = (u8)bin2bcd(CDROM_LEADOUT);
+ } else {
+ toc->hdr.first_track = CDROM_LEADOUT;
+ toc->hdr.last_track = CDROM_LEADOUT;
+ }
+ }
+
+ if (stat)
+ return stat;
+
+ toc->hdr.toc_length = be16_to_cpu(toc->hdr.toc_length);
+
+ if (drive->atapi_flags & IDE_AFLAG_TOCTRACKS_AS_BCD) {
+ toc->hdr.first_track = bcd2bin(toc->hdr.first_track);
+ toc->hdr.last_track = bcd2bin(toc->hdr.last_track);
+ }
+
+ for (i = 0; i <= ntracks; i++) {
+ if (drive->atapi_flags & IDE_AFLAG_TOCADDR_AS_BCD) {
+ if (drive->atapi_flags & IDE_AFLAG_TOCTRACKS_AS_BCD)
+ toc->ent[i].track = bcd2bin(toc->ent[i].track);
+ msf_from_bcd(&toc->ent[i].addr.msf);
+ }
+ toc->ent[i].addr.lba = msf_to_lba(toc->ent[i].addr.msf.minute,
+ toc->ent[i].addr.msf.second,
+ toc->ent[i].addr.msf.frame);
+ }
+
+ if (toc->hdr.first_track != CDROM_LEADOUT) {
+ /* read the multisession information */
+ stat = cdrom_read_tocentry(drive, 0, 0, 1, (char *)&ms_tmp,
+ sizeof(ms_tmp), sense);
+ if (stat)
+ return stat;
+
+ toc->last_session_lba = be32_to_cpu(ms_tmp.ent.addr.lba);
+ } else {
+ ms_tmp.hdr.last_track = CDROM_LEADOUT;
+ ms_tmp.hdr.first_track = ms_tmp.hdr.last_track;
+ toc->last_session_lba = msf_to_lba(0, 2, 0); /* 0m 2s 0f */
+ }
+
+ if (drive->atapi_flags & IDE_AFLAG_TOCADDR_AS_BCD) {
+ /* re-read multisession information using MSF format */
+ stat = cdrom_read_tocentry(drive, 0, 1, 1, (char *)&ms_tmp,
+ sizeof(ms_tmp), sense);
+ if (stat)
+ return stat;
+
+ msf_from_bcd(&ms_tmp.ent.addr.msf);
+ toc->last_session_lba = msf_to_lba(ms_tmp.ent.addr.msf.minute,
+ ms_tmp.ent.addr.msf.second,
+ ms_tmp.ent.addr.msf.frame);
+ }
+
+ toc->xa_flag = (ms_tmp.hdr.first_track != ms_tmp.hdr.last_track);
+
+ /* now try to get the total cdrom capacity */
+ stat = cdrom_get_last_written(cdi, &last_written);
+ if (!stat && (last_written > toc->capacity)) {
+ toc->capacity = last_written;
+ set_capacity(info->disk, toc->capacity * sectors_per_frame);
+ drive->probed_capacity = toc->capacity * sectors_per_frame;
+ }
+
+ /* Remember that we've read this stuff. */
+ drive->atapi_flags |= IDE_AFLAG_TOC_VALID;
+
+ return 0;
+}
+
+int ide_cdrom_get_capabilities(ide_drive_t *drive, u8 *buf)
+{
+ struct cdrom_info *info = drive->driver_data;
+ struct cdrom_device_info *cdi = &info->devinfo;
+ struct packet_command cgc;
+ int stat, attempts = 3, size = ATAPI_CAPABILITIES_PAGE_SIZE;
+
+ ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__);
+
+ if ((drive->atapi_flags & IDE_AFLAG_FULL_CAPS_PAGE) == 0)
+ size -= ATAPI_CAPABILITIES_PAGE_PAD_SIZE;
+
+ init_cdrom_command(&cgc, buf, size, CGC_DATA_UNKNOWN);
+ do {
+ /* we seem to get stat=0x01,err=0x00 the first time (??) */
+ stat = cdrom_mode_sense(cdi, &cgc, GPMODE_CAPABILITIES_PAGE, 0);
+ if (!stat)
+ break;
+ } while (--attempts);
+ return stat;
+}
+
+void ide_cdrom_update_speed(ide_drive_t *drive, u8 *buf)
+{
+ struct cdrom_info *cd = drive->driver_data;
+ u16 curspeed, maxspeed;
+
+ ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__);
+
+ if (drive->atapi_flags & IDE_AFLAG_LE_SPEED_FIELDS) {
+ curspeed = le16_to_cpup((__le16 *)&buf[8 + 14]);
+ maxspeed = le16_to_cpup((__le16 *)&buf[8 + 8]);
+ } else {
+ curspeed = be16_to_cpup((__be16 *)&buf[8 + 14]);
+ maxspeed = be16_to_cpup((__be16 *)&buf[8 + 8]);
+ }
+
+ ide_debug_log(IDE_DBG_PROBE, "%s: curspeed: %u, maxspeed: %u\n",
+ __func__, curspeed, maxspeed);
+
+ cd->current_speed = (curspeed + (176/2)) / 176;
+ cd->max_speed = (maxspeed + (176/2)) / 176;
+}
+
+#define IDE_CD_CAPABILITIES \
+ (CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK | CDC_SELECT_SPEED | \
+ CDC_SELECT_DISC | CDC_MULTI_SESSION | CDC_MCN | CDC_MEDIA_CHANGED | \
+ CDC_PLAY_AUDIO | CDC_RESET | CDC_DRIVE_STATUS | CDC_CD_R | \
+ CDC_CD_RW | CDC_DVD | CDC_DVD_R | CDC_DVD_RAM | CDC_GENERIC_PACKET | \
+ CDC_MO_DRIVE | CDC_MRW | CDC_MRW_W | CDC_RAM)
+
+static struct cdrom_device_ops ide_cdrom_dops = {
+ .open = ide_cdrom_open_real,
+ .release = ide_cdrom_release_real,
+ .drive_status = ide_cdrom_drive_status,
+ .media_changed = ide_cdrom_check_media_change_real,
+ .tray_move = ide_cdrom_tray_move,
+ .lock_door = ide_cdrom_lock_door,
+ .select_speed = ide_cdrom_select_speed,
+ .get_last_session = ide_cdrom_get_last_session,
+ .get_mcn = ide_cdrom_get_mcn,
+ .reset = ide_cdrom_reset,
+ .audio_ioctl = ide_cdrom_audio_ioctl,
+ .capability = IDE_CD_CAPABILITIES,
+ .generic_packet = ide_cdrom_packet,
+};
+
+static int ide_cdrom_register(ide_drive_t *drive, int nslots)
+{
+ struct cdrom_info *info = drive->driver_data;
+ struct cdrom_device_info *devinfo = &info->devinfo;
+
+ ide_debug_log(IDE_DBG_PROBE, "Call %s, nslots: %d\n", __func__, nslots);
+
+ devinfo->ops = &ide_cdrom_dops;
+ devinfo->speed = info->current_speed;
+ devinfo->capacity = nslots;
+ devinfo->handle = drive;
+ strcpy(devinfo->name, drive->name);
+
+ if (drive->atapi_flags & IDE_AFLAG_NO_SPEED_SELECT)
+ devinfo->mask |= CDC_SELECT_SPEED;
+
+ devinfo->disk = info->disk;
+ return register_cdrom(devinfo);
+}
+
+static int ide_cdrom_probe_capabilities(ide_drive_t *drive)
+{
+ struct cdrom_info *cd = drive->driver_data;
+ struct cdrom_device_info *cdi = &cd->devinfo;
+ u8 buf[ATAPI_CAPABILITIES_PAGE_SIZE];
+ mechtype_t mechtype;
+ int nslots = 1;
+
+ ide_debug_log(IDE_DBG_PROBE, "Call %s, drive->media: 0x%x, "
+ "drive->atapi_flags: 0x%lx\n", __func__, drive->media,
+ drive->atapi_flags);
+
+ cdi->mask = (CDC_CD_R | CDC_CD_RW | CDC_DVD | CDC_DVD_R |
+ CDC_DVD_RAM | CDC_SELECT_DISC | CDC_PLAY_AUDIO |
+ CDC_MO_DRIVE | CDC_RAM);
+
+ if (drive->media == ide_optical) {
+ cdi->mask &= ~(CDC_MO_DRIVE | CDC_RAM);
+ printk(KERN_ERR PFX "%s: ATAPI magneto-optical drive\n",
+ drive->name);
+ return nslots;
+ }
+
+ if (drive->atapi_flags & IDE_AFLAG_PRE_ATAPI12) {
+ drive->atapi_flags &= ~IDE_AFLAG_NO_EJECT;
+ cdi->mask &= ~CDC_PLAY_AUDIO;
+ return nslots;
+ }
+
+ /*
+ * We have to cheat a little here. the packet will eventually be queued
+ * with ide_cdrom_packet(), which extracts the drive from cdi->handle.
+ * Since this device hasn't been registered with the Uniform layer yet,
+ * it can't do this. Same goes for cdi->ops.
+ */
+ cdi->handle = drive;
+ cdi->ops = &ide_cdrom_dops;
+
+ if (ide_cdrom_get_capabilities(drive, buf))
+ return 0;
+
+ if ((buf[8 + 6] & 0x01) == 0)
+ drive->dev_flags &= ~IDE_DFLAG_DOORLOCKING;
+ if (buf[8 + 6] & 0x08)
+ drive->atapi_flags &= ~IDE_AFLAG_NO_EJECT;
+ if (buf[8 + 3] & 0x01)
+ cdi->mask &= ~CDC_CD_R;
+ if (buf[8 + 3] & 0x02)
+ cdi->mask &= ~(CDC_CD_RW | CDC_RAM);
+ if (buf[8 + 2] & 0x38)
+ cdi->mask &= ~CDC_DVD;
+ if (buf[8 + 3] & 0x20)
+ cdi->mask &= ~(CDC_DVD_RAM | CDC_RAM);
+ if (buf[8 + 3] & 0x10)
+ cdi->mask &= ~CDC_DVD_R;
+ if ((buf[8 + 4] & 0x01) || (drive->atapi_flags & IDE_AFLAG_PLAY_AUDIO_OK))
+ cdi->mask &= ~CDC_PLAY_AUDIO;
+
+ mechtype = buf[8 + 6] >> 5;
+ if (mechtype == mechtype_caddy ||
+ mechtype == mechtype_popup ||
+ (drive->atapi_flags & IDE_AFLAG_NO_AUTOCLOSE))
+ cdi->mask |= CDC_CLOSE_TRAY;
+
+ if (cdi->sanyo_slot > 0) {
+ cdi->mask &= ~CDC_SELECT_DISC;
+ nslots = 3;
+ } else if (mechtype == mechtype_individual_changer ||
+ mechtype == mechtype_cartridge_changer) {
+ nslots = cdrom_number_of_slots(cdi);
+ if (nslots > 1)
+ cdi->mask &= ~CDC_SELECT_DISC;
+ }
+
+ ide_cdrom_update_speed(drive, buf);
+
+ printk(KERN_INFO PFX "%s: ATAPI", drive->name);
+
+ /* don't print speed if the drive reported 0 */
+ if (cd->max_speed)
+ printk(KERN_CONT " %dX", cd->max_speed);
+
+ printk(KERN_CONT " %s", (cdi->mask & CDC_DVD) ? "CD-ROM" : "DVD-ROM");
+
+ if ((cdi->mask & CDC_DVD_R) == 0 || (cdi->mask & CDC_DVD_RAM) == 0)
+ printk(KERN_CONT " DVD%s%s",
+ (cdi->mask & CDC_DVD_R) ? "" : "-R",
+ (cdi->mask & CDC_DVD_RAM) ? "" : "/RAM");
+
+ if ((cdi->mask & CDC_CD_R) == 0 || (cdi->mask & CDC_CD_RW) == 0)
+ printk(KERN_CONT " CD%s%s",
+ (cdi->mask & CDC_CD_R) ? "" : "-R",
+ (cdi->mask & CDC_CD_RW) ? "" : "/RW");
+
+ if ((cdi->mask & CDC_SELECT_DISC) == 0)
+ printk(KERN_CONT " changer w/%d slots", nslots);
+ else
+ printk(KERN_CONT " drive");
+
+ printk(KERN_CONT ", %dkB Cache\n",
+ be16_to_cpup((__be16 *)&buf[8 + 12]));
+
+ return nslots;
+}
+
+/* standard prep_rq_fn that builds 10 byte cmds */
+static int ide_cdrom_prep_fs(struct request_queue *q, struct request *rq)
+{
+ int hard_sect = queue_hardsect_size(q);
+ long block = (long)rq->hard_sector / (hard_sect >> 9);
+ unsigned long blocks = rq->hard_nr_sectors / (hard_sect >> 9);
+
+ memset(rq->cmd, 0, BLK_MAX_CDB);
+
+ if (rq_data_dir(rq) == READ)
+ rq->cmd[0] = GPCMD_READ_10;
+ else
+ rq->cmd[0] = GPCMD_WRITE_10;
+
+ /*
+ * fill in lba
+ */
+ rq->cmd[2] = (block >> 24) & 0xff;
+ rq->cmd[3] = (block >> 16) & 0xff;
+ rq->cmd[4] = (block >> 8) & 0xff;
+ rq->cmd[5] = block & 0xff;
+
+ /*
+ * and transfer length
+ */
+ rq->cmd[7] = (blocks >> 8) & 0xff;
+ rq->cmd[8] = blocks & 0xff;
+ rq->cmd_len = 10;
+ return BLKPREP_OK;
+}
+
+/*
+ * Most of the SCSI commands are supported directly by ATAPI devices.
+ * This transform handles the few exceptions.
+ */
+static int ide_cdrom_prep_pc(struct request *rq)
+{
+ u8 *c = rq->cmd;
+
+ /* transform 6-byte read/write commands to the 10-byte version */
+ if (c[0] == READ_6 || c[0] == WRITE_6) {
+ c[8] = c[4];
+ c[5] = c[3];
+ c[4] = c[2];
+ c[3] = c[1] & 0x1f;
+ c[2] = 0;
+ c[1] &= 0xe0;
+ c[0] += (READ_10 - READ_6);
+ rq->cmd_len = 10;
+ return BLKPREP_OK;
+ }
+
+ /*
+ * it's silly to pretend we understand 6-byte sense commands, just
+ * reject with ILLEGAL_REQUEST and the caller should take the
+ * appropriate action
+ */
+ if (c[0] == MODE_SENSE || c[0] == MODE_SELECT) {
+ rq->errors = ILLEGAL_REQUEST;
+ return BLKPREP_KILL;
+ }
+
+ return BLKPREP_OK;
+}
+
+static int ide_cdrom_prep_fn(struct request_queue *q, struct request *rq)
+{
+ if (blk_fs_request(rq))
+ return ide_cdrom_prep_fs(q, rq);
+ else if (blk_pc_request(rq))
+ return ide_cdrom_prep_pc(rq);
+
+ return 0;
+}
+
+struct cd_list_entry {
+ const char *id_model;
+ const char *id_firmware;
+ unsigned int cd_flags;
+};
+
+#ifdef CONFIG_IDE_PROC_FS
+static sector_t ide_cdrom_capacity(ide_drive_t *drive)
+{
+ unsigned long capacity, sectors_per_frame;
+
+ if (cdrom_read_capacity(drive, &capacity, &sectors_per_frame, NULL))
+ return 0;
+
+ return capacity * sectors_per_frame;
+}
+
+static int proc_idecd_read_capacity(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ ide_drive_t *drive = data;
+ int len;
+
+ len = sprintf(page, "%llu\n", (long long)ide_cdrom_capacity(drive));
+ PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
+}
+
+static ide_proc_entry_t idecd_proc[] = {
+ { "capacity", S_IFREG|S_IRUGO, proc_idecd_read_capacity, NULL },
+ { NULL, 0, NULL, NULL }
+};
+
+ide_devset_rw_flag(dsc_overlap, IDE_DFLAG_DSC_OVERLAP);
+
+static const struct ide_proc_devset idecd_settings[] = {
+ IDE_PROC_DEVSET(dsc_overlap, 0, 1),
+ { 0 },
+};
+
+static ide_proc_entry_t *ide_cd_proc_entries(ide_drive_t *drive)
+{
+ return idecd_proc;
+}
+
+static const struct ide_proc_devset *ide_cd_proc_devsets(ide_drive_t *drive)
+{
+ return idecd_settings;
+}
+#endif
+
+static const struct cd_list_entry ide_cd_quirks_list[] = {
+ /* Limit transfer size per interrupt. */
+ { "SAMSUNG CD-ROM SCR-2430", NULL, IDE_AFLAG_LIMIT_NFRAMES },
+ { "SAMSUNG CD-ROM SCR-2432", NULL, IDE_AFLAG_LIMIT_NFRAMES },
+ /* SCR-3231 doesn't support the SET_CD_SPEED command. */
+ { "SAMSUNG CD-ROM SCR-3231", NULL, IDE_AFLAG_NO_SPEED_SELECT },
+ /* Old NEC260 (not R) was released before ATAPI 1.2 spec. */
+ { "NEC CD-ROM DRIVE:260", "1.01", IDE_AFLAG_TOCADDR_AS_BCD |
+ IDE_AFLAG_PRE_ATAPI12, },
+ /* Vertos 300, some versions of this drive like to talk BCD. */
+ { "V003S0DS", NULL, IDE_AFLAG_VERTOS_300_SSD, },
+ /* Vertos 600 ESD. */
+ { "V006E0DS", NULL, IDE_AFLAG_VERTOS_600_ESD, },
+ /*
+ * Sanyo 3 CD changer uses a non-standard command for CD changing
+ * (by default standard ATAPI support for CD changers is used).
+ */
+ { "CD-ROM CDR-C3 G", NULL, IDE_AFLAG_SANYO_3CD },
+ { "CD-ROM CDR-C3G", NULL, IDE_AFLAG_SANYO_3CD },
+ { "CD-ROM CDR_C36", NULL, IDE_AFLAG_SANYO_3CD },
+ /* Stingray 8X CD-ROM. */
+ { "STINGRAY 8422 IDE 8X CD-ROM 7-27-95", NULL, IDE_AFLAG_PRE_ATAPI12 },
+ /*
+ * ACER 50X CD-ROM and WPI 32X CD-ROM require the full spec length
+ * mode sense page capabilities size, but older drives break.
+ */
+ { "ATAPI CD ROM DRIVE 50X MAX", NULL, IDE_AFLAG_FULL_CAPS_PAGE },
+ { "WPI CDS-32X", NULL, IDE_AFLAG_FULL_CAPS_PAGE },
+ /* ACER/AOpen 24X CD-ROM has the speed fields byte-swapped. */
+ { "", "241N", IDE_AFLAG_LE_SPEED_FIELDS },
+ /*
+ * Some drives used by Apple don't advertise audio play
+ * but they do support reading TOC & audio datas.
+ */
+ { "MATSHITADVD-ROM SR-8187", NULL, IDE_AFLAG_PLAY_AUDIO_OK },
+ { "MATSHITADVD-ROM SR-8186", NULL, IDE_AFLAG_PLAY_AUDIO_OK },
+ { "MATSHITADVD-ROM SR-8176", NULL, IDE_AFLAG_PLAY_AUDIO_OK },
+ { "MATSHITADVD-ROM SR-8174", NULL, IDE_AFLAG_PLAY_AUDIO_OK },
+ { "Optiarc DVD RW AD-5200A", NULL, IDE_AFLAG_PLAY_AUDIO_OK },
+ { "Optiarc DVD RW AD-7200A", NULL, IDE_AFLAG_PLAY_AUDIO_OK },
+ { "Optiarc DVD RW AD-7543A", NULL, IDE_AFLAG_NO_AUTOCLOSE },
+ { "TEAC CD-ROM CD-224E", NULL, IDE_AFLAG_NO_AUTOCLOSE },
+ { NULL, NULL, 0 }
+};
+
+static unsigned int ide_cd_flags(u16 *id)
+{
+ const struct cd_list_entry *cle = ide_cd_quirks_list;
+
+ while (cle->id_model) {
+ if (strcmp(cle->id_model, (char *)&id[ATA_ID_PROD]) == 0 &&
+ (cle->id_firmware == NULL ||
+ strstr((char *)&id[ATA_ID_FW_REV], cle->id_firmware)))
+ return cle->cd_flags;
+ cle++;
+ }
+
+ return 0;
+}
+
+static int ide_cdrom_setup(ide_drive_t *drive)
+{
+ struct cdrom_info *cd = drive->driver_data;
+ struct cdrom_device_info *cdi = &cd->devinfo;
+ u16 *id = drive->id;
+ char *fw_rev = (char *)&id[ATA_ID_FW_REV];
+ int nslots;
+
+ ide_debug_log(IDE_DBG_PROBE, "Call %s\n", __func__);
+
+ blk_queue_prep_rq(drive->queue, ide_cdrom_prep_fn);
+ blk_queue_dma_alignment(drive->queue, 31);
+ blk_queue_update_dma_pad(drive->queue, 15);
+ drive->queue->unplug_delay = (1 * HZ) / 1000;
+ if (!drive->queue->unplug_delay)
+ drive->queue->unplug_delay = 1;
+
+ drive->dev_flags |= IDE_DFLAG_MEDIA_CHANGED;
+ drive->atapi_flags = IDE_AFLAG_NO_EJECT | ide_cd_flags(id);
+
+ if ((drive->atapi_flags & IDE_AFLAG_VERTOS_300_SSD) &&
+ fw_rev[4] == '1' && fw_rev[6] <= '2')
+ drive->atapi_flags |= (IDE_AFLAG_TOCTRACKS_AS_BCD |
+ IDE_AFLAG_TOCADDR_AS_BCD);
+ else if ((drive->atapi_flags & IDE_AFLAG_VERTOS_600_ESD) &&
+ fw_rev[4] == '1' && fw_rev[6] <= '2')
+ drive->atapi_flags |= IDE_AFLAG_TOCTRACKS_AS_BCD;
+ else if (drive->atapi_flags & IDE_AFLAG_SANYO_3CD)
+ /* 3 => use CD in slot 0 */
+ cdi->sanyo_slot = 3;
+
+ nslots = ide_cdrom_probe_capabilities(drive);
+
+ /* set correct block size */
+ blk_queue_hardsect_size(drive->queue, CD_FRAMESIZE);
+
+ if (drive->next != drive)
+ drive->dev_flags |= IDE_DFLAG_DSC_OVERLAP;
+ else
+ drive->dev_flags &= ~IDE_DFLAG_DSC_OVERLAP;
+
+ if (ide_cdrom_register(drive, nslots)) {
+ printk(KERN_ERR PFX "%s: %s failed to register device with the"
+ " cdrom driver.\n", drive->name, __func__);
+ cd->devinfo.handle = NULL;
+ return 1;
+ }
+
+ ide_proc_register_driver(drive, cd->driver);
+ return 0;
+}
+
+static void ide_cd_remove(ide_drive_t *drive)
+{
+ struct cdrom_info *info = drive->driver_data;
+
+ ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__);
+
+ ide_proc_unregister_driver(drive, info->driver);
+
+ del_gendisk(info->disk);
+
+ ide_cd_put(info);
+}
+
+static void ide_cd_release(struct kref *kref)
+{
+ struct cdrom_info *info = to_ide_drv(kref, cdrom_info);
+ struct cdrom_device_info *devinfo = &info->devinfo;
+ ide_drive_t *drive = info->drive;
+ struct gendisk *g = info->disk;
+
+ ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__);
+
+ kfree(info->toc);
+ if (devinfo->handle == drive)
+ unregister_cdrom(devinfo);
+ drive->dev_flags &= ~IDE_DFLAG_DSC_OVERLAP;
+ drive->driver_data = NULL;
+ blk_queue_prep_rq(drive->queue, NULL);
+ g->private_data = NULL;
+ put_disk(g);
+ kfree(info);
+}
+
+static int ide_cd_probe(ide_drive_t *);
+
+static ide_driver_t ide_cdrom_driver = {
+ .gen_driver = {
+ .owner = THIS_MODULE,
+ .name = "ide-cdrom",
+ .bus = &ide_bus_type,
+ },
+ .probe = ide_cd_probe,
+ .remove = ide_cd_remove,
+ .version = IDECD_VERSION,
+ .do_request = ide_cd_do_request,
+ .end_request = ide_end_request,
+ .error = __ide_error,
+#ifdef CONFIG_IDE_PROC_FS
+ .proc_entries = ide_cd_proc_entries,
+ .proc_devsets = ide_cd_proc_devsets,
+#endif
+};
+
+static int idecd_open(struct block_device *bdev, fmode_t mode)
+{
+ struct cdrom_info *info = ide_cd_get(bdev->bd_disk);
+ int rc = -ENOMEM;
+
+ if (!info)
+ return -ENXIO;
+
+ rc = cdrom_open(&info->devinfo, bdev, mode);
+
+ if (rc < 0)
+ ide_cd_put(info);
+
+ return rc;
+}
+
+static int idecd_release(struct gendisk *disk, fmode_t mode)
+{
+ struct cdrom_info *info = ide_drv_g(disk, cdrom_info);
+
+ cdrom_release(&info->devinfo, mode);
+
+ ide_cd_put(info);
+
+ return 0;
+}
+
+static int idecd_set_spindown(struct cdrom_device_info *cdi, unsigned long arg)
+{
+ struct packet_command cgc;
+ char buffer[16];
+ int stat;
+ char spindown;
+
+ if (copy_from_user(&spindown, (void __user *)arg, sizeof(char)))
+ return -EFAULT;
+
+ init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_UNKNOWN);
+
+ stat = cdrom_mode_sense(cdi, &cgc, GPMODE_CDROM_PAGE, 0);
+ if (stat)
+ return stat;
+
+ buffer[11] = (buffer[11] & 0xf0) | (spindown & 0x0f);
+ return cdrom_mode_select(cdi, &cgc);
+}
+
+static int idecd_get_spindown(struct cdrom_device_info *cdi, unsigned long arg)
+{
+ struct packet_command cgc;
+ char buffer[16];
+ int stat;
+ char spindown;
+
+ init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_UNKNOWN);
+
+ stat = cdrom_mode_sense(cdi, &cgc, GPMODE_CDROM_PAGE, 0);
+ if (stat)
+ return stat;
+
+ spindown = buffer[11] & 0x0f;
+ if (copy_to_user((void __user *)arg, &spindown, sizeof(char)))
+ return -EFAULT;
+ return 0;
+}
+
+static int idecd_ioctl(struct block_device *bdev, fmode_t mode,
+ unsigned int cmd, unsigned long arg)
+{
+ struct cdrom_info *info = ide_drv_g(bdev->bd_disk, cdrom_info);
+ int err;
+
+ switch (cmd) {
+ case CDROMSETSPINDOWN:
+ return idecd_set_spindown(&info->devinfo, arg);
+ case CDROMGETSPINDOWN:
+ return idecd_get_spindown(&info->devinfo, arg);
+ default:
+ break;
+ }
+
+ err = generic_ide_ioctl(info->drive, bdev, cmd, arg);
+ if (err == -EINVAL)
+ err = cdrom_ioctl(&info->devinfo, bdev, mode, cmd, arg);
+
+ return err;
+}
+
+static int idecd_media_changed(struct gendisk *disk)
+{
+ struct cdrom_info *info = ide_drv_g(disk, cdrom_info);
+ return cdrom_media_changed(&info->devinfo);
+}
+
+static int idecd_revalidate_disk(struct gendisk *disk)
+{
+ struct cdrom_info *info = ide_drv_g(disk, cdrom_info);
+ struct request_sense sense;
+
+ ide_cd_read_toc(info->drive, &sense);
+
+ return 0;
+}
+
+static struct block_device_operations idecd_ops = {
+ .owner = THIS_MODULE,
+ .open = idecd_open,
+ .release = idecd_release,
+ .locked_ioctl = idecd_ioctl,
+ .media_changed = idecd_media_changed,
+ .revalidate_disk = idecd_revalidate_disk
+};
+
+/* module options */
+static char *ignore;
+module_param(ignore, charp, 0400);
+
+static unsigned long debug_mask;
+module_param(debug_mask, ulong, 0644);
+
+MODULE_DESCRIPTION("ATAPI CD-ROM Driver");
+
+static int ide_cd_probe(ide_drive_t *drive)
+{
+ struct cdrom_info *info;
+ struct gendisk *g;
+ struct request_sense sense;
+
+ ide_debug_log(IDE_DBG_PROBE, "Call %s, drive->driver_req: %s, "
+ "drive->media: 0x%x\n", __func__, drive->driver_req,
+ drive->media);
+
+ if (!strstr("ide-cdrom", drive->driver_req))
+ goto failed;
+
+ if (drive->media != ide_cdrom && drive->media != ide_optical)
+ goto failed;
+
+ /* skip drives that we were told to ignore */
+ if (ignore != NULL) {
+ if (strstr(ignore, drive->name)) {
+ printk(KERN_INFO PFX "ignoring drive %s\n",
+ drive->name);
+ goto failed;
+ }
+ }
+
+ drive->debug_mask = debug_mask;
+
+ info = kzalloc(sizeof(struct cdrom_info), GFP_KERNEL);
+ if (info == NULL) {
+ printk(KERN_ERR PFX "%s: Can't allocate a cdrom structure\n",
+ drive->name);
+ goto failed;
+ }
+
+ g = alloc_disk(1 << PARTN_BITS);
+ if (!g)
+ goto out_free_cd;
+
+ ide_init_disk(g, drive);
+
+ kref_init(&info->kref);
+
+ info->drive = drive;
+ info->driver = &ide_cdrom_driver;
+ info->disk = g;
+
+ g->private_data = &info->driver;
+
+ drive->driver_data = info;
+
+ g->minors = 1;
+ g->driverfs_dev = &drive->gendev;
+ g->flags = GENHD_FL_CD | GENHD_FL_REMOVABLE;
+ if (ide_cdrom_setup(drive)) {
+ ide_cd_release(&info->kref);
+ goto failed;
+ }
+
+ ide_cd_read_toc(drive, &sense);
+ g->fops = &idecd_ops;
+ g->flags |= GENHD_FL_REMOVABLE;
+ add_disk(g);
+ return 0;
+
+out_free_cd:
+ kfree(info);
+failed:
+ return -ENODEV;
+}
+
+static void __exit ide_cdrom_exit(void)
+{
+ driver_unregister(&ide_cdrom_driver.gen_driver);
+}
+
+static int __init ide_cdrom_init(void)
+{
+ printk(KERN_INFO DRV_NAME " driver " IDECD_VERSION "\n");
+ return driver_register(&ide_cdrom_driver.gen_driver);
+}
+
+MODULE_ALIAS("ide:*m-cdrom*");
+MODULE_ALIAS("ide-cd");
+module_init(ide_cdrom_init);
+module_exit(ide_cdrom_exit);
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/ide-cd.h b/drivers/ide/ide-cd.h
new file mode 100644
index 0000000..5882b9a
--- /dev/null
+++ b/drivers/ide/ide-cd.h
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 1996-98 Erik Andersen
+ * Copyright (C) 1998-2000 Jens Axboe
+ */
+#ifndef _IDE_CD_H
+#define _IDE_CD_H
+
+#include <linux/cdrom.h>
+#include <asm/byteorder.h>
+
+/*
+ * typical timeout for packet command
+ */
+#define ATAPI_WAIT_PC (60 * HZ)
+#define ATAPI_WAIT_WRITE_BUSY (10 * HZ)
+
+/************************************************************************/
+
+#define SECTOR_BITS 9
+#ifndef SECTOR_SIZE
+#define SECTOR_SIZE (1 << SECTOR_BITS)
+#endif
+#define SECTORS_PER_FRAME (CD_FRAMESIZE >> SECTOR_BITS)
+#define SECTOR_BUFFER_SIZE (CD_FRAMESIZE * 32)
+
+/* Capabilities Page size including 8 bytes of Mode Page Header */
+#define ATAPI_CAPABILITIES_PAGE_SIZE (8 + 20)
+#define ATAPI_CAPABILITIES_PAGE_PAD_SIZE 4
+
+/* Structure of a MSF cdrom address. */
+struct atapi_msf {
+ byte reserved;
+ byte minute;
+ byte second;
+ byte frame;
+};
+
+/* Space to hold the disk TOC. */
+#define MAX_TRACKS 99
+struct atapi_toc_header {
+ unsigned short toc_length;
+ byte first_track;
+ byte last_track;
+};
+
+struct atapi_toc_entry {
+ byte reserved1;
+#if defined(__BIG_ENDIAN_BITFIELD)
+ __u8 adr : 4;
+ __u8 control : 4;
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
+ __u8 control : 4;
+ __u8 adr : 4;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+ byte track;
+ byte reserved2;
+ union {
+ unsigned lba;
+ struct atapi_msf msf;
+ } addr;
+};
+
+struct atapi_toc {
+ int last_session_lba;
+ int xa_flag;
+ unsigned long capacity;
+ struct atapi_toc_header hdr;
+ struct atapi_toc_entry ent[MAX_TRACKS+1];
+ /* One extra for the leadout. */
+};
+
+/* Extra per-device info for cdrom drives. */
+struct cdrom_info {
+ ide_drive_t *drive;
+ ide_driver_t *driver;
+ struct gendisk *disk;
+ struct kref kref;
+
+ /* Buffer for table of contents. NULL if we haven't allocated
+ a TOC buffer for this device yet. */
+
+ struct atapi_toc *toc;
+
+ /* The result of the last successful request sense command
+ on this device. */
+ struct request_sense sense_data;
+
+ struct request request_sense_request;
+ unsigned long last_block;
+ unsigned long start_seek;
+
+ u8 max_speed; /* Max speed of the drive. */
+ u8 current_speed; /* Current speed of the drive. */
+
+ /* Per-device info needed by cdrom.c generic driver. */
+ struct cdrom_device_info devinfo;
+
+ unsigned long write_timeout;
+};
+
+/* ide-cd_verbose.c */
+void ide_cd_log_error(const char *, struct request *, struct request_sense *);
+
+/* ide-cd.c functions used by ide-cd_ioctl.c */
+int ide_cd_queue_pc(ide_drive_t *, const unsigned char *, int, void *,
+ unsigned *, struct request_sense *, int, unsigned int);
+int ide_cd_read_toc(ide_drive_t *, struct request_sense *);
+int ide_cdrom_get_capabilities(ide_drive_t *, u8 *);
+void ide_cdrom_update_speed(ide_drive_t *, u8 *);
+int cdrom_check_status(ide_drive_t *, struct request_sense *);
+
+/* ide-cd_ioctl.c */
+int ide_cdrom_open_real(struct cdrom_device_info *, int);
+void ide_cdrom_release_real(struct cdrom_device_info *);
+int ide_cdrom_drive_status(struct cdrom_device_info *, int);
+int ide_cdrom_check_media_change_real(struct cdrom_device_info *, int);
+int ide_cdrom_tray_move(struct cdrom_device_info *, int);
+int ide_cdrom_lock_door(struct cdrom_device_info *, int);
+int ide_cdrom_select_speed(struct cdrom_device_info *, int);
+int ide_cdrom_get_last_session(struct cdrom_device_info *,
+ struct cdrom_multisession *);
+int ide_cdrom_get_mcn(struct cdrom_device_info *, struct cdrom_mcn *);
+int ide_cdrom_reset(struct cdrom_device_info *cdi);
+int ide_cdrom_audio_ioctl(struct cdrom_device_info *, unsigned int, void *);
+int ide_cdrom_packet(struct cdrom_device_info *, struct packet_command *);
+
+#endif /* _IDE_CD_H */
diff --git a/drivers/ide/ide-cd_ioctl.c b/drivers/ide/ide-cd_ioctl.c
new file mode 100644
index 0000000..df3df00
--- /dev/null
+++ b/drivers/ide/ide-cd_ioctl.c
@@ -0,0 +1,471 @@
+/*
+ * cdrom.c IOCTLs handling for ide-cd driver.
+ *
+ * Copyright (C) 1994-1996 Scott Snyder <snyder@fnald0.fnal.gov>
+ * Copyright (C) 1996-1998 Erik Andersen <andersee@debian.org>
+ * Copyright (C) 1998-2000 Jens Axboe <axboe@suse.de>
+ */
+
+#include <linux/kernel.h>
+#include <linux/cdrom.h>
+#include <linux/ide.h>
+#include <scsi/scsi.h>
+
+#include "ide-cd.h"
+
+/****************************************************************************
+ * Other driver requests (open, close, check media change).
+ */
+int ide_cdrom_open_real(struct cdrom_device_info *cdi, int purpose)
+{
+ return 0;
+}
+
+/*
+ * Close down the device. Invalidate all cached blocks.
+ */
+void ide_cdrom_release_real(struct cdrom_device_info *cdi)
+{
+ ide_drive_t *drive = cdi->handle;
+
+ if (!cdi->use_count)
+ drive->atapi_flags &= ~IDE_AFLAG_TOC_VALID;
+}
+
+/*
+ * add logic to try GET_EVENT command first to check for media and tray
+ * status. this should be supported by newer cd-r/w and all DVD etc
+ * drives
+ */
+int ide_cdrom_drive_status(struct cdrom_device_info *cdi, int slot_nr)
+{
+ ide_drive_t *drive = cdi->handle;
+ struct media_event_desc med;
+ struct request_sense sense;
+ int stat;
+
+ if (slot_nr != CDSL_CURRENT)
+ return -EINVAL;
+
+ stat = cdrom_check_status(drive, &sense);
+ if (!stat || sense.sense_key == UNIT_ATTENTION)
+ return CDS_DISC_OK;
+
+ if (!cdrom_get_media_event(cdi, &med)) {
+ if (med.media_present)
+ return CDS_DISC_OK;
+ else if (med.door_open)
+ return CDS_TRAY_OPEN;
+ else
+ return CDS_NO_DISC;
+ }
+
+ if (sense.sense_key == NOT_READY && sense.asc == 0x04
+ && sense.ascq == 0x04)
+ return CDS_DISC_OK;
+
+ /*
+ * If not using Mt Fuji extended media tray reports,
+ * just return TRAY_OPEN since ATAPI doesn't provide
+ * any other way to detect this...
+ */
+ if (sense.sense_key == NOT_READY) {
+ if (sense.asc == 0x3a && sense.ascq == 1)
+ return CDS_NO_DISC;
+ else
+ return CDS_TRAY_OPEN;
+ }
+ return CDS_DRIVE_NOT_READY;
+}
+
+int ide_cdrom_check_media_change_real(struct cdrom_device_info *cdi,
+ int slot_nr)
+{
+ ide_drive_t *drive = cdi->handle;
+ int retval;
+
+ if (slot_nr == CDSL_CURRENT) {
+ (void) cdrom_check_status(drive, NULL);
+ retval = (drive->dev_flags & IDE_DFLAG_MEDIA_CHANGED) ? 1 : 0;
+ drive->dev_flags &= ~IDE_DFLAG_MEDIA_CHANGED;
+ return retval;
+ } else {
+ return -EINVAL;
+ }
+}
+
+/* Eject the disk if EJECTFLAG is 0.
+ If EJECTFLAG is 1, try to reload the disk. */
+static
+int cdrom_eject(ide_drive_t *drive, int ejectflag,
+ struct request_sense *sense)
+{
+ struct cdrom_info *cd = drive->driver_data;
+ struct cdrom_device_info *cdi = &cd->devinfo;
+ char loej = 0x02;
+ unsigned char cmd[BLK_MAX_CDB];
+
+ if ((drive->atapi_flags & IDE_AFLAG_NO_EJECT) && !ejectflag)
+ return -EDRIVE_CANT_DO_THIS;
+
+ /* reload fails on some drives, if the tray is locked */
+ if ((drive->atapi_flags & IDE_AFLAG_DOOR_LOCKED) && ejectflag)
+ return 0;
+
+ /* only tell drive to close tray if open, if it can do that */
+ if (ejectflag && (cdi->mask & CDC_CLOSE_TRAY))
+ loej = 0;
+
+ memset(cmd, 0, BLK_MAX_CDB);
+
+ cmd[0] = GPCMD_START_STOP_UNIT;
+ cmd[4] = loej | (ejectflag != 0);
+
+ return ide_cd_queue_pc(drive, cmd, 0, NULL, NULL, sense, 0, 0);
+}
+
+/* Lock the door if LOCKFLAG is nonzero; unlock it otherwise. */
+static
+int ide_cd_lockdoor(ide_drive_t *drive, int lockflag,
+ struct request_sense *sense)
+{
+ struct request_sense my_sense;
+ int stat;
+
+ if (sense == NULL)
+ sense = &my_sense;
+
+ /* If the drive cannot lock the door, just pretend. */
+ if ((drive->dev_flags & IDE_DFLAG_DOORLOCKING) == 0) {
+ stat = 0;
+ } else {
+ unsigned char cmd[BLK_MAX_CDB];
+
+ memset(cmd, 0, BLK_MAX_CDB);
+
+ cmd[0] = GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL;
+ cmd[4] = lockflag ? 1 : 0;
+
+ stat = ide_cd_queue_pc(drive, cmd, 0, NULL, NULL,
+ sense, 0, 0);
+ }
+
+ /* If we got an illegal field error, the drive
+ probably cannot lock the door. */
+ if (stat != 0 &&
+ sense->sense_key == ILLEGAL_REQUEST &&
+ (sense->asc == 0x24 || sense->asc == 0x20)) {
+ printk(KERN_ERR "%s: door locking not supported\n",
+ drive->name);
+ drive->dev_flags &= ~IDE_DFLAG_DOORLOCKING;
+ stat = 0;
+ }
+
+ /* no medium, that's alright. */
+ if (stat != 0 && sense->sense_key == NOT_READY && sense->asc == 0x3a)
+ stat = 0;
+
+ if (stat == 0) {
+ if (lockflag)
+ drive->atapi_flags |= IDE_AFLAG_DOOR_LOCKED;
+ else
+ drive->atapi_flags &= ~IDE_AFLAG_DOOR_LOCKED;
+ }
+
+ return stat;
+}
+
+int ide_cdrom_tray_move(struct cdrom_device_info *cdi, int position)
+{
+ ide_drive_t *drive = cdi->handle;
+ struct request_sense sense;
+
+ if (position) {
+ int stat = ide_cd_lockdoor(drive, 0, &sense);
+
+ if (stat)
+ return stat;
+ }
+
+ return cdrom_eject(drive, !position, &sense);
+}
+
+int ide_cdrom_lock_door(struct cdrom_device_info *cdi, int lock)
+{
+ ide_drive_t *drive = cdi->handle;
+
+ return ide_cd_lockdoor(drive, lock, NULL);
+}
+
+/*
+ * ATAPI devices are free to select the speed you request or any slower
+ * rate. :-( Requesting too fast a speed will _not_ produce an error.
+ */
+int ide_cdrom_select_speed(struct cdrom_device_info *cdi, int speed)
+{
+ ide_drive_t *drive = cdi->handle;
+ struct cdrom_info *cd = drive->driver_data;
+ struct request_sense sense;
+ u8 buf[ATAPI_CAPABILITIES_PAGE_SIZE];
+ int stat;
+ unsigned char cmd[BLK_MAX_CDB];
+
+ if (speed == 0)
+ speed = 0xffff; /* set to max */
+ else
+ speed *= 177; /* Nx to kbytes/s */
+
+ memset(cmd, 0, BLK_MAX_CDB);
+
+ cmd[0] = GPCMD_SET_SPEED;
+ /* Read Drive speed in kbytes/second MSB/LSB */
+ cmd[2] = (speed >> 8) & 0xff;
+ cmd[3] = speed & 0xff;
+ if ((cdi->mask & (CDC_CD_R | CDC_CD_RW | CDC_DVD_R)) !=
+ (CDC_CD_R | CDC_CD_RW | CDC_DVD_R)) {
+ /* Write Drive speed in kbytes/second MSB/LSB */
+ cmd[4] = (speed >> 8) & 0xff;
+ cmd[5] = speed & 0xff;
+ }
+
+ stat = ide_cd_queue_pc(drive, cmd, 0, NULL, NULL, &sense, 0, 0);
+
+ if (!ide_cdrom_get_capabilities(drive, buf)) {
+ ide_cdrom_update_speed(drive, buf);
+ cdi->speed = cd->current_speed;
+ }
+
+ return 0;
+}
+
+int ide_cdrom_get_last_session(struct cdrom_device_info *cdi,
+ struct cdrom_multisession *ms_info)
+{
+ struct atapi_toc *toc;
+ ide_drive_t *drive = cdi->handle;
+ struct cdrom_info *info = drive->driver_data;
+ struct request_sense sense;
+ int ret;
+
+ if ((drive->atapi_flags & IDE_AFLAG_TOC_VALID) == 0 || !info->toc) {
+ ret = ide_cd_read_toc(drive, &sense);
+ if (ret)
+ return ret;
+ }
+
+ toc = info->toc;
+ ms_info->addr.lba = toc->last_session_lba;
+ ms_info->xa_flag = toc->xa_flag;
+
+ return 0;
+}
+
+int ide_cdrom_get_mcn(struct cdrom_device_info *cdi,
+ struct cdrom_mcn *mcn_info)
+{
+ ide_drive_t *drive = cdi->handle;
+ int stat, mcnlen;
+ char buf[24];
+ unsigned char cmd[BLK_MAX_CDB];
+ unsigned len = sizeof(buf);
+
+ memset(cmd, 0, BLK_MAX_CDB);
+
+ cmd[0] = GPCMD_READ_SUBCHANNEL;
+ cmd[1] = 2; /* MSF addressing */
+ cmd[2] = 0x40; /* request subQ data */
+ cmd[3] = 2; /* format */
+ cmd[8] = len;
+
+ stat = ide_cd_queue_pc(drive, cmd, 0, buf, &len, NULL, 0, 0);
+ if (stat)
+ return stat;
+
+ mcnlen = sizeof(mcn_info->medium_catalog_number) - 1;
+ memcpy(mcn_info->medium_catalog_number, buf + 9, mcnlen);
+ mcn_info->medium_catalog_number[mcnlen] = '\0';
+
+ return 0;
+}
+
+int ide_cdrom_reset(struct cdrom_device_info *cdi)
+{
+ ide_drive_t *drive = cdi->handle;
+ struct cdrom_info *cd = drive->driver_data;
+ struct request_sense sense;
+ struct request *rq;
+ int ret;
+
+ rq = blk_get_request(drive->queue, READ, __GFP_WAIT);
+ rq->cmd_type = REQ_TYPE_SPECIAL;
+ rq->cmd_flags = REQ_QUIET;
+ ret = blk_execute_rq(drive->queue, cd->disk, rq, 0);
+ blk_put_request(rq);
+ /*
+ * A reset will unlock the door. If it was previously locked,
+ * lock it again.
+ */
+ if (drive->atapi_flags & IDE_AFLAG_DOOR_LOCKED)
+ (void)ide_cd_lockdoor(drive, 1, &sense);
+
+ return ret;
+}
+
+static int ide_cd_get_toc_entry(ide_drive_t *drive, int track,
+ struct atapi_toc_entry **ent)
+{
+ struct cdrom_info *info = drive->driver_data;
+ struct atapi_toc *toc = info->toc;
+ int ntracks;
+
+ /*
+ * don't serve cached data, if the toc isn't valid
+ */
+ if ((drive->atapi_flags & IDE_AFLAG_TOC_VALID) == 0)
+ return -EINVAL;
+
+ /* Check validity of requested track number. */
+ ntracks = toc->hdr.last_track - toc->hdr.first_track + 1;
+
+ if (toc->hdr.first_track == CDROM_LEADOUT)
+ ntracks = 0;
+
+ if (track == CDROM_LEADOUT)
+ *ent = &toc->ent[ntracks];
+ else if (track < toc->hdr.first_track || track > toc->hdr.last_track)
+ return -EINVAL;
+ else
+ *ent = &toc->ent[track - toc->hdr.first_track];
+
+ return 0;
+}
+
+static int ide_cd_fake_play_trkind(ide_drive_t *drive, void *arg)
+{
+ struct cdrom_ti *ti = arg;
+ struct atapi_toc_entry *first_toc, *last_toc;
+ unsigned long lba_start, lba_end;
+ int stat;
+ struct request_sense sense;
+ unsigned char cmd[BLK_MAX_CDB];
+
+ stat = ide_cd_get_toc_entry(drive, ti->cdti_trk0, &first_toc);
+ if (stat)
+ return stat;
+
+ stat = ide_cd_get_toc_entry(drive, ti->cdti_trk1, &last_toc);
+ if (stat)
+ return stat;
+
+ if (ti->cdti_trk1 != CDROM_LEADOUT)
+ ++last_toc;
+ lba_start = first_toc->addr.lba;
+ lba_end = last_toc->addr.lba;
+
+ if (lba_end <= lba_start)
+ return -EINVAL;
+
+ memset(cmd, 0, BLK_MAX_CDB);
+
+ cmd[0] = GPCMD_PLAY_AUDIO_MSF;
+ lba_to_msf(lba_start, &cmd[3], &cmd[4], &cmd[5]);
+ lba_to_msf(lba_end - 1, &cmd[6], &cmd[7], &cmd[8]);
+
+ return ide_cd_queue_pc(drive, cmd, 0, NULL, NULL, &sense, 0, 0);
+}
+
+static int ide_cd_read_tochdr(ide_drive_t *drive, void *arg)
+{
+ struct cdrom_info *cd = drive->driver_data;
+ struct cdrom_tochdr *tochdr = arg;
+ struct atapi_toc *toc;
+ int stat;
+
+ /* Make sure our saved TOC is valid. */
+ stat = ide_cd_read_toc(drive, NULL);
+ if (stat)
+ return stat;
+
+ toc = cd->toc;
+ tochdr->cdth_trk0 = toc->hdr.first_track;
+ tochdr->cdth_trk1 = toc->hdr.last_track;
+
+ return 0;
+}
+
+static int ide_cd_read_tocentry(ide_drive_t *drive, void *arg)
+{
+ struct cdrom_tocentry *tocentry = arg;
+ struct atapi_toc_entry *toce;
+ int stat;
+
+ stat = ide_cd_get_toc_entry(drive, tocentry->cdte_track, &toce);
+ if (stat)
+ return stat;
+
+ tocentry->cdte_ctrl = toce->control;
+ tocentry->cdte_adr = toce->adr;
+ if (tocentry->cdte_format == CDROM_MSF) {
+ lba_to_msf(toce->addr.lba,
+ &tocentry->cdte_addr.msf.minute,
+ &tocentry->cdte_addr.msf.second,
+ &tocentry->cdte_addr.msf.frame);
+ } else
+ tocentry->cdte_addr.lba = toce->addr.lba;
+
+ return 0;
+}
+
+int ide_cdrom_audio_ioctl(struct cdrom_device_info *cdi,
+ unsigned int cmd, void *arg)
+{
+ ide_drive_t *drive = cdi->handle;
+
+ switch (cmd) {
+ /*
+ * emulate PLAY_AUDIO_TI command with PLAY_AUDIO_10, since
+ * atapi doesn't support it
+ */
+ case CDROMPLAYTRKIND:
+ return ide_cd_fake_play_trkind(drive, arg);
+ case CDROMREADTOCHDR:
+ return ide_cd_read_tochdr(drive, arg);
+ case CDROMREADTOCENTRY:
+ return ide_cd_read_tocentry(drive, arg);
+ default:
+ return -EINVAL;
+ }
+}
+
+/* the generic packet interface to cdrom.c */
+int ide_cdrom_packet(struct cdrom_device_info *cdi,
+ struct packet_command *cgc)
+{
+ ide_drive_t *drive = cdi->handle;
+ unsigned int flags = 0;
+ unsigned len = cgc->buflen;
+
+ if (cgc->timeout <= 0)
+ cgc->timeout = ATAPI_WAIT_PC;
+
+ /* here we queue the commands from the uniform CD-ROM
+ layer. the packet must be complete, as we do not
+ touch it at all. */
+
+ if (cgc->data_direction == CGC_DATA_WRITE)
+ flags |= REQ_RW;
+
+ if (cgc->sense)
+ memset(cgc->sense, 0, sizeof(struct request_sense));
+
+ if (cgc->quiet)
+ flags |= REQ_QUIET;
+
+ cgc->stat = ide_cd_queue_pc(drive, cgc->cmd,
+ cgc->data_direction == CGC_DATA_WRITE,
+ cgc->buffer, &len,
+ cgc->sense, cgc->timeout, flags);
+ if (!cgc->stat)
+ cgc->buflen -= len;
+ return cgc->stat;
+}
diff --git a/drivers/ide/ide-cd_verbose.c b/drivers/ide/ide-cd_verbose.c
new file mode 100644
index 0000000..6490a2d
--- /dev/null
+++ b/drivers/ide/ide-cd_verbose.c
@@ -0,0 +1,359 @@
+/*
+ * Verbose error logging for ATAPI CD/DVD devices.
+ *
+ * Copyright (C) 1994-1996 Scott Snyder <snyder@fnald0.fnal.gov>
+ * Copyright (C) 1996-1998 Erik Andersen <andersee@debian.org>
+ * Copyright (C) 1998-2000 Jens Axboe <axboe@suse.de>
+ */
+
+#include <linux/kernel.h>
+#include <linux/blkdev.h>
+#include <linux/cdrom.h>
+#include <scsi/scsi.h>
+
+#ifndef CONFIG_BLK_DEV_IDECD_VERBOSE_ERRORS
+void ide_cd_log_error(const char *name, struct request *failed_command,
+ struct request_sense *sense)
+{
+ /* Suppress printing unit attention and `in progress of becoming ready'
+ errors when we're not being verbose. */
+ if (sense->sense_key == UNIT_ATTENTION ||
+ (sense->sense_key == NOT_READY && (sense->asc == 4 ||
+ sense->asc == 0x3a)))
+ return;
+
+ printk(KERN_ERR "%s: error code: 0x%02x sense_key: 0x%02x "
+ "asc: 0x%02x ascq: 0x%02x\n",
+ name, sense->error_code, sense->sense_key,
+ sense->asc, sense->ascq);
+}
+#else
+/* The generic packet command opcodes for CD/DVD Logical Units,
+ * From Table 57 of the SFF8090 Ver. 3 (Mt. Fuji) draft standard. */
+static const struct {
+ unsigned short packet_command;
+ const char * const text;
+} packet_command_texts[] = {
+ { GPCMD_TEST_UNIT_READY, "Test Unit Ready" },
+ { GPCMD_REQUEST_SENSE, "Request Sense" },
+ { GPCMD_FORMAT_UNIT, "Format Unit" },
+ { GPCMD_INQUIRY, "Inquiry" },
+ { GPCMD_START_STOP_UNIT, "Start/Stop Unit" },
+ { GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL, "Prevent/Allow Medium Removal" },
+ { GPCMD_READ_FORMAT_CAPACITIES, "Read Format Capacities" },
+ { GPCMD_READ_CDVD_CAPACITY, "Read Cd/Dvd Capacity" },
+ { GPCMD_READ_10, "Read 10" },
+ { GPCMD_WRITE_10, "Write 10" },
+ { GPCMD_SEEK, "Seek" },
+ { GPCMD_WRITE_AND_VERIFY_10, "Write and Verify 10" },
+ { GPCMD_VERIFY_10, "Verify 10" },
+ { GPCMD_FLUSH_CACHE, "Flush Cache" },
+ { GPCMD_READ_SUBCHANNEL, "Read Subchannel" },
+ { GPCMD_READ_TOC_PMA_ATIP, "Read Table of Contents" },
+ { GPCMD_READ_HEADER, "Read Header" },
+ { GPCMD_PLAY_AUDIO_10, "Play Audio 10" },
+ { GPCMD_GET_CONFIGURATION, "Get Configuration" },
+ { GPCMD_PLAY_AUDIO_MSF, "Play Audio MSF" },
+ { GPCMD_PLAYAUDIO_TI, "Play Audio TrackIndex" },
+ { GPCMD_GET_EVENT_STATUS_NOTIFICATION,
+ "Get Event Status Notification" },
+ { GPCMD_PAUSE_RESUME, "Pause/Resume" },
+ { GPCMD_STOP_PLAY_SCAN, "Stop Play/Scan" },
+ { GPCMD_READ_DISC_INFO, "Read Disc Info" },
+ { GPCMD_READ_TRACK_RZONE_INFO, "Read Track Rzone Info" },
+ { GPCMD_RESERVE_RZONE_TRACK, "Reserve Rzone Track" },
+ { GPCMD_SEND_OPC, "Send OPC" },
+ { GPCMD_MODE_SELECT_10, "Mode Select 10" },
+ { GPCMD_REPAIR_RZONE_TRACK, "Repair Rzone Track" },
+ { GPCMD_MODE_SENSE_10, "Mode Sense 10" },
+ { GPCMD_CLOSE_TRACK, "Close Track" },
+ { GPCMD_BLANK, "Blank" },
+ { GPCMD_SEND_EVENT, "Send Event" },
+ { GPCMD_SEND_KEY, "Send Key" },
+ { GPCMD_REPORT_KEY, "Report Key" },
+ { GPCMD_LOAD_UNLOAD, "Load/Unload" },
+ { GPCMD_SET_READ_AHEAD, "Set Read-ahead" },
+ { GPCMD_READ_12, "Read 12" },
+ { GPCMD_GET_PERFORMANCE, "Get Performance" },
+ { GPCMD_SEND_DVD_STRUCTURE, "Send DVD Structure" },
+ { GPCMD_READ_DVD_STRUCTURE, "Read DVD Structure" },
+ { GPCMD_SET_STREAMING, "Set Streaming" },
+ { GPCMD_READ_CD_MSF, "Read CD MSF" },
+ { GPCMD_SCAN, "Scan" },
+ { GPCMD_SET_SPEED, "Set Speed" },
+ { GPCMD_PLAY_CD, "Play CD" },
+ { GPCMD_MECHANISM_STATUS, "Mechanism Status" },
+ { GPCMD_READ_CD, "Read CD" },
+};
+
+/* From Table 303 of the SFF8090 Ver. 3 (Mt. Fuji) draft standard. */
+static const char * const sense_key_texts[16] = {
+ "No sense data",
+ "Recovered error",
+ "Not ready",
+ "Medium error",
+ "Hardware error",
+ "Illegal request",
+ "Unit attention",
+ "Data protect",
+ "Blank check",
+ "(reserved)",
+ "(reserved)",
+ "Aborted command",
+ "(reserved)",
+ "(reserved)",
+ "Miscompare",
+ "(reserved)",
+};
+
+/* From Table 304 of the SFF8090 Ver. 3 (Mt. Fuji) draft standard. */
+static const struct {
+ unsigned long asc_ascq;
+ const char * const text;
+} sense_data_texts[] = {
+ { 0x000000, "No additional sense information" },
+ { 0x000011, "Play operation in progress" },
+ { 0x000012, "Play operation paused" },
+ { 0x000013, "Play operation successfully completed" },
+ { 0x000014, "Play operation stopped due to error" },
+ { 0x000015, "No current audio status to return" },
+ { 0x010c0a, "Write error - padding blocks added" },
+ { 0x011700, "Recovered data with no error correction applied" },
+ { 0x011701, "Recovered data with retries" },
+ { 0x011702, "Recovered data with positive head offset" },
+ { 0x011703, "Recovered data with negative head offset" },
+ { 0x011704, "Recovered data with retries and/or CIRC applied" },
+ { 0x011705, "Recovered data using previous sector ID" },
+ { 0x011800, "Recovered data with error correction applied" },
+ { 0x011801, "Recovered data with error correction and retries applied"},
+ { 0x011802, "Recovered data - the data was auto-reallocated" },
+ { 0x011803, "Recovered data with CIRC" },
+ { 0x011804, "Recovered data with L-EC" },
+ { 0x015d00, "Failure prediction threshold exceeded"
+ " - Predicted logical unit failure" },
+ { 0x015d01, "Failure prediction threshold exceeded"
+ " - Predicted media failure" },
+ { 0x015dff, "Failure prediction threshold exceeded - False" },
+ { 0x017301, "Power calibration area almost full" },
+ { 0x020400, "Logical unit not ready - cause not reportable" },
+ /* Following is misspelled in ATAPI 2.6, _and_ in Mt. Fuji */
+ { 0x020401, "Logical unit not ready"
+ " - in progress [sic] of becoming ready" },
+ { 0x020402, "Logical unit not ready - initializing command required" },
+ { 0x020403, "Logical unit not ready - manual intervention required" },
+ { 0x020404, "Logical unit not ready - format in progress" },
+ { 0x020407, "Logical unit not ready - operation in progress" },
+ { 0x020408, "Logical unit not ready - long write in progress" },
+ { 0x020600, "No reference position found (media may be upside down)" },
+ { 0x023000, "Incompatible medium installed" },
+ { 0x023a00, "Medium not present" },
+ { 0x025300, "Media load or eject failed" },
+ { 0x025700, "Unable to recover table of contents" },
+ { 0x030300, "Peripheral device write fault" },
+ { 0x030301, "No write current" },
+ { 0x030302, "Excessive write errors" },
+ { 0x030c00, "Write error" },
+ { 0x030c01, "Write error - Recovered with auto reallocation" },
+ { 0x030c02, "Write error - auto reallocation failed" },
+ { 0x030c03, "Write error - recommend reassignment" },
+ { 0x030c04, "Compression check miscompare error" },
+ { 0x030c05, "Data expansion occurred during compress" },
+ { 0x030c06, "Block not compressible" },
+ { 0x030c07, "Write error - recovery needed" },
+ { 0x030c08, "Write error - recovery failed" },
+ { 0x030c09, "Write error - loss of streaming" },
+ { 0x031100, "Unrecovered read error" },
+ { 0x031106, "CIRC unrecovered error" },
+ { 0x033101, "Format command failed" },
+ { 0x033200, "No defect spare location available" },
+ { 0x033201, "Defect list update failure" },
+ { 0x035100, "Erase failure" },
+ { 0x037200, "Session fixation error" },
+ { 0x037201, "Session fixation error writin lead-in" },
+ { 0x037202, "Session fixation error writin lead-out" },
+ { 0x037300, "CD control error" },
+ { 0x037302, "Power calibration area is full" },
+ { 0x037303, "Power calibration area error" },
+ { 0x037304, "Program memory area / RMA update failure" },
+ { 0x037305, "Program memory area / RMA is full" },
+ { 0x037306, "Program memory area / RMA is (almost) full" },
+ { 0x040200, "No seek complete" },
+ { 0x040300, "Write fault" },
+ { 0x040900, "Track following error" },
+ { 0x040901, "Tracking servo failure" },
+ { 0x040902, "Focus servo failure" },
+ { 0x040903, "Spindle servo failure" },
+ { 0x041500, "Random positioning error" },
+ { 0x041501, "Mechanical positioning or changer error" },
+ { 0x041502, "Positioning error detected by read of medium" },
+ { 0x043c00, "Mechanical positioning or changer error" },
+ { 0x044000, "Diagnostic failure on component (ASCQ)" },
+ { 0x044400, "Internal CD/DVD logical unit failure" },
+ { 0x04b600, "Media load mechanism failed" },
+ { 0x051a00, "Parameter list length error" },
+ { 0x052000, "Invalid command operation code" },
+ { 0x052100, "Logical block address out of range" },
+ { 0x052102, "Invalid address for write" },
+ { 0x052400, "Invalid field in command packet" },
+ { 0x052600, "Invalid field in parameter list" },
+ { 0x052601, "Parameter not supported" },
+ { 0x052602, "Parameter value invalid" },
+ { 0x052700, "Write protected media" },
+ { 0x052c00, "Command sequence error" },
+ { 0x052c03, "Current program area is not empty" },
+ { 0x052c04, "Current program area is empty" },
+ { 0x053001, "Cannot read medium - unknown format" },
+ { 0x053002, "Cannot read medium - incompatible format" },
+ { 0x053900, "Saving parameters not supported" },
+ { 0x054e00, "Overlapped commands attempted" },
+ { 0x055302, "Medium removal prevented" },
+ { 0x055500, "System resource failure" },
+ { 0x056300, "End of user area encountered on this track" },
+ { 0x056400, "Illegal mode for this track or incompatible medium" },
+ { 0x056f00, "Copy protection key exchange failure"
+ " - Authentication failure" },
+ { 0x056f01, "Copy protection key exchange failure - Key not present" },
+ { 0x056f02, "Copy protection key exchange failure"
+ " - Key not established" },
+ { 0x056f03, "Read of scrambled sector without authentication" },
+ { 0x056f04, "Media region code is mismatched to logical unit" },
+ { 0x056f05, "Drive region must be permanent"
+ " / region reset count error" },
+ { 0x057203, "Session fixation error - incomplete track in session" },
+ { 0x057204, "Empty or partially written reserved track" },
+ { 0x057205, "No more RZONE reservations are allowed" },
+ { 0x05bf00, "Loss of streaming" },
+ { 0x062800, "Not ready to ready transition, medium may have changed" },
+ { 0x062900, "Power on, reset or hardware reset occurred" },
+ { 0x062a00, "Parameters changed" },
+ { 0x062a01, "Mode parameters changed" },
+ { 0x062e00, "Insufficient time for operation" },
+ { 0x063f00, "Logical unit operating conditions have changed" },
+ { 0x063f01, "Microcode has been changed" },
+ { 0x065a00, "Operator request or state change input (unspecified)" },
+ { 0x065a01, "Operator medium removal request" },
+ { 0x0bb900, "Play operation aborted" },
+ /* Here we use 0xff for the key (not a valid key) to signify
+ * that these can have _any_ key value associated with them... */
+ { 0xff0401, "Logical unit is in process of becoming ready" },
+ { 0xff0400, "Logical unit not ready, cause not reportable" },
+ { 0xff0402, "Logical unit not ready, initializing command required" },
+ { 0xff0403, "Logical unit not ready, manual intervention required" },
+ { 0xff0500, "Logical unit does not respond to selection" },
+ { 0xff0800, "Logical unit communication failure" },
+ { 0xff0802, "Logical unit communication parity error" },
+ { 0xff0801, "Logical unit communication time-out" },
+ { 0xff2500, "Logical unit not supported" },
+ { 0xff4c00, "Logical unit failed self-configuration" },
+ { 0xff3e00, "Logical unit has not self-configured yet" },
+};
+
+void ide_cd_log_error(const char *name, struct request *failed_command,
+ struct request_sense *sense)
+{
+ int i;
+ const char *s = "bad sense key!";
+ char buf[80];
+
+ printk(KERN_ERR "ATAPI device %s:\n", name);
+ if (sense->error_code == 0x70)
+ printk(KERN_CONT " Error: ");
+ else if (sense->error_code == 0x71)
+ printk(" Deferred Error: ");
+ else if (sense->error_code == 0x7f)
+ printk(KERN_CONT " Vendor-specific Error: ");
+ else
+ printk(KERN_CONT " Unknown Error Type: ");
+
+ if (sense->sense_key < ARRAY_SIZE(sense_key_texts))
+ s = sense_key_texts[sense->sense_key];
+
+ printk(KERN_CONT "%s -- (Sense key=0x%02x)\n", s, sense->sense_key);
+
+ if (sense->asc == 0x40) {
+ sprintf(buf, "Diagnostic failure on component 0x%02x",
+ sense->ascq);
+ s = buf;
+ } else {
+ int lo = 0, mid, hi = ARRAY_SIZE(sense_data_texts);
+ unsigned long key = (sense->sense_key << 16);
+
+ key |= (sense->asc << 8);
+ if (!(sense->ascq >= 0x80 && sense->ascq <= 0xdd))
+ key |= sense->ascq;
+ s = NULL;
+
+ while (hi > lo) {
+ mid = (lo + hi) / 2;
+ if (sense_data_texts[mid].asc_ascq == key ||
+ sense_data_texts[mid].asc_ascq == (0xff0000|key)) {
+ s = sense_data_texts[mid].text;
+ break;
+ } else if (sense_data_texts[mid].asc_ascq > key)
+ hi = mid;
+ else
+ lo = mid + 1;
+ }
+ }
+
+ if (s == NULL) {
+ if (sense->asc > 0x80)
+ s = "(vendor-specific error)";
+ else
+ s = "(reserved error code)";
+ }
+
+ printk(KERN_ERR " %s -- (asc=0x%02x, ascq=0x%02x)\n",
+ s, sense->asc, sense->ascq);
+
+ if (failed_command != NULL) {
+ int lo = 0, mid, hi = ARRAY_SIZE(packet_command_texts);
+ s = NULL;
+
+ while (hi > lo) {
+ mid = (lo + hi) / 2;
+ if (packet_command_texts[mid].packet_command ==
+ failed_command->cmd[0]) {
+ s = packet_command_texts[mid].text;
+ break;
+ }
+ if (packet_command_texts[mid].packet_command >
+ failed_command->cmd[0])
+ hi = mid;
+ else
+ lo = mid + 1;
+ }
+
+ printk(KERN_ERR " The failed \"%s\" packet command "
+ "was: \n \"", s);
+ for (i = 0; i < BLK_MAX_CDB; i++)
+ printk(KERN_CONT "%02x ", failed_command->cmd[i]);
+ printk(KERN_CONT "\"\n");
+ }
+
+ /* The SKSV bit specifies validity of the sense_key_specific
+ * in the next two commands. It is bit 7 of the first byte.
+ * In the case of NOT_READY, if SKSV is set the drive can
+ * give us nice ETA readings.
+ */
+ if (sense->sense_key == NOT_READY && (sense->sks[0] & 0x80)) {
+ int progress = (sense->sks[1] << 8 | sense->sks[2]) * 100;
+
+ printk(KERN_ERR " Command is %02d%% complete\n",
+ progress / 0xffff);
+ }
+
+ if (sense->sense_key == ILLEGAL_REQUEST &&
+ (sense->sks[0] & 0x80) != 0) {
+ printk(KERN_ERR " Error in %s byte %d",
+ (sense->sks[0] & 0x40) != 0 ?
+ "command packet" : "command data",
+ (sense->sks[1] << 8) + sense->sks[2]);
+
+ if ((sense->sks[0] & 0x40) != 0)
+ printk(KERN_CONT " bit %d", sense->sks[0] & 0x07);
+
+ printk(KERN_CONT "\n");
+ }
+}
+#endif
diff --git a/drivers/ide/ide-cs.c b/drivers/ide/ide-cs.c
new file mode 100644
index 0000000..f50210f
--- /dev/null
+++ b/drivers/ide/ide-cs.c
@@ -0,0 +1,473 @@
+/*======================================================================
+
+ A driver for PCMCIA IDE/ATA disk cards
+
+ The contents of this file are subject to the Mozilla Public
+ License Version 1.1 (the "License"); you may not use this file
+ except in compliance with the License. You may obtain a copy of
+ the License at http://www.mozilla.org/MPL/
+
+ Software distributed under the License is distributed on an "AS
+ IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ implied. See the License for the specific language governing
+ rights and limitations under the License.
+
+ 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.
+
+ Alternatively, the contents of this file may be used under the
+ terms of the GNU General Public License version 2 (the "GPL"), in
+ which case the provisions of the GPL are applicable instead of the
+ above. If you wish to allow the use of your version of this file
+ only under the terms of the GPL and not to allow others to use
+ your version of this file under the MPL, indicate your decision
+ by deleting the provisions above and replace them with the notice
+ and other provisions required by the GPL. If you do not delete
+ the provisions above, a recipient may use your version of this
+ file under either the MPL or the GPL.
+
+======================================================================*/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/ioport.h>
+#include <linux/ide.h>
+#include <linux/major.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <asm/system.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 "ide-cs"
+
+/*====================================================================*/
+
+/* Module parameters */
+
+MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
+MODULE_DESCRIPTION("PCMCIA ATA/IDE card driver");
+MODULE_LICENSE("Dual MPL/GPL");
+
+#define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0)
+
+#ifdef CONFIG_PCMCIA_DEBUG
+INT_MODULE_PARM(pc_debug, 0);
+#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
+#else
+#define DEBUG(n, args...)
+#endif
+
+/*====================================================================*/
+
+typedef struct ide_info_t {
+ struct pcmcia_device *p_dev;
+ struct ide_host *host;
+ int ndev;
+ dev_node_t node;
+} ide_info_t;
+
+static void ide_release(struct pcmcia_device *);
+static int ide_config(struct pcmcia_device *);
+
+static void ide_detach(struct pcmcia_device *p_dev);
+
+
+
+
+/*======================================================================
+
+ ide_attach() creates an "instance" of the driver, allocating
+ local data structures for one device. The device is registered
+ with Card Services.
+
+======================================================================*/
+
+static int ide_probe(struct pcmcia_device *link)
+{
+ ide_info_t *info;
+
+ DEBUG(0, "ide_attach()\n");
+
+ /* Create new ide device */
+ info = kzalloc(sizeof(*info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ info->p_dev = link;
+ link->priv = info;
+
+ link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+ link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
+ link->io.IOAddrLines = 3;
+ link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING;
+ link->irq.IRQInfo1 = IRQ_LEVEL_ID;
+ link->conf.Attributes = CONF_ENABLE_IRQ;
+ link->conf.IntType = INT_MEMORY_AND_IO;
+
+ return ide_config(link);
+} /* ide_attach */
+
+/*======================================================================
+
+ This deletes a driver "instance". The device is de-registered
+ with Card Services. If it has been released, all local data
+ structures are freed. Otherwise, the structures will be freed
+ when the device is released.
+
+======================================================================*/
+
+static void ide_detach(struct pcmcia_device *link)
+{
+ ide_info_t *info = link->priv;
+ ide_hwif_t *hwif = info->host->ports[0];
+ unsigned long data_addr, ctl_addr;
+
+ DEBUG(0, "ide_detach(0x%p)\n", link);
+
+ data_addr = hwif->io_ports.data_addr;
+ ctl_addr = hwif->io_ports.ctl_addr;
+
+ ide_release(link);
+
+ release_region(ctl_addr, 1);
+ release_region(data_addr, 8);
+
+ kfree(info);
+} /* ide_detach */
+
+static const struct ide_port_ops idecs_port_ops = {
+ .quirkproc = ide_undecoded_slave,
+};
+
+static const struct ide_port_info idecs_port_info = {
+ .port_ops = &idecs_port_ops,
+ .host_flags = IDE_HFLAG_NO_DMA,
+};
+
+static struct ide_host *idecs_register(unsigned long io, unsigned long ctl,
+ unsigned long irq, struct pcmcia_device *handle)
+{
+ struct ide_host *host;
+ ide_hwif_t *hwif;
+ int i, rc;
+ hw_regs_t hw, *hws[] = { &hw, NULL, NULL, NULL };
+
+ if (!request_region(io, 8, DRV_NAME)) {
+ printk(KERN_ERR "%s: I/O resource 0x%lX-0x%lX not free.\n",
+ DRV_NAME, io, io + 7);
+ return NULL;
+ }
+
+ if (!request_region(ctl, 1, DRV_NAME)) {
+ printk(KERN_ERR "%s: I/O resource 0x%lX not free.\n",
+ DRV_NAME, ctl);
+ release_region(io, 8);
+ return NULL;
+ }
+
+ memset(&hw, 0, sizeof(hw));
+ ide_std_init_ports(&hw, io, ctl);
+ hw.irq = irq;
+ hw.chipset = ide_pci;
+ hw.dev = &handle->dev;
+
+ rc = ide_host_add(&idecs_port_info, hws, &host);
+ if (rc)
+ goto out_release;
+
+ hwif = host->ports[0];
+
+ if (hwif->present)
+ return host;
+
+ /* retry registration in case device is still spinning up */
+ for (i = 0; i < 10; i++) {
+ msleep(100);
+ ide_port_scan(hwif);
+ if (hwif->present)
+ return host;
+ }
+
+ return host;
+
+out_release:
+ release_region(ctl, 1);
+ release_region(io, 8);
+ return NULL;
+}
+
+/*======================================================================
+
+ ide_config() is scheduled to run after a CARD_INSERTION event
+ is received, to configure the PCMCIA socket, and to make the
+ ide device available to the system.
+
+======================================================================*/
+
+#define CS_CHECK(fn, ret) \
+do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
+
+struct pcmcia_config_check {
+ unsigned long ctl_base;
+ int skip_vcc;
+ int is_kme;
+};
+
+static int pcmcia_check_one_config(struct pcmcia_device *pdev,
+ cistpl_cftable_entry_t *cfg,
+ cistpl_cftable_entry_t *dflt,
+ unsigned int vcc,
+ void *priv_data)
+{
+ struct pcmcia_config_check *stk = priv_data;
+
+ /* Check for matching Vcc, unless we're desperate */
+ if (!stk->skip_vcc) {
+ if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) {
+ if (vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000)
+ return -ENODEV;
+ } else if (dflt->vcc.present & (1 << CISTPL_POWER_VNOM)) {
+ if (vcc != dflt->vcc.param[CISTPL_POWER_VNOM] / 10000)
+ return -ENODEV;
+ }
+ }
+
+ if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM))
+ pdev->conf.Vpp = cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
+ else if (dflt->vpp1.present & (1 << CISTPL_POWER_VNOM))
+ pdev->conf.Vpp = dflt->vpp1.param[CISTPL_POWER_VNOM] / 10000;
+
+ if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
+ cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &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 = (stk->is_kme) ? 2 : 1;
+ if (pcmcia_request_io(pdev, &pdev->io) != 0)
+ return -ENODEV;
+ stk->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)
+ return -ENODEV;
+ stk->ctl_base = pdev->io.BasePort1 + 0x0e;
+ } else
+ return -ENODEV;
+ /* If we've got this far, we're done */
+ return 0;
+ }
+ return -ENODEV;
+}
+
+static int ide_config(struct pcmcia_device *link)
+{
+ ide_info_t *info = link->priv;
+ struct pcmcia_config_check *stk = NULL;
+ int last_ret = 0, last_fn = 0, is_kme = 0;
+ unsigned long io_base, ctl_base;
+ struct ide_host *host;
+
+ DEBUG(0, "ide_config(0x%p)\n", link);
+
+ is_kme = ((link->manf_id == MANFID_KME) &&
+ ((link->card_id == PRODID_KME_KXLC005_A) ||
+ (link->card_id == PRODID_KME_KXLC005_B)));
+
+ stk = kzalloc(sizeof(*stk), GFP_KERNEL);
+ if (!stk)
+ goto err_mem;
+ stk->is_kme = is_kme;
+ stk->skip_vcc = io_base = ctl_base = 0;
+
+ if (pcmcia_loop_config(link, pcmcia_check_one_config, stk)) {
+ stk->skip_vcc = 1;
+ if (pcmcia_loop_config(link, pcmcia_check_one_config, stk))
+ goto failed; /* No suitable config found */
+ }
+ io_base = link->io.BasePort1;
+ ctl_base = stk->ctl_base;
+
+ CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq));
+ CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf));
+
+ /* disable drive interrupts during IDE probe */
+ outb(0x02, ctl_base);
+
+ /* special setup for KXLC005 card */
+ if (is_kme)
+ outb(0x81, ctl_base+1);
+
+ host = idecs_register(io_base, ctl_base, link->irq.AssignedIRQ, link);
+ if (host == NULL && link->io.NumPorts1 == 0x20) {
+ outb(0x02, ctl_base + 0x10);
+ host = idecs_register(io_base + 0x10, ctl_base + 0x10,
+ link->irq.AssignedIRQ, link);
+ }
+
+ if (host == NULL)
+ goto failed;
+
+ info->ndev = 1;
+ sprintf(info->node.dev_name, "hd%c", 'a' + host->ports[0]->index * 2);
+ info->node.major = host->ports[0]->major;
+ info->node.minor = 0;
+ info->host = host;
+ link->dev_node = &info->node;
+ printk(KERN_INFO "ide-cs: %s: Vpp = %d.%d\n",
+ info->node.dev_name, link->conf.Vpp / 10, link->conf.Vpp % 10);
+
+ kfree(stk);
+ return 0;
+
+err_mem:
+ printk(KERN_NOTICE "ide-cs: ide_config failed memory allocation\n");
+ goto failed;
+
+cs_failed:
+ cs_error(link, last_fn, last_ret);
+failed:
+ kfree(stk);
+ ide_release(link);
+ return -ENODEV;
+} /* ide_config */
+
+/*======================================================================
+
+ After a card is removed, ide_release() will unregister the net
+ device, and release the PCMCIA configuration. If the device is
+ still open, this will be postponed until it is closed.
+
+======================================================================*/
+
+static void ide_release(struct pcmcia_device *link)
+{
+ ide_info_t *info = link->priv;
+ struct ide_host *host = info->host;
+
+ DEBUG(0, "ide_release(0x%p)\n", link);
+
+ if (info->ndev)
+ /* FIXME: if this fails we need to queue the cleanup somehow
+ -- need to investigate the required PCMCIA magic */
+ ide_host_remove(host);
+
+ info->ndev = 0;
+
+ pcmcia_disable_device(link);
+} /* ide_release */
+
+
+/*======================================================================
+
+ The card status event handler. Mostly, this schedules other
+ stuff to run after an event is received. A CARD_REMOVAL event
+ also sets some flags to discourage the ide drivers from
+ talking to the ports.
+
+======================================================================*/
+
+static struct pcmcia_device_id ide_ids[] = {
+ PCMCIA_DEVICE_FUNC_ID(4),
+ PCMCIA_DEVICE_MANF_CARD(0x0000, 0x0000), /* Corsair */
+ 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(0x0032, 0x2904),
+ PCMCIA_DEVICE_MANF_CARD(0x0045, 0x0401), /* SanDisk CFA */
+ PCMCIA_DEVICE_MANF_CARD(0x004f, 0x0000), /* Kingston */
+ PCMCIA_DEVICE_MANF_CARD(0x0097, 0x1620), /* TI emulated */
+ PCMCIA_DEVICE_MANF_CARD(0x0098, 0x0000), /* Toshiba */
+ PCMCIA_DEVICE_MANF_CARD(0x00a4, 0x002d),
+ 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("Hyperstone", "Model1", 0x3d5b9ef5, 0xca6ab420),
+ PCMCIA_DEVICE_PROD_ID12("IBM", "microdrive", 0xb569a6e5, 0xa6d76178),
+ PCMCIA_DEVICE_PROD_ID12("IBM", "IBM17JSSFP20", 0xb569a6e5, 0xf2508753),
+ PCMCIA_DEVICE_PROD_ID12("KINGSTON", "CF8GB", 0x2e6d1829, 0xacbe682e),
+ PCMCIA_DEVICE_PROD_ID12("IO DATA", "CBIDE2 ", 0x547e66dc, 0x8671043b),
+ PCMCIA_DEVICE_PROD_ID12("IO DATA", "PCIDE", 0x547e66dc, 0x5c5ab149),
+ PCMCIA_DEVICE_PROD_ID12("IO DATA", "PCIDEII", 0x547e66dc, 0xb3662674),
+ PCMCIA_DEVICE_PROD_ID12("LOOKMEET", "CBIDE2 ", 0xe37be2b5, 0x8671043b),
+ PCMCIA_DEVICE_PROD_ID12("M-Systems", "CF300", 0x7ed2ad87, 0x7e9e78ee),
+ PCMCIA_DEVICE_PROD_ID12("M-Systems", "CF500", 0x7ed2ad87, 0x7a13045c),
+ PCMCIA_DEVICE_PROD_ID2("NinjaATA-", 0xebe0bd79),
+ PCMCIA_DEVICE_PROD_ID12("PCMCIA", "CD-ROM", 0x281f1c5d, 0x66536591),
+ 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", "TS1GCF45", 0x709b1bf1, 0xf68b6f32),
+ PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS1GCF80", 0x709b1bf1, 0x2a54d4b1),
+ PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS2GCF120", 0x709b1bf1, 0x969aa4f2),
+ PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS4GCF120", 0x709b1bf1, 0xf54a91c8),
+ PCMCIA_DEVICE_PROD_ID12("WIT", "IDE16", 0x244e5994, 0x3e232852),
+ PCMCIA_DEVICE_PROD_ID12("WEIDA", "TWTTI", 0xcc7cf69c, 0x212bb918),
+ PCMCIA_DEVICE_PROD_ID1("STI Flash", 0xe4a13209),
+ PCMCIA_DEVICE_PROD_ID12("STI", "Flash 5.0", 0xbf2df18d, 0x8cb57a0e),
+ PCMCIA_MFC_DEVICE_PROD_ID12(1, "SanDisk", "ConnectPlus", 0x7a954bd9, 0x74be00c6),
+ PCMCIA_DEVICE_PROD_ID2("Flash Card", 0x5a362506),
+ PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, ide_ids);
+
+static struct pcmcia_driver ide_cs_driver = {
+ .owner = THIS_MODULE,
+ .drv = {
+ .name = "ide-cs",
+ },
+ .probe = ide_probe,
+ .remove = ide_detach,
+ .id_table = ide_ids,
+};
+
+static int __init init_ide_cs(void)
+{
+ return pcmcia_register_driver(&ide_cs_driver);
+}
+
+static void __exit exit_ide_cs(void)
+{
+ pcmcia_unregister_driver(&ide_cs_driver);
+}
+
+late_initcall(init_ide_cs);
+module_exit(exit_ide_cs);
diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c
new file mode 100644
index 0000000..eb9fac4
--- /dev/null
+++ b/drivers/ide/ide-disk.c
@@ -0,0 +1,742 @@
+/*
+ * Copyright (C) 1994-1998 Linus Torvalds & authors (see below)
+ * Copyright (C) 1998-2002 Linux ATA Development
+ * Andre Hedrick <andre@linux-ide.org>
+ * Copyright (C) 2003 Red Hat
+ * Copyright (C) 2003-2005, 2007 Bartlomiej Zolnierkiewicz
+ */
+
+/*
+ * Mostly written by Mark Lord <mlord@pobox.com>
+ * and Gadi Oxman <gadio@netvision.net.il>
+ * and Andre Hedrick <andre@linux-ide.org>
+ *
+ * This is the IDE/ATA disk driver, as evolved from hd.c and ide.c.
+ */
+
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/major.h>
+#include <linux/errno.h>
+#include <linux/genhd.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/leds.h>
+#include <linux/ide.h>
+#include <linux/hdreg.h>
+
+#include <asm/byteorder.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/div64.h>
+
+#include "ide-disk.h"
+
+static const u8 ide_rw_cmds[] = {
+ ATA_CMD_READ_MULTI,
+ ATA_CMD_WRITE_MULTI,
+ ATA_CMD_READ_MULTI_EXT,
+ ATA_CMD_WRITE_MULTI_EXT,
+ ATA_CMD_PIO_READ,
+ ATA_CMD_PIO_WRITE,
+ ATA_CMD_PIO_READ_EXT,
+ ATA_CMD_PIO_WRITE_EXT,
+ ATA_CMD_READ,
+ ATA_CMD_WRITE,
+ ATA_CMD_READ_EXT,
+ ATA_CMD_WRITE_EXT,
+};
+
+static const u8 ide_data_phases[] = {
+ TASKFILE_MULTI_IN,
+ TASKFILE_MULTI_OUT,
+ TASKFILE_IN,
+ TASKFILE_OUT,
+ TASKFILE_IN_DMA,
+ TASKFILE_OUT_DMA,
+};
+
+static void ide_tf_set_cmd(ide_drive_t *drive, ide_task_t *task, u8 dma)
+{
+ u8 index, lba48, write;
+
+ lba48 = (task->tf_flags & IDE_TFLAG_LBA48) ? 2 : 0;
+ write = (task->tf_flags & IDE_TFLAG_WRITE) ? 1 : 0;
+
+ if (dma)
+ index = 8;
+ else
+ index = drive->mult_count ? 0 : 4;
+
+ task->tf.command = ide_rw_cmds[index + lba48 + write];
+
+ if (dma)
+ index = 8; /* fixup index */
+
+ task->data_phase = ide_data_phases[index / 2 + write];
+}
+
+/*
+ * __ide_do_rw_disk() issues READ and WRITE commands to a disk,
+ * using LBA if supported, or CHS otherwise, to address sectors.
+ */
+static ide_startstop_t __ide_do_rw_disk(ide_drive_t *drive, struct request *rq,
+ sector_t block)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ u16 nsectors = (u16)rq->nr_sectors;
+ u8 lba48 = !!(drive->dev_flags & IDE_DFLAG_LBA48);
+ u8 dma = !!(drive->dev_flags & IDE_DFLAG_USING_DMA);
+ ide_task_t task;
+ struct ide_taskfile *tf = &task.tf;
+ ide_startstop_t rc;
+
+ if ((hwif->host_flags & IDE_HFLAG_NO_LBA48_DMA) && lba48 && dma) {
+ if (block + rq->nr_sectors > 1ULL << 28)
+ dma = 0;
+ else
+ lba48 = 0;
+ }
+
+ if (!dma) {
+ ide_init_sg_cmd(drive, rq);
+ ide_map_sg(drive, rq);
+ }
+
+ memset(&task, 0, sizeof(task));
+ task.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
+
+ if (drive->dev_flags & IDE_DFLAG_LBA) {
+ if (lba48) {
+ pr_debug("%s: LBA=0x%012llx\n", drive->name,
+ (unsigned long long)block);
+
+ tf->hob_nsect = (nsectors >> 8) & 0xff;
+ tf->hob_lbal = (u8)(block >> 24);
+ if (sizeof(block) != 4) {
+ tf->hob_lbam = (u8)((u64)block >> 32);
+ tf->hob_lbah = (u8)((u64)block >> 40);
+ }
+
+ tf->nsect = nsectors & 0xff;
+ tf->lbal = (u8) block;
+ tf->lbam = (u8)(block >> 8);
+ tf->lbah = (u8)(block >> 16);
+
+ task.tf_flags |= (IDE_TFLAG_LBA48 | IDE_TFLAG_HOB);
+ } else {
+ tf->nsect = nsectors & 0xff;
+ tf->lbal = block;
+ tf->lbam = block >>= 8;
+ tf->lbah = block >>= 8;
+ tf->device = (block >> 8) & 0xf;
+ }
+
+ tf->device |= ATA_LBA;
+ } else {
+ unsigned int sect, head, cyl, track;
+
+ track = (int)block / drive->sect;
+ sect = (int)block % drive->sect + 1;
+ head = track % drive->head;
+ cyl = track / drive->head;
+
+ pr_debug("%s: CHS=%u/%u/%u\n", drive->name, cyl, head, sect);
+
+ tf->nsect = nsectors & 0xff;
+ tf->lbal = sect;
+ tf->lbam = cyl;
+ tf->lbah = cyl >> 8;
+ tf->device = head;
+ }
+
+ if (rq_data_dir(rq))
+ task.tf_flags |= IDE_TFLAG_WRITE;
+
+ ide_tf_set_cmd(drive, &task, dma);
+ if (!dma)
+ hwif->data_phase = task.data_phase;
+ task.rq = rq;
+
+ rc = do_rw_taskfile(drive, &task);
+
+ if (rc == ide_stopped && dma) {
+ /* fallback to PIO */
+ task.tf_flags |= IDE_TFLAG_DMA_PIO_FALLBACK;
+ ide_tf_set_cmd(drive, &task, 0);
+ hwif->data_phase = task.data_phase;
+ ide_init_sg_cmd(drive, rq);
+ rc = do_rw_taskfile(drive, &task);
+ }
+
+ return rc;
+}
+
+/*
+ * 268435455 == 137439 MB or 28bit limit
+ * 320173056 == 163929 MB or 48bit addressing
+ * 1073741822 == 549756 MB or 48bit addressing fake drive
+ */
+
+static ide_startstop_t ide_do_rw_disk(ide_drive_t *drive, struct request *rq,
+ sector_t block)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+
+ BUG_ON(drive->dev_flags & IDE_DFLAG_BLOCKED);
+
+ if (!blk_fs_request(rq)) {
+ blk_dump_rq_flags(rq, "ide_do_rw_disk - bad command");
+ ide_end_request(drive, 0, 0);
+ return ide_stopped;
+ }
+
+ ledtrig_ide_activity();
+
+ pr_debug("%s: %sing: block=%llu, sectors=%lu, buffer=0x%08lx\n",
+ drive->name, rq_data_dir(rq) == READ ? "read" : "writ",
+ (unsigned long long)block, rq->nr_sectors,
+ (unsigned long)rq->buffer);
+
+ if (hwif->rw_disk)
+ hwif->rw_disk(drive, rq);
+
+ return __ide_do_rw_disk(drive, rq, block);
+}
+
+/*
+ * Queries for true maximum capacity of the drive.
+ * Returns maximum LBA address (> 0) of the drive, 0 if failed.
+ */
+static u64 idedisk_read_native_max_address(ide_drive_t *drive, int lba48)
+{
+ ide_task_t args;
+ struct ide_taskfile *tf = &args.tf;
+ u64 addr = 0;
+
+ /* Create IDE/ATA command request structure */
+ memset(&args, 0, sizeof(ide_task_t));
+ if (lba48)
+ tf->command = ATA_CMD_READ_NATIVE_MAX_EXT;
+ else
+ tf->command = ATA_CMD_READ_NATIVE_MAX;
+ tf->device = ATA_LBA;
+ args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
+ if (lba48)
+ args.tf_flags |= (IDE_TFLAG_LBA48 | IDE_TFLAG_HOB);
+ /* submit command request */
+ ide_no_data_taskfile(drive, &args);
+
+ /* if OK, compute maximum address value */
+ if ((tf->status & 0x01) == 0)
+ addr = ide_get_lba_addr(tf, lba48) + 1;
+
+ return addr;
+}
+
+/*
+ * Sets maximum virtual LBA address of the drive.
+ * Returns new maximum virtual LBA address (> 0) or 0 on failure.
+ */
+static u64 idedisk_set_max_address(ide_drive_t *drive, u64 addr_req, int lba48)
+{
+ ide_task_t args;
+ struct ide_taskfile *tf = &args.tf;
+ u64 addr_set = 0;
+
+ addr_req--;
+ /* Create IDE/ATA command request structure */
+ memset(&args, 0, sizeof(ide_task_t));
+ tf->lbal = (addr_req >> 0) & 0xff;
+ tf->lbam = (addr_req >>= 8) & 0xff;
+ tf->lbah = (addr_req >>= 8) & 0xff;
+ if (lba48) {
+ tf->hob_lbal = (addr_req >>= 8) & 0xff;
+ tf->hob_lbam = (addr_req >>= 8) & 0xff;
+ tf->hob_lbah = (addr_req >>= 8) & 0xff;
+ tf->command = ATA_CMD_SET_MAX_EXT;
+ } else {
+ tf->device = (addr_req >>= 8) & 0x0f;
+ tf->command = ATA_CMD_SET_MAX;
+ }
+ tf->device |= ATA_LBA;
+ args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
+ if (lba48)
+ args.tf_flags |= (IDE_TFLAG_LBA48 | IDE_TFLAG_HOB);
+ /* submit command request */
+ ide_no_data_taskfile(drive, &args);
+ /* if OK, compute maximum address value */
+ if ((tf->status & 0x01) == 0)
+ addr_set = ide_get_lba_addr(tf, lba48) + 1;
+
+ return addr_set;
+}
+
+static unsigned long long sectors_to_MB(unsigned long long n)
+{
+ n <<= 9; /* make it bytes */
+ do_div(n, 1000000); /* make it MB */
+ return n;
+}
+
+/*
+ * Some disks report total number of sectors instead of
+ * maximum sector address. We list them here.
+ */
+static const struct drive_list_entry hpa_list[] = {
+ { "ST340823A", NULL },
+ { "ST320413A", NULL },
+ { "ST310211A", NULL },
+ { NULL, NULL }
+};
+
+static void idedisk_check_hpa(ide_drive_t *drive)
+{
+ unsigned long long capacity, set_max;
+ int lba48 = ata_id_lba48_enabled(drive->id);
+
+ capacity = drive->capacity64;
+
+ set_max = idedisk_read_native_max_address(drive, lba48);
+
+ if (ide_in_drive_list(drive->id, hpa_list)) {
+ /*
+ * Since we are inclusive wrt to firmware revisions do this
+ * extra check and apply the workaround only when needed.
+ */
+ if (set_max == capacity + 1)
+ set_max--;
+ }
+
+ if (set_max <= capacity)
+ return;
+
+ printk(KERN_INFO "%s: Host Protected Area detected.\n"
+ "\tcurrent capacity is %llu sectors (%llu MB)\n"
+ "\tnative capacity is %llu sectors (%llu MB)\n",
+ drive->name,
+ capacity, sectors_to_MB(capacity),
+ set_max, sectors_to_MB(set_max));
+
+ set_max = idedisk_set_max_address(drive, set_max, lba48);
+
+ if (set_max) {
+ drive->capacity64 = set_max;
+ printk(KERN_INFO "%s: Host Protected Area disabled.\n",
+ drive->name);
+ }
+}
+
+static int ide_disk_get_capacity(ide_drive_t *drive)
+{
+ u16 *id = drive->id;
+ int lba;
+
+ if (ata_id_lba48_enabled(id)) {
+ /* drive speaks 48-bit LBA */
+ lba = 1;
+ drive->capacity64 = ata_id_u64(id, ATA_ID_LBA_CAPACITY_2);
+ } else if (ata_id_has_lba(id) && ata_id_is_lba_capacity_ok(id)) {
+ /* drive speaks 28-bit LBA */
+ lba = 1;
+ drive->capacity64 = ata_id_u32(id, ATA_ID_LBA_CAPACITY);
+ } else {
+ /* drive speaks boring old 28-bit CHS */
+ lba = 0;
+ drive->capacity64 = drive->cyl * drive->head * drive->sect;
+ }
+
+ if (lba) {
+ drive->dev_flags |= IDE_DFLAG_LBA;
+
+ /*
+ * If this device supports the Host Protected Area feature set,
+ * then we may need to change our opinion about its capacity.
+ */
+ if (ata_id_hpa_enabled(id))
+ idedisk_check_hpa(drive);
+ }
+
+ /* limit drive capacity to 137GB if LBA48 cannot be used */
+ if ((drive->dev_flags & IDE_DFLAG_LBA48) == 0 &&
+ drive->capacity64 > 1ULL << 28) {
+ printk(KERN_WARNING "%s: cannot use LBA48 - full capacity "
+ "%llu sectors (%llu MB)\n",
+ drive->name, (unsigned long long)drive->capacity64,
+ sectors_to_MB(drive->capacity64));
+ drive->capacity64 = 1ULL << 28;
+ }
+
+ if ((drive->hwif->host_flags & IDE_HFLAG_NO_LBA48_DMA) &&
+ (drive->dev_flags & IDE_DFLAG_LBA48)) {
+ if (drive->capacity64 > 1ULL << 28) {
+ printk(KERN_INFO "%s: cannot use LBA48 DMA - PIO mode"
+ " will be used for accessing sectors "
+ "> %u\n", drive->name, 1 << 28);
+ } else
+ drive->dev_flags &= ~IDE_DFLAG_LBA48;
+ }
+
+ return 0;
+}
+
+static void idedisk_prepare_flush(struct request_queue *q, struct request *rq)
+{
+ ide_drive_t *drive = q->queuedata;
+ ide_task_t *task = kmalloc(sizeof(*task), GFP_ATOMIC);
+
+ /* FIXME: map struct ide_taskfile on rq->cmd[] */
+ BUG_ON(task == NULL);
+
+ memset(task, 0, sizeof(*task));
+ if (ata_id_flush_ext_enabled(drive->id) &&
+ (drive->capacity64 >= (1UL << 28)))
+ task->tf.command = ATA_CMD_FLUSH_EXT;
+ else
+ task->tf.command = ATA_CMD_FLUSH;
+ task->tf_flags = IDE_TFLAG_OUT_TF | IDE_TFLAG_OUT_DEVICE |
+ IDE_TFLAG_DYN;
+ task->data_phase = TASKFILE_NO_DATA;
+
+ rq->cmd_type = REQ_TYPE_ATA_TASKFILE;
+ rq->cmd_flags |= REQ_SOFTBARRIER;
+ rq->special = task;
+}
+
+ide_devset_get(multcount, mult_count);
+
+/*
+ * This is tightly woven into the driver->do_special can not touch.
+ * DON'T do it again until a total personality rewrite is committed.
+ */
+static int set_multcount(ide_drive_t *drive, int arg)
+{
+ struct request *rq;
+ int error;
+
+ if (arg < 0 || arg > (drive->id[ATA_ID_MAX_MULTSECT] & 0xff))
+ return -EINVAL;
+
+ if (drive->special.b.set_multmode)
+ return -EBUSY;
+
+ rq = blk_get_request(drive->queue, READ, __GFP_WAIT);
+ rq->cmd_type = REQ_TYPE_ATA_TASKFILE;
+
+ drive->mult_req = arg;
+ drive->special.b.set_multmode = 1;
+ error = blk_execute_rq(drive->queue, NULL, rq, 0);
+ blk_put_request(rq);
+
+ return (drive->mult_count == arg) ? 0 : -EIO;
+}
+
+ide_devset_get_flag(nowerr, IDE_DFLAG_NOWERR);
+
+static int set_nowerr(ide_drive_t *drive, int arg)
+{
+ if (arg < 0 || arg > 1)
+ return -EINVAL;
+
+ if (arg)
+ drive->dev_flags |= IDE_DFLAG_NOWERR;
+ else
+ drive->dev_flags &= ~IDE_DFLAG_NOWERR;
+
+ drive->bad_wstat = arg ? BAD_R_STAT : BAD_W_STAT;
+
+ return 0;
+}
+
+static int ide_do_setfeature(ide_drive_t *drive, u8 feature, u8 nsect)
+{
+ ide_task_t task;
+
+ memset(&task, 0, sizeof(task));
+ task.tf.feature = feature;
+ task.tf.nsect = nsect;
+ task.tf.command = ATA_CMD_SET_FEATURES;
+ task.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
+
+ return ide_no_data_taskfile(drive, &task);
+}
+
+static void update_ordered(ide_drive_t *drive)
+{
+ u16 *id = drive->id;
+ unsigned ordered = QUEUE_ORDERED_NONE;
+ prepare_flush_fn *prep_fn = NULL;
+
+ if (drive->dev_flags & IDE_DFLAG_WCACHE) {
+ unsigned long long capacity;
+ int barrier;
+ /*
+ * We must avoid issuing commands a drive does not
+ * understand or we may crash it. We check flush cache
+ * is supported. We also check we have the LBA48 flush
+ * cache if the drive capacity is too large. By this
+ * time we have trimmed the drive capacity if LBA48 is
+ * not available so we don't need to recheck that.
+ */
+ capacity = ide_gd_capacity(drive);
+ barrier = ata_id_flush_enabled(id) &&
+ (drive->dev_flags & IDE_DFLAG_NOFLUSH) == 0 &&
+ ((drive->dev_flags & IDE_DFLAG_LBA48) == 0 ||
+ capacity <= (1ULL << 28) ||
+ ata_id_flush_ext_enabled(id));
+
+ printk(KERN_INFO "%s: cache flushes %ssupported\n",
+ drive->name, barrier ? "" : "not ");
+
+ if (barrier) {
+ ordered = QUEUE_ORDERED_DRAIN_FLUSH;
+ prep_fn = idedisk_prepare_flush;
+ }
+ } else
+ ordered = QUEUE_ORDERED_DRAIN;
+
+ blk_queue_ordered(drive->queue, ordered, prep_fn);
+}
+
+ide_devset_get_flag(wcache, IDE_DFLAG_WCACHE);
+
+static int set_wcache(ide_drive_t *drive, int arg)
+{
+ int err = 1;
+
+ if (arg < 0 || arg > 1)
+ return -EINVAL;
+
+ if (ata_id_flush_enabled(drive->id)) {
+ err = ide_do_setfeature(drive,
+ arg ? SETFEATURES_WC_ON : SETFEATURES_WC_OFF, 0);
+ if (err == 0) {
+ if (arg)
+ drive->dev_flags |= IDE_DFLAG_WCACHE;
+ else
+ drive->dev_flags &= ~IDE_DFLAG_WCACHE;
+ }
+ }
+
+ update_ordered(drive);
+
+ return err;
+}
+
+static int do_idedisk_flushcache(ide_drive_t *drive)
+{
+ ide_task_t args;
+
+ memset(&args, 0, sizeof(ide_task_t));
+ if (ata_id_flush_ext_enabled(drive->id))
+ args.tf.command = ATA_CMD_FLUSH_EXT;
+ else
+ args.tf.command = ATA_CMD_FLUSH;
+ args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
+ return ide_no_data_taskfile(drive, &args);
+}
+
+ide_devset_get(acoustic, acoustic);
+
+static int set_acoustic(ide_drive_t *drive, int arg)
+{
+ if (arg < 0 || arg > 254)
+ return -EINVAL;
+
+ ide_do_setfeature(drive,
+ arg ? SETFEATURES_AAM_ON : SETFEATURES_AAM_OFF, arg);
+
+ drive->acoustic = arg;
+
+ return 0;
+}
+
+ide_devset_get_flag(addressing, IDE_DFLAG_LBA48);
+
+/*
+ * drive->addressing:
+ * 0: 28-bit
+ * 1: 48-bit
+ * 2: 48-bit capable doing 28-bit
+ */
+static int set_addressing(ide_drive_t *drive, int arg)
+{
+ if (arg < 0 || arg > 2)
+ return -EINVAL;
+
+ if (arg && ((drive->hwif->host_flags & IDE_HFLAG_NO_LBA48) ||
+ ata_id_lba48_enabled(drive->id) == 0))
+ return -EIO;
+
+ if (arg == 2)
+ arg = 0;
+
+ if (arg)
+ drive->dev_flags |= IDE_DFLAG_LBA48;
+ else
+ drive->dev_flags &= ~IDE_DFLAG_LBA48;
+
+ return 0;
+}
+
+ide_ext_devset_rw(acoustic, acoustic);
+ide_ext_devset_rw(address, addressing);
+ide_ext_devset_rw(multcount, multcount);
+ide_ext_devset_rw(wcache, wcache);
+
+ide_ext_devset_rw_sync(nowerr, nowerr);
+
+static int ide_disk_check(ide_drive_t *drive, const char *s)
+{
+ return 1;
+}
+
+static void ide_disk_setup(ide_drive_t *drive)
+{
+ struct ide_disk_obj *idkp = drive->driver_data;
+ struct request_queue *q = drive->queue;
+ ide_hwif_t *hwif = drive->hwif;
+ u16 *id = drive->id;
+ char *m = (char *)&id[ATA_ID_PROD];
+ unsigned long long capacity;
+
+ ide_proc_register_driver(drive, idkp->driver);
+
+ if ((drive->dev_flags & IDE_DFLAG_ID_READ) == 0)
+ return;
+
+ if (drive->dev_flags & IDE_DFLAG_REMOVABLE) {
+ /*
+ * Removable disks (eg. SYQUEST); ignore 'WD' drives
+ */
+ if (m[0] != 'W' || m[1] != 'D')
+ drive->dev_flags |= IDE_DFLAG_DOORLOCKING;
+ }
+
+ (void)set_addressing(drive, 1);
+
+ if (drive->dev_flags & IDE_DFLAG_LBA48) {
+ int max_s = 2048;
+
+ if (max_s > hwif->rqsize)
+ max_s = hwif->rqsize;
+
+ blk_queue_max_sectors(q, max_s);
+ }
+
+ printk(KERN_INFO "%s: max request size: %dKiB\n", drive->name,
+ q->max_sectors / 2);
+
+ if (ata_id_is_ssd(id) || ata_id_is_cfa(id))
+ queue_flag_set_unlocked(QUEUE_FLAG_NONROT, q);
+
+ /* calculate drive capacity, and select LBA if possible */
+ ide_disk_get_capacity(drive);
+
+ /*
+ * if possible, give fdisk access to more of the drive,
+ * by correcting bios_cyls:
+ */
+ capacity = ide_gd_capacity(drive);
+
+ if ((drive->dev_flags & IDE_DFLAG_FORCED_GEOM) == 0) {
+ if (ata_id_lba48_enabled(drive->id)) {
+ /* compatibility */
+ drive->bios_sect = 63;
+ drive->bios_head = 255;
+ }
+
+ if (drive->bios_sect && drive->bios_head) {
+ unsigned int cap0 = capacity; /* truncate to 32 bits */
+ unsigned int cylsz, cyl;
+
+ if (cap0 != capacity)
+ drive->bios_cyl = 65535;
+ else {
+ cylsz = drive->bios_sect * drive->bios_head;
+ cyl = cap0 / cylsz;
+ if (cyl > 65535)
+ cyl = 65535;
+ if (cyl > drive->bios_cyl)
+ drive->bios_cyl = cyl;
+ }
+ }
+ }
+ printk(KERN_INFO "%s: %llu sectors (%llu MB)",
+ drive->name, capacity, sectors_to_MB(capacity));
+
+ /* Only print cache size when it was specified */
+ if (id[ATA_ID_BUF_SIZE])
+ printk(KERN_CONT " w/%dKiB Cache", id[ATA_ID_BUF_SIZE] / 2);
+
+ printk(KERN_CONT ", CHS=%d/%d/%d\n",
+ drive->bios_cyl, drive->bios_head, drive->bios_sect);
+
+ /* write cache enabled? */
+ if ((id[ATA_ID_CSFO] & 1) || ata_id_wcache_enabled(id))
+ drive->dev_flags |= IDE_DFLAG_WCACHE;
+
+ set_wcache(drive, 1);
+
+ if ((drive->dev_flags & IDE_DFLAG_LBA) == 0 &&
+ (drive->head == 0 || drive->head > 16)) {
+ printk(KERN_ERR "%s: invalid geometry: %d physical heads?\n",
+ drive->name, drive->head);
+ drive->dev_flags &= ~IDE_DFLAG_ATTACH;
+ } else
+ drive->dev_flags |= IDE_DFLAG_ATTACH;
+}
+
+static void ide_disk_flush(ide_drive_t *drive)
+{
+ if (ata_id_flush_enabled(drive->id) == 0 ||
+ (drive->dev_flags & IDE_DFLAG_WCACHE) == 0)
+ return;
+
+ if (do_idedisk_flushcache(drive))
+ printk(KERN_INFO "%s: wcache flush failed!\n", drive->name);
+}
+
+static int ide_disk_init_media(ide_drive_t *drive, struct gendisk *disk)
+{
+ return 0;
+}
+
+static int ide_disk_set_doorlock(ide_drive_t *drive, struct gendisk *disk,
+ int on)
+{
+ ide_task_t task;
+ int ret;
+
+ if ((drive->dev_flags & IDE_DFLAG_DOORLOCKING) == 0)
+ return 0;
+
+ memset(&task, 0, sizeof(task));
+ task.tf.command = on ? ATA_CMD_MEDIA_LOCK : ATA_CMD_MEDIA_UNLOCK;
+ task.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
+
+ ret = ide_no_data_taskfile(drive, &task);
+
+ if (ret)
+ drive->dev_flags &= ~IDE_DFLAG_DOORLOCKING;
+
+ return ret;
+}
+
+const struct ide_disk_ops ide_ata_disk_ops = {
+ .check = ide_disk_check,
+ .get_capacity = ide_disk_get_capacity,
+ .setup = ide_disk_setup,
+ .flush = ide_disk_flush,
+ .init_media = ide_disk_init_media,
+ .set_doorlock = ide_disk_set_doorlock,
+ .do_request = ide_do_rw_disk,
+ .end_request = ide_end_request,
+ .ioctl = ide_disk_ioctl,
+};
diff --git a/drivers/ide/ide-disk.h b/drivers/ide/ide-disk.h
new file mode 100644
index 0000000..d511dab
--- /dev/null
+++ b/drivers/ide/ide-disk.h
@@ -0,0 +1,29 @@
+#ifndef __IDE_DISK_H
+#define __IDE_DISK_H
+
+#include "ide-gd.h"
+
+#ifdef CONFIG_IDE_GD_ATA
+/* ide-disk.c */
+extern const struct ide_disk_ops ide_ata_disk_ops;
+ide_decl_devset(address);
+ide_decl_devset(multcount);
+ide_decl_devset(nowerr);
+ide_decl_devset(wcache);
+ide_decl_devset(acoustic);
+
+/* ide-disk_ioctl.c */
+int ide_disk_ioctl(ide_drive_t *, struct block_device *, fmode_t, unsigned int,
+ unsigned long);
+
+#ifdef CONFIG_IDE_PROC_FS
+/* ide-disk_proc.c */
+extern ide_proc_entry_t ide_disk_proc[];
+extern const struct ide_proc_devset ide_disk_settings[];
+#endif
+#else
+#define ide_disk_proc NULL
+#define ide_disk_settings NULL
+#endif
+
+#endif /* __IDE_DISK_H */
diff --git a/drivers/ide/ide-disk_ioctl.c b/drivers/ide/ide-disk_ioctl.c
new file mode 100644
index 0000000..7b783dd
--- /dev/null
+++ b/drivers/ide/ide-disk_ioctl.c
@@ -0,0 +1,26 @@
+#include <linux/kernel.h>
+#include <linux/ide.h>
+#include <linux/hdreg.h>
+
+#include "ide-disk.h"
+
+static const struct ide_ioctl_devset ide_disk_ioctl_settings[] = {
+{ HDIO_GET_ADDRESS, HDIO_SET_ADDRESS, &ide_devset_address },
+{ HDIO_GET_MULTCOUNT, HDIO_SET_MULTCOUNT, &ide_devset_multcount },
+{ HDIO_GET_NOWERR, HDIO_SET_NOWERR, &ide_devset_nowerr },
+{ HDIO_GET_WCACHE, HDIO_SET_WCACHE, &ide_devset_wcache },
+{ HDIO_GET_ACOUSTIC, HDIO_SET_ACOUSTIC, &ide_devset_acoustic },
+{ 0 }
+};
+
+int ide_disk_ioctl(ide_drive_t *drive, struct block_device *bdev, fmode_t mode,
+ unsigned int cmd, unsigned long arg)
+{
+ int err;
+
+ err = ide_setting_ioctl(drive, bdev, cmd, arg, ide_disk_ioctl_settings);
+ if (err != -EOPNOTSUPP)
+ return err;
+
+ return generic_ide_ioctl(drive, bdev, cmd, arg);
+}
diff --git a/drivers/ide/ide-disk_proc.c b/drivers/ide/ide-disk_proc.c
new file mode 100644
index 0000000..1146f42
--- /dev/null
+++ b/drivers/ide/ide-disk_proc.c
@@ -0,0 +1,129 @@
+#include <linux/kernel.h>
+#include <linux/ide.h>
+#include <linux/hdreg.h>
+
+#include "ide-disk.h"
+
+static int smart_enable(ide_drive_t *drive)
+{
+ ide_task_t args;
+ struct ide_taskfile *tf = &args.tf;
+
+ memset(&args, 0, sizeof(ide_task_t));
+ tf->feature = ATA_SMART_ENABLE;
+ tf->lbam = ATA_SMART_LBAM_PASS;
+ tf->lbah = ATA_SMART_LBAH_PASS;
+ tf->command = ATA_CMD_SMART;
+ args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
+ return ide_no_data_taskfile(drive, &args);
+}
+
+static int get_smart_data(ide_drive_t *drive, u8 *buf, u8 sub_cmd)
+{
+ ide_task_t args;
+ struct ide_taskfile *tf = &args.tf;
+
+ memset(&args, 0, sizeof(ide_task_t));
+ tf->feature = sub_cmd;
+ tf->nsect = 0x01;
+ tf->lbam = ATA_SMART_LBAM_PASS;
+ tf->lbah = ATA_SMART_LBAH_PASS;
+ tf->command = ATA_CMD_SMART;
+ args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
+ args.data_phase = TASKFILE_IN;
+ (void) smart_enable(drive);
+ return ide_raw_taskfile(drive, &args, buf, 1);
+}
+
+static int proc_idedisk_read_cache
+ (char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ ide_drive_t *drive = (ide_drive_t *) data;
+ char *out = page;
+ int len;
+
+ if (drive->dev_flags & IDE_DFLAG_ID_READ)
+ len = sprintf(out, "%i\n", drive->id[ATA_ID_BUF_SIZE] / 2);
+ else
+ len = sprintf(out, "(none)\n");
+
+ PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
+}
+
+static int proc_idedisk_read_capacity
+ (char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ ide_drive_t*drive = (ide_drive_t *)data;
+ int len;
+
+ len = sprintf(page, "%llu\n", (long long)ide_gd_capacity(drive));
+
+ PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
+}
+
+static int proc_idedisk_read_smart(char *page, char **start, off_t off,
+ int count, int *eof, void *data, u8 sub_cmd)
+{
+ ide_drive_t *drive = (ide_drive_t *)data;
+ int len = 0, i = 0;
+
+ if (get_smart_data(drive, page, sub_cmd) == 0) {
+ unsigned short *val = (unsigned short *) page;
+ char *out = (char *)val + SECTOR_SIZE;
+
+ page = out;
+ do {
+ out += sprintf(out, "%04x%c", le16_to_cpu(*val),
+ (++i & 7) ? ' ' : '\n');
+ val += 1;
+ } while (i < SECTOR_SIZE / 2);
+ len = out - page;
+ }
+
+ PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
+}
+
+static int proc_idedisk_read_sv
+ (char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ return proc_idedisk_read_smart(page, start, off, count, eof, data,
+ ATA_SMART_READ_VALUES);
+}
+
+static int proc_idedisk_read_st
+ (char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ return proc_idedisk_read_smart(page, start, off, count, eof, data,
+ ATA_SMART_READ_THRESHOLDS);
+}
+
+ide_proc_entry_t ide_disk_proc[] = {
+ { "cache", S_IFREG|S_IRUGO, proc_idedisk_read_cache, NULL },
+ { "capacity", S_IFREG|S_IRUGO, proc_idedisk_read_capacity, NULL },
+ { "geometry", S_IFREG|S_IRUGO, proc_ide_read_geometry, NULL },
+ { "smart_values", S_IFREG|S_IRUSR, proc_idedisk_read_sv, NULL },
+ { "smart_thresholds", S_IFREG|S_IRUSR, proc_idedisk_read_st, NULL },
+ { NULL, 0, NULL, NULL }
+};
+
+ide_devset_rw_field(bios_cyl, bios_cyl);
+ide_devset_rw_field(bios_head, bios_head);
+ide_devset_rw_field(bios_sect, bios_sect);
+ide_devset_rw_field(failures, failures);
+ide_devset_rw_field(lun, lun);
+ide_devset_rw_field(max_failures, max_failures);
+
+const struct ide_proc_devset ide_disk_settings[] = {
+ IDE_PROC_DEVSET(acoustic, 0, 254),
+ IDE_PROC_DEVSET(address, 0, 2),
+ IDE_PROC_DEVSET(bios_cyl, 0, 65535),
+ IDE_PROC_DEVSET(bios_head, 0, 255),
+ IDE_PROC_DEVSET(bios_sect, 0, 63),
+ IDE_PROC_DEVSET(failures, 0, 65535),
+ IDE_PROC_DEVSET(lun, 0, 7),
+ IDE_PROC_DEVSET(max_failures, 0, 65535),
+ IDE_PROC_DEVSET(multcount, 0, 16),
+ IDE_PROC_DEVSET(nowerr, 0, 1),
+ IDE_PROC_DEVSET(wcache, 0, 1),
+ { 0 },
+};
diff --git a/drivers/ide/ide-dma-sff.c b/drivers/ide/ide-dma-sff.c
new file mode 100644
index 0000000..cac431f
--- /dev/null
+++ b/drivers/ide/ide-dma-sff.c
@@ -0,0 +1,356 @@
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/ide.h>
+#include <linux/scatterlist.h>
+#include <linux/dma-mapping.h>
+#include <linux/io.h>
+
+/**
+ * config_drive_for_dma - attempt to activate IDE DMA
+ * @drive: the drive to place in DMA mode
+ *
+ * If the drive supports at least mode 2 DMA or UDMA of any kind
+ * then attempt to place it into DMA mode. Drives that are known to
+ * support DMA but predate the DMA properties or that are known
+ * to have DMA handling bugs are also set up appropriately based
+ * on the good/bad drive lists.
+ */
+
+int config_drive_for_dma(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ u16 *id = drive->id;
+
+ if (drive->media != ide_disk) {
+ if (hwif->host_flags & IDE_HFLAG_NO_ATAPI_DMA)
+ return 0;
+ }
+
+ /*
+ * Enable DMA on any drive that has
+ * UltraDMA (mode 0/1/2/3/4/5/6) enabled
+ */
+ if ((id[ATA_ID_FIELD_VALID] & 4) &&
+ ((id[ATA_ID_UDMA_MODES] >> 8) & 0x7f))
+ return 1;
+
+ /*
+ * Enable DMA on any drive that has mode2 DMA
+ * (multi or single) enabled
+ */
+ if (id[ATA_ID_FIELD_VALID] & 2) /* regular DMA */
+ if ((id[ATA_ID_MWDMA_MODES] & 0x404) == 0x404 ||
+ (id[ATA_ID_SWDMA_MODES] & 0x404) == 0x404)
+ return 1;
+
+ /* Consult the list of known "good" drives */
+ if (ide_dma_good_drive(drive))
+ return 1;
+
+ return 0;
+}
+
+/**
+ * ide_dma_host_set - Enable/disable DMA on a host
+ * @drive: drive to control
+ *
+ * Enable/disable DMA on an IDE controller following generic
+ * bus-mastering IDE controller behaviour.
+ */
+
+void ide_dma_host_set(ide_drive_t *drive, int on)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ u8 unit = drive->dn & 1;
+ u8 dma_stat = hwif->tp_ops->read_sff_dma_status(hwif);
+
+ if (on)
+ dma_stat |= (1 << (5 + unit));
+ else
+ dma_stat &= ~(1 << (5 + unit));
+
+ if (hwif->host_flags & IDE_HFLAG_MMIO)
+ writeb(dma_stat,
+ (void __iomem *)(hwif->dma_base + ATA_DMA_STATUS));
+ else
+ outb(dma_stat, hwif->dma_base + ATA_DMA_STATUS);
+}
+EXPORT_SYMBOL_GPL(ide_dma_host_set);
+
+/**
+ * ide_build_dmatable - build IDE DMA table
+ *
+ * ide_build_dmatable() prepares a dma request. We map the command
+ * to get the pci bus addresses of the buffers and then build up
+ * the PRD table that the IDE layer wants to be fed.
+ *
+ * Most chipsets correctly interpret a length of 0x0000 as 64KB,
+ * but at least one (e.g. CS5530) misinterprets it as zero (!).
+ * So we break the 64KB entry into two 32KB entries instead.
+ *
+ * Returns the number of built PRD entries if all went okay,
+ * returns 0 otherwise.
+ *
+ * May also be invoked from trm290.c
+ */
+
+int ide_build_dmatable(ide_drive_t *drive, struct request *rq)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ __le32 *table = (__le32 *)hwif->dmatable_cpu;
+ unsigned int is_trm290 = (hwif->chipset == ide_trm290) ? 1 : 0;
+ unsigned int count = 0;
+ int i;
+ struct scatterlist *sg;
+
+ hwif->sg_nents = ide_build_sglist(drive, rq);
+ if (hwif->sg_nents == 0)
+ return 0;
+
+ for_each_sg(hwif->sg_table, sg, hwif->sg_nents, i) {
+ u32 cur_addr, cur_len, xcount, bcount;
+
+ cur_addr = sg_dma_address(sg);
+ cur_len = sg_dma_len(sg);
+
+ /*
+ * Fill in the dma table, without crossing any 64kB boundaries.
+ * Most hardware requires 16-bit alignment of all blocks,
+ * but the trm290 requires 32-bit alignment.
+ */
+
+ while (cur_len) {
+ if (count++ >= PRD_ENTRIES)
+ goto use_pio_instead;
+
+ bcount = 0x10000 - (cur_addr & 0xffff);
+ if (bcount > cur_len)
+ bcount = cur_len;
+ *table++ = cpu_to_le32(cur_addr);
+ xcount = bcount & 0xffff;
+ if (is_trm290)
+ xcount = ((xcount >> 2) - 1) << 16;
+ else if (xcount == 0x0000) {
+ if (count++ >= PRD_ENTRIES)
+ goto use_pio_instead;
+ *table++ = cpu_to_le32(0x8000);
+ *table++ = cpu_to_le32(cur_addr + 0x8000);
+ xcount = 0x8000;
+ }
+ *table++ = cpu_to_le32(xcount);
+ cur_addr += bcount;
+ cur_len -= bcount;
+ }
+ }
+
+ if (count) {
+ if (!is_trm290)
+ *--table |= cpu_to_le32(0x80000000);
+ return count;
+ }
+
+use_pio_instead:
+ printk(KERN_ERR "%s: %s\n", drive->name,
+ count ? "DMA table too small" : "empty DMA table?");
+
+ ide_destroy_dmatable(drive);
+
+ return 0; /* revert to PIO for this request */
+}
+EXPORT_SYMBOL_GPL(ide_build_dmatable);
+
+/**
+ * ide_dma_setup - begin a DMA phase
+ * @drive: target device
+ *
+ * Build an IDE DMA PRD (IDE speak for scatter gather table)
+ * and then set up the DMA transfer registers for a device
+ * that follows generic IDE PCI DMA behaviour. Controllers can
+ * override this function if they need to
+ *
+ * Returns 0 on success. If a PIO fallback is required then 1
+ * is returned.
+ */
+
+int ide_dma_setup(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ struct request *rq = hwif->hwgroup->rq;
+ unsigned int reading;
+ u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0;
+ u8 dma_stat;
+
+ if (rq_data_dir(rq))
+ reading = 0;
+ else
+ reading = 1 << 3;
+
+ /* fall back to pio! */
+ if (!ide_build_dmatable(drive, rq)) {
+ ide_map_sg(drive, rq);
+ return 1;
+ }
+
+ /* PRD table */
+ if (hwif->host_flags & IDE_HFLAG_MMIO)
+ writel(hwif->dmatable_dma,
+ (void __iomem *)(hwif->dma_base + ATA_DMA_TABLE_OFS));
+ else
+ outl(hwif->dmatable_dma, hwif->dma_base + ATA_DMA_TABLE_OFS);
+
+ /* specify r/w */
+ if (mmio)
+ writeb(reading, (void __iomem *)(hwif->dma_base + ATA_DMA_CMD));
+ else
+ outb(reading, hwif->dma_base + ATA_DMA_CMD);
+
+ /* read DMA status for INTR & ERROR flags */
+ dma_stat = hwif->tp_ops->read_sff_dma_status(hwif);
+
+ /* clear INTR & ERROR flags */
+ if (mmio)
+ writeb(dma_stat | 6,
+ (void __iomem *)(hwif->dma_base + ATA_DMA_STATUS));
+ else
+ outb(dma_stat | 6, hwif->dma_base + ATA_DMA_STATUS);
+
+ drive->waiting_for_dma = 1;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ide_dma_setup);
+
+/**
+ * dma_timer_expiry - handle a DMA timeout
+ * @drive: Drive that timed out
+ *
+ * An IDE DMA transfer timed out. In the event of an error we ask
+ * the driver to resolve the problem, if a DMA transfer is still
+ * in progress we continue to wait (arguably we need to add a
+ * secondary 'I don't care what the drive thinks' timeout here)
+ * Finally if we have an interrupt we let it complete the I/O.
+ * But only one time - we clear expiry and if it's still not
+ * completed after WAIT_CMD, we error and retry in PIO.
+ * This can occur if an interrupt is lost or due to hang or bugs.
+ */
+
+static int dma_timer_expiry(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ u8 dma_stat = hwif->tp_ops->read_sff_dma_status(hwif);
+
+ printk(KERN_WARNING "%s: %s: DMA status (0x%02x)\n",
+ drive->name, __func__, dma_stat);
+
+ if ((dma_stat & 0x18) == 0x18) /* BUSY Stupid Early Timer !! */
+ return WAIT_CMD;
+
+ hwif->hwgroup->expiry = NULL; /* one free ride for now */
+
+ /* 1 dmaing, 2 error, 4 intr */
+ if (dma_stat & 2) /* ERROR */
+ return -1;
+
+ if (dma_stat & 1) /* DMAing */
+ return WAIT_CMD;
+
+ if (dma_stat & 4) /* Got an Interrupt */
+ return WAIT_CMD;
+
+ return 0; /* Status is unknown -- reset the bus */
+}
+
+void ide_dma_exec_cmd(ide_drive_t *drive, u8 command)
+{
+ /* issue cmd to drive */
+ ide_execute_command(drive, command, &ide_dma_intr, 2 * WAIT_CMD,
+ dma_timer_expiry);
+}
+EXPORT_SYMBOL_GPL(ide_dma_exec_cmd);
+
+void ide_dma_start(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ u8 dma_cmd;
+
+ /* Note that this is done *after* the cmd has
+ * been issued to the drive, as per the BM-IDE spec.
+ * The Promise Ultra33 doesn't work correctly when
+ * we do this part before issuing the drive cmd.
+ */
+ if (hwif->host_flags & IDE_HFLAG_MMIO) {
+ dma_cmd = readb((void __iomem *)(hwif->dma_base + ATA_DMA_CMD));
+ /* start DMA */
+ writeb(dma_cmd | 1,
+ (void __iomem *)(hwif->dma_base + ATA_DMA_CMD));
+ } else {
+ dma_cmd = inb(hwif->dma_base + ATA_DMA_CMD);
+ outb(dma_cmd | 1, hwif->dma_base + ATA_DMA_CMD);
+ }
+
+ wmb();
+}
+EXPORT_SYMBOL_GPL(ide_dma_start);
+
+/* returns 1 on error, 0 otherwise */
+int ide_dma_end(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0;
+ u8 dma_stat = 0, dma_cmd = 0;
+
+ drive->waiting_for_dma = 0;
+
+ if (mmio) {
+ /* get DMA command mode */
+ dma_cmd = readb((void __iomem *)(hwif->dma_base + ATA_DMA_CMD));
+ /* stop DMA */
+ writeb(dma_cmd & ~1,
+ (void __iomem *)(hwif->dma_base + ATA_DMA_CMD));
+ } else {
+ dma_cmd = inb(hwif->dma_base + ATA_DMA_CMD);
+ outb(dma_cmd & ~1, hwif->dma_base + ATA_DMA_CMD);
+ }
+
+ /* get DMA status */
+ dma_stat = hwif->tp_ops->read_sff_dma_status(hwif);
+
+ if (mmio)
+ /* clear the INTR & ERROR bits */
+ writeb(dma_stat | 6,
+ (void __iomem *)(hwif->dma_base + ATA_DMA_STATUS));
+ else
+ outb(dma_stat | 6, hwif->dma_base + ATA_DMA_STATUS);
+
+ /* purge DMA mappings */
+ ide_destroy_dmatable(drive);
+ /* verify good DMA status */
+ wmb();
+ return (dma_stat & 7) != 4 ? (0x10 | dma_stat) : 0;
+}
+EXPORT_SYMBOL_GPL(ide_dma_end);
+
+/* returns 1 if dma irq issued, 0 otherwise */
+int ide_dma_test_irq(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ u8 dma_stat = hwif->tp_ops->read_sff_dma_status(hwif);
+
+ /* return 1 if INTR asserted */
+ if ((dma_stat & 4) == 4)
+ return 1;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ide_dma_test_irq);
+
+const struct ide_dma_ops sff_dma_ops = {
+ .dma_host_set = ide_dma_host_set,
+ .dma_setup = ide_dma_setup,
+ .dma_exec_cmd = ide_dma_exec_cmd,
+ .dma_start = ide_dma_start,
+ .dma_end = ide_dma_end,
+ .dma_test_irq = ide_dma_test_irq,
+ .dma_timeout = ide_dma_timeout,
+ .dma_lost_irq = ide_dma_lost_irq,
+};
+EXPORT_SYMBOL_GPL(sff_dma_ops);
diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c
new file mode 100644
index 0000000..fffd117
--- /dev/null
+++ b/drivers/ide/ide-dma.c
@@ -0,0 +1,501 @@
+/*
+ * IDE DMA support (including IDE PCI BM-DMA).
+ *
+ * Copyright (C) 1995-1998 Mark Lord
+ * Copyright (C) 1999-2000 Andre Hedrick <andre@linux-ide.org>
+ * Copyright (C) 2004, 2007 Bartlomiej Zolnierkiewicz
+ *
+ * May be copied or modified under the terms of the GNU General Public License
+ *
+ * DMA is supported for all IDE devices (disk drives, cdroms, tapes, floppies).
+ */
+
+/*
+ * Special Thanks to Mark for his Six years of work.
+ */
+
+/*
+ * Thanks to "Christopher J. Reimer" <reimer@doe.carleton.ca> for
+ * fixing the problem with the BIOS on some Acer motherboards.
+ *
+ * Thanks to "Benoit Poulot-Cazajous" <poulot@chorus.fr> for testing
+ * "TX" chipset compatibility and for providing patches for the "TX" chipset.
+ *
+ * Thanks to Christian Brunner <chb@muc.de> for taking a good first crack
+ * at generic DMA -- his patches were referred to when preparing this code.
+ *
+ * Most importantly, thanks to Robert Bringman <rob@mars.trion.com>
+ * for supplying a Promise UDMA board & WD UDMA drive for this work!
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/ide.h>
+#include <linux/scatterlist.h>
+#include <linux/dma-mapping.h>
+
+static const struct drive_list_entry drive_whitelist[] = {
+ { "Micropolis 2112A" , NULL },
+ { "CONNER CTMA 4000" , NULL },
+ { "CONNER CTT8000-A" , NULL },
+ { "ST34342A" , NULL },
+ { NULL , NULL }
+};
+
+static const struct drive_list_entry drive_blacklist[] = {
+ { "WDC AC11000H" , NULL },
+ { "WDC AC22100H" , NULL },
+ { "WDC AC32500H" , NULL },
+ { "WDC AC33100H" , NULL },
+ { "WDC AC31600H" , NULL },
+ { "WDC AC32100H" , "24.09P07" },
+ { "WDC AC23200L" , "21.10N21" },
+ { "Compaq CRD-8241B" , NULL },
+ { "CRD-8400B" , NULL },
+ { "CRD-8480B", NULL },
+ { "CRD-8482B", NULL },
+ { "CRD-84" , NULL },
+ { "SanDisk SDP3B" , NULL },
+ { "SanDisk SDP3B-64" , NULL },
+ { "SANYO CD-ROM CRD" , NULL },
+ { "HITACHI CDR-8" , NULL },
+ { "HITACHI CDR-8335" , NULL },
+ { "HITACHI CDR-8435" , NULL },
+ { "Toshiba CD-ROM XM-6202B" , NULL },
+ { "TOSHIBA CD-ROM XM-1702BC", NULL },
+ { "CD-532E-A" , NULL },
+ { "E-IDE CD-ROM CR-840", NULL },
+ { "CD-ROM Drive/F5A", NULL },
+ { "WPI CDD-820", NULL },
+ { "SAMSUNG CD-ROM SC-148C", NULL },
+ { "SAMSUNG CD-ROM SC", NULL },
+ { "ATAPI CD-ROM DRIVE 40X MAXIMUM", NULL },
+ { "_NEC DV5800A", NULL },
+ { "SAMSUNG CD-ROM SN-124", "N001" },
+ { "Seagate STT20000A", NULL },
+ { "CD-ROM CDR_U200", "1.09" },
+ { NULL , NULL }
+
+};
+
+/**
+ * ide_dma_intr - IDE DMA interrupt handler
+ * @drive: the drive the interrupt is for
+ *
+ * Handle an interrupt completing a read/write DMA transfer on an
+ * IDE device
+ */
+
+ide_startstop_t ide_dma_intr(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ u8 stat = 0, dma_stat = 0;
+
+ dma_stat = hwif->dma_ops->dma_end(drive);
+ stat = hwif->tp_ops->read_status(hwif);
+
+ if (OK_STAT(stat, DRIVE_READY, drive->bad_wstat | ATA_DRQ)) {
+ if (!dma_stat) {
+ struct request *rq = hwif->hwgroup->rq;
+
+ task_end_request(drive, rq, stat);
+ return ide_stopped;
+ }
+ printk(KERN_ERR "%s: %s: bad DMA status (0x%02x)\n",
+ drive->name, __func__, dma_stat);
+ }
+ return ide_error(drive, "dma_intr", stat);
+}
+EXPORT_SYMBOL_GPL(ide_dma_intr);
+
+int ide_dma_good_drive(ide_drive_t *drive)
+{
+ return ide_in_drive_list(drive->id, drive_whitelist);
+}
+
+/**
+ * ide_build_sglist - map IDE scatter gather for DMA I/O
+ * @drive: the drive to build the DMA table for
+ * @rq: the request holding the sg list
+ *
+ * Perform the DMA mapping magic necessary to access the source or
+ * target buffers of a request via DMA. The lower layers of the
+ * kernel provide the necessary cache management so that we can
+ * operate in a portable fashion.
+ */
+
+int ide_build_sglist(ide_drive_t *drive, struct request *rq)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ struct scatterlist *sg = hwif->sg_table;
+
+ ide_map_sg(drive, rq);
+
+ if (rq_data_dir(rq) == READ)
+ hwif->sg_dma_direction = DMA_FROM_DEVICE;
+ else
+ hwif->sg_dma_direction = DMA_TO_DEVICE;
+
+ return dma_map_sg(hwif->dev, sg, hwif->sg_nents,
+ hwif->sg_dma_direction);
+}
+EXPORT_SYMBOL_GPL(ide_build_sglist);
+
+/**
+ * ide_destroy_dmatable - clean up DMA mapping
+ * @drive: The drive to unmap
+ *
+ * Teardown mappings after DMA has completed. This must be called
+ * after the completion of each use of ide_build_dmatable and before
+ * the next use of ide_build_dmatable. Failure to do so will cause
+ * an oops as only one mapping can be live for each target at a given
+ * time.
+ */
+
+void ide_destroy_dmatable(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = drive->hwif;
+
+ dma_unmap_sg(hwif->dev, hwif->sg_table, hwif->sg_nents,
+ hwif->sg_dma_direction);
+}
+EXPORT_SYMBOL_GPL(ide_destroy_dmatable);
+
+/**
+ * ide_dma_off_quietly - Generic DMA kill
+ * @drive: drive to control
+ *
+ * Turn off the current DMA on this IDE controller.
+ */
+
+void ide_dma_off_quietly(ide_drive_t *drive)
+{
+ drive->dev_flags &= ~IDE_DFLAG_USING_DMA;
+ ide_toggle_bounce(drive, 0);
+
+ drive->hwif->dma_ops->dma_host_set(drive, 0);
+}
+EXPORT_SYMBOL(ide_dma_off_quietly);
+
+/**
+ * ide_dma_off - disable DMA on a device
+ * @drive: drive to disable DMA on
+ *
+ * Disable IDE DMA for a device on this IDE controller.
+ * Inform the user that DMA has been disabled.
+ */
+
+void ide_dma_off(ide_drive_t *drive)
+{
+ printk(KERN_INFO "%s: DMA disabled\n", drive->name);
+ ide_dma_off_quietly(drive);
+}
+EXPORT_SYMBOL(ide_dma_off);
+
+/**
+ * ide_dma_on - Enable DMA on a device
+ * @drive: drive to enable DMA on
+ *
+ * Enable IDE DMA for a device on this IDE controller.
+ */
+
+void ide_dma_on(ide_drive_t *drive)
+{
+ drive->dev_flags |= IDE_DFLAG_USING_DMA;
+ ide_toggle_bounce(drive, 1);
+
+ drive->hwif->dma_ops->dma_host_set(drive, 1);
+}
+
+int __ide_dma_bad_drive(ide_drive_t *drive)
+{
+ u16 *id = drive->id;
+
+ int blacklist = ide_in_drive_list(id, drive_blacklist);
+ if (blacklist) {
+ printk(KERN_WARNING "%s: Disabling (U)DMA for %s (blacklisted)\n",
+ drive->name, (char *)&id[ATA_ID_PROD]);
+ return blacklist;
+ }
+ return 0;
+}
+EXPORT_SYMBOL(__ide_dma_bad_drive);
+
+static const u8 xfer_mode_bases[] = {
+ XFER_UDMA_0,
+ XFER_MW_DMA_0,
+ XFER_SW_DMA_0,
+};
+
+static unsigned int ide_get_mode_mask(ide_drive_t *drive, u8 base, u8 req_mode)
+{
+ u16 *id = drive->id;
+ ide_hwif_t *hwif = drive->hwif;
+ const struct ide_port_ops *port_ops = hwif->port_ops;
+ unsigned int mask = 0;
+
+ switch (base) {
+ case XFER_UDMA_0:
+ if ((id[ATA_ID_FIELD_VALID] & 4) == 0)
+ break;
+
+ if (port_ops && port_ops->udma_filter)
+ mask = port_ops->udma_filter(drive);
+ else
+ mask = hwif->ultra_mask;
+ mask &= id[ATA_ID_UDMA_MODES];
+
+ /*
+ * avoid false cable warning from eighty_ninty_three()
+ */
+ if (req_mode > XFER_UDMA_2) {
+ if ((mask & 0x78) && (eighty_ninty_three(drive) == 0))
+ mask &= 0x07;
+ }
+ break;
+ case XFER_MW_DMA_0:
+ if ((id[ATA_ID_FIELD_VALID] & 2) == 0)
+ break;
+ if (port_ops && port_ops->mdma_filter)
+ mask = port_ops->mdma_filter(drive);
+ else
+ mask = hwif->mwdma_mask;
+ mask &= id[ATA_ID_MWDMA_MODES];
+ break;
+ case XFER_SW_DMA_0:
+ if (id[ATA_ID_FIELD_VALID] & 2) {
+ mask = id[ATA_ID_SWDMA_MODES] & hwif->swdma_mask;
+ } else if (id[ATA_ID_OLD_DMA_MODES] >> 8) {
+ u8 mode = id[ATA_ID_OLD_DMA_MODES] >> 8;
+
+ /*
+ * if the mode is valid convert it to the mask
+ * (the maximum allowed mode is XFER_SW_DMA_2)
+ */
+ if (mode <= 2)
+ mask = ((2 << mode) - 1) & hwif->swdma_mask;
+ }
+ break;
+ default:
+ BUG();
+ break;
+ }
+
+ return mask;
+}
+
+/**
+ * ide_find_dma_mode - compute DMA speed
+ * @drive: IDE device
+ * @req_mode: requested mode
+ *
+ * Checks the drive/host capabilities and finds the speed to use for
+ * the DMA transfer. The speed is then limited by the requested mode.
+ *
+ * Returns 0 if the drive/host combination is incapable of DMA transfers
+ * or if the requested mode is not a DMA mode.
+ */
+
+u8 ide_find_dma_mode(ide_drive_t *drive, u8 req_mode)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ unsigned int mask;
+ int x, i;
+ u8 mode = 0;
+
+ if (drive->media != ide_disk) {
+ if (hwif->host_flags & IDE_HFLAG_NO_ATAPI_DMA)
+ return 0;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(xfer_mode_bases); i++) {
+ if (req_mode < xfer_mode_bases[i])
+ continue;
+ mask = ide_get_mode_mask(drive, xfer_mode_bases[i], req_mode);
+ x = fls(mask) - 1;
+ if (x >= 0) {
+ mode = xfer_mode_bases[i] + x;
+ break;
+ }
+ }
+
+ if (hwif->chipset == ide_acorn && mode == 0) {
+ /*
+ * is this correct?
+ */
+ if (ide_dma_good_drive(drive) &&
+ drive->id[ATA_ID_EIDE_DMA_TIME] < 150)
+ mode = XFER_MW_DMA_1;
+ }
+
+ mode = min(mode, req_mode);
+
+ printk(KERN_INFO "%s: %s mode selected\n", drive->name,
+ mode ? ide_xfer_verbose(mode) : "no DMA");
+
+ return mode;
+}
+EXPORT_SYMBOL_GPL(ide_find_dma_mode);
+
+static int ide_tune_dma(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ u8 speed;
+
+ if (ata_id_has_dma(drive->id) == 0 ||
+ (drive->dev_flags & IDE_DFLAG_NODMA))
+ return 0;
+
+ /* consult the list of known "bad" drives */
+ if (__ide_dma_bad_drive(drive))
+ return 0;
+
+ if (ide_id_dma_bug(drive))
+ return 0;
+
+ if (hwif->host_flags & IDE_HFLAG_TRUST_BIOS_FOR_DMA)
+ return config_drive_for_dma(drive);
+
+ speed = ide_max_dma_mode(drive);
+
+ if (!speed)
+ return 0;
+
+ if (ide_set_dma_mode(drive, speed))
+ return 0;
+
+ return 1;
+}
+
+static int ide_dma_check(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = drive->hwif;
+
+ if (ide_tune_dma(drive))
+ return 0;
+
+ /* TODO: always do PIO fallback */
+ if (hwif->host_flags & IDE_HFLAG_TRUST_BIOS_FOR_DMA)
+ return -1;
+
+ ide_set_max_pio(drive);
+
+ return -1;
+}
+
+int ide_id_dma_bug(ide_drive_t *drive)
+{
+ u16 *id = drive->id;
+
+ if (id[ATA_ID_FIELD_VALID] & 4) {
+ if ((id[ATA_ID_UDMA_MODES] >> 8) &&
+ (id[ATA_ID_MWDMA_MODES] >> 8))
+ goto err_out;
+ } else if (id[ATA_ID_FIELD_VALID] & 2) {
+ if ((id[ATA_ID_MWDMA_MODES] >> 8) &&
+ (id[ATA_ID_SWDMA_MODES] >> 8))
+ goto err_out;
+ }
+ return 0;
+err_out:
+ printk(KERN_ERR "%s: bad DMA info in identify block\n", drive->name);
+ return 1;
+}
+
+int ide_set_dma(ide_drive_t *drive)
+{
+ int rc;
+
+ /*
+ * Force DMAing for the beginning of the check.
+ * Some chipsets appear to do interesting
+ * things, if not checked and cleared.
+ * PARANOIA!!!
+ */
+ ide_dma_off_quietly(drive);
+
+ rc = ide_dma_check(drive);
+ if (rc)
+ return rc;
+
+ ide_dma_on(drive);
+
+ return 0;
+}
+
+void ide_check_dma_crc(ide_drive_t *drive)
+{
+ u8 mode;
+
+ ide_dma_off_quietly(drive);
+ drive->crc_count = 0;
+ mode = drive->current_speed;
+ /*
+ * Don't try non Ultra-DMA modes without iCRC's. Force the
+ * device to PIO and make the user enable SWDMA/MWDMA modes.
+ */
+ if (mode > XFER_UDMA_0 && mode <= XFER_UDMA_7)
+ mode--;
+ else
+ mode = XFER_PIO_4;
+ ide_set_xfer_rate(drive, mode);
+ if (drive->current_speed >= XFER_SW_DMA_0)
+ ide_dma_on(drive);
+}
+
+void ide_dma_lost_irq(ide_drive_t *drive)
+{
+ printk(KERN_ERR "%s: DMA interrupt recovery\n", drive->name);
+}
+EXPORT_SYMBOL_GPL(ide_dma_lost_irq);
+
+void ide_dma_timeout(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = drive->hwif;
+
+ printk(KERN_ERR "%s: timeout waiting for DMA\n", drive->name);
+
+ if (hwif->dma_ops->dma_test_irq(drive))
+ return;
+
+ ide_dump_status(drive, "DMA timeout", hwif->tp_ops->read_status(hwif));
+
+ hwif->dma_ops->dma_end(drive);
+}
+EXPORT_SYMBOL_GPL(ide_dma_timeout);
+
+void ide_release_dma_engine(ide_hwif_t *hwif)
+{
+ if (hwif->dmatable_cpu) {
+ int prd_size = hwif->prd_max_nents * hwif->prd_ent_size;
+
+ dma_free_coherent(hwif->dev, prd_size,
+ hwif->dmatable_cpu, hwif->dmatable_dma);
+ hwif->dmatable_cpu = NULL;
+ }
+}
+EXPORT_SYMBOL_GPL(ide_release_dma_engine);
+
+int ide_allocate_dma_engine(ide_hwif_t *hwif)
+{
+ int prd_size;
+
+ if (hwif->prd_max_nents == 0)
+ hwif->prd_max_nents = PRD_ENTRIES;
+ if (hwif->prd_ent_size == 0)
+ hwif->prd_ent_size = PRD_BYTES;
+
+ prd_size = hwif->prd_max_nents * hwif->prd_ent_size;
+
+ hwif->dmatable_cpu = dma_alloc_coherent(hwif->dev, prd_size,
+ &hwif->dmatable_dma,
+ GFP_ATOMIC);
+ if (hwif->dmatable_cpu == NULL) {
+ printk(KERN_ERR "%s: unable to allocate PRD table\n",
+ hwif->name);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ide_allocate_dma_engine);
diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c
new file mode 100644
index 0000000..aeb1ad7
--- /dev/null
+++ b/drivers/ide/ide-floppy.c
@@ -0,0 +1,578 @@
+/*
+ * IDE ATAPI floppy driver.
+ *
+ * Copyright (C) 1996-1999 Gadi Oxman <gadio@netvision.net.il>
+ * Copyright (C) 2000-2002 Paul Bristow <paul@paulbristow.net>
+ * Copyright (C) 2005 Bartlomiej Zolnierkiewicz
+ *
+ * This driver supports the following IDE floppy drives:
+ *
+ * LS-120/240 SuperDisk
+ * Iomega Zip 100/250
+ * Iomega PC Card Clik!/PocketZip
+ *
+ * For a historical changelog see
+ * Documentation/ide/ChangeLog.ide-floppy.1996-2002
+ */
+
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/major.h>
+#include <linux/errno.h>
+#include <linux/genhd.h>
+#include <linux/slab.h>
+#include <linux/cdrom.h>
+#include <linux/ide.h>
+#include <linux/hdreg.h>
+#include <linux/bitops.h>
+#include <linux/mutex.h>
+#include <linux/scatterlist.h>
+
+#include <scsi/scsi_ioctl.h>
+
+#include <asm/byteorder.h>
+#include <linux/irq.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+#include <asm/unaligned.h>
+
+#include "ide-floppy.h"
+
+/*
+ * After each failed packet command we issue a request sense command and retry
+ * the packet command IDEFLOPPY_MAX_PC_RETRIES times.
+ */
+#define IDEFLOPPY_MAX_PC_RETRIES 3
+
+/* format capacities descriptor codes */
+#define CAPACITY_INVALID 0x00
+#define CAPACITY_UNFORMATTED 0x01
+#define CAPACITY_CURRENT 0x02
+#define CAPACITY_NO_CARTRIDGE 0x03
+
+/*
+ * The following delay solves a problem with ATAPI Zip 100 drive where BSY bit
+ * was apparently being deasserted before the unit was ready to receive data.
+ */
+#define IDEFLOPPY_PC_DELAY (HZ/20) /* default delay for ZIP 100 (50ms) */
+
+/* Error code returned in rq->errors to the higher part of the driver. */
+#define IDEFLOPPY_ERROR_GENERAL 101
+
+/*
+ * Used to finish servicing a request. For read/write requests, we will call
+ * ide_end_request to pass to the next buffer.
+ */
+static int ide_floppy_end_request(ide_drive_t *drive, int uptodate, int nsecs)
+{
+ struct ide_disk_obj *floppy = drive->driver_data;
+ struct request *rq = HWGROUP(drive)->rq;
+ int error;
+
+ ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__);
+
+ switch (uptodate) {
+ case 0:
+ error = IDEFLOPPY_ERROR_GENERAL;
+ break;
+
+ case 1:
+ error = 0;
+ break;
+
+ default:
+ error = uptodate;
+ }
+
+ if (error)
+ floppy->failed_pc = NULL;
+ /* Why does this happen? */
+ if (!rq)
+ return 0;
+ if (!blk_special_request(rq)) {
+ /* our real local end request function */
+ ide_end_request(drive, uptodate, nsecs);
+ return 0;
+ }
+ rq->errors = error;
+ /* fixme: need to move this local also */
+ ide_end_drive_cmd(drive, 0, 0);
+ return 0;
+}
+
+static void idefloppy_update_buffers(ide_drive_t *drive,
+ struct ide_atapi_pc *pc)
+{
+ struct request *rq = pc->rq;
+ struct bio *bio = rq->bio;
+
+ while ((bio = rq->bio) != NULL)
+ ide_floppy_end_request(drive, 1, 0);
+}
+
+static void ide_floppy_callback(ide_drive_t *drive, int dsc)
+{
+ struct ide_disk_obj *floppy = drive->driver_data;
+ struct ide_atapi_pc *pc = drive->pc;
+ int uptodate = pc->error ? 0 : 1;
+
+ ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__);
+
+ if (floppy->failed_pc == pc)
+ floppy->failed_pc = NULL;
+
+ if (pc->c[0] == GPCMD_READ_10 || pc->c[0] == GPCMD_WRITE_10 ||
+ (pc->rq && blk_pc_request(pc->rq)))
+ uptodate = 1; /* FIXME */
+ else if (pc->c[0] == GPCMD_REQUEST_SENSE) {
+ u8 *buf = pc->buf;
+
+ if (!pc->error) {
+ floppy->sense_key = buf[2] & 0x0F;
+ floppy->asc = buf[12];
+ floppy->ascq = buf[13];
+ floppy->progress_indication = buf[15] & 0x80 ?
+ (u16)get_unaligned((u16 *)&buf[16]) : 0x10000;
+
+ if (floppy->failed_pc)
+ ide_debug_log(IDE_DBG_PC, "pc = %x, ",
+ floppy->failed_pc->c[0]);
+
+ ide_debug_log(IDE_DBG_SENSE, "sense key = %x, asc = %x,"
+ "ascq = %x\n", floppy->sense_key,
+ floppy->asc, floppy->ascq);
+ } else
+ printk(KERN_ERR PFX "Error in REQUEST SENSE itself - "
+ "Aborting request!\n");
+ }
+
+ ide_floppy_end_request(drive, uptodate, 0);
+}
+
+static void ide_floppy_report_error(struct ide_disk_obj *floppy,
+ struct ide_atapi_pc *pc)
+{
+ /* supress error messages resulting from Medium not present */
+ if (floppy->sense_key == 0x02 &&
+ floppy->asc == 0x3a &&
+ floppy->ascq == 0x00)
+ return;
+
+ printk(KERN_ERR PFX "%s: I/O error, pc = %2x, key = %2x, "
+ "asc = %2x, ascq = %2x\n",
+ floppy->drive->name, pc->c[0], floppy->sense_key,
+ floppy->asc, floppy->ascq);
+
+}
+
+static ide_startstop_t idefloppy_issue_pc(ide_drive_t *drive,
+ struct ide_atapi_pc *pc)
+{
+ struct ide_disk_obj *floppy = drive->driver_data;
+
+ if (floppy->failed_pc == NULL &&
+ pc->c[0] != GPCMD_REQUEST_SENSE)
+ floppy->failed_pc = pc;
+
+ /* Set the current packet command */
+ drive->pc = pc;
+
+ if (pc->retries > IDEFLOPPY_MAX_PC_RETRIES) {
+ if (!(pc->flags & PC_FLAG_SUPPRESS_ERROR))
+ ide_floppy_report_error(floppy, pc);
+ /* Giving up */
+ pc->error = IDEFLOPPY_ERROR_GENERAL;
+
+ floppy->failed_pc = NULL;
+ drive->pc_callback(drive, 0);
+ return ide_stopped;
+ }
+
+ ide_debug_log(IDE_DBG_FUNC, "%s: Retry #%d\n", __func__, pc->retries);
+
+ pc->retries++;
+
+ return ide_issue_pc(drive, WAIT_FLOPPY_CMD, NULL);
+}
+
+void ide_floppy_create_read_capacity_cmd(struct ide_atapi_pc *pc)
+{
+ ide_init_pc(pc);
+ pc->c[0] = GPCMD_READ_FORMAT_CAPACITIES;
+ pc->c[7] = 255;
+ pc->c[8] = 255;
+ pc->req_xfer = 255;
+}
+
+/* A mode sense command is used to "sense" floppy parameters. */
+void ide_floppy_create_mode_sense_cmd(struct ide_atapi_pc *pc, u8 page_code)
+{
+ u16 length = 8; /* sizeof(Mode Parameter Header) = 8 Bytes */
+
+ ide_init_pc(pc);
+ pc->c[0] = GPCMD_MODE_SENSE_10;
+ pc->c[1] = 0;
+ pc->c[2] = page_code;
+
+ switch (page_code) {
+ case IDEFLOPPY_CAPABILITIES_PAGE:
+ length += 12;
+ break;
+ case IDEFLOPPY_FLEXIBLE_DISK_PAGE:
+ length += 32;
+ break;
+ default:
+ printk(KERN_ERR PFX "unsupported page code in %s\n", __func__);
+ }
+ put_unaligned(cpu_to_be16(length), (u16 *) &pc->c[7]);
+ pc->req_xfer = length;
+}
+
+static void idefloppy_create_rw_cmd(ide_drive_t *drive,
+ struct ide_atapi_pc *pc, struct request *rq,
+ unsigned long sector)
+{
+ struct ide_disk_obj *floppy = drive->driver_data;
+ int block = sector / floppy->bs_factor;
+ int blocks = rq->nr_sectors / floppy->bs_factor;
+ int cmd = rq_data_dir(rq);
+
+ ide_debug_log(IDE_DBG_FUNC, "%s: block: %d, blocks: %d\n", __func__,
+ block, blocks);
+
+ ide_init_pc(pc);
+ pc->c[0] = cmd == READ ? GPCMD_READ_10 : GPCMD_WRITE_10;
+ put_unaligned(cpu_to_be16(blocks), (unsigned short *)&pc->c[7]);
+ put_unaligned(cpu_to_be32(block), (unsigned int *) &pc->c[2]);
+
+ memcpy(rq->cmd, pc->c, 12);
+
+ pc->rq = rq;
+ pc->b_count = 0;
+ if (rq->cmd_flags & REQ_RW)
+ pc->flags |= PC_FLAG_WRITING;
+ pc->buf = NULL;
+ pc->req_xfer = pc->buf_size = blocks * floppy->block_size;
+ pc->flags |= PC_FLAG_DMA_OK;
+}
+
+static void idefloppy_blockpc_cmd(struct ide_disk_obj *floppy,
+ struct ide_atapi_pc *pc, struct request *rq)
+{
+ ide_init_pc(pc);
+ memcpy(pc->c, rq->cmd, sizeof(pc->c));
+ pc->rq = rq;
+ pc->b_count = 0;
+ if (rq->data_len && rq_data_dir(rq) == WRITE)
+ pc->flags |= PC_FLAG_WRITING;
+ pc->buf = rq->data;
+ if (rq->bio)
+ pc->flags |= PC_FLAG_DMA_OK;
+ /*
+ * possibly problematic, doesn't look like ide-floppy correctly
+ * handled scattered requests if dma fails...
+ */
+ pc->req_xfer = pc->buf_size = rq->data_len;
+}
+
+static ide_startstop_t ide_floppy_do_request(ide_drive_t *drive,
+ struct request *rq, sector_t block)
+{
+ struct ide_disk_obj *floppy = drive->driver_data;
+ ide_hwif_t *hwif = drive->hwif;
+ struct ide_atapi_pc *pc;
+
+ ide_debug_log(IDE_DBG_FUNC, "%s: dev: %s, cmd: 0x%x, cmd_type: %x, "
+ "errors: %d\n",
+ __func__, rq->rq_disk ? rq->rq_disk->disk_name : "?",
+ rq->cmd[0], rq->cmd_type, rq->errors);
+
+ ide_debug_log(IDE_DBG_FUNC, "%s: sector: %ld, nr_sectors: %ld, "
+ "current_nr_sectors: %d\n",
+ __func__, (long)rq->sector, rq->nr_sectors,
+ rq->current_nr_sectors);
+
+ if (rq->errors >= ERROR_MAX) {
+ if (floppy->failed_pc)
+ ide_floppy_report_error(floppy, floppy->failed_pc);
+ else
+ printk(KERN_ERR PFX "%s: I/O error\n", drive->name);
+
+ ide_floppy_end_request(drive, 0, 0);
+ return ide_stopped;
+ }
+ if (blk_fs_request(rq)) {
+ if (((long)rq->sector % floppy->bs_factor) ||
+ (rq->nr_sectors % floppy->bs_factor)) {
+ printk(KERN_ERR PFX "%s: unsupported r/w rq size\n",
+ drive->name);
+ ide_floppy_end_request(drive, 0, 0);
+ return ide_stopped;
+ }
+ pc = &floppy->queued_pc;
+ idefloppy_create_rw_cmd(drive, pc, rq, (unsigned long)block);
+ } else if (blk_special_request(rq)) {
+ pc = (struct ide_atapi_pc *) rq->buffer;
+ } else if (blk_pc_request(rq)) {
+ pc = &floppy->queued_pc;
+ idefloppy_blockpc_cmd(floppy, pc, rq);
+ } else {
+ blk_dump_rq_flags(rq, PFX "unsupported command in queue");
+ ide_floppy_end_request(drive, 0, 0);
+ return ide_stopped;
+ }
+
+ ide_init_sg_cmd(drive, rq);
+ ide_map_sg(drive, rq);
+
+ pc->sg = hwif->sg_table;
+ pc->sg_cnt = hwif->sg_nents;
+
+ pc->rq = rq;
+
+ return idefloppy_issue_pc(drive, pc);
+}
+
+/*
+ * Look at the flexible disk page parameters. We ignore the CHS capacity
+ * parameters and use the LBA parameters instead.
+ */
+static int ide_floppy_get_flexible_disk_page(ide_drive_t *drive)
+{
+ struct ide_disk_obj *floppy = drive->driver_data;
+ struct gendisk *disk = floppy->disk;
+ struct ide_atapi_pc pc;
+ u8 *page;
+ int capacity, lba_capacity;
+ u16 transfer_rate, sector_size, cyls, rpm;
+ u8 heads, sectors;
+
+ ide_floppy_create_mode_sense_cmd(&pc, IDEFLOPPY_FLEXIBLE_DISK_PAGE);
+
+ if (ide_queue_pc_tail(drive, disk, &pc)) {
+ printk(KERN_ERR PFX "Can't get flexible disk page params\n");
+ return 1;
+ }
+
+ if (pc.buf[3] & 0x80)
+ drive->dev_flags |= IDE_DFLAG_WP;
+ else
+ drive->dev_flags &= ~IDE_DFLAG_WP;
+
+ set_disk_ro(disk, !!(drive->dev_flags & IDE_DFLAG_WP));
+
+ page = &pc.buf[8];
+
+ transfer_rate = be16_to_cpup((__be16 *)&pc.buf[8 + 2]);
+ sector_size = be16_to_cpup((__be16 *)&pc.buf[8 + 6]);
+ cyls = be16_to_cpup((__be16 *)&pc.buf[8 + 8]);
+ rpm = be16_to_cpup((__be16 *)&pc.buf[8 + 28]);
+ heads = pc.buf[8 + 4];
+ sectors = pc.buf[8 + 5];
+
+ capacity = cyls * heads * sectors * sector_size;
+
+ if (memcmp(page, &floppy->flexible_disk_page, 32))
+ printk(KERN_INFO PFX "%s: %dkB, %d/%d/%d CHS, %d kBps, "
+ "%d sector size, %d rpm\n",
+ drive->name, capacity / 1024, cyls, heads,
+ sectors, transfer_rate / 8, sector_size, rpm);
+
+ memcpy(&floppy->flexible_disk_page, page, 32);
+ drive->bios_cyl = cyls;
+ drive->bios_head = heads;
+ drive->bios_sect = sectors;
+ lba_capacity = floppy->blocks * floppy->block_size;
+
+ if (capacity < lba_capacity) {
+ printk(KERN_NOTICE PFX "%s: The disk reports a capacity of %d "
+ "bytes, but the drive only handles %d\n",
+ drive->name, lba_capacity, capacity);
+ floppy->blocks = floppy->block_size ?
+ capacity / floppy->block_size : 0;
+ drive->capacity64 = floppy->blocks * floppy->bs_factor;
+ }
+
+ return 0;
+}
+
+/*
+ * Determine if a media is present in the floppy drive, and if so, its LBA
+ * capacity.
+ */
+static int ide_floppy_get_capacity(ide_drive_t *drive)
+{
+ struct ide_disk_obj *floppy = drive->driver_data;
+ struct gendisk *disk = floppy->disk;
+ struct ide_atapi_pc pc;
+ u8 *cap_desc;
+ u8 header_len, desc_cnt;
+ int i, rc = 1, blocks, length;
+
+ drive->bios_cyl = 0;
+ drive->bios_head = drive->bios_sect = 0;
+ floppy->blocks = 0;
+ floppy->bs_factor = 1;
+ drive->capacity64 = 0;
+
+ ide_floppy_create_read_capacity_cmd(&pc);
+ if (ide_queue_pc_tail(drive, disk, &pc)) {
+ printk(KERN_ERR PFX "Can't get floppy parameters\n");
+ return 1;
+ }
+ header_len = pc.buf[3];
+ cap_desc = &pc.buf[4];
+ desc_cnt = header_len / 8; /* capacity descriptor of 8 bytes */
+
+ for (i = 0; i < desc_cnt; i++) {
+ unsigned int desc_start = 4 + i*8;
+
+ blocks = be32_to_cpup((__be32 *)&pc.buf[desc_start]);
+ length = be16_to_cpup((__be16 *)&pc.buf[desc_start + 6]);
+
+ ide_debug_log(IDE_DBG_PROBE, "Descriptor %d: %dkB, %d blocks, "
+ "%d sector size\n",
+ i, blocks * length / 1024, blocks, length);
+
+ if (i)
+ continue;
+ /*
+ * the code below is valid only for the 1st descriptor, ie i=0
+ */
+
+ switch (pc.buf[desc_start + 4] & 0x03) {
+ /* Clik! drive returns this instead of CAPACITY_CURRENT */
+ case CAPACITY_UNFORMATTED:
+ if (!(drive->atapi_flags & IDE_AFLAG_CLIK_DRIVE))
+ /*
+ * If it is not a clik drive, break out
+ * (maintains previous driver behaviour)
+ */
+ break;
+ case CAPACITY_CURRENT:
+ /* Normal Zip/LS-120 disks */
+ if (memcmp(cap_desc, &floppy->cap_desc, 8))
+ printk(KERN_INFO PFX "%s: %dkB, %d blocks, %d "
+ "sector size\n",
+ drive->name, blocks * length / 1024,
+ blocks, length);
+ memcpy(&floppy->cap_desc, cap_desc, 8);
+
+ if (!length || length % 512) {
+ printk(KERN_NOTICE PFX "%s: %d bytes block size"
+ " not supported\n", drive->name, length);
+ } else {
+ floppy->blocks = blocks;
+ floppy->block_size = length;
+ floppy->bs_factor = length / 512;
+ if (floppy->bs_factor != 1)
+ printk(KERN_NOTICE PFX "%s: Warning: "
+ "non 512 bytes block size not "
+ "fully supported\n",
+ drive->name);
+ drive->capacity64 =
+ floppy->blocks * floppy->bs_factor;
+ rc = 0;
+ }
+ break;
+ case CAPACITY_NO_CARTRIDGE:
+ /*
+ * This is a KERN_ERR so it appears on screen
+ * for the user to see
+ */
+ printk(KERN_ERR PFX "%s: No disk in drive\n",
+ drive->name);
+ break;
+ case CAPACITY_INVALID:
+ printk(KERN_ERR PFX "%s: Invalid capacity for disk "
+ "in drive\n", drive->name);
+ break;
+ }
+ ide_debug_log(IDE_DBG_PROBE, "Descriptor 0 Code: %d\n",
+ pc.buf[desc_start + 4] & 0x03);
+ }
+
+ /* Clik! disk does not support get_flexible_disk_page */
+ if (!(drive->atapi_flags & IDE_AFLAG_CLIK_DRIVE))
+ (void) ide_floppy_get_flexible_disk_page(drive);
+
+ return rc;
+}
+
+static void ide_floppy_setup(ide_drive_t *drive)
+{
+ struct ide_disk_obj *floppy = drive->driver_data;
+ u16 *id = drive->id;
+
+ drive->pc_callback = ide_floppy_callback;
+ drive->pc_update_buffers = idefloppy_update_buffers;
+ drive->pc_io_buffers = ide_io_buffers;
+
+ /*
+ * We used to check revisions here. At this point however I'm giving up.
+ * Just assume they are all broken, its easier.
+ *
+ * The actual reason for the workarounds was likely a driver bug after
+ * all rather than a firmware bug, and the workaround below used to hide
+ * it. It should be fixed as of version 1.9, but to be on the safe side
+ * we'll leave the limitation below for the 2.2.x tree.
+ */
+ if (!strncmp((char *)&id[ATA_ID_PROD], "IOMEGA ZIP 100 ATAPI", 20)) {
+ drive->atapi_flags |= IDE_AFLAG_ZIP_DRIVE;
+ /* This value will be visible in the /proc/ide/hdx/settings */
+ drive->pc_delay = IDEFLOPPY_PC_DELAY;
+ blk_queue_max_sectors(drive->queue, 64);
+ }
+
+ /*
+ * Guess what? The IOMEGA Clik! drive also needs the above fix. It makes
+ * nasty clicking noises without it, so please don't remove this.
+ */
+ if (strncmp((char *)&id[ATA_ID_PROD], "IOMEGA Clik!", 11) == 0) {
+ blk_queue_max_sectors(drive->queue, 64);
+ drive->atapi_flags |= IDE_AFLAG_CLIK_DRIVE;
+ /* IOMEGA Clik! drives do not support lock/unlock commands */
+ drive->dev_flags &= ~IDE_DFLAG_DOORLOCKING;
+ }
+
+ (void) ide_floppy_get_capacity(drive);
+
+ ide_proc_register_driver(drive, floppy->driver);
+
+ drive->dev_flags |= IDE_DFLAG_ATTACH;
+}
+
+static void ide_floppy_flush(ide_drive_t *drive)
+{
+}
+
+static int ide_floppy_init_media(ide_drive_t *drive, struct gendisk *disk)
+{
+ int ret = 0;
+
+ if (ide_do_test_unit_ready(drive, disk))
+ ide_do_start_stop(drive, disk, 1);
+
+ ret = ide_floppy_get_capacity(drive);
+
+ set_capacity(disk, ide_gd_capacity(drive));
+
+ return ret;
+}
+
+const struct ide_disk_ops ide_atapi_disk_ops = {
+ .check = ide_check_atapi_device,
+ .get_capacity = ide_floppy_get_capacity,
+ .setup = ide_floppy_setup,
+ .flush = ide_floppy_flush,
+ .init_media = ide_floppy_init_media,
+ .set_doorlock = ide_set_media_lock,
+ .do_request = ide_floppy_do_request,
+ .end_request = ide_floppy_end_request,
+ .ioctl = ide_floppy_ioctl,
+};
diff --git a/drivers/ide/ide-floppy.h b/drivers/ide/ide-floppy.h
new file mode 100644
index 0000000..6dd2beb
--- /dev/null
+++ b/drivers/ide/ide-floppy.h
@@ -0,0 +1,39 @@
+#ifndef __IDE_FLOPPY_H
+#define __IDE_FLOPPY_H
+
+#include "ide-gd.h"
+
+#ifdef CONFIG_IDE_GD_ATAPI
+/*
+ * Pages of the SELECT SENSE / MODE SENSE packet commands.
+ * See SFF-8070i spec.
+ */
+#define IDEFLOPPY_CAPABILITIES_PAGE 0x1b
+#define IDEFLOPPY_FLEXIBLE_DISK_PAGE 0x05
+
+/* IOCTLs used in low-level formatting. */
+#define IDEFLOPPY_IOCTL_FORMAT_SUPPORTED 0x4600
+#define IDEFLOPPY_IOCTL_FORMAT_GET_CAPACITY 0x4601
+#define IDEFLOPPY_IOCTL_FORMAT_START 0x4602
+#define IDEFLOPPY_IOCTL_FORMAT_GET_PROGRESS 0x4603
+
+/* ide-floppy.c */
+extern const struct ide_disk_ops ide_atapi_disk_ops;
+void ide_floppy_create_mode_sense_cmd(struct ide_atapi_pc *, u8);
+void ide_floppy_create_read_capacity_cmd(struct ide_atapi_pc *);
+
+/* ide-floppy_ioctl.c */
+int ide_floppy_ioctl(ide_drive_t *, struct block_device *, fmode_t,
+ unsigned int, unsigned long);
+
+#ifdef CONFIG_IDE_PROC_FS
+/* ide-floppy_proc.c */
+extern ide_proc_entry_t ide_floppy_proc[];
+extern const struct ide_proc_devset ide_floppy_settings[];
+#endif
+#else
+#define ide_floppy_proc NULL
+#define ide_floppy_settings NULL
+#endif
+
+#endif /*__IDE_FLOPPY_H */
diff --git a/drivers/ide/ide-floppy_ioctl.c b/drivers/ide/ide-floppy_ioctl.c
new file mode 100644
index 0000000..2bc51ff
--- /dev/null
+++ b/drivers/ide/ide-floppy_ioctl.c
@@ -0,0 +1,289 @@
+/*
+ * ide-floppy IOCTLs handling.
+ */
+
+#include <linux/kernel.h>
+#include <linux/ide.h>
+#include <linux/cdrom.h>
+
+#include <asm/unaligned.h>
+
+#include <scsi/scsi_ioctl.h>
+
+#include "ide-floppy.h"
+
+/*
+ * Obtain the list of formattable capacities.
+ * Very similar to ide_floppy_get_capacity, except that we push the capacity
+ * descriptors to userland, instead of our own structures.
+ *
+ * Userland gives us the following structure:
+ *
+ * struct idefloppy_format_capacities {
+ * int nformats;
+ * struct {
+ * int nblocks;
+ * int blocksize;
+ * } formats[];
+ * };
+ *
+ * userland initializes nformats to the number of allocated formats[] records.
+ * On exit we set nformats to the number of records we've actually initialized.
+ */
+
+static int ide_floppy_get_format_capacities(ide_drive_t *drive, int __user *arg)
+{
+ struct ide_disk_obj *floppy = drive->driver_data;
+ struct ide_atapi_pc pc;
+ u8 header_len, desc_cnt;
+ int i, blocks, length, u_array_size, u_index;
+ int __user *argp;
+
+ if (get_user(u_array_size, arg))
+ return -EFAULT;
+
+ if (u_array_size <= 0)
+ return -EINVAL;
+
+ ide_floppy_create_read_capacity_cmd(&pc);
+ if (ide_queue_pc_tail(drive, floppy->disk, &pc)) {
+ printk(KERN_ERR "ide-floppy: Can't get floppy parameters\n");
+ return -EIO;
+ }
+
+ header_len = pc.buf[3];
+ desc_cnt = header_len / 8; /* capacity descriptor of 8 bytes */
+
+ u_index = 0;
+ argp = arg + 1;
+
+ /*
+ * We always skip the first capacity descriptor. That's the current
+ * capacity. We are interested in the remaining descriptors, the
+ * formattable capacities.
+ */
+ for (i = 1; i < desc_cnt; i++) {
+ unsigned int desc_start = 4 + i*8;
+
+ if (u_index >= u_array_size)
+ break; /* User-supplied buffer too small */
+
+ blocks = be32_to_cpup((__be32 *)&pc.buf[desc_start]);
+ length = be16_to_cpup((__be16 *)&pc.buf[desc_start + 6]);
+
+ if (put_user(blocks, argp))
+ return -EFAULT;
+
+ ++argp;
+
+ if (put_user(length, argp))
+ return -EFAULT;
+
+ ++argp;
+
+ ++u_index;
+ }
+
+ if (put_user(u_index, arg))
+ return -EFAULT;
+
+ return 0;
+}
+
+static void ide_floppy_create_format_unit_cmd(struct ide_atapi_pc *pc, int b,
+ int l, int flags)
+{
+ ide_init_pc(pc);
+ pc->c[0] = GPCMD_FORMAT_UNIT;
+ pc->c[1] = 0x17;
+
+ memset(pc->buf, 0, 12);
+ pc->buf[1] = 0xA2;
+ /* Default format list header, u8 1: FOV/DCRT/IMM bits set */
+
+ if (flags & 1) /* Verify bit on... */
+ pc->buf[1] ^= 0x20; /* ... turn off DCRT bit */
+ pc->buf[3] = 8;
+
+ put_unaligned(cpu_to_be32(b), (unsigned int *)(&pc->buf[4]));
+ put_unaligned(cpu_to_be32(l), (unsigned int *)(&pc->buf[8]));
+ pc->buf_size = 12;
+ pc->flags |= PC_FLAG_WRITING;
+}
+
+static int ide_floppy_get_sfrp_bit(ide_drive_t *drive)
+{
+ struct ide_disk_obj *floppy = drive->driver_data;
+ struct ide_atapi_pc pc;
+
+ drive->atapi_flags &= ~IDE_AFLAG_SRFP;
+
+ ide_floppy_create_mode_sense_cmd(&pc, IDEFLOPPY_CAPABILITIES_PAGE);
+ pc.flags |= PC_FLAG_SUPPRESS_ERROR;
+
+ if (ide_queue_pc_tail(drive, floppy->disk, &pc))
+ return 1;
+
+ if (pc.buf[8 + 2] & 0x40)
+ drive->atapi_flags |= IDE_AFLAG_SRFP;
+
+ return 0;
+}
+
+static int ide_floppy_format_unit(ide_drive_t *drive, int __user *arg)
+{
+ struct ide_disk_obj *floppy = drive->driver_data;
+ struct ide_atapi_pc pc;
+ int blocks, length, flags, err = 0;
+
+ if (floppy->openers > 1) {
+ /* Don't format if someone is using the disk */
+ drive->dev_flags &= ~IDE_DFLAG_FORMAT_IN_PROGRESS;
+ return -EBUSY;
+ }
+
+ drive->dev_flags |= IDE_DFLAG_FORMAT_IN_PROGRESS;
+
+ /*
+ * Send ATAPI_FORMAT_UNIT to the drive.
+ *
+ * Userland gives us the following structure:
+ *
+ * struct idefloppy_format_command {
+ * int nblocks;
+ * int blocksize;
+ * int flags;
+ * } ;
+ *
+ * flags is a bitmask, currently, the only defined flag is:
+ *
+ * 0x01 - verify media after format.
+ */
+ if (get_user(blocks, arg) ||
+ get_user(length, arg+1) ||
+ get_user(flags, arg+2)) {
+ err = -EFAULT;
+ goto out;
+ }
+
+ (void)ide_floppy_get_sfrp_bit(drive);
+ ide_floppy_create_format_unit_cmd(&pc, blocks, length, flags);
+
+ if (ide_queue_pc_tail(drive, floppy->disk, &pc))
+ err = -EIO;
+
+out:
+ if (err)
+ drive->dev_flags &= ~IDE_DFLAG_FORMAT_IN_PROGRESS;
+ return err;
+}
+
+/*
+ * Get ATAPI_FORMAT_UNIT progress indication.
+ *
+ * Userland gives a pointer to an int. The int is set to a progress
+ * indicator 0-65536, with 65536=100%.
+ *
+ * If the drive does not support format progress indication, we just check
+ * the dsc bit, and return either 0 or 65536.
+ */
+
+static int ide_floppy_get_format_progress(ide_drive_t *drive, int __user *arg)
+{
+ struct ide_disk_obj *floppy = drive->driver_data;
+ struct ide_atapi_pc pc;
+ int progress_indication = 0x10000;
+
+ if (drive->atapi_flags & IDE_AFLAG_SRFP) {
+ ide_create_request_sense_cmd(drive, &pc);
+ if (ide_queue_pc_tail(drive, floppy->disk, &pc))
+ return -EIO;
+
+ if (floppy->sense_key == 2 &&
+ floppy->asc == 4 &&
+ floppy->ascq == 4)
+ progress_indication = floppy->progress_indication;
+
+ /* Else assume format_unit has finished, and we're at 0x10000 */
+ } else {
+ ide_hwif_t *hwif = drive->hwif;
+ unsigned long flags;
+ u8 stat;
+
+ local_irq_save(flags);
+ stat = hwif->tp_ops->read_status(hwif);
+ local_irq_restore(flags);
+
+ progress_indication = ((stat & ATA_DSC) == 0) ? 0 : 0x10000;
+ }
+
+ if (put_user(progress_indication, arg))
+ return -EFAULT;
+
+ return 0;
+}
+
+static int ide_floppy_lockdoor(ide_drive_t *drive, struct ide_atapi_pc *pc,
+ unsigned long arg, unsigned int cmd)
+{
+ struct ide_disk_obj *floppy = drive->driver_data;
+ struct gendisk *disk = floppy->disk;
+ int prevent = (arg && cmd != CDROMEJECT) ? 1 : 0;
+
+ if (floppy->openers > 1)
+ return -EBUSY;
+
+ ide_set_media_lock(drive, disk, prevent);
+
+ if (cmd == CDROMEJECT)
+ ide_do_start_stop(drive, disk, 2);
+
+ return 0;
+}
+
+static int ide_floppy_format_ioctl(ide_drive_t *drive, fmode_t mode,
+ unsigned int cmd, void __user *argp)
+{
+ switch (cmd) {
+ case IDEFLOPPY_IOCTL_FORMAT_SUPPORTED:
+ return 0;
+ case IDEFLOPPY_IOCTL_FORMAT_GET_CAPACITY:
+ return ide_floppy_get_format_capacities(drive, argp);
+ case IDEFLOPPY_IOCTL_FORMAT_START:
+ if (!(mode & FMODE_WRITE))
+ return -EPERM;
+ return ide_floppy_format_unit(drive, (int __user *)argp);
+ case IDEFLOPPY_IOCTL_FORMAT_GET_PROGRESS:
+ return ide_floppy_get_format_progress(drive, argp);
+ default:
+ return -ENOTTY;
+ }
+}
+
+int ide_floppy_ioctl(ide_drive_t *drive, struct block_device *bdev,
+ fmode_t mode, unsigned int cmd, unsigned long arg)
+{
+ struct ide_atapi_pc pc;
+ void __user *argp = (void __user *)arg;
+ int err;
+
+ if (cmd == CDROMEJECT || cmd == CDROM_LOCKDOOR)
+ return ide_floppy_lockdoor(drive, &pc, arg, cmd);
+
+ err = ide_floppy_format_ioctl(drive, mode, cmd, argp);
+ if (err != -ENOTTY)
+ return err;
+
+ /*
+ * skip SCSI_IOCTL_SEND_COMMAND (deprecated)
+ * and CDROM_SEND_PACKET (legacy) ioctls
+ */
+ if (cmd != CDROM_SEND_PACKET && cmd != SCSI_IOCTL_SEND_COMMAND)
+ err = scsi_cmd_ioctl(bdev->bd_disk->queue, bdev->bd_disk,
+ mode, cmd, argp);
+
+ if (err == -ENOTTY)
+ err = generic_ide_ioctl(drive, bdev, cmd, arg);
+
+ return err;
+}
diff --git a/drivers/ide/ide-floppy_proc.c b/drivers/ide/ide-floppy_proc.c
new file mode 100644
index 0000000..3ec762c
--- /dev/null
+++ b/drivers/ide/ide-floppy_proc.c
@@ -0,0 +1,33 @@
+#include <linux/kernel.h>
+#include <linux/ide.h>
+
+#include "ide-floppy.h"
+
+static int proc_idefloppy_read_capacity(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ ide_drive_t*drive = (ide_drive_t *)data;
+ int len;
+
+ len = sprintf(page, "%llu\n", (long long)ide_gd_capacity(drive));
+ PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
+}
+
+ide_proc_entry_t ide_floppy_proc[] = {
+ { "capacity", S_IFREG|S_IRUGO, proc_idefloppy_read_capacity, NULL },
+ { "geometry", S_IFREG|S_IRUGO, proc_ide_read_geometry, NULL },
+ { NULL, 0, NULL, NULL }
+};
+
+ide_devset_rw_field(bios_cyl, bios_cyl);
+ide_devset_rw_field(bios_head, bios_head);
+ide_devset_rw_field(bios_sect, bios_sect);
+ide_devset_rw_field(ticks, pc_delay);
+
+const struct ide_proc_devset ide_floppy_settings[] = {
+ IDE_PROC_DEVSET(bios_cyl, 0, 1023),
+ IDE_PROC_DEVSET(bios_head, 0, 255),
+ IDE_PROC_DEVSET(bios_sect, 0, 63),
+ IDE_PROC_DEVSET(ticks, 0, 255),
+ { 0 },
+};
diff --git a/drivers/ide/ide-gd.c b/drivers/ide/ide-gd.c
new file mode 100644
index 0000000..b8078b3
--- /dev/null
+++ b/drivers/ide/ide-gd.c
@@ -0,0 +1,401 @@
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/genhd.h>
+#include <linux/mutex.h>
+#include <linux/ide.h>
+#include <linux/hdreg.h>
+
+#if !defined(CONFIG_DEBUG_BLOCK_EXT_DEVT)
+#define IDE_DISK_MINORS (1 << PARTN_BITS)
+#else
+#define IDE_DISK_MINORS 0
+#endif
+
+#include "ide-disk.h"
+#include "ide-floppy.h"
+
+#define IDE_GD_VERSION "1.18"
+
+/* module parameters */
+static unsigned long debug_mask;
+module_param(debug_mask, ulong, 0644);
+
+static DEFINE_MUTEX(ide_disk_ref_mutex);
+
+static void ide_disk_release(struct kref *);
+
+static struct ide_disk_obj *ide_disk_get(struct gendisk *disk)
+{
+ struct ide_disk_obj *idkp = NULL;
+
+ mutex_lock(&ide_disk_ref_mutex);
+ idkp = ide_drv_g(disk, ide_disk_obj);
+ if (idkp) {
+ if (ide_device_get(idkp->drive))
+ idkp = NULL;
+ else
+ kref_get(&idkp->kref);
+ }
+ mutex_unlock(&ide_disk_ref_mutex);
+ return idkp;
+}
+
+static void ide_disk_put(struct ide_disk_obj *idkp)
+{
+ ide_drive_t *drive = idkp->drive;
+
+ mutex_lock(&ide_disk_ref_mutex);
+ kref_put(&idkp->kref, ide_disk_release);
+ ide_device_put(drive);
+ mutex_unlock(&ide_disk_ref_mutex);
+}
+
+sector_t ide_gd_capacity(ide_drive_t *drive)
+{
+ return drive->capacity64;
+}
+
+static int ide_gd_probe(ide_drive_t *);
+
+static void ide_gd_remove(ide_drive_t *drive)
+{
+ struct ide_disk_obj *idkp = drive->driver_data;
+ struct gendisk *g = idkp->disk;
+
+ ide_proc_unregister_driver(drive, idkp->driver);
+
+ del_gendisk(g);
+
+ drive->disk_ops->flush(drive);
+
+ ide_disk_put(idkp);
+}
+
+static void ide_disk_release(struct kref *kref)
+{
+ struct ide_disk_obj *idkp = to_ide_drv(kref, ide_disk_obj);
+ ide_drive_t *drive = idkp->drive;
+ struct gendisk *g = idkp->disk;
+
+ drive->disk_ops = NULL;
+ drive->driver_data = NULL;
+ g->private_data = NULL;
+ put_disk(g);
+ kfree(idkp);
+}
+
+/*
+ * On HPA drives the capacity needs to be
+ * reinitilized on resume otherwise the disk
+ * can not be used and a hard reset is required
+ */
+static void ide_gd_resume(ide_drive_t *drive)
+{
+ if (ata_id_hpa_enabled(drive->id))
+ (void)drive->disk_ops->get_capacity(drive);
+}
+
+static void ide_gd_shutdown(ide_drive_t *drive)
+{
+#ifdef CONFIG_ALPHA
+ /* On Alpha, halt(8) doesn't actually turn the machine off,
+ it puts you into the sort of firmware monitor. Typically,
+ it's used to boot another kernel image, so it's not much
+ different from reboot(8). Therefore, we don't need to
+ spin down the disk in this case, especially since Alpha
+ firmware doesn't handle disks in standby mode properly.
+ On the other hand, it's reasonably safe to turn the power
+ off when the shutdown process reaches the firmware prompt,
+ as the firmware initialization takes rather long time -
+ at least 10 seconds, which should be sufficient for
+ the disk to expire its write cache. */
+ if (system_state != SYSTEM_POWER_OFF) {
+#else
+ if (system_state == SYSTEM_RESTART) {
+#endif
+ drive->disk_ops->flush(drive);
+ return;
+ }
+
+ printk(KERN_INFO "Shutdown: %s\n", drive->name);
+
+ drive->gendev.bus->suspend(&drive->gendev, PMSG_SUSPEND);
+}
+
+#ifdef CONFIG_IDE_PROC_FS
+static ide_proc_entry_t *ide_disk_proc_entries(ide_drive_t *drive)
+{
+ return (drive->media == ide_disk) ? ide_disk_proc : ide_floppy_proc;
+}
+
+static const struct ide_proc_devset *ide_disk_proc_devsets(ide_drive_t *drive)
+{
+ return (drive->media == ide_disk) ? ide_disk_settings
+ : ide_floppy_settings;
+}
+#endif
+
+static ide_startstop_t ide_gd_do_request(ide_drive_t *drive,
+ struct request *rq, sector_t sector)
+{
+ return drive->disk_ops->do_request(drive, rq, sector);
+}
+
+static int ide_gd_end_request(ide_drive_t *drive, int uptodate, int nrsecs)
+{
+ return drive->disk_ops->end_request(drive, uptodate, nrsecs);
+}
+
+static ide_driver_t ide_gd_driver = {
+ .gen_driver = {
+ .owner = THIS_MODULE,
+ .name = "ide-gd",
+ .bus = &ide_bus_type,
+ },
+ .probe = ide_gd_probe,
+ .remove = ide_gd_remove,
+ .resume = ide_gd_resume,
+ .shutdown = ide_gd_shutdown,
+ .version = IDE_GD_VERSION,
+ .do_request = ide_gd_do_request,
+ .end_request = ide_gd_end_request,
+ .error = __ide_error,
+#ifdef CONFIG_IDE_PROC_FS
+ .proc_entries = ide_disk_proc_entries,
+ .proc_devsets = ide_disk_proc_devsets,
+#endif
+};
+
+static int ide_gd_open(struct block_device *bdev, fmode_t mode)
+{
+ struct gendisk *disk = bdev->bd_disk;
+ struct ide_disk_obj *idkp;
+ ide_drive_t *drive;
+ int ret = 0;
+
+ idkp = ide_disk_get(disk);
+ if (idkp == NULL)
+ return -ENXIO;
+
+ drive = idkp->drive;
+
+ ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__);
+
+ idkp->openers++;
+
+ if ((drive->dev_flags & IDE_DFLAG_REMOVABLE) && idkp->openers == 1) {
+ drive->dev_flags &= ~IDE_DFLAG_FORMAT_IN_PROGRESS;
+ /* Just in case */
+
+ ret = drive->disk_ops->init_media(drive, disk);
+
+ /*
+ * Allow O_NDELAY to open a drive without a disk, or with an
+ * unreadable disk, so that we can get the format capacity
+ * of the drive or begin the format - Sam
+ */
+ if (ret && (mode & FMODE_NDELAY) == 0) {
+ ret = -EIO;
+ goto out_put_idkp;
+ }
+
+ if ((drive->dev_flags & IDE_DFLAG_WP) && (mode & FMODE_WRITE)) {
+ ret = -EROFS;
+ goto out_put_idkp;
+ }
+
+ /*
+ * Ignore the return code from door_lock,
+ * since the open() has already succeeded,
+ * and the door_lock is irrelevant at this point.
+ */
+ drive->disk_ops->set_doorlock(drive, disk, 1);
+ drive->dev_flags |= IDE_DFLAG_MEDIA_CHANGED;
+ check_disk_change(bdev);
+ } else if (drive->dev_flags & IDE_DFLAG_FORMAT_IN_PROGRESS) {
+ ret = -EBUSY;
+ goto out_put_idkp;
+ }
+ return 0;
+
+out_put_idkp:
+ idkp->openers--;
+ ide_disk_put(idkp);
+ return ret;
+}
+
+static int ide_gd_release(struct gendisk *disk, fmode_t mode)
+{
+ struct ide_disk_obj *idkp = ide_drv_g(disk, ide_disk_obj);
+ ide_drive_t *drive = idkp->drive;
+
+ ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__);
+
+ if (idkp->openers == 1)
+ drive->disk_ops->flush(drive);
+
+ if ((drive->dev_flags & IDE_DFLAG_REMOVABLE) && idkp->openers == 1) {
+ drive->disk_ops->set_doorlock(drive, disk, 0);
+ drive->dev_flags &= ~IDE_DFLAG_FORMAT_IN_PROGRESS;
+ }
+
+ idkp->openers--;
+
+ ide_disk_put(idkp);
+
+ return 0;
+}
+
+static int ide_gd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
+{
+ struct ide_disk_obj *idkp = ide_drv_g(bdev->bd_disk, ide_disk_obj);
+ ide_drive_t *drive = idkp->drive;
+
+ geo->heads = drive->bios_head;
+ geo->sectors = drive->bios_sect;
+ geo->cylinders = (u16)drive->bios_cyl; /* truncate */
+ return 0;
+}
+
+static int ide_gd_media_changed(struct gendisk *disk)
+{
+ struct ide_disk_obj *idkp = ide_drv_g(disk, ide_disk_obj);
+ ide_drive_t *drive = idkp->drive;
+ int ret;
+
+ /* do not scan partitions twice if this is a removable device */
+ if (drive->dev_flags & IDE_DFLAG_ATTACH) {
+ drive->dev_flags &= ~IDE_DFLAG_ATTACH;
+ return 0;
+ }
+
+ ret = !!(drive->dev_flags & IDE_DFLAG_MEDIA_CHANGED);
+ drive->dev_flags &= ~IDE_DFLAG_MEDIA_CHANGED;
+
+ return ret;
+}
+
+static int ide_gd_revalidate_disk(struct gendisk *disk)
+{
+ struct ide_disk_obj *idkp = ide_drv_g(disk, ide_disk_obj);
+ ide_drive_t *drive = idkp->drive;
+
+ if (ide_gd_media_changed(disk))
+ drive->disk_ops->get_capacity(drive);
+
+ set_capacity(disk, ide_gd_capacity(drive));
+ return 0;
+}
+
+static int ide_gd_ioctl(struct block_device *bdev, fmode_t mode,
+ unsigned int cmd, unsigned long arg)
+{
+ struct ide_disk_obj *idkp = ide_drv_g(bdev->bd_disk, ide_disk_obj);
+ ide_drive_t *drive = idkp->drive;
+
+ return drive->disk_ops->ioctl(drive, bdev, mode, cmd, arg);
+}
+
+static struct block_device_operations ide_gd_ops = {
+ .owner = THIS_MODULE,
+ .open = ide_gd_open,
+ .release = ide_gd_release,
+ .locked_ioctl = ide_gd_ioctl,
+ .getgeo = ide_gd_getgeo,
+ .media_changed = ide_gd_media_changed,
+ .revalidate_disk = ide_gd_revalidate_disk
+};
+
+static int ide_gd_probe(ide_drive_t *drive)
+{
+ const struct ide_disk_ops *disk_ops = NULL;
+ struct ide_disk_obj *idkp;
+ struct gendisk *g;
+
+ /* strstr("foo", "") is non-NULL */
+ if (!strstr("ide-gd", drive->driver_req))
+ goto failed;
+
+#ifdef CONFIG_IDE_GD_ATA
+ if (drive->media == ide_disk)
+ disk_ops = &ide_ata_disk_ops;
+#endif
+#ifdef CONFIG_IDE_GD_ATAPI
+ if (drive->media == ide_floppy)
+ disk_ops = &ide_atapi_disk_ops;
+#endif
+ if (disk_ops == NULL)
+ goto failed;
+
+ if (disk_ops->check(drive, DRV_NAME) == 0) {
+ printk(KERN_ERR PFX "%s: not supported by this driver\n",
+ drive->name);
+ goto failed;
+ }
+
+ idkp = kzalloc(sizeof(*idkp), GFP_KERNEL);
+ if (!idkp) {
+ printk(KERN_ERR PFX "%s: can't allocate a disk structure\n",
+ drive->name);
+ goto failed;
+ }
+
+ g = alloc_disk_node(IDE_DISK_MINORS, hwif_to_node(drive->hwif));
+ if (!g)
+ goto out_free_idkp;
+
+ ide_init_disk(g, drive);
+
+ kref_init(&idkp->kref);
+
+ idkp->drive = drive;
+ idkp->driver = &ide_gd_driver;
+ idkp->disk = g;
+
+ g->private_data = &idkp->driver;
+
+ drive->driver_data = idkp;
+ drive->debug_mask = debug_mask;
+ drive->disk_ops = disk_ops;
+
+ disk_ops->setup(drive);
+
+ set_capacity(g, ide_gd_capacity(drive));
+
+ g->minors = IDE_DISK_MINORS;
+ g->driverfs_dev = &drive->gendev;
+ g->flags |= GENHD_FL_EXT_DEVT;
+ if (drive->dev_flags & IDE_DFLAG_REMOVABLE)
+ g->flags = GENHD_FL_REMOVABLE;
+ g->fops = &ide_gd_ops;
+ add_disk(g);
+ return 0;
+
+out_free_idkp:
+ kfree(idkp);
+failed:
+ return -ENODEV;
+}
+
+static int __init ide_gd_init(void)
+{
+ printk(KERN_INFO DRV_NAME " driver " IDE_GD_VERSION "\n");
+ return driver_register(&ide_gd_driver.gen_driver);
+}
+
+static void __exit ide_gd_exit(void)
+{
+ driver_unregister(&ide_gd_driver.gen_driver);
+}
+
+MODULE_ALIAS("ide:*m-disk*");
+MODULE_ALIAS("ide-disk");
+MODULE_ALIAS("ide:*m-floppy*");
+MODULE_ALIAS("ide-floppy");
+module_init(ide_gd_init);
+module_exit(ide_gd_exit);
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("generic ATA/ATAPI disk driver");
diff --git a/drivers/ide/ide-gd.h b/drivers/ide/ide-gd.h
new file mode 100644
index 0000000..7d3d101
--- /dev/null
+++ b/drivers/ide/ide-gd.h
@@ -0,0 +1,44 @@
+#ifndef __IDE_GD_H
+#define __IDE_GD_H
+
+#define DRV_NAME "ide-gd"
+#define PFX DRV_NAME ": "
+
+/* define to see debug info */
+#define IDE_GD_DEBUG_LOG 0
+
+#if IDE_GD_DEBUG_LOG
+#define ide_debug_log(lvl, fmt, args...) __ide_debug_log(lvl, fmt, args)
+#else
+#define ide_debug_log(lvl, fmt, args...) do {} while (0)
+#endif
+
+struct ide_disk_obj {
+ ide_drive_t *drive;
+ ide_driver_t *driver;
+ struct gendisk *disk;
+ struct kref kref;
+ unsigned int openers; /* protected by BKL for now */
+
+ /* Last failed packet command */
+ struct ide_atapi_pc *failed_pc;
+ /* used for blk_{fs,pc}_request() requests */
+ struct ide_atapi_pc queued_pc;
+
+ /* Last error information */
+ u8 sense_key, asc, ascq;
+
+ int progress_indication;
+
+ /* Device information */
+ /* Current format */
+ int blocks, block_size, bs_factor;
+ /* Last format capacity descriptor */
+ u8 cap_desc[8];
+ /* Copy of the flexible disk page */
+ u8 flexible_disk_page[32];
+};
+
+sector_t ide_gd_capacity(ide_drive_t *);
+
+#endif /* __IDE_GD_H */
diff --git a/drivers/ide/ide-generic.c b/drivers/ide/ide-generic.c
new file mode 100644
index 0000000..81a5282
--- /dev/null
+++ b/drivers/ide/ide-generic.c
@@ -0,0 +1,204 @@
+/*
+ * generic/default IDE host driver
+ *
+ * Copyright (C) 2004, 2008 Bartlomiej Zolnierkiewicz
+ * This code was split off from ide.c. See it for original copyrights.
+ *
+ * May be copied or modified under the terms of the GNU General Public License.
+ */
+
+/*
+ * For special cases new interfaces may be added using sysfs, i.e.
+ *
+ * echo -n "0x168:0x36e:10" > /sys/class/ide_generic/add
+ *
+ * will add an interface using I/O ports 0x168-0x16f/0x36e and IRQ 10.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/ide.h>
+#include <linux/pci_ids.h>
+
+/* FIXME: convert m32r to use ide_platform host driver */
+#ifdef CONFIG_M32R
+#include <asm/m32r.h>
+#endif
+
+#define DRV_NAME "ide_generic"
+
+static int probe_mask;
+module_param(probe_mask, int, 0);
+MODULE_PARM_DESC(probe_mask, "probe mask for legacy ISA IDE ports");
+
+static ssize_t store_add(struct class *cls, const char *buf, size_t n)
+{
+ unsigned int base, ctl;
+ int irq, rc;
+ hw_regs_t hw, *hws[] = { &hw, NULL, NULL, NULL };
+
+ if (sscanf(buf, "%x:%x:%d", &base, &ctl, &irq) != 3)
+ return -EINVAL;
+
+ memset(&hw, 0, sizeof(hw));
+ ide_std_init_ports(&hw, base, ctl);
+ hw.irq = irq;
+ hw.chipset = ide_generic;
+
+ rc = ide_host_add(NULL, hws, NULL);
+ if (rc)
+ return rc;
+
+ return n;
+};
+
+static struct class_attribute ide_generic_class_attrs[] = {
+ __ATTR(add, S_IWUSR, NULL, store_add),
+ __ATTR_NULL
+};
+
+static void ide_generic_class_release(struct class *cls)
+{
+ kfree(cls);
+}
+
+static int __init ide_generic_sysfs_init(void)
+{
+ struct class *cls;
+ int rc;
+
+ cls = kzalloc(sizeof(*cls), GFP_KERNEL);
+ if (!cls)
+ return -ENOMEM;
+
+ cls->name = DRV_NAME;
+ cls->owner = THIS_MODULE;
+ cls->class_release = ide_generic_class_release;
+ cls->class_attrs = ide_generic_class_attrs;
+
+ rc = class_register(cls);
+ if (rc) {
+ kfree(cls);
+ return rc;
+ }
+
+ return 0;
+}
+
+#if defined(CONFIG_PLAT_M32700UT) || defined(CONFIG_PLAT_MAPPI2) \
+ || defined(CONFIG_PLAT_OPSPUT)
+static const u16 legacy_bases[] = { 0x1f0 };
+static const int legacy_irqs[] = { PLD_IRQ_CFIREQ };
+#elif defined(CONFIG_PLAT_MAPPI3)
+static const u16 legacy_bases[] = { 0x1f0, 0x170 };
+static const int legacy_irqs[] = { PLD_IRQ_CFIREQ, PLD_IRQ_IDEIREQ };
+#elif defined(CONFIG_ALPHA)
+static const u16 legacy_bases[] = { 0x1f0, 0x170, 0x1e8, 0x168 };
+static const int legacy_irqs[] = { 14, 15, 11, 10 };
+#else
+static const u16 legacy_bases[] = { 0x1f0, 0x170, 0x1e8, 0x168, 0x1e0, 0x160 };
+static const int legacy_irqs[] = { 14, 15, 11, 10, 8, 12 };
+#endif
+
+static void ide_generic_check_pci_legacy_iobases(int *primary, int *secondary)
+{
+ struct pci_dev *p = NULL;
+ u16 val;
+
+ for_each_pci_dev(p) {
+
+ if (pci_resource_start(p, 0) == 0x1f0)
+ *primary = 1;
+ if (pci_resource_start(p, 2) == 0x170)
+ *secondary = 1;
+
+ /* Cyrix CS55{1,2}0 pre SFF MWDMA ATA on the bridge */
+ if (p->vendor == PCI_VENDOR_ID_CYRIX &&
+ (p->device == PCI_DEVICE_ID_CYRIX_5510 ||
+ p->device == PCI_DEVICE_ID_CYRIX_5520))
+ *primary = *secondary = 1;
+
+ /* Intel MPIIX - PIO ATA on non PCI side of bridge */
+ if (p->vendor == PCI_VENDOR_ID_INTEL &&
+ p->device == PCI_DEVICE_ID_INTEL_82371MX) {
+
+ pci_read_config_word(p, 0x6C, &val);
+ if (val & 0x8000) {
+ /* ATA port enabled */
+ if (val & 0x4000)
+ *secondary = 1;
+ else
+ *primary = 1;
+ }
+ }
+ }
+}
+
+static int __init ide_generic_init(void)
+{
+ hw_regs_t hw, *hws[] = { &hw, NULL, NULL, NULL };
+ unsigned long io_addr;
+ int i, rc = 0, primary = 0, secondary = 0;
+
+ ide_generic_check_pci_legacy_iobases(&primary, &secondary);
+
+ if (!probe_mask) {
+ printk(KERN_INFO DRV_NAME ": please use \"probe_mask=0x3f\" "
+ "module parameter for probing all legacy ISA IDE ports\n");
+
+ if (primary == 0)
+ probe_mask |= 0x1;
+
+ if (secondary == 0)
+ probe_mask |= 0x2;
+ } else
+ printk(KERN_INFO DRV_NAME ": enforcing probing of I/O ports "
+ "upon user request\n");
+
+ for (i = 0; i < ARRAY_SIZE(legacy_bases); i++) {
+ io_addr = legacy_bases[i];
+
+ if ((probe_mask & (1 << i)) && io_addr) {
+ if (!request_region(io_addr, 8, DRV_NAME)) {
+ printk(KERN_ERR "%s: I/O resource 0x%lX-0x%lX "
+ "not free.\n",
+ DRV_NAME, io_addr, io_addr + 7);
+ continue;
+ }
+
+ if (!request_region(io_addr + 0x206, 1, DRV_NAME)) {
+ printk(KERN_ERR "%s: I/O resource 0x%lX "
+ "not free.\n",
+ DRV_NAME, io_addr + 0x206);
+ release_region(io_addr, 8);
+ continue;
+ }
+
+ memset(&hw, 0, sizeof(hw));
+ ide_std_init_ports(&hw, io_addr, io_addr + 0x206);
+#ifdef CONFIG_IA64
+ hw.irq = isa_irq_to_vector(legacy_irqs[i]);
+#else
+ hw.irq = legacy_irqs[i];
+#endif
+ hw.chipset = ide_generic;
+
+ rc = ide_host_add(NULL, hws, NULL);
+ if (rc) {
+ release_region(io_addr + 0x206, 1);
+ release_region(io_addr, 8);
+ }
+ }
+ }
+
+ if (ide_generic_sysfs_init())
+ printk(KERN_ERR DRV_NAME ": failed to create ide_generic "
+ "class\n");
+
+ return rc;
+}
+
+module_init(ide_generic_init);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/ide-h8300.c b/drivers/ide/ide-h8300.c
new file mode 100644
index 0000000..e2cdd2e
--- /dev/null
+++ b/drivers/ide/ide-h8300.c
@@ -0,0 +1,217 @@
+/*
+ * H8/300 generic IDE interface
+ */
+
+#include <linux/init.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#define DRV_NAME "ide-h8300"
+
+#define bswap(d) \
+({ \
+ u16 r; \
+ __asm__("mov.b %w1,r1h\n\t" \
+ "mov.b %x1,r1l\n\t" \
+ "mov.w r1,%0" \
+ :"=r"(r) \
+ :"r"(d) \
+ :"er1"); \
+ (r); \
+})
+
+static void mm_outw(u16 d, unsigned long a)
+{
+ __asm__("mov.b %w0,r2h\n\t"
+ "mov.b %x0,r2l\n\t"
+ "mov.w r2,@%1"
+ :
+ :"r"(d),"r"(a)
+ :"er2");
+}
+
+static u16 mm_inw(unsigned long a)
+{
+ register u16 r __asm__("er0");
+ __asm__("mov.w @%1,r2\n\t"
+ "mov.b r2l,%x0\n\t"
+ "mov.b r2h,%w0"
+ :"=r"(r)
+ :"r"(a)
+ :"er2");
+ return r;
+}
+
+static void h8300_tf_load(ide_drive_t *drive, ide_task_t *task)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ struct ide_io_ports *io_ports = &hwif->io_ports;
+ struct ide_taskfile *tf = &task->tf;
+ u8 HIHI = (task->tf_flags & IDE_TFLAG_LBA48) ? 0xE0 : 0xEF;
+
+ if (task->tf_flags & IDE_TFLAG_FLAGGED)
+ HIHI = 0xFF;
+
+ if (task->tf_flags & IDE_TFLAG_OUT_DATA)
+ mm_outw((tf->hob_data << 8) | tf->data, io_ports->data_addr);
+
+ if (task->tf_flags & IDE_TFLAG_OUT_HOB_FEATURE)
+ outb(tf->hob_feature, io_ports->feature_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_HOB_NSECT)
+ outb(tf->hob_nsect, io_ports->nsect_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAL)
+ outb(tf->hob_lbal, io_ports->lbal_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAM)
+ outb(tf->hob_lbam, io_ports->lbam_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAH)
+ outb(tf->hob_lbah, io_ports->lbah_addr);
+
+ if (task->tf_flags & IDE_TFLAG_OUT_FEATURE)
+ outb(tf->feature, io_ports->feature_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_NSECT)
+ outb(tf->nsect, io_ports->nsect_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_LBAL)
+ outb(tf->lbal, io_ports->lbal_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_LBAM)
+ outb(tf->lbam, io_ports->lbam_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_LBAH)
+ outb(tf->lbah, io_ports->lbah_addr);
+
+ if (task->tf_flags & IDE_TFLAG_OUT_DEVICE)
+ outb((tf->device & HIHI) | drive->select,
+ io_ports->device_addr);
+}
+
+static void h8300_tf_read(ide_drive_t *drive, ide_task_t *task)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ struct ide_io_ports *io_ports = &hwif->io_ports;
+ struct ide_taskfile *tf = &task->tf;
+
+ if (task->tf_flags & IDE_TFLAG_IN_DATA) {
+ u16 data = mm_inw(io_ports->data_addr);
+
+ tf->data = data & 0xff;
+ tf->hob_data = (data >> 8) & 0xff;
+ }
+
+ /* be sure we're looking at the low order bits */
+ outb(ATA_DEVCTL_OBS & ~0x80, io_ports->ctl_addr);
+
+ if (task->tf_flags & IDE_TFLAG_IN_FEATURE)
+ tf->feature = inb(io_ports->feature_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_NSECT)
+ tf->nsect = inb(io_ports->nsect_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_LBAL)
+ tf->lbal = inb(io_ports->lbal_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_LBAM)
+ tf->lbam = inb(io_ports->lbam_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_LBAH)
+ tf->lbah = inb(io_ports->lbah_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_DEVICE)
+ tf->device = inb(io_ports->device_addr);
+
+ if (task->tf_flags & IDE_TFLAG_LBA48) {
+ outb(ATA_DEVCTL_OBS | 0x80, io_ports->ctl_addr);
+
+ if (task->tf_flags & IDE_TFLAG_IN_HOB_FEATURE)
+ tf->hob_feature = inb(io_ports->feature_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_HOB_NSECT)
+ tf->hob_nsect = inb(io_ports->nsect_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAL)
+ tf->hob_lbal = inb(io_ports->lbal_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAM)
+ tf->hob_lbam = inb(io_ports->lbam_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAH)
+ tf->hob_lbah = inb(io_ports->lbah_addr);
+ }
+}
+
+static void mm_outsw(unsigned long addr, void *buf, u32 len)
+{
+ unsigned short *bp = (unsigned short *)buf;
+ for (; len > 0; len--, bp++)
+ *(volatile u16 *)addr = bswap(*bp);
+}
+
+static void mm_insw(unsigned long addr, void *buf, u32 len)
+{
+ unsigned short *bp = (unsigned short *)buf;
+ for (; len > 0; len--, bp++)
+ *bp = bswap(*(volatile u16 *)addr);
+}
+
+static void h8300_input_data(ide_drive_t *drive, struct request *rq,
+ void *buf, unsigned int len)
+{
+ mm_insw(drive->hwif->io_ports.data_addr, buf, (len + 1) / 2);
+}
+
+static void h8300_output_data(ide_drive_t *drive, struct request *rq,
+ void *buf, unsigned int len)
+{
+ mm_outsw(drive->hwif->io_ports.data_addr, buf, (len + 1) / 2);
+}
+
+static const struct ide_tp_ops h8300_tp_ops = {
+ .exec_command = ide_exec_command,
+ .read_status = ide_read_status,
+ .read_altstatus = ide_read_altstatus,
+ .read_sff_dma_status = ide_read_sff_dma_status,
+
+ .set_irq = ide_set_irq,
+
+ .tf_load = h8300_tf_load,
+ .tf_read = h8300_tf_read,
+
+ .input_data = h8300_input_data,
+ .output_data = h8300_output_data,
+};
+
+#define H8300_IDE_GAP (2)
+
+static inline void hw_setup(hw_regs_t *hw)
+{
+ int i;
+
+ memset(hw, 0, sizeof(hw_regs_t));
+ for (i = 0; i <= 7; i++)
+ hw->io_ports_array[i] = CONFIG_H8300_IDE_BASE + H8300_IDE_GAP*i;
+ hw->io_ports.ctl_addr = CONFIG_H8300_IDE_ALT;
+ hw->irq = EXT_IRQ0 + CONFIG_H8300_IDE_IRQ;
+ hw->chipset = ide_generic;
+}
+
+static const struct ide_port_info h8300_port_info = {
+ .tp_ops = &h8300_tp_ops,
+ .host_flags = IDE_HFLAG_NO_IO_32BIT | IDE_HFLAG_NO_DMA,
+};
+
+static int __init h8300_ide_init(void)
+{
+ hw_regs_t hw, *hws[] = { &hw, NULL, NULL, NULL };
+
+ printk(KERN_INFO DRV_NAME ": H8/300 generic IDE interface\n");
+
+ if (!request_region(CONFIG_H8300_IDE_BASE, H8300_IDE_GAP*8, "ide-h8300"))
+ goto out_busy;
+ if (!request_region(CONFIG_H8300_IDE_ALT, H8300_IDE_GAP, "ide-h8300")) {
+ release_region(CONFIG_H8300_IDE_BASE, H8300_IDE_GAP*8);
+ goto out_busy;
+ }
+
+ hw_setup(&hw);
+
+ return ide_host_add(&h8300_port_info, hws, NULL);
+
+out_busy:
+ printk(KERN_ERR "ide-h8300: IDE I/F resource already used.\n");
+
+ return -EBUSY;
+}
+
+module_init(h8300_ide_init);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c
new file mode 100644
index 0000000..81f99bd
--- /dev/null
+++ b/drivers/ide/ide-io.c
@@ -0,0 +1,1539 @@
+/*
+ * IDE I/O functions
+ *
+ * Basic PIO and command management functionality.
+ *
+ * This code was split off from ide.c. See ide.c for history and original
+ * copyrights.
+ *
+ * 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.
+ *
+ * For the avoidance of doubt the "preferred form" of this code is one which
+ * is in an open non patent encumbered format. Where cryptographic key signing
+ * forms part of the process of creating an executable the information
+ * including keys needed to generate an equivalently functional executable
+ * are deemed to be part of the source code.
+ */
+
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/major.h>
+#include <linux/errno.h>
+#include <linux/genhd.h>
+#include <linux/blkpg.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/ide.h>
+#include <linux/hdreg.h>
+#include <linux/completion.h>
+#include <linux/reboot.h>
+#include <linux/cdrom.h>
+#include <linux/seq_file.h>
+#include <linux/device.h>
+#include <linux/kmod.h>
+#include <linux/scatterlist.h>
+#include <linux/bitops.h>
+
+#include <asm/byteorder.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+static int __ide_end_request(ide_drive_t *drive, struct request *rq,
+ int uptodate, unsigned int nr_bytes, int dequeue)
+{
+ int ret = 1;
+ int error = 0;
+
+ if (uptodate <= 0)
+ error = uptodate ? uptodate : -EIO;
+
+ /*
+ * if failfast is set on a request, override number of sectors and
+ * complete the whole request right now
+ */
+ if (blk_noretry_request(rq) && error)
+ nr_bytes = rq->hard_nr_sectors << 9;
+
+ if (!blk_fs_request(rq) && error && !rq->errors)
+ rq->errors = -EIO;
+
+ /*
+ * decide whether to reenable DMA -- 3 is a random magic for now,
+ * if we DMA timeout more than 3 times, just stay in PIO
+ */
+ if ((drive->dev_flags & IDE_DFLAG_DMA_PIO_RETRY) &&
+ drive->retry_pio <= 3) {
+ drive->dev_flags &= ~IDE_DFLAG_DMA_PIO_RETRY;
+ ide_dma_on(drive);
+ }
+
+ if (!__blk_end_request(rq, error, nr_bytes)) {
+ if (dequeue)
+ HWGROUP(drive)->rq = NULL;
+ ret = 0;
+ }
+
+ return ret;
+}
+
+/**
+ * ide_end_request - complete an IDE I/O
+ * @drive: IDE device for the I/O
+ * @uptodate:
+ * @nr_sectors: number of sectors completed
+ *
+ * This is our end_request wrapper function. We complete the I/O
+ * update random number input and dequeue the request, which if
+ * it was tagged may be out of order.
+ */
+
+int ide_end_request (ide_drive_t *drive, int uptodate, int nr_sectors)
+{
+ unsigned int nr_bytes = nr_sectors << 9;
+ struct request *rq;
+ unsigned long flags;
+ int ret = 1;
+
+ /*
+ * room for locking improvements here, the calls below don't
+ * need the queue lock held at all
+ */
+ spin_lock_irqsave(&ide_lock, flags);
+ rq = HWGROUP(drive)->rq;
+
+ if (!nr_bytes) {
+ if (blk_pc_request(rq))
+ nr_bytes = rq->data_len;
+ else
+ nr_bytes = rq->hard_cur_sectors << 9;
+ }
+
+ ret = __ide_end_request(drive, rq, uptodate, nr_bytes, 1);
+
+ spin_unlock_irqrestore(&ide_lock, flags);
+ return ret;
+}
+EXPORT_SYMBOL(ide_end_request);
+
+static void ide_complete_power_step(ide_drive_t *drive, struct request *rq)
+{
+ struct request_pm_state *pm = rq->data;
+
+#ifdef DEBUG_PM
+ printk(KERN_INFO "%s: complete_power_step(step: %d)\n",
+ drive->name, pm->pm_step);
+#endif
+ if (drive->media != ide_disk)
+ return;
+
+ switch (pm->pm_step) {
+ case IDE_PM_FLUSH_CACHE: /* Suspend step 1 (flush cache) */
+ if (pm->pm_state == PM_EVENT_FREEZE)
+ pm->pm_step = IDE_PM_COMPLETED;
+ else
+ pm->pm_step = IDE_PM_STANDBY;
+ break;
+ case IDE_PM_STANDBY: /* Suspend step 2 (standby) */
+ pm->pm_step = IDE_PM_COMPLETED;
+ break;
+ case IDE_PM_RESTORE_PIO: /* Resume step 1 (restore PIO) */
+ pm->pm_step = IDE_PM_IDLE;
+ break;
+ case IDE_PM_IDLE: /* Resume step 2 (idle)*/
+ pm->pm_step = IDE_PM_RESTORE_DMA;
+ break;
+ }
+}
+
+static ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request *rq)
+{
+ struct request_pm_state *pm = rq->data;
+ ide_task_t *args = rq->special;
+
+ memset(args, 0, sizeof(*args));
+
+ switch (pm->pm_step) {
+ case IDE_PM_FLUSH_CACHE: /* Suspend step 1 (flush cache) */
+ if (drive->media != ide_disk)
+ break;
+ /* Not supported? Switch to next step now. */
+ if (ata_id_flush_enabled(drive->id) == 0 ||
+ (drive->dev_flags & IDE_DFLAG_WCACHE) == 0) {
+ ide_complete_power_step(drive, rq);
+ return ide_stopped;
+ }
+ if (ata_id_flush_ext_enabled(drive->id))
+ args->tf.command = ATA_CMD_FLUSH_EXT;
+ else
+ args->tf.command = ATA_CMD_FLUSH;
+ goto out_do_tf;
+ case IDE_PM_STANDBY: /* Suspend step 2 (standby) */
+ args->tf.command = ATA_CMD_STANDBYNOW1;
+ goto out_do_tf;
+ case IDE_PM_RESTORE_PIO: /* Resume step 1 (restore PIO) */
+ ide_set_max_pio(drive);
+ /*
+ * skip IDE_PM_IDLE for ATAPI devices
+ */
+ if (drive->media != ide_disk)
+ pm->pm_step = IDE_PM_RESTORE_DMA;
+ else
+ ide_complete_power_step(drive, rq);
+ return ide_stopped;
+ case IDE_PM_IDLE: /* Resume step 2 (idle) */
+ args->tf.command = ATA_CMD_IDLEIMMEDIATE;
+ goto out_do_tf;
+ case IDE_PM_RESTORE_DMA: /* Resume step 3 (restore DMA) */
+ /*
+ * Right now, all we do is call ide_set_dma(drive),
+ * we could be smarter and check for current xfer_speed
+ * in struct drive etc...
+ */
+ if (drive->hwif->dma_ops == NULL)
+ break;
+ /*
+ * TODO: respect IDE_DFLAG_USING_DMA
+ */
+ ide_set_dma(drive);
+ break;
+ }
+
+ pm->pm_step = IDE_PM_COMPLETED;
+ return ide_stopped;
+
+out_do_tf:
+ args->tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
+ args->data_phase = TASKFILE_NO_DATA;
+ return do_rw_taskfile(drive, args);
+}
+
+/**
+ * ide_end_dequeued_request - complete an IDE I/O
+ * @drive: IDE device for the I/O
+ * @uptodate:
+ * @nr_sectors: number of sectors completed
+ *
+ * Complete an I/O that is no longer on the request queue. This
+ * typically occurs when we pull the request and issue a REQUEST_SENSE.
+ * We must still finish the old request but we must not tamper with the
+ * queue in the meantime.
+ *
+ * NOTE: This path does not handle barrier, but barrier is not supported
+ * on ide-cd anyway.
+ */
+
+int ide_end_dequeued_request(ide_drive_t *drive, struct request *rq,
+ int uptodate, int nr_sectors)
+{
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&ide_lock, flags);
+ BUG_ON(!blk_rq_started(rq));
+ ret = __ide_end_request(drive, rq, uptodate, nr_sectors << 9, 0);
+ spin_unlock_irqrestore(&ide_lock, flags);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(ide_end_dequeued_request);
+
+
+/**
+ * ide_complete_pm_request - end the current Power Management request
+ * @drive: target drive
+ * @rq: request
+ *
+ * This function cleans up the current PM request and stops the queue
+ * if necessary.
+ */
+static void ide_complete_pm_request (ide_drive_t *drive, struct request *rq)
+{
+ unsigned long flags;
+
+#ifdef DEBUG_PM
+ printk("%s: completing PM request, %s\n", drive->name,
+ blk_pm_suspend_request(rq) ? "suspend" : "resume");
+#endif
+ spin_lock_irqsave(&ide_lock, flags);
+ if (blk_pm_suspend_request(rq)) {
+ blk_stop_queue(drive->queue);
+ } else {
+ drive->dev_flags &= ~IDE_DFLAG_BLOCKED;
+ blk_start_queue(drive->queue);
+ }
+ HWGROUP(drive)->rq = NULL;
+ if (__blk_end_request(rq, 0, 0))
+ BUG();
+ spin_unlock_irqrestore(&ide_lock, flags);
+}
+
+/**
+ * ide_end_drive_cmd - end an explicit drive command
+ * @drive: command
+ * @stat: status bits
+ * @err: error bits
+ *
+ * Clean up after success/failure of an explicit drive command.
+ * These get thrown onto the queue so they are synchronized with
+ * real I/O operations on the drive.
+ *
+ * In LBA48 mode we have to read the register set twice to get
+ * all the extra information out.
+ */
+
+void ide_end_drive_cmd (ide_drive_t *drive, u8 stat, u8 err)
+{
+ unsigned long flags;
+ struct request *rq;
+
+ spin_lock_irqsave(&ide_lock, flags);
+ rq = HWGROUP(drive)->rq;
+ spin_unlock_irqrestore(&ide_lock, flags);
+
+ if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) {
+ ide_task_t *task = (ide_task_t *)rq->special;
+
+ if (rq->errors == 0)
+ rq->errors = !OK_STAT(stat, ATA_DRDY, BAD_STAT);
+
+ if (task) {
+ struct ide_taskfile *tf = &task->tf;
+
+ tf->error = err;
+ tf->status = stat;
+
+ drive->hwif->tp_ops->tf_read(drive, task);
+
+ if (task->tf_flags & IDE_TFLAG_DYN)
+ kfree(task);
+ }
+ } else if (blk_pm_request(rq)) {
+ struct request_pm_state *pm = rq->data;
+
+ ide_complete_power_step(drive, rq);
+ if (pm->pm_step == IDE_PM_COMPLETED)
+ ide_complete_pm_request(drive, rq);
+ return;
+ }
+
+ spin_lock_irqsave(&ide_lock, flags);
+ HWGROUP(drive)->rq = NULL;
+ rq->errors = err;
+ if (unlikely(__blk_end_request(rq, (rq->errors ? -EIO : 0),
+ blk_rq_bytes(rq))))
+ BUG();
+ spin_unlock_irqrestore(&ide_lock, flags);
+}
+
+EXPORT_SYMBOL(ide_end_drive_cmd);
+
+static void ide_kill_rq(ide_drive_t *drive, struct request *rq)
+{
+ if (rq->rq_disk) {
+ ide_driver_t *drv;
+
+ drv = *(ide_driver_t **)rq->rq_disk->private_data;
+ drv->end_request(drive, 0, 0);
+ } else
+ ide_end_request(drive, 0, 0);
+}
+
+static ide_startstop_t ide_ata_error(ide_drive_t *drive, struct request *rq, u8 stat, u8 err)
+{
+ ide_hwif_t *hwif = drive->hwif;
+
+ if ((stat & ATA_BUSY) ||
+ ((stat & ATA_DF) && (drive->dev_flags & IDE_DFLAG_NOWERR) == 0)) {
+ /* other bits are useless when BUSY */
+ rq->errors |= ERROR_RESET;
+ } else if (stat & ATA_ERR) {
+ /* err has different meaning on cdrom and tape */
+ if (err == ATA_ABORTED) {
+ if ((drive->dev_flags & IDE_DFLAG_LBA) &&
+ /* some newer drives don't support ATA_CMD_INIT_DEV_PARAMS */
+ hwif->tp_ops->read_status(hwif) == ATA_CMD_INIT_DEV_PARAMS)
+ return ide_stopped;
+ } else if ((err & BAD_CRC) == BAD_CRC) {
+ /* UDMA crc error, just retry the operation */
+ drive->crc_count++;
+ } else if (err & (ATA_BBK | ATA_UNC)) {
+ /* retries won't help these */
+ rq->errors = ERROR_MAX;
+ } else if (err & ATA_TRK0NF) {
+ /* help it find track zero */
+ rq->errors |= ERROR_RECAL;
+ }
+ }
+
+ if ((stat & ATA_DRQ) && rq_data_dir(rq) == READ &&
+ (hwif->host_flags & IDE_HFLAG_ERROR_STOPS_FIFO) == 0) {
+ int nsect = drive->mult_count ? drive->mult_count : 1;
+
+ ide_pad_transfer(drive, READ, nsect * SECTOR_SIZE);
+ }
+
+ if (rq->errors >= ERROR_MAX || blk_noretry_request(rq)) {
+ ide_kill_rq(drive, rq);
+ return ide_stopped;
+ }
+
+ if (hwif->tp_ops->read_status(hwif) & (ATA_BUSY | ATA_DRQ))
+ rq->errors |= ERROR_RESET;
+
+ if ((rq->errors & ERROR_RESET) == ERROR_RESET) {
+ ++rq->errors;
+ return ide_do_reset(drive);
+ }
+
+ if ((rq->errors & ERROR_RECAL) == ERROR_RECAL)
+ drive->special.b.recalibrate = 1;
+
+ ++rq->errors;
+
+ return ide_stopped;
+}
+
+static ide_startstop_t ide_atapi_error(ide_drive_t *drive, struct request *rq, u8 stat, u8 err)
+{
+ ide_hwif_t *hwif = drive->hwif;
+
+ if ((stat & ATA_BUSY) ||
+ ((stat & ATA_DF) && (drive->dev_flags & IDE_DFLAG_NOWERR) == 0)) {
+ /* other bits are useless when BUSY */
+ rq->errors |= ERROR_RESET;
+ } else {
+ /* add decoding error stuff */
+ }
+
+ if (hwif->tp_ops->read_status(hwif) & (ATA_BUSY | ATA_DRQ))
+ /* force an abort */
+ hwif->tp_ops->exec_command(hwif, ATA_CMD_IDLEIMMEDIATE);
+
+ if (rq->errors >= ERROR_MAX) {
+ ide_kill_rq(drive, rq);
+ } else {
+ if ((rq->errors & ERROR_RESET) == ERROR_RESET) {
+ ++rq->errors;
+ return ide_do_reset(drive);
+ }
+ ++rq->errors;
+ }
+
+ return ide_stopped;
+}
+
+ide_startstop_t
+__ide_error(ide_drive_t *drive, struct request *rq, u8 stat, u8 err)
+{
+ if (drive->media == ide_disk)
+ return ide_ata_error(drive, rq, stat, err);
+ return ide_atapi_error(drive, rq, stat, err);
+}
+
+EXPORT_SYMBOL_GPL(__ide_error);
+
+/**
+ * ide_error - handle an error on the IDE
+ * @drive: drive the error occurred on
+ * @msg: message to report
+ * @stat: status bits
+ *
+ * ide_error() takes action based on the error returned by the drive.
+ * For normal I/O that may well include retries. We deal with
+ * both new-style (taskfile) and old style command handling here.
+ * In the case of taskfile command handling there is work left to
+ * do
+ */
+
+ide_startstop_t ide_error (ide_drive_t *drive, const char *msg, u8 stat)
+{
+ struct request *rq;
+ u8 err;
+
+ err = ide_dump_status(drive, msg, stat);
+
+ if ((rq = HWGROUP(drive)->rq) == NULL)
+ return ide_stopped;
+
+ /* retry only "normal" I/O: */
+ if (!blk_fs_request(rq)) {
+ rq->errors = 1;
+ ide_end_drive_cmd(drive, stat, err);
+ return ide_stopped;
+ }
+
+ if (rq->rq_disk) {
+ ide_driver_t *drv;
+
+ drv = *(ide_driver_t **)rq->rq_disk->private_data;
+ return drv->error(drive, rq, stat, err);
+ } else
+ return __ide_error(drive, rq, stat, err);
+}
+
+EXPORT_SYMBOL_GPL(ide_error);
+
+static void ide_tf_set_specify_cmd(ide_drive_t *drive, struct ide_taskfile *tf)
+{
+ tf->nsect = drive->sect;
+ tf->lbal = drive->sect;
+ tf->lbam = drive->cyl;
+ tf->lbah = drive->cyl >> 8;
+ tf->device = (drive->head - 1) | drive->select;
+ tf->command = ATA_CMD_INIT_DEV_PARAMS;
+}
+
+static void ide_tf_set_restore_cmd(ide_drive_t *drive, struct ide_taskfile *tf)
+{
+ tf->nsect = drive->sect;
+ tf->command = ATA_CMD_RESTORE;
+}
+
+static void ide_tf_set_setmult_cmd(ide_drive_t *drive, struct ide_taskfile *tf)
+{
+ tf->nsect = drive->mult_req;
+ tf->command = ATA_CMD_SET_MULTI;
+}
+
+static ide_startstop_t ide_disk_special(ide_drive_t *drive)
+{
+ special_t *s = &drive->special;
+ ide_task_t args;
+
+ memset(&args, 0, sizeof(ide_task_t));
+ args.data_phase = TASKFILE_NO_DATA;
+
+ if (s->b.set_geometry) {
+ s->b.set_geometry = 0;
+ ide_tf_set_specify_cmd(drive, &args.tf);
+ } else if (s->b.recalibrate) {
+ s->b.recalibrate = 0;
+ ide_tf_set_restore_cmd(drive, &args.tf);
+ } else if (s->b.set_multmode) {
+ s->b.set_multmode = 0;
+ ide_tf_set_setmult_cmd(drive, &args.tf);
+ } else if (s->all) {
+ int special = s->all;
+ s->all = 0;
+ printk(KERN_ERR "%s: bad special flag: 0x%02x\n", drive->name, special);
+ return ide_stopped;
+ }
+
+ args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE |
+ IDE_TFLAG_CUSTOM_HANDLER;
+
+ do_rw_taskfile(drive, &args);
+
+ return ide_started;
+}
+
+/**
+ * do_special - issue some special commands
+ * @drive: drive the command is for
+ *
+ * do_special() is used to issue ATA_CMD_INIT_DEV_PARAMS,
+ * ATA_CMD_RESTORE and ATA_CMD_SET_MULTI commands to a drive.
+ *
+ * It used to do much more, but has been scaled back.
+ */
+
+static ide_startstop_t do_special (ide_drive_t *drive)
+{
+ special_t *s = &drive->special;
+
+#ifdef DEBUG
+ printk("%s: do_special: 0x%02x\n", drive->name, s->all);
+#endif
+ if (drive->media == ide_disk)
+ return ide_disk_special(drive);
+
+ s->all = 0;
+ drive->mult_req = 0;
+ return ide_stopped;
+}
+
+void ide_map_sg(ide_drive_t *drive, struct request *rq)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ struct scatterlist *sg = hwif->sg_table;
+
+ if (hwif->sg_mapped) /* needed by ide-scsi */
+ return;
+
+ if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) {
+ sg_init_one(sg, rq->buffer, rq->nr_sectors * SECTOR_SIZE);
+ hwif->sg_nents = 1;
+ } else if (!rq->bio) {
+ sg_init_one(sg, rq->data, rq->data_len);
+ hwif->sg_nents = 1;
+ } else {
+ hwif->sg_nents = blk_rq_map_sg(drive->queue, rq, sg);
+ }
+}
+
+EXPORT_SYMBOL_GPL(ide_map_sg);
+
+void ide_init_sg_cmd(ide_drive_t *drive, struct request *rq)
+{
+ ide_hwif_t *hwif = drive->hwif;
+
+ hwif->nsect = hwif->nleft = rq->nr_sectors;
+ hwif->cursg_ofs = 0;
+ hwif->cursg = NULL;
+}
+
+EXPORT_SYMBOL_GPL(ide_init_sg_cmd);
+
+/**
+ * execute_drive_command - issue special drive command
+ * @drive: the drive to issue the command on
+ * @rq: the request structure holding the command
+ *
+ * execute_drive_cmd() issues a special drive command, usually
+ * initiated by ioctl() from the external hdparm program. The
+ * command can be a drive command, drive task or taskfile
+ * operation. Weirdly you can call it with NULL to wait for
+ * all commands to finish. Don't do this as that is due to change
+ */
+
+static ide_startstop_t execute_drive_cmd (ide_drive_t *drive,
+ struct request *rq)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ ide_task_t *task = rq->special;
+
+ if (task) {
+ hwif->data_phase = task->data_phase;
+
+ switch (hwif->data_phase) {
+ case TASKFILE_MULTI_OUT:
+ case TASKFILE_OUT:
+ case TASKFILE_MULTI_IN:
+ case TASKFILE_IN:
+ ide_init_sg_cmd(drive, rq);
+ ide_map_sg(drive, rq);
+ default:
+ break;
+ }
+
+ return do_rw_taskfile(drive, task);
+ }
+
+ /*
+ * NULL is actually a valid way of waiting for
+ * all current requests to be flushed from the queue.
+ */
+#ifdef DEBUG
+ printk("%s: DRIVE_CMD (null)\n", drive->name);
+#endif
+ ide_end_drive_cmd(drive, hwif->tp_ops->read_status(hwif),
+ ide_read_error(drive));
+
+ return ide_stopped;
+}
+
+int ide_devset_execute(ide_drive_t *drive, const struct ide_devset *setting,
+ int arg)
+{
+ struct request_queue *q = drive->queue;
+ struct request *rq;
+ int ret = 0;
+
+ if (!(setting->flags & DS_SYNC))
+ return setting->set(drive, arg);
+
+ rq = blk_get_request(q, READ, __GFP_WAIT);
+ rq->cmd_type = REQ_TYPE_SPECIAL;
+ rq->cmd_len = 5;
+ rq->cmd[0] = REQ_DEVSET_EXEC;
+ *(int *)&rq->cmd[1] = arg;
+ rq->special = setting->set;
+
+ if (blk_execute_rq(q, NULL, rq, 0))
+ ret = rq->errors;
+ blk_put_request(rq);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(ide_devset_execute);
+
+static ide_startstop_t ide_special_rq(ide_drive_t *drive, struct request *rq)
+{
+ u8 cmd = rq->cmd[0];
+
+ if (cmd == REQ_PARK_HEADS || cmd == REQ_UNPARK_HEADS) {
+ ide_task_t task;
+ struct ide_taskfile *tf = &task.tf;
+
+ memset(&task, 0, sizeof(task));
+ if (cmd == REQ_PARK_HEADS) {
+ drive->sleep = *(unsigned long *)rq->special;
+ drive->dev_flags |= IDE_DFLAG_SLEEPING;
+ tf->command = ATA_CMD_IDLEIMMEDIATE;
+ tf->feature = 0x44;
+ tf->lbal = 0x4c;
+ tf->lbam = 0x4e;
+ tf->lbah = 0x55;
+ task.tf_flags |= IDE_TFLAG_CUSTOM_HANDLER;
+ } else /* cmd == REQ_UNPARK_HEADS */
+ tf->command = ATA_CMD_CHK_POWER;
+
+ task.tf_flags |= IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
+ task.rq = rq;
+ drive->hwif->data_phase = task.data_phase = TASKFILE_NO_DATA;
+ return do_rw_taskfile(drive, &task);
+ }
+
+ switch (cmd) {
+ case REQ_DEVSET_EXEC:
+ {
+ int err, (*setfunc)(ide_drive_t *, int) = rq->special;
+
+ err = setfunc(drive, *(int *)&rq->cmd[1]);
+ if (err)
+ rq->errors = err;
+ else
+ err = 1;
+ ide_end_request(drive, err, 0);
+ return ide_stopped;
+ }
+ case REQ_DRIVE_RESET:
+ return ide_do_reset(drive);
+ default:
+ blk_dump_rq_flags(rq, "ide_special_rq - bad request");
+ ide_end_request(drive, 0, 0);
+ return ide_stopped;
+ }
+}
+
+static void ide_check_pm_state(ide_drive_t *drive, struct request *rq)
+{
+ struct request_pm_state *pm = rq->data;
+
+ if (blk_pm_suspend_request(rq) &&
+ pm->pm_step == IDE_PM_START_SUSPEND)
+ /* Mark drive blocked when starting the suspend sequence. */
+ drive->dev_flags |= IDE_DFLAG_BLOCKED;
+ else if (blk_pm_resume_request(rq) &&
+ pm->pm_step == IDE_PM_START_RESUME) {
+ /*
+ * The first thing we do on wakeup is to wait for BSY bit to
+ * go away (with a looong timeout) as a drive on this hwif may
+ * just be POSTing itself.
+ * We do that before even selecting as the "other" device on
+ * the bus may be broken enough to walk on our toes at this
+ * point.
+ */
+ ide_hwif_t *hwif = drive->hwif;
+ int rc;
+#ifdef DEBUG_PM
+ printk("%s: Wakeup request inited, waiting for !BSY...\n", drive->name);
+#endif
+ rc = ide_wait_not_busy(hwif, 35000);
+ if (rc)
+ printk(KERN_WARNING "%s: bus not ready on wakeup\n", drive->name);
+ SELECT_DRIVE(drive);
+ hwif->tp_ops->set_irq(hwif, 1);
+ rc = ide_wait_not_busy(hwif, 100000);
+ if (rc)
+ printk(KERN_WARNING "%s: drive not ready on wakeup\n", drive->name);
+ }
+}
+
+/**
+ * start_request - start of I/O and command issuing for IDE
+ *
+ * start_request() initiates handling of a new I/O request. It
+ * accepts commands and I/O (read/write) requests.
+ *
+ * FIXME: this function needs a rename
+ */
+
+static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq)
+{
+ ide_startstop_t startstop;
+
+ BUG_ON(!blk_rq_started(rq));
+
+#ifdef DEBUG
+ printk("%s: start_request: current=0x%08lx\n",
+ HWIF(drive)->name, (unsigned long) rq);
+#endif
+
+ /* bail early if we've exceeded max_failures */
+ if (drive->max_failures && (drive->failures > drive->max_failures)) {
+ rq->cmd_flags |= REQ_FAILED;
+ goto kill_rq;
+ }
+
+ if (blk_pm_request(rq))
+ ide_check_pm_state(drive, rq);
+
+ SELECT_DRIVE(drive);
+ if (ide_wait_stat(&startstop, drive, drive->ready_stat,
+ ATA_BUSY | ATA_DRQ, WAIT_READY)) {
+ printk(KERN_ERR "%s: drive not ready for command\n", drive->name);
+ return startstop;
+ }
+ if (!drive->special.all) {
+ ide_driver_t *drv;
+
+ /*
+ * We reset the drive so we need to issue a SETFEATURES.
+ * Do it _after_ do_special() restored device parameters.
+ */
+ if (drive->current_speed == 0xff)
+ ide_config_drive_speed(drive, drive->desired_speed);
+
+ if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE)
+ return execute_drive_cmd(drive, rq);
+ else if (blk_pm_request(rq)) {
+ struct request_pm_state *pm = rq->data;
+#ifdef DEBUG_PM
+ printk("%s: start_power_step(step: %d)\n",
+ drive->name, pm->pm_step);
+#endif
+ startstop = ide_start_power_step(drive, rq);
+ if (startstop == ide_stopped &&
+ pm->pm_step == IDE_PM_COMPLETED)
+ ide_complete_pm_request(drive, rq);
+ return startstop;
+ } else if (!rq->rq_disk && blk_special_request(rq))
+ /*
+ * TODO: Once all ULDs have been modified to
+ * check for specific op codes rather than
+ * blindly accepting any special request, the
+ * check for ->rq_disk above may be replaced
+ * by a more suitable mechanism or even
+ * dropped entirely.
+ */
+ return ide_special_rq(drive, rq);
+
+ drv = *(ide_driver_t **)rq->rq_disk->private_data;
+
+ return drv->do_request(drive, rq, rq->sector);
+ }
+ return do_special(drive);
+kill_rq:
+ ide_kill_rq(drive, rq);
+ return ide_stopped;
+}
+
+/**
+ * ide_stall_queue - pause an IDE device
+ * @drive: drive to stall
+ * @timeout: time to stall for (jiffies)
+ *
+ * ide_stall_queue() can be used by a drive to give excess bandwidth back
+ * to the hwgroup by sleeping for timeout jiffies.
+ */
+
+void ide_stall_queue (ide_drive_t *drive, unsigned long timeout)
+{
+ if (timeout > WAIT_WORSTCASE)
+ timeout = WAIT_WORSTCASE;
+ drive->sleep = timeout + jiffies;
+ drive->dev_flags |= IDE_DFLAG_SLEEPING;
+}
+
+EXPORT_SYMBOL(ide_stall_queue);
+
+#define WAKEUP(drive) ((drive)->service_start + 2 * (drive)->service_time)
+
+/**
+ * choose_drive - select a drive to service
+ * @hwgroup: hardware group to select on
+ *
+ * choose_drive() selects the next drive which will be serviced.
+ * This is necessary because the IDE layer can't issue commands
+ * to both drives on the same cable, unlike SCSI.
+ */
+
+static inline ide_drive_t *choose_drive (ide_hwgroup_t *hwgroup)
+{
+ ide_drive_t *drive, *best;
+
+repeat:
+ best = NULL;
+ drive = hwgroup->drive;
+
+ /*
+ * drive is doing pre-flush, ordered write, post-flush sequence. even
+ * though that is 3 requests, it must be seen as a single transaction.
+ * we must not preempt this drive until that is complete
+ */
+ if (blk_queue_flushing(drive->queue)) {
+ /*
+ * small race where queue could get replugged during
+ * the 3-request flush cycle, just yank the plug since
+ * we want it to finish asap
+ */
+ blk_remove_plug(drive->queue);
+ return drive;
+ }
+
+ do {
+ u8 dev_s = !!(drive->dev_flags & IDE_DFLAG_SLEEPING);
+ u8 best_s = (best && !!(best->dev_flags & IDE_DFLAG_SLEEPING));
+
+ if ((dev_s == 0 || time_after_eq(jiffies, drive->sleep)) &&
+ !elv_queue_empty(drive->queue)) {
+ if (best == NULL ||
+ (dev_s && (best_s == 0 || time_before(drive->sleep, best->sleep))) ||
+ (best_s == 0 && time_before(WAKEUP(drive), WAKEUP(best)))) {
+ if (!blk_queue_plugged(drive->queue))
+ best = drive;
+ }
+ }
+ } while ((drive = drive->next) != hwgroup->drive);
+
+ if (best && (best->dev_flags & IDE_DFLAG_NICE1) &&
+ (best->dev_flags & IDE_DFLAG_SLEEPING) == 0 &&
+ best != hwgroup->drive && best->service_time > WAIT_MIN_SLEEP) {
+ long t = (signed long)(WAKEUP(best) - jiffies);
+ if (t >= WAIT_MIN_SLEEP) {
+ /*
+ * We *may* have some time to spare, but first let's see if
+ * someone can potentially benefit from our nice mood today..
+ */
+ drive = best->next;
+ do {
+ if ((drive->dev_flags & IDE_DFLAG_SLEEPING) == 0
+ && time_before(jiffies - best->service_time, WAKEUP(drive))
+ && time_before(WAKEUP(drive), jiffies + t))
+ {
+ ide_stall_queue(best, min_t(long, t, 10 * WAIT_MIN_SLEEP));
+ goto repeat;
+ }
+ } while ((drive = drive->next) != best);
+ }
+ }
+ return best;
+}
+
+/*
+ * Issue a new request to a drive from hwgroup
+ * Caller must have already done spin_lock_irqsave(&ide_lock, ..);
+ *
+ * A hwgroup is a serialized group of IDE interfaces. Usually there is
+ * exactly one hwif (interface) per hwgroup, but buggy controllers (eg. CMD640)
+ * may have both interfaces in a single hwgroup to "serialize" access.
+ * Or possibly multiple ISA interfaces can share a common IRQ by being grouped
+ * together into one hwgroup for serialized access.
+ *
+ * Note also that several hwgroups can end up sharing a single IRQ,
+ * possibly along with many other devices. This is especially common in
+ * PCI-based systems with off-board IDE controller cards.
+ *
+ * The IDE driver uses the single global ide_lock spinlock to protect
+ * access to the request queues, and to protect the hwgroup->busy flag.
+ *
+ * The first thread into the driver for a particular hwgroup sets the
+ * hwgroup->busy flag to indicate that this hwgroup is now active,
+ * and then initiates processing of the top request from the request queue.
+ *
+ * Other threads attempting entry notice the busy setting, and will simply
+ * queue their new requests and exit immediately. Note that hwgroup->busy
+ * remains set even when the driver is merely awaiting the next interrupt.
+ * Thus, the meaning is "this hwgroup is busy processing a request".
+ *
+ * When processing of a request completes, the completing thread or IRQ-handler
+ * will start the next request from the queue. If no more work remains,
+ * the driver will clear the hwgroup->busy flag and exit.
+ *
+ * The ide_lock (spinlock) is used to protect all access to the
+ * hwgroup->busy flag, but is otherwise not needed for most processing in
+ * the driver. This makes the driver much more friendlier to shared IRQs
+ * than previous designs, while remaining 100% (?) SMP safe and capable.
+ */
+static void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq)
+{
+ ide_drive_t *drive;
+ ide_hwif_t *hwif;
+ struct request *rq;
+ ide_startstop_t startstop;
+ int loops = 0;
+
+ /* caller must own ide_lock */
+ BUG_ON(!irqs_disabled());
+
+ while (!hwgroup->busy) {
+ hwgroup->busy = 1;
+ /* for atari only */
+ ide_get_lock(ide_intr, hwgroup);
+ drive = choose_drive(hwgroup);
+ if (drive == NULL) {
+ int sleeping = 0;
+ unsigned long sleep = 0; /* shut up, gcc */
+ hwgroup->rq = NULL;
+ drive = hwgroup->drive;
+ do {
+ if ((drive->dev_flags & IDE_DFLAG_SLEEPING) &&
+ (sleeping == 0 ||
+ time_before(drive->sleep, sleep))) {
+ sleeping = 1;
+ sleep = drive->sleep;
+ }
+ } while ((drive = drive->next) != hwgroup->drive);
+ if (sleeping) {
+ /*
+ * Take a short snooze, and then wake up this hwgroup again.
+ * This gives other hwgroups on the same a chance to
+ * play fairly with us, just in case there are big differences
+ * in relative throughputs.. don't want to hog the cpu too much.
+ */
+ if (time_before(sleep, jiffies + WAIT_MIN_SLEEP))
+ sleep = jiffies + WAIT_MIN_SLEEP;
+#if 1
+ if (timer_pending(&hwgroup->timer))
+ printk(KERN_CRIT "ide_set_handler: timer already active\n");
+#endif
+ /* so that ide_timer_expiry knows what to do */
+ hwgroup->sleeping = 1;
+ hwgroup->req_gen_timer = hwgroup->req_gen;
+ mod_timer(&hwgroup->timer, sleep);
+ /* we purposely leave hwgroup->busy==1
+ * while sleeping */
+ } else {
+ /* Ugly, but how can we sleep for the lock
+ * otherwise? perhaps from tq_disk?
+ */
+
+ /* for atari only */
+ ide_release_lock();
+ hwgroup->busy = 0;
+ }
+
+ /* no more work for this hwgroup (for now) */
+ return;
+ }
+ again:
+ hwif = HWIF(drive);
+ if (hwgroup->hwif->sharing_irq && hwif != hwgroup->hwif) {
+ /*
+ * set nIEN for previous hwif, drives in the
+ * quirk_list may not like intr setups/cleanups
+ */
+ if (drive->quirk_list != 1)
+ hwif->tp_ops->set_irq(hwif, 0);
+ }
+ hwgroup->hwif = hwif;
+ hwgroup->drive = drive;
+ drive->dev_flags &= ~(IDE_DFLAG_SLEEPING | IDE_DFLAG_PARKED);
+ drive->service_start = jiffies;
+
+ if (blk_queue_plugged(drive->queue)) {
+ printk(KERN_ERR "ide: huh? queue was plugged!\n");
+ break;
+ }
+
+ /*
+ * we know that the queue isn't empty, but this can happen
+ * if the q->prep_rq_fn() decides to kill a request
+ */
+ rq = elv_next_request(drive->queue);
+ if (!rq) {
+ hwgroup->busy = 0;
+ break;
+ }
+
+ /*
+ * Sanity: don't accept a request that isn't a PM request
+ * if we are currently power managed. This is very important as
+ * blk_stop_queue() doesn't prevent the elv_next_request()
+ * above to return us whatever is in the queue. Since we call
+ * ide_do_request() ourselves, we end up taking requests while
+ * the queue is blocked...
+ *
+ * We let requests forced at head of queue with ide-preempt
+ * though. I hope that doesn't happen too much, hopefully not
+ * unless the subdriver triggers such a thing in its own PM
+ * state machine.
+ *
+ * We count how many times we loop here to make sure we service
+ * all drives in the hwgroup without looping for ever
+ */
+ if ((drive->dev_flags & IDE_DFLAG_BLOCKED) &&
+ blk_pm_request(rq) == 0 &&
+ (rq->cmd_flags & REQ_PREEMPT) == 0) {
+ drive = drive->next ? drive->next : hwgroup->drive;
+ if (loops++ < 4 && !blk_queue_plugged(drive->queue))
+ goto again;
+ /* We clear busy, there should be no pending ATA command at this point. */
+ hwgroup->busy = 0;
+ break;
+ }
+
+ hwgroup->rq = rq;
+
+ /*
+ * Some systems have trouble with IDE IRQs arriving while
+ * the driver is still setting things up. So, here we disable
+ * the IRQ used by this interface while the request is being started.
+ * This may look bad at first, but pretty much the same thing
+ * happens anyway when any interrupt comes in, IDE or otherwise
+ * -- the kernel masks the IRQ while it is being handled.
+ */
+ if (masked_irq != IDE_NO_IRQ && hwif->irq != masked_irq)
+ disable_irq_nosync(hwif->irq);
+ spin_unlock(&ide_lock);
+ local_irq_enable_in_hardirq();
+ /* allow other IRQs while we start this request */
+ startstop = start_request(drive, rq);
+ spin_lock_irq(&ide_lock);
+ if (masked_irq != IDE_NO_IRQ && hwif->irq != masked_irq)
+ enable_irq(hwif->irq);
+ if (startstop == ide_stopped)
+ hwgroup->busy = 0;
+ }
+}
+
+/*
+ * Passes the stuff to ide_do_request
+ */
+void do_ide_request(struct request_queue *q)
+{
+ ide_drive_t *drive = q->queuedata;
+
+ ide_do_request(HWGROUP(drive), IDE_NO_IRQ);
+}
+
+/*
+ * un-busy the hwgroup etc, and clear any pending DMA status. we want to
+ * retry the current request in pio mode instead of risking tossing it
+ * all away
+ */
+static ide_startstop_t ide_dma_timeout_retry(ide_drive_t *drive, int error)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct request *rq;
+ ide_startstop_t ret = ide_stopped;
+
+ /*
+ * end current dma transaction
+ */
+
+ if (error < 0) {
+ printk(KERN_WARNING "%s: DMA timeout error\n", drive->name);
+ (void)hwif->dma_ops->dma_end(drive);
+ ret = ide_error(drive, "dma timeout error",
+ hwif->tp_ops->read_status(hwif));
+ } else {
+ printk(KERN_WARNING "%s: DMA timeout retry\n", drive->name);
+ hwif->dma_ops->dma_timeout(drive);
+ }
+
+ /*
+ * disable dma for now, but remember that we did so because of
+ * a timeout -- we'll reenable after we finish this next request
+ * (or rather the first chunk of it) in pio.
+ */
+ drive->dev_flags |= IDE_DFLAG_DMA_PIO_RETRY;
+ drive->retry_pio++;
+ ide_dma_off_quietly(drive);
+
+ /*
+ * un-busy drive etc (hwgroup->busy is cleared on return) and
+ * make sure request is sane
+ */
+ rq = HWGROUP(drive)->rq;
+
+ if (!rq)
+ goto out;
+
+ HWGROUP(drive)->rq = NULL;
+
+ rq->errors = 0;
+
+ if (!rq->bio)
+ goto out;
+
+ rq->sector = rq->bio->bi_sector;
+ rq->current_nr_sectors = bio_iovec(rq->bio)->bv_len >> 9;
+ rq->hard_cur_sectors = rq->current_nr_sectors;
+ rq->buffer = bio_data(rq->bio);
+out:
+ return ret;
+}
+
+/**
+ * ide_timer_expiry - handle lack of an IDE interrupt
+ * @data: timer callback magic (hwgroup)
+ *
+ * An IDE command has timed out before the expected drive return
+ * occurred. At this point we attempt to clean up the current
+ * mess. If the current handler includes an expiry handler then
+ * we invoke the expiry handler, and providing it is happy the
+ * work is done. If that fails we apply generic recovery rules
+ * invoking the handler and checking the drive DMA status. We
+ * have an excessively incestuous relationship with the DMA
+ * logic that wants cleaning up.
+ */
+
+void ide_timer_expiry (unsigned long data)
+{
+ ide_hwgroup_t *hwgroup = (ide_hwgroup_t *) data;
+ ide_handler_t *handler;
+ ide_expiry_t *expiry;
+ unsigned long flags;
+ unsigned long wait = -1;
+
+ spin_lock_irqsave(&ide_lock, flags);
+
+ if (((handler = hwgroup->handler) == NULL) ||
+ (hwgroup->req_gen != hwgroup->req_gen_timer)) {
+ /*
+ * Either a marginal timeout occurred
+ * (got the interrupt just as timer expired),
+ * or we were "sleeping" to give other devices a chance.
+ * Either way, we don't really want to complain about anything.
+ */
+ if (hwgroup->sleeping) {
+ hwgroup->sleeping = 0;
+ hwgroup->busy = 0;
+ }
+ } else {
+ ide_drive_t *drive = hwgroup->drive;
+ if (!drive) {
+ printk(KERN_ERR "ide_timer_expiry: hwgroup->drive was NULL\n");
+ hwgroup->handler = NULL;
+ } else {
+ ide_hwif_t *hwif;
+ ide_startstop_t startstop = ide_stopped;
+ if (!hwgroup->busy) {
+ hwgroup->busy = 1; /* paranoia */
+ printk(KERN_ERR "%s: ide_timer_expiry: hwgroup->busy was 0 ??\n", drive->name);
+ }
+ if ((expiry = hwgroup->expiry) != NULL) {
+ /* continue */
+ if ((wait = expiry(drive)) > 0) {
+ /* reset timer */
+ hwgroup->timer.expires = jiffies + wait;
+ hwgroup->req_gen_timer = hwgroup->req_gen;
+ add_timer(&hwgroup->timer);
+ spin_unlock_irqrestore(&ide_lock, flags);
+ return;
+ }
+ }
+ hwgroup->handler = NULL;
+ /*
+ * We need to simulate a real interrupt when invoking
+ * the handler() function, which means we need to
+ * globally mask the specific IRQ:
+ */
+ spin_unlock(&ide_lock);
+ hwif = HWIF(drive);
+ /* disable_irq_nosync ?? */
+ disable_irq(hwif->irq);
+ /* local CPU only,
+ * as if we were handling an interrupt */
+ local_irq_disable();
+ if (hwgroup->polling) {
+ startstop = handler(drive);
+ } else if (drive_is_ready(drive)) {
+ if (drive->waiting_for_dma)
+ hwif->dma_ops->dma_lost_irq(drive);
+ (void)ide_ack_intr(hwif);
+ printk(KERN_WARNING "%s: lost interrupt\n", drive->name);
+ startstop = handler(drive);
+ } else {
+ if (drive->waiting_for_dma) {
+ startstop = ide_dma_timeout_retry(drive, wait);
+ } else
+ startstop =
+ ide_error(drive, "irq timeout",
+ hwif->tp_ops->read_status(hwif));
+ }
+ drive->service_time = jiffies - drive->service_start;
+ spin_lock_irq(&ide_lock);
+ enable_irq(hwif->irq);
+ if (startstop == ide_stopped)
+ hwgroup->busy = 0;
+ }
+ }
+ ide_do_request(hwgroup, IDE_NO_IRQ);
+ spin_unlock_irqrestore(&ide_lock, flags);
+}
+
+/**
+ * unexpected_intr - handle an unexpected IDE interrupt
+ * @irq: interrupt line
+ * @hwgroup: hwgroup being processed
+ *
+ * There's nothing really useful we can do with an unexpected interrupt,
+ * other than reading the status register (to clear it), and logging it.
+ * There should be no way that an irq can happen before we're ready for it,
+ * so we needn't worry much about losing an "important" interrupt here.
+ *
+ * On laptops (and "green" PCs), an unexpected interrupt occurs whenever
+ * the drive enters "idle", "standby", or "sleep" mode, so if the status
+ * looks "good", we just ignore the interrupt completely.
+ *
+ * This routine assumes __cli() is in effect when called.
+ *
+ * If an unexpected interrupt happens on irq15 while we are handling irq14
+ * and if the two interfaces are "serialized" (CMD640), then it looks like
+ * we could screw up by interfering with a new request being set up for
+ * irq15.
+ *
+ * In reality, this is a non-issue. The new command is not sent unless
+ * the drive is ready to accept one, in which case we know the drive is
+ * not trying to interrupt us. And ide_set_handler() is always invoked
+ * before completing the issuance of any new drive command, so we will not
+ * be accidentally invoked as a result of any valid command completion
+ * interrupt.
+ *
+ * Note that we must walk the entire hwgroup here. We know which hwif
+ * is doing the current command, but we don't know which hwif burped
+ * mysteriously.
+ */
+
+static void unexpected_intr (int irq, ide_hwgroup_t *hwgroup)
+{
+ u8 stat;
+ ide_hwif_t *hwif = hwgroup->hwif;
+
+ /*
+ * handle the unexpected interrupt
+ */
+ do {
+ if (hwif->irq == irq) {
+ stat = hwif->tp_ops->read_status(hwif);
+
+ if (!OK_STAT(stat, ATA_DRDY, BAD_STAT)) {
+ /* Try to not flood the console with msgs */
+ static unsigned long last_msgtime, count;
+ ++count;
+ if (time_after(jiffies, last_msgtime + HZ)) {
+ last_msgtime = jiffies;
+ printk(KERN_ERR "%s%s: unexpected interrupt, "
+ "status=0x%02x, count=%ld\n",
+ hwif->name,
+ (hwif->next==hwgroup->hwif) ? "" : "(?)", stat, count);
+ }
+ }
+ }
+ } while ((hwif = hwif->next) != hwgroup->hwif);
+}
+
+/**
+ * ide_intr - default IDE interrupt handler
+ * @irq: interrupt number
+ * @dev_id: hwif group
+ * @regs: unused weirdness from the kernel irq layer
+ *
+ * This is the default IRQ handler for the IDE layer. You should
+ * not need to override it. If you do be aware it is subtle in
+ * places
+ *
+ * hwgroup->hwif is the interface in the group currently performing
+ * a command. hwgroup->drive is the drive and hwgroup->handler is
+ * the IRQ handler to call. As we issue a command the handlers
+ * step through multiple states, reassigning the handler to the
+ * next step in the process. Unlike a smart SCSI controller IDE
+ * expects the main processor to sequence the various transfer
+ * stages. We also manage a poll timer to catch up with most
+ * timeout situations. There are still a few where the handlers
+ * don't ever decide to give up.
+ *
+ * The handler eventually returns ide_stopped to indicate the
+ * request completed. At this point we issue the next request
+ * on the hwgroup and the process begins again.
+ */
+
+irqreturn_t ide_intr (int irq, void *dev_id)
+{
+ unsigned long flags;
+ ide_hwgroup_t *hwgroup = (ide_hwgroup_t *)dev_id;
+ ide_hwif_t *hwif;
+ ide_drive_t *drive;
+ ide_handler_t *handler;
+ ide_startstop_t startstop;
+
+ spin_lock_irqsave(&ide_lock, flags);
+ hwif = hwgroup->hwif;
+
+ if (!ide_ack_intr(hwif)) {
+ spin_unlock_irqrestore(&ide_lock, flags);
+ return IRQ_NONE;
+ }
+
+ if ((handler = hwgroup->handler) == NULL || hwgroup->polling) {
+ /*
+ * Not expecting an interrupt from this drive.
+ * That means this could be:
+ * (1) an interrupt from another PCI device
+ * sharing the same PCI INT# as us.
+ * or (2) a drive just entered sleep or standby mode,
+ * and is interrupting to let us know.
+ * or (3) a spurious interrupt of unknown origin.
+ *
+ * For PCI, we cannot tell the difference,
+ * so in that case we just ignore it and hope it goes away.
+ *
+ * FIXME: unexpected_intr should be hwif-> then we can
+ * remove all the ifdef PCI crap
+ */
+#ifdef CONFIG_BLK_DEV_IDEPCI
+ if (hwif->chipset != ide_pci)
+#endif /* CONFIG_BLK_DEV_IDEPCI */
+ {
+ /*
+ * Probably not a shared PCI interrupt,
+ * so we can safely try to do something about it:
+ */
+ unexpected_intr(irq, hwgroup);
+#ifdef CONFIG_BLK_DEV_IDEPCI
+ } else {
+ /*
+ * Whack the status register, just in case
+ * we have a leftover pending IRQ.
+ */
+ (void)hwif->tp_ops->read_status(hwif);
+#endif /* CONFIG_BLK_DEV_IDEPCI */
+ }
+ spin_unlock_irqrestore(&ide_lock, flags);
+ return IRQ_NONE;
+ }
+ drive = hwgroup->drive;
+ if (!drive) {
+ /*
+ * This should NEVER happen, and there isn't much
+ * we could do about it here.
+ *
+ * [Note - this can occur if the drive is hot unplugged]
+ */
+ spin_unlock_irqrestore(&ide_lock, flags);
+ return IRQ_HANDLED;
+ }
+ if (!drive_is_ready(drive)) {
+ /*
+ * This happens regularly when we share a PCI IRQ with
+ * another device. Unfortunately, it can also happen
+ * with some buggy drives that trigger the IRQ before
+ * their status register is up to date. Hopefully we have
+ * enough advance overhead that the latter isn't a problem.
+ */
+ spin_unlock_irqrestore(&ide_lock, flags);
+ return IRQ_NONE;
+ }
+ if (!hwgroup->busy) {
+ hwgroup->busy = 1; /* paranoia */
+ printk(KERN_ERR "%s: ide_intr: hwgroup->busy was 0 ??\n", drive->name);
+ }
+ hwgroup->handler = NULL;
+ hwgroup->req_gen++;
+ del_timer(&hwgroup->timer);
+ spin_unlock(&ide_lock);
+
+ if (hwif->port_ops && hwif->port_ops->clear_irq)
+ hwif->port_ops->clear_irq(drive);
+
+ if (drive->dev_flags & IDE_DFLAG_UNMASK)
+ local_irq_enable_in_hardirq();
+
+ /* service this interrupt, may set handler for next interrupt */
+ startstop = handler(drive);
+
+ spin_lock_irq(&ide_lock);
+ /*
+ * Note that handler() may have set things up for another
+ * interrupt to occur soon, but it cannot happen until
+ * we exit from this routine, because it will be the
+ * same irq as is currently being serviced here, and Linux
+ * won't allow another of the same (on any CPU) until we return.
+ */
+ drive->service_time = jiffies - drive->service_start;
+ if (startstop == ide_stopped) {
+ if (hwgroup->handler == NULL) { /* paranoia */
+ hwgroup->busy = 0;
+ ide_do_request(hwgroup, hwif->irq);
+ } else {
+ printk(KERN_ERR "%s: ide_intr: huh? expected NULL handler "
+ "on exit\n", drive->name);
+ }
+ }
+ spin_unlock_irqrestore(&ide_lock, flags);
+ return IRQ_HANDLED;
+}
+
+/**
+ * ide_do_drive_cmd - issue IDE special command
+ * @drive: device to issue command
+ * @rq: request to issue
+ *
+ * This function issues a special IDE device request
+ * onto the request queue.
+ *
+ * the rq is queued at the head of the request queue, displacing
+ * the currently-being-processed request and this function
+ * returns immediately without waiting for the new rq to be
+ * completed. This is VERY DANGEROUS, and is intended for
+ * careful use by the ATAPI tape/cdrom driver code.
+ */
+
+void ide_do_drive_cmd(ide_drive_t *drive, struct request *rq)
+{
+ unsigned long flags;
+ ide_hwgroup_t *hwgroup = HWGROUP(drive);
+
+ spin_lock_irqsave(&ide_lock, flags);
+ hwgroup->rq = NULL;
+ __elv_add_request(drive->queue, rq, ELEVATOR_INSERT_FRONT, 0);
+ blk_start_queueing(drive->queue);
+ spin_unlock_irqrestore(&ide_lock, flags);
+}
+
+EXPORT_SYMBOL(ide_do_drive_cmd);
+
+void ide_pktcmd_tf_load(ide_drive_t *drive, u32 tf_flags, u16 bcount, u8 dma)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ ide_task_t task;
+
+ memset(&task, 0, sizeof(task));
+ task.tf_flags = IDE_TFLAG_OUT_LBAH | IDE_TFLAG_OUT_LBAM |
+ IDE_TFLAG_OUT_FEATURE | tf_flags;
+ task.tf.feature = dma; /* Use PIO/DMA */
+ task.tf.lbam = bcount & 0xff;
+ task.tf.lbah = (bcount >> 8) & 0xff;
+
+ ide_tf_dump(drive->name, &task.tf);
+ hwif->tp_ops->set_irq(hwif, 1);
+ SELECT_MASK(drive, 0);
+ hwif->tp_ops->tf_load(drive, &task);
+}
+
+EXPORT_SYMBOL_GPL(ide_pktcmd_tf_load);
+
+void ide_pad_transfer(ide_drive_t *drive, int write, int len)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ u8 buf[4] = { 0 };
+
+ while (len > 0) {
+ if (write)
+ hwif->tp_ops->output_data(drive, NULL, buf, min(4, len));
+ else
+ hwif->tp_ops->input_data(drive, NULL, buf, min(4, len));
+ len -= 4;
+ }
+}
+EXPORT_SYMBOL_GPL(ide_pad_transfer);
diff --git a/drivers/ide/ide-ioctls.c b/drivers/ide/ide-ioctls.c
new file mode 100644
index 0000000..fcde16b
--- /dev/null
+++ b/drivers/ide/ide-ioctls.c
@@ -0,0 +1,298 @@
+/*
+ * IDE ioctls handling.
+ */
+
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+
+static const struct ide_ioctl_devset ide_ioctl_settings[] = {
+{ HDIO_GET_32BIT, HDIO_SET_32BIT, &ide_devset_io_32bit },
+{ HDIO_GET_KEEPSETTINGS, HDIO_SET_KEEPSETTINGS, &ide_devset_keepsettings },
+{ HDIO_GET_UNMASKINTR, HDIO_SET_UNMASKINTR, &ide_devset_unmaskirq },
+{ HDIO_GET_DMA, HDIO_SET_DMA, &ide_devset_using_dma },
+{ -1, HDIO_SET_PIO_MODE, &ide_devset_pio_mode },
+{ 0 }
+};
+
+int ide_setting_ioctl(ide_drive_t *drive, struct block_device *bdev,
+ unsigned int cmd, unsigned long arg,
+ const struct ide_ioctl_devset *s)
+{
+ const struct ide_devset *ds;
+ unsigned long flags;
+ int err = -EOPNOTSUPP;
+
+ for (; (ds = s->setting); s++) {
+ if (ds->get && s->get_ioctl == cmd)
+ goto read_val;
+ else if (ds->set && s->set_ioctl == cmd)
+ goto set_val;
+ }
+
+ return err;
+
+read_val:
+ mutex_lock(&ide_setting_mtx);
+ spin_lock_irqsave(&ide_lock, flags);
+ err = ds->get(drive);
+ spin_unlock_irqrestore(&ide_lock, flags);
+ mutex_unlock(&ide_setting_mtx);
+ return err >= 0 ? put_user(err, (long __user *)arg) : err;
+
+set_val:
+ if (bdev != bdev->bd_contains)
+ err = -EINVAL;
+ else {
+ if (!capable(CAP_SYS_ADMIN))
+ err = -EACCES;
+ else {
+ mutex_lock(&ide_setting_mtx);
+ err = ide_devset_execute(drive, ds, arg);
+ mutex_unlock(&ide_setting_mtx);
+ }
+ }
+ return err;
+}
+EXPORT_SYMBOL_GPL(ide_setting_ioctl);
+
+static int ide_get_identity_ioctl(ide_drive_t *drive, unsigned int cmd,
+ unsigned long arg)
+{
+ u16 *id = NULL;
+ int size = (cmd == HDIO_GET_IDENTITY) ? (ATA_ID_WORDS * 2) : 142;
+ int rc = 0;
+
+ if ((drive->dev_flags & IDE_DFLAG_ID_READ) == 0) {
+ rc = -ENOMSG;
+ goto out;
+ }
+
+ id = kmalloc(size, GFP_KERNEL);
+ if (id == NULL) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ memcpy(id, drive->id, size);
+ ata_id_to_hd_driveid(id);
+
+ if (copy_to_user((void __user *)arg, id, size))
+ rc = -EFAULT;
+
+ kfree(id);
+out:
+ return rc;
+}
+
+static int ide_get_nice_ioctl(ide_drive_t *drive, unsigned long arg)
+{
+ return put_user((!!(drive->dev_flags & IDE_DFLAG_DSC_OVERLAP)
+ << IDE_NICE_DSC_OVERLAP) |
+ (!!(drive->dev_flags & IDE_DFLAG_NICE1)
+ << IDE_NICE_1), (long __user *)arg);
+}
+
+static int ide_set_nice_ioctl(ide_drive_t *drive, unsigned long arg)
+{
+ if (arg != (arg & ((1 << IDE_NICE_DSC_OVERLAP) | (1 << IDE_NICE_1))))
+ return -EPERM;
+
+ if (((arg >> IDE_NICE_DSC_OVERLAP) & 1) &&
+ (drive->media == ide_disk || drive->media == ide_floppy ||
+ (drive->dev_flags & IDE_DFLAG_SCSI)))
+ return -EPERM;
+
+ if ((arg >> IDE_NICE_DSC_OVERLAP) & 1)
+ drive->dev_flags |= IDE_DFLAG_DSC_OVERLAP;
+ else
+ drive->dev_flags &= ~IDE_DFLAG_DSC_OVERLAP;
+
+ if ((arg >> IDE_NICE_1) & 1)
+ drive->dev_flags |= IDE_DFLAG_NICE1;
+ else
+ drive->dev_flags &= ~IDE_DFLAG_NICE1;
+
+ return 0;
+}
+
+static int ide_cmd_ioctl(ide_drive_t *drive, unsigned cmd, unsigned long arg)
+{
+ u8 *buf = NULL;
+ int bufsize = 0, err = 0;
+ u8 args[4], xfer_rate = 0;
+ ide_task_t tfargs;
+ struct ide_taskfile *tf = &tfargs.tf;
+ u16 *id = drive->id;
+
+ if (NULL == (void *) arg) {
+ struct request *rq;
+
+ rq = blk_get_request(drive->queue, READ, __GFP_WAIT);
+ rq->cmd_type = REQ_TYPE_ATA_TASKFILE;
+ err = blk_execute_rq(drive->queue, NULL, rq, 0);
+ blk_put_request(rq);
+
+ return err;
+ }
+
+ if (copy_from_user(args, (void __user *)arg, 4))
+ return -EFAULT;
+
+ memset(&tfargs, 0, sizeof(ide_task_t));
+ tf->feature = args[2];
+ if (args[0] == ATA_CMD_SMART) {
+ tf->nsect = args[3];
+ tf->lbal = args[1];
+ tf->lbam = 0x4f;
+ tf->lbah = 0xc2;
+ tfargs.tf_flags = IDE_TFLAG_OUT_TF | IDE_TFLAG_IN_NSECT;
+ } else {
+ tf->nsect = args[1];
+ tfargs.tf_flags = IDE_TFLAG_OUT_FEATURE |
+ IDE_TFLAG_OUT_NSECT | IDE_TFLAG_IN_NSECT;
+ }
+ tf->command = args[0];
+ tfargs.data_phase = args[3] ? TASKFILE_IN : TASKFILE_NO_DATA;
+
+ if (args[3]) {
+ tfargs.tf_flags |= IDE_TFLAG_IO_16BIT;
+ bufsize = SECTOR_SIZE * args[3];
+ buf = kzalloc(bufsize, GFP_KERNEL);
+ if (buf == NULL)
+ return -ENOMEM;
+ }
+
+ if (tf->command == ATA_CMD_SET_FEATURES &&
+ tf->feature == SETFEATURES_XFER &&
+ tf->nsect >= XFER_SW_DMA_0 &&
+ (id[ATA_ID_UDMA_MODES] ||
+ id[ATA_ID_MWDMA_MODES] ||
+ id[ATA_ID_SWDMA_MODES])) {
+ xfer_rate = args[1];
+ if (tf->nsect > XFER_UDMA_2 && !eighty_ninty_three(drive)) {
+ printk(KERN_WARNING "%s: UDMA speeds >UDMA33 cannot "
+ "be set\n", drive->name);
+ goto abort;
+ }
+ }
+
+ err = ide_raw_taskfile(drive, &tfargs, buf, args[3]);
+
+ args[0] = tf->status;
+ args[1] = tf->error;
+ args[2] = tf->nsect;
+
+ if (!err && xfer_rate) {
+ /* active-retuning-calls future */
+ ide_set_xfer_rate(drive, xfer_rate);
+ ide_driveid_update(drive);
+ }
+abort:
+ if (copy_to_user((void __user *)arg, &args, 4))
+ err = -EFAULT;
+ if (buf) {
+ if (copy_to_user((void __user *)(arg + 4), buf, bufsize))
+ err = -EFAULT;
+ kfree(buf);
+ }
+ return err;
+}
+
+static int ide_task_ioctl(ide_drive_t *drive, unsigned cmd, unsigned long arg)
+{
+ void __user *p = (void __user *)arg;
+ int err = 0;
+ u8 args[7];
+ ide_task_t task;
+
+ if (copy_from_user(args, p, 7))
+ return -EFAULT;
+
+ memset(&task, 0, sizeof(task));
+ memcpy(&task.tf_array[7], &args[1], 6);
+ task.tf.command = args[0];
+ task.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
+
+ err = ide_no_data_taskfile(drive, &task);
+
+ args[0] = task.tf.command;
+ memcpy(&args[1], &task.tf_array[7], 6);
+
+ if (copy_to_user(p, args, 7))
+ err = -EFAULT;
+
+ return err;
+}
+
+static int generic_drive_reset(ide_drive_t *drive)
+{
+ struct request *rq;
+ int ret = 0;
+
+ rq = blk_get_request(drive->queue, READ, __GFP_WAIT);
+ rq->cmd_type = REQ_TYPE_SPECIAL;
+ rq->cmd_len = 1;
+ rq->cmd[0] = REQ_DRIVE_RESET;
+ rq->cmd_flags |= REQ_SOFTBARRIER;
+ if (blk_execute_rq(drive->queue, NULL, rq, 1))
+ ret = rq->errors;
+ blk_put_request(rq);
+ return ret;
+}
+
+int generic_ide_ioctl(ide_drive_t *drive, struct block_device *bdev,
+ unsigned int cmd, unsigned long arg)
+{
+ int err;
+
+ err = ide_setting_ioctl(drive, bdev, cmd, arg, ide_ioctl_settings);
+ if (err != -EOPNOTSUPP)
+ return err;
+
+ switch (cmd) {
+ case HDIO_OBSOLETE_IDENTITY:
+ case HDIO_GET_IDENTITY:
+ if (bdev != bdev->bd_contains)
+ return -EINVAL;
+ return ide_get_identity_ioctl(drive, cmd, arg);
+ case HDIO_GET_NICE:
+ return ide_get_nice_ioctl(drive, arg);
+ case HDIO_SET_NICE:
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+ return ide_set_nice_ioctl(drive, arg);
+#ifdef CONFIG_IDE_TASK_IOCTL
+ case HDIO_DRIVE_TASKFILE:
+ if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
+ return -EACCES;
+ if (drive->media == ide_disk)
+ return ide_taskfile_ioctl(drive, cmd, arg);
+ return -ENOMSG;
+#endif
+ case HDIO_DRIVE_CMD:
+ if (!capable(CAP_SYS_RAWIO))
+ return -EACCES;
+ return ide_cmd_ioctl(drive, cmd, arg);
+ case HDIO_DRIVE_TASK:
+ if (!capable(CAP_SYS_RAWIO))
+ return -EACCES;
+ return ide_task_ioctl(drive, cmd, arg);
+ case HDIO_DRIVE_RESET:
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+ return generic_drive_reset(drive);
+ case HDIO_GET_BUSSTATE:
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+ if (put_user(BUSSTATE_ON, (long __user *)arg))
+ return -EFAULT;
+ return 0;
+ case HDIO_SET_BUSSTATE:
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+ return -EOPNOTSUPP;
+ default:
+ return -EINVAL;
+ }
+}
+EXPORT_SYMBOL(generic_ide_ioctl);
diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c
new file mode 100644
index 0000000..e60fc63
--- /dev/null
+++ b/drivers/ide/ide-iops.c
@@ -0,0 +1,1230 @@
+/*
+ * Copyright (C) 2000-2002 Andre Hedrick <andre@linux-ide.org>
+ * Copyright (C) 2003 Red Hat
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/major.h>
+#include <linux/errno.h>
+#include <linux/genhd.h>
+#include <linux/blkpg.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/ide.h>
+#include <linux/bitops.h>
+#include <linux/nmi.h>
+
+#include <asm/byteorder.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+/*
+ * Conventional PIO operations for ATA devices
+ */
+
+static u8 ide_inb (unsigned long port)
+{
+ return (u8) inb(port);
+}
+
+static void ide_outb (u8 val, unsigned long port)
+{
+ outb(val, port);
+}
+
+/*
+ * MMIO operations, typically used for SATA controllers
+ */
+
+static u8 ide_mm_inb (unsigned long port)
+{
+ return (u8) readb((void __iomem *) port);
+}
+
+static void ide_mm_outb (u8 value, unsigned long port)
+{
+ writeb(value, (void __iomem *) port);
+}
+
+void SELECT_DRIVE (ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ const struct ide_port_ops *port_ops = hwif->port_ops;
+ ide_task_t task;
+
+ if (port_ops && port_ops->selectproc)
+ port_ops->selectproc(drive);
+
+ memset(&task, 0, sizeof(task));
+ task.tf_flags = IDE_TFLAG_OUT_DEVICE;
+
+ drive->hwif->tp_ops->tf_load(drive, &task);
+}
+
+void SELECT_MASK(ide_drive_t *drive, int mask)
+{
+ const struct ide_port_ops *port_ops = drive->hwif->port_ops;
+
+ if (port_ops && port_ops->maskproc)
+ port_ops->maskproc(drive, mask);
+}
+
+void ide_exec_command(ide_hwif_t *hwif, u8 cmd)
+{
+ if (hwif->host_flags & IDE_HFLAG_MMIO)
+ writeb(cmd, (void __iomem *)hwif->io_ports.command_addr);
+ else
+ outb(cmd, hwif->io_ports.command_addr);
+}
+EXPORT_SYMBOL_GPL(ide_exec_command);
+
+u8 ide_read_status(ide_hwif_t *hwif)
+{
+ if (hwif->host_flags & IDE_HFLAG_MMIO)
+ return readb((void __iomem *)hwif->io_ports.status_addr);
+ else
+ return inb(hwif->io_ports.status_addr);
+}
+EXPORT_SYMBOL_GPL(ide_read_status);
+
+u8 ide_read_altstatus(ide_hwif_t *hwif)
+{
+ if (hwif->host_flags & IDE_HFLAG_MMIO)
+ return readb((void __iomem *)hwif->io_ports.ctl_addr);
+ else
+ return inb(hwif->io_ports.ctl_addr);
+}
+EXPORT_SYMBOL_GPL(ide_read_altstatus);
+
+u8 ide_read_sff_dma_status(ide_hwif_t *hwif)
+{
+ if (hwif->host_flags & IDE_HFLAG_MMIO)
+ return readb((void __iomem *)(hwif->dma_base + ATA_DMA_STATUS));
+ else
+ return inb(hwif->dma_base + ATA_DMA_STATUS);
+}
+EXPORT_SYMBOL_GPL(ide_read_sff_dma_status);
+
+void ide_set_irq(ide_hwif_t *hwif, int on)
+{
+ u8 ctl = ATA_DEVCTL_OBS;
+
+ if (on == 4) { /* hack for SRST */
+ ctl |= 4;
+ on &= ~4;
+ }
+
+ ctl |= on ? 0 : 2;
+
+ if (hwif->host_flags & IDE_HFLAG_MMIO)
+ writeb(ctl, (void __iomem *)hwif->io_ports.ctl_addr);
+ else
+ outb(ctl, hwif->io_ports.ctl_addr);
+}
+EXPORT_SYMBOL_GPL(ide_set_irq);
+
+void ide_tf_load(ide_drive_t *drive, ide_task_t *task)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ struct ide_io_ports *io_ports = &hwif->io_ports;
+ struct ide_taskfile *tf = &task->tf;
+ void (*tf_outb)(u8 addr, unsigned long port);
+ u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0;
+ u8 HIHI = (task->tf_flags & IDE_TFLAG_LBA48) ? 0xE0 : 0xEF;
+
+ if (mmio)
+ tf_outb = ide_mm_outb;
+ else
+ tf_outb = ide_outb;
+
+ if (task->tf_flags & IDE_TFLAG_FLAGGED)
+ HIHI = 0xFF;
+
+ if (task->tf_flags & IDE_TFLAG_OUT_DATA) {
+ u16 data = (tf->hob_data << 8) | tf->data;
+
+ if (mmio)
+ writew(data, (void __iomem *)io_ports->data_addr);
+ else
+ outw(data, io_ports->data_addr);
+ }
+
+ if (task->tf_flags & IDE_TFLAG_OUT_HOB_FEATURE)
+ tf_outb(tf->hob_feature, io_ports->feature_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_HOB_NSECT)
+ tf_outb(tf->hob_nsect, io_ports->nsect_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAL)
+ tf_outb(tf->hob_lbal, io_ports->lbal_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAM)
+ tf_outb(tf->hob_lbam, io_ports->lbam_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAH)
+ tf_outb(tf->hob_lbah, io_ports->lbah_addr);
+
+ if (task->tf_flags & IDE_TFLAG_OUT_FEATURE)
+ tf_outb(tf->feature, io_ports->feature_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_NSECT)
+ tf_outb(tf->nsect, io_ports->nsect_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_LBAL)
+ tf_outb(tf->lbal, io_ports->lbal_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_LBAM)
+ tf_outb(tf->lbam, io_ports->lbam_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_LBAH)
+ tf_outb(tf->lbah, io_ports->lbah_addr);
+
+ if (task->tf_flags & IDE_TFLAG_OUT_DEVICE)
+ tf_outb((tf->device & HIHI) | drive->select,
+ io_ports->device_addr);
+}
+EXPORT_SYMBOL_GPL(ide_tf_load);
+
+void ide_tf_read(ide_drive_t *drive, ide_task_t *task)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ struct ide_io_ports *io_ports = &hwif->io_ports;
+ struct ide_taskfile *tf = &task->tf;
+ void (*tf_outb)(u8 addr, unsigned long port);
+ u8 (*tf_inb)(unsigned long port);
+ u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0;
+
+ if (mmio) {
+ tf_outb = ide_mm_outb;
+ tf_inb = ide_mm_inb;
+ } else {
+ tf_outb = ide_outb;
+ tf_inb = ide_inb;
+ }
+
+ if (task->tf_flags & IDE_TFLAG_IN_DATA) {
+ u16 data;
+
+ if (mmio)
+ data = readw((void __iomem *)io_ports->data_addr);
+ else
+ data = inw(io_ports->data_addr);
+
+ tf->data = data & 0xff;
+ tf->hob_data = (data >> 8) & 0xff;
+ }
+
+ /* be sure we're looking at the low order bits */
+ tf_outb(ATA_DEVCTL_OBS & ~0x80, io_ports->ctl_addr);
+
+ if (task->tf_flags & IDE_TFLAG_IN_FEATURE)
+ tf->feature = tf_inb(io_ports->feature_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_NSECT)
+ tf->nsect = tf_inb(io_ports->nsect_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_LBAL)
+ tf->lbal = tf_inb(io_ports->lbal_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_LBAM)
+ tf->lbam = tf_inb(io_ports->lbam_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_LBAH)
+ tf->lbah = tf_inb(io_ports->lbah_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_DEVICE)
+ tf->device = tf_inb(io_ports->device_addr);
+
+ if (task->tf_flags & IDE_TFLAG_LBA48) {
+ tf_outb(ATA_DEVCTL_OBS | 0x80, io_ports->ctl_addr);
+
+ if (task->tf_flags & IDE_TFLAG_IN_HOB_FEATURE)
+ tf->hob_feature = tf_inb(io_ports->feature_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_HOB_NSECT)
+ tf->hob_nsect = tf_inb(io_ports->nsect_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAL)
+ tf->hob_lbal = tf_inb(io_ports->lbal_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAM)
+ tf->hob_lbam = tf_inb(io_ports->lbam_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAH)
+ tf->hob_lbah = tf_inb(io_ports->lbah_addr);
+ }
+}
+EXPORT_SYMBOL_GPL(ide_tf_read);
+
+/*
+ * Some localbus EIDE interfaces require a special access sequence
+ * when using 32-bit I/O instructions to transfer data. We call this
+ * the "vlb_sync" sequence, which consists of three successive reads
+ * of the sector count register location, with interrupts disabled
+ * to ensure that the reads all happen together.
+ */
+static void ata_vlb_sync(unsigned long port)
+{
+ (void)inb(port);
+ (void)inb(port);
+ (void)inb(port);
+}
+
+/*
+ * This is used for most PIO data transfers *from* the IDE interface
+ *
+ * These routines will round up any request for an odd number of bytes,
+ * so if an odd len is specified, be sure that there's at least one
+ * extra byte allocated for the buffer.
+ */
+void ide_input_data(ide_drive_t *drive, struct request *rq, void *buf,
+ unsigned int len)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ struct ide_io_ports *io_ports = &hwif->io_ports;
+ unsigned long data_addr = io_ports->data_addr;
+ u8 io_32bit = drive->io_32bit;
+ u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0;
+
+ len++;
+
+ if (io_32bit) {
+ unsigned long uninitialized_var(flags);
+
+ if ((io_32bit & 2) && !mmio) {
+ local_irq_save(flags);
+ ata_vlb_sync(io_ports->nsect_addr);
+ }
+
+ if (mmio)
+ __ide_mm_insl((void __iomem *)data_addr, buf, len / 4);
+ else
+ insl(data_addr, buf, len / 4);
+
+ if ((io_32bit & 2) && !mmio)
+ local_irq_restore(flags);
+
+ if ((len & 3) >= 2) {
+ if (mmio)
+ __ide_mm_insw((void __iomem *)data_addr,
+ (u8 *)buf + (len & ~3), 1);
+ else
+ insw(data_addr, (u8 *)buf + (len & ~3), 1);
+ }
+ } else {
+ if (mmio)
+ __ide_mm_insw((void __iomem *)data_addr, buf, len / 2);
+ else
+ insw(data_addr, buf, len / 2);
+ }
+}
+EXPORT_SYMBOL_GPL(ide_input_data);
+
+/*
+ * This is used for most PIO data transfers *to* the IDE interface
+ */
+void ide_output_data(ide_drive_t *drive, struct request *rq, void *buf,
+ unsigned int len)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ struct ide_io_ports *io_ports = &hwif->io_ports;
+ unsigned long data_addr = io_ports->data_addr;
+ u8 io_32bit = drive->io_32bit;
+ u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0;
+
+ len++;
+
+ if (io_32bit) {
+ unsigned long uninitialized_var(flags);
+
+ if ((io_32bit & 2) && !mmio) {
+ local_irq_save(flags);
+ ata_vlb_sync(io_ports->nsect_addr);
+ }
+
+ if (mmio)
+ __ide_mm_outsl((void __iomem *)data_addr, buf, len / 4);
+ else
+ outsl(data_addr, buf, len / 4);
+
+ if ((io_32bit & 2) && !mmio)
+ local_irq_restore(flags);
+
+ if ((len & 3) >= 2) {
+ if (mmio)
+ __ide_mm_outsw((void __iomem *)data_addr,
+ (u8 *)buf + (len & ~3), 1);
+ else
+ outsw(data_addr, (u8 *)buf + (len & ~3), 1);
+ }
+ } else {
+ if (mmio)
+ __ide_mm_outsw((void __iomem *)data_addr, buf, len / 2);
+ else
+ outsw(data_addr, buf, len / 2);
+ }
+}
+EXPORT_SYMBOL_GPL(ide_output_data);
+
+u8 ide_read_error(ide_drive_t *drive)
+{
+ ide_task_t task;
+
+ memset(&task, 0, sizeof(task));
+ task.tf_flags = IDE_TFLAG_IN_FEATURE;
+
+ drive->hwif->tp_ops->tf_read(drive, &task);
+
+ return task.tf.error;
+}
+EXPORT_SYMBOL_GPL(ide_read_error);
+
+void ide_read_bcount_and_ireason(ide_drive_t *drive, u16 *bcount, u8 *ireason)
+{
+ ide_task_t task;
+
+ memset(&task, 0, sizeof(task));
+ task.tf_flags = IDE_TFLAG_IN_LBAH | IDE_TFLAG_IN_LBAM |
+ IDE_TFLAG_IN_NSECT;
+
+ drive->hwif->tp_ops->tf_read(drive, &task);
+
+ *bcount = (task.tf.lbah << 8) | task.tf.lbam;
+ *ireason = task.tf.nsect & 3;
+}
+EXPORT_SYMBOL_GPL(ide_read_bcount_and_ireason);
+
+const struct ide_tp_ops default_tp_ops = {
+ .exec_command = ide_exec_command,
+ .read_status = ide_read_status,
+ .read_altstatus = ide_read_altstatus,
+ .read_sff_dma_status = ide_read_sff_dma_status,
+
+ .set_irq = ide_set_irq,
+
+ .tf_load = ide_tf_load,
+ .tf_read = ide_tf_read,
+
+ .input_data = ide_input_data,
+ .output_data = ide_output_data,
+};
+
+void ide_fix_driveid(u16 *id)
+{
+#ifndef __LITTLE_ENDIAN
+# ifdef __BIG_ENDIAN
+ int i;
+
+ for (i = 0; i < 256; i++)
+ id[i] = __le16_to_cpu(id[i]);
+# else
+# error "Please fix <asm/byteorder.h>"
+# endif
+#endif
+}
+
+/*
+ * ide_fixstring() cleans up and (optionally) byte-swaps a text string,
+ * removing leading/trailing blanks and compressing internal blanks.
+ * It is primarily used to tidy up the model name/number fields as
+ * returned by the ATA_CMD_ID_ATA[PI] commands.
+ */
+
+void ide_fixstring (u8 *s, const int bytecount, const int byteswap)
+{
+ u8 *p, *end = &s[bytecount & ~1]; /* bytecount must be even */
+
+ if (byteswap) {
+ /* convert from big-endian to host byte order */
+ for (p = s ; p != end ; p += 2)
+ be16_to_cpus((u16 *) p);
+ }
+
+ /* strip leading blanks */
+ p = s;
+ while (s != end && *s == ' ')
+ ++s;
+ /* compress internal blanks and strip trailing blanks */
+ while (s != end && *s) {
+ if (*s++ != ' ' || (s != end && *s && *s != ' '))
+ *p++ = *(s-1);
+ }
+ /* wipe out trailing garbage */
+ while (p != end)
+ *p++ = '\0';
+}
+
+EXPORT_SYMBOL(ide_fixstring);
+
+/*
+ * Needed for PCI irq sharing
+ */
+int drive_is_ready (ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ u8 stat = 0;
+
+ if (drive->waiting_for_dma)
+ return hwif->dma_ops->dma_test_irq(drive);
+
+ /*
+ * We do a passive status test under shared PCI interrupts on
+ * cards that truly share the ATA side interrupt, but may also share
+ * an interrupt with another pci card/device. We make no assumptions
+ * about possible isa-pnp and pci-pnp issues yet.
+ */
+ if (hwif->io_ports.ctl_addr &&
+ (hwif->host_flags & IDE_HFLAG_BROKEN_ALTSTATUS) == 0)
+ stat = hwif->tp_ops->read_altstatus(hwif);
+ else
+ /* Note: this may clear a pending IRQ!! */
+ stat = hwif->tp_ops->read_status(hwif);
+
+ if (stat & ATA_BUSY)
+ /* drive busy: definitely not interrupting */
+ return 0;
+
+ /* drive ready: *might* be interrupting */
+ return 1;
+}
+
+EXPORT_SYMBOL(drive_is_ready);
+
+/*
+ * This routine busy-waits for the drive status to be not "busy".
+ * It then checks the status for all of the "good" bits and none
+ * of the "bad" bits, and if all is okay it returns 0. All other
+ * cases return error -- caller may then invoke ide_error().
+ *
+ * This routine should get fixed to not hog the cpu during extra long waits..
+ * That could be done by busy-waiting for the first jiffy or two, and then
+ * setting a timer to wake up at half second intervals thereafter,
+ * until timeout is achieved, before timing out.
+ */
+static int __ide_wait_stat(ide_drive_t *drive, u8 good, u8 bad, unsigned long timeout, u8 *rstat)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ const struct ide_tp_ops *tp_ops = hwif->tp_ops;
+ unsigned long flags;
+ int i;
+ u8 stat;
+
+ udelay(1); /* spec allows drive 400ns to assert "BUSY" */
+ stat = tp_ops->read_status(hwif);
+
+ if (stat & ATA_BUSY) {
+ local_irq_set(flags);
+ timeout += jiffies;
+ while ((stat = tp_ops->read_status(hwif)) & ATA_BUSY) {
+ if (time_after(jiffies, timeout)) {
+ /*
+ * One last read after the timeout in case
+ * heavy interrupt load made us not make any
+ * progress during the timeout..
+ */
+ stat = tp_ops->read_status(hwif);
+ if ((stat & ATA_BUSY) == 0)
+ break;
+
+ local_irq_restore(flags);
+ *rstat = stat;
+ return -EBUSY;
+ }
+ }
+ local_irq_restore(flags);
+ }
+ /*
+ * Allow status to settle, then read it again.
+ * A few rare drives vastly violate the 400ns spec here,
+ * so we'll wait up to 10usec for a "good" status
+ * rather than expensively fail things immediately.
+ * This fix courtesy of Matthew Faupel & Niccolo Rigacci.
+ */
+ for (i = 0; i < 10; i++) {
+ udelay(1);
+ stat = tp_ops->read_status(hwif);
+
+ if (OK_STAT(stat, good, bad)) {
+ *rstat = stat;
+ return 0;
+ }
+ }
+ *rstat = stat;
+ return -EFAULT;
+}
+
+/*
+ * In case of error returns error value after doing "*startstop = ide_error()".
+ * The caller should return the updated value of "startstop" in this case,
+ * "startstop" is unchanged when the function returns 0.
+ */
+int ide_wait_stat(ide_startstop_t *startstop, ide_drive_t *drive, u8 good, u8 bad, unsigned long timeout)
+{
+ int err;
+ u8 stat;
+
+ /* bail early if we've exceeded max_failures */
+ if (drive->max_failures && (drive->failures > drive->max_failures)) {
+ *startstop = ide_stopped;
+ return 1;
+ }
+
+ err = __ide_wait_stat(drive, good, bad, timeout, &stat);
+
+ if (err) {
+ char *s = (err == -EBUSY) ? "status timeout" : "status error";
+ *startstop = ide_error(drive, s, stat);
+ }
+
+ return err;
+}
+
+EXPORT_SYMBOL(ide_wait_stat);
+
+/**
+ * ide_in_drive_list - look for drive in black/white list
+ * @id: drive identifier
+ * @table: list to inspect
+ *
+ * Look for a drive in the blacklist and the whitelist tables
+ * Returns 1 if the drive is found in the table.
+ */
+
+int ide_in_drive_list(u16 *id, const struct drive_list_entry *table)
+{
+ for ( ; table->id_model; table++)
+ if ((!strcmp(table->id_model, (char *)&id[ATA_ID_PROD])) &&
+ (!table->id_firmware ||
+ strstr((char *)&id[ATA_ID_FW_REV], table->id_firmware)))
+ return 1;
+ return 0;
+}
+
+EXPORT_SYMBOL_GPL(ide_in_drive_list);
+
+/*
+ * Early UDMA66 devices don't set bit14 to 1, only bit13 is valid.
+ * We list them here and depend on the device side cable detection for them.
+ *
+ * Some optical devices with the buggy firmwares have the same problem.
+ */
+static const struct drive_list_entry ivb_list[] = {
+ { "QUANTUM FIREBALLlct10 05" , "A03.0900" },
+ { "TSSTcorp CDDVDW SH-S202J" , "SB00" },
+ { "TSSTcorp CDDVDW SH-S202J" , "SB01" },
+ { "TSSTcorp CDDVDW SH-S202N" , "SB00" },
+ { "TSSTcorp CDDVDW SH-S202N" , "SB01" },
+ { "TSSTcorp CDDVDW SH-S202H" , "SB00" },
+ { "TSSTcorp CDDVDW SH-S202H" , "SB01" },
+ { "SAMSUNG SP0822N" , "WA100-10" },
+ { NULL , NULL }
+};
+
+/*
+ * All hosts that use the 80c ribbon must use!
+ * The name is derived from upper byte of word 93 and the 80c ribbon.
+ */
+u8 eighty_ninty_three (ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ u16 *id = drive->id;
+ int ivb = ide_in_drive_list(id, ivb_list);
+
+ if (hwif->cbl == ATA_CBL_PATA40_SHORT)
+ return 1;
+
+ if (ivb)
+ printk(KERN_DEBUG "%s: skipping word 93 validity check\n",
+ drive->name);
+
+ if (ata_id_is_sata(id) && !ivb)
+ return 1;
+
+ if (hwif->cbl != ATA_CBL_PATA80 && !ivb)
+ goto no_80w;
+
+ /*
+ * FIXME:
+ * - change master/slave IDENTIFY order
+ * - force bit13 (80c cable present) check also for !ivb devices
+ * (unless the slave device is pre-ATA3)
+ */
+ if ((id[ATA_ID_HW_CONFIG] & 0x4000) ||
+ (ivb && (id[ATA_ID_HW_CONFIG] & 0x2000)))
+ return 1;
+
+no_80w:
+ if (drive->dev_flags & IDE_DFLAG_UDMA33_WARNED)
+ return 0;
+
+ printk(KERN_WARNING "%s: %s side 80-wire cable detection failed, "
+ "limiting max speed to UDMA33\n",
+ drive->name,
+ hwif->cbl == ATA_CBL_PATA80 ? "drive" : "host");
+
+ drive->dev_flags |= IDE_DFLAG_UDMA33_WARNED;
+
+ return 0;
+}
+
+int ide_driveid_update(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ const struct ide_tp_ops *tp_ops = hwif->tp_ops;
+ u16 *id;
+ unsigned long flags;
+ u8 stat;
+
+ /*
+ * Re-read drive->id for possible DMA mode
+ * change (copied from ide-probe.c)
+ */
+
+ SELECT_MASK(drive, 1);
+ tp_ops->set_irq(hwif, 0);
+ msleep(50);
+ tp_ops->exec_command(hwif, ATA_CMD_ID_ATA);
+
+ if (ide_busy_sleep(hwif, WAIT_WORSTCASE, 1)) {
+ SELECT_MASK(drive, 0);
+ return 0;
+ }
+
+ msleep(50); /* wait for IRQ and ATA_DRQ */
+ stat = tp_ops->read_status(hwif);
+
+ if (!OK_STAT(stat, ATA_DRQ, BAD_R_STAT)) {
+ SELECT_MASK(drive, 0);
+ printk("%s: CHECK for good STATUS\n", drive->name);
+ return 0;
+ }
+ local_irq_save(flags);
+ SELECT_MASK(drive, 0);
+ id = kmalloc(SECTOR_SIZE, GFP_ATOMIC);
+ if (!id) {
+ local_irq_restore(flags);
+ return 0;
+ }
+ tp_ops->input_data(drive, NULL, id, SECTOR_SIZE);
+ (void)tp_ops->read_status(hwif); /* clear drive IRQ */
+ local_irq_enable();
+ local_irq_restore(flags);
+ ide_fix_driveid(id);
+
+ drive->id[ATA_ID_UDMA_MODES] = id[ATA_ID_UDMA_MODES];
+ drive->id[ATA_ID_MWDMA_MODES] = id[ATA_ID_MWDMA_MODES];
+ drive->id[ATA_ID_SWDMA_MODES] = id[ATA_ID_SWDMA_MODES];
+ /* anything more ? */
+
+ kfree(id);
+
+ if ((drive->dev_flags & IDE_DFLAG_USING_DMA) && ide_id_dma_bug(drive))
+ ide_dma_off(drive);
+
+ return 1;
+}
+
+int ide_config_drive_speed(ide_drive_t *drive, u8 speed)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ const struct ide_tp_ops *tp_ops = hwif->tp_ops;
+ u16 *id = drive->id, i;
+ int error = 0;
+ u8 stat;
+ ide_task_t task;
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+ if (hwif->dma_ops) /* check if host supports DMA */
+ hwif->dma_ops->dma_host_set(drive, 0);
+#endif
+
+ /* Skip setting PIO flow-control modes on pre-EIDE drives */
+ if ((speed & 0xf8) == XFER_PIO_0 && ata_id_has_iordy(drive->id) == 0)
+ goto skip;
+
+ /*
+ * Don't use ide_wait_cmd here - it will
+ * attempt to set_geometry and recalibrate,
+ * but for some reason these don't work at
+ * this point (lost interrupt).
+ */
+ /*
+ * Select the drive, and issue the SETFEATURES command
+ */
+ disable_irq_nosync(hwif->irq);
+
+ /*
+ * FIXME: we race against the running IRQ here if
+ * this is called from non IRQ context. If we use
+ * disable_irq() we hang on the error path. Work
+ * is needed.
+ */
+
+ udelay(1);
+ SELECT_DRIVE(drive);
+ SELECT_MASK(drive, 1);
+ udelay(1);
+ tp_ops->set_irq(hwif, 0);
+
+ memset(&task, 0, sizeof(task));
+ task.tf_flags = IDE_TFLAG_OUT_FEATURE | IDE_TFLAG_OUT_NSECT;
+ task.tf.feature = SETFEATURES_XFER;
+ task.tf.nsect = speed;
+
+ tp_ops->tf_load(drive, &task);
+
+ tp_ops->exec_command(hwif, ATA_CMD_SET_FEATURES);
+
+ if (drive->quirk_list == 2)
+ tp_ops->set_irq(hwif, 1);
+
+ error = __ide_wait_stat(drive, drive->ready_stat,
+ ATA_BUSY | ATA_DRQ | ATA_ERR,
+ WAIT_CMD, &stat);
+
+ SELECT_MASK(drive, 0);
+
+ enable_irq(hwif->irq);
+
+ if (error) {
+ (void) ide_dump_status(drive, "set_drive_speed_status", stat);
+ return error;
+ }
+
+ id[ATA_ID_UDMA_MODES] &= ~0xFF00;
+ id[ATA_ID_MWDMA_MODES] &= ~0x0F00;
+ id[ATA_ID_SWDMA_MODES] &= ~0x0F00;
+
+ skip:
+#ifdef CONFIG_BLK_DEV_IDEDMA
+ if (speed >= XFER_SW_DMA_0 && (drive->dev_flags & IDE_DFLAG_USING_DMA))
+ hwif->dma_ops->dma_host_set(drive, 1);
+ else if (hwif->dma_ops) /* check if host supports DMA */
+ ide_dma_off_quietly(drive);
+#endif
+
+ if (speed >= XFER_UDMA_0) {
+ i = 1 << (speed - XFER_UDMA_0);
+ id[ATA_ID_UDMA_MODES] |= (i << 8 | i);
+ } else if (speed >= XFER_MW_DMA_0) {
+ i = 1 << (speed - XFER_MW_DMA_0);
+ id[ATA_ID_MWDMA_MODES] |= (i << 8 | i);
+ } else if (speed >= XFER_SW_DMA_0) {
+ i = 1 << (speed - XFER_SW_DMA_0);
+ id[ATA_ID_SWDMA_MODES] |= (i << 8 | i);
+ }
+
+ if (!drive->init_speed)
+ drive->init_speed = speed;
+ drive->current_speed = speed;
+ return error;
+}
+
+/*
+ * This should get invoked any time we exit the driver to
+ * wait for an interrupt response from a drive. handler() points
+ * at the appropriate code to handle the next interrupt, and a
+ * timer is started to prevent us from waiting forever in case
+ * something goes wrong (see the ide_timer_expiry() handler later on).
+ *
+ * See also ide_execute_command
+ */
+static void __ide_set_handler (ide_drive_t *drive, ide_handler_t *handler,
+ unsigned int timeout, ide_expiry_t *expiry)
+{
+ ide_hwgroup_t *hwgroup = HWGROUP(drive);
+
+ BUG_ON(hwgroup->handler);
+ hwgroup->handler = handler;
+ hwgroup->expiry = expiry;
+ hwgroup->timer.expires = jiffies + timeout;
+ hwgroup->req_gen_timer = hwgroup->req_gen;
+ add_timer(&hwgroup->timer);
+}
+
+void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler,
+ unsigned int timeout, ide_expiry_t *expiry)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&ide_lock, flags);
+ __ide_set_handler(drive, handler, timeout, expiry);
+ spin_unlock_irqrestore(&ide_lock, flags);
+}
+
+EXPORT_SYMBOL(ide_set_handler);
+
+/**
+ * ide_execute_command - execute an IDE command
+ * @drive: IDE drive to issue the command against
+ * @command: command byte to write
+ * @handler: handler for next phase
+ * @timeout: timeout for command
+ * @expiry: handler to run on timeout
+ *
+ * Helper function to issue an IDE command. This handles the
+ * atomicity requirements, command timing and ensures that the
+ * handler and IRQ setup do not race. All IDE command kick off
+ * should go via this function or do equivalent locking.
+ */
+
+void ide_execute_command(ide_drive_t *drive, u8 cmd, ide_handler_t *handler,
+ unsigned timeout, ide_expiry_t *expiry)
+{
+ unsigned long flags;
+ ide_hwif_t *hwif = HWIF(drive);
+
+ spin_lock_irqsave(&ide_lock, flags);
+ __ide_set_handler(drive, handler, timeout, expiry);
+ hwif->tp_ops->exec_command(hwif, cmd);
+ /*
+ * Drive takes 400nS to respond, we must avoid the IRQ being
+ * serviced before that.
+ *
+ * FIXME: we could skip this delay with care on non shared devices
+ */
+ ndelay(400);
+ spin_unlock_irqrestore(&ide_lock, flags);
+}
+EXPORT_SYMBOL(ide_execute_command);
+
+void ide_execute_pkt_cmd(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ide_lock, flags);
+ hwif->tp_ops->exec_command(hwif, ATA_CMD_PACKET);
+ ndelay(400);
+ spin_unlock_irqrestore(&ide_lock, flags);
+}
+EXPORT_SYMBOL_GPL(ide_execute_pkt_cmd);
+
+static inline void ide_complete_drive_reset(ide_drive_t *drive, int err)
+{
+ struct request *rq = drive->hwif->hwgroup->rq;
+
+ if (rq && blk_special_request(rq) && rq->cmd[0] == REQ_DRIVE_RESET)
+ ide_end_request(drive, err ? err : 1, 0);
+}
+
+/* needed below */
+static ide_startstop_t do_reset1 (ide_drive_t *, int);
+
+/*
+ * atapi_reset_pollfunc() gets invoked to poll the interface for completion every 50ms
+ * during an atapi drive reset operation. If the drive has not yet responded,
+ * and we have not yet hit our maximum waiting time, then the timer is restarted
+ * for another 50ms.
+ */
+static ide_startstop_t atapi_reset_pollfunc (ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ ide_hwgroup_t *hwgroup = hwif->hwgroup;
+ u8 stat;
+
+ SELECT_DRIVE(drive);
+ udelay (10);
+ stat = hwif->tp_ops->read_status(hwif);
+
+ if (OK_STAT(stat, 0, ATA_BUSY))
+ printk("%s: ATAPI reset complete\n", drive->name);
+ else {
+ if (time_before(jiffies, hwgroup->poll_timeout)) {
+ ide_set_handler(drive, &atapi_reset_pollfunc, HZ/20, NULL);
+ /* continue polling */
+ return ide_started;
+ }
+ /* end of polling */
+ hwgroup->polling = 0;
+ printk("%s: ATAPI reset timed-out, status=0x%02x\n",
+ drive->name, stat);
+ /* do it the old fashioned way */
+ return do_reset1(drive, 1);
+ }
+ /* done polling */
+ hwgroup->polling = 0;
+ ide_complete_drive_reset(drive, 0);
+ return ide_stopped;
+}
+
+static void ide_reset_report_error(ide_hwif_t *hwif, u8 err)
+{
+ static const char *err_master_vals[] =
+ { NULL, "passed", "formatter device error",
+ "sector buffer error", "ECC circuitry error",
+ "controlling MPU error" };
+
+ u8 err_master = err & 0x7f;
+
+ printk(KERN_ERR "%s: reset: master: ", hwif->name);
+ if (err_master && err_master < 6)
+ printk(KERN_CONT "%s", err_master_vals[err_master]);
+ else
+ printk(KERN_CONT "error (0x%02x?)", err);
+ if (err & 0x80)
+ printk(KERN_CONT "; slave: failed");
+ printk(KERN_CONT "\n");
+}
+
+/*
+ * reset_pollfunc() gets invoked to poll the interface for completion every 50ms
+ * during an ide reset operation. If the drives have not yet responded,
+ * and we have not yet hit our maximum waiting time, then the timer is restarted
+ * for another 50ms.
+ */
+static ide_startstop_t reset_pollfunc (ide_drive_t *drive)
+{
+ ide_hwgroup_t *hwgroup = HWGROUP(drive);
+ ide_hwif_t *hwif = HWIF(drive);
+ const struct ide_port_ops *port_ops = hwif->port_ops;
+ u8 tmp;
+ int err = 0;
+
+ if (port_ops && port_ops->reset_poll) {
+ err = port_ops->reset_poll(drive);
+ if (err) {
+ printk(KERN_ERR "%s: host reset_poll failure for %s.\n",
+ hwif->name, drive->name);
+ goto out;
+ }
+ }
+
+ tmp = hwif->tp_ops->read_status(hwif);
+
+ if (!OK_STAT(tmp, 0, ATA_BUSY)) {
+ if (time_before(jiffies, hwgroup->poll_timeout)) {
+ ide_set_handler(drive, &reset_pollfunc, HZ/20, NULL);
+ /* continue polling */
+ return ide_started;
+ }
+ printk("%s: reset timed-out, status=0x%02x\n", hwif->name, tmp);
+ drive->failures++;
+ err = -EIO;
+ } else {
+ tmp = ide_read_error(drive);
+
+ if (tmp == 1) {
+ printk(KERN_INFO "%s: reset: success\n", hwif->name);
+ drive->failures = 0;
+ } else {
+ ide_reset_report_error(hwif, tmp);
+ drive->failures++;
+ err = -EIO;
+ }
+ }
+out:
+ hwgroup->polling = 0; /* done polling */
+ ide_complete_drive_reset(drive, err);
+ return ide_stopped;
+}
+
+static void ide_disk_pre_reset(ide_drive_t *drive)
+{
+ int legacy = (drive->id[ATA_ID_CFS_ENABLE_2] & 0x0400) ? 0 : 1;
+
+ drive->special.all = 0;
+ drive->special.b.set_geometry = legacy;
+ drive->special.b.recalibrate = legacy;
+
+ drive->mult_count = 0;
+ drive->dev_flags &= ~IDE_DFLAG_PARKED;
+
+ if ((drive->dev_flags & IDE_DFLAG_KEEP_SETTINGS) == 0 &&
+ (drive->dev_flags & IDE_DFLAG_USING_DMA) == 0)
+ drive->mult_req = 0;
+
+ if (drive->mult_req != drive->mult_count)
+ drive->special.b.set_multmode = 1;
+}
+
+static void pre_reset(ide_drive_t *drive)
+{
+ const struct ide_port_ops *port_ops = drive->hwif->port_ops;
+
+ if (drive->media == ide_disk)
+ ide_disk_pre_reset(drive);
+ else
+ drive->dev_flags |= IDE_DFLAG_POST_RESET;
+
+ if (drive->dev_flags & IDE_DFLAG_USING_DMA) {
+ if (drive->crc_count)
+ ide_check_dma_crc(drive);
+ else
+ ide_dma_off(drive);
+ }
+
+ if ((drive->dev_flags & IDE_DFLAG_KEEP_SETTINGS) == 0) {
+ if ((drive->dev_flags & IDE_DFLAG_USING_DMA) == 0) {
+ drive->dev_flags &= ~IDE_DFLAG_UNMASK;
+ drive->io_32bit = 0;
+ }
+ return;
+ }
+
+ if (port_ops && port_ops->pre_reset)
+ port_ops->pre_reset(drive);
+
+ if (drive->current_speed != 0xff)
+ drive->desired_speed = drive->current_speed;
+ drive->current_speed = 0xff;
+}
+
+/*
+ * do_reset1() attempts to recover a confused drive by resetting it.
+ * Unfortunately, resetting a disk drive actually resets all devices on
+ * the same interface, so it can really be thought of as resetting the
+ * interface rather than resetting the drive.
+ *
+ * ATAPI devices have their own reset mechanism which allows them to be
+ * individually reset without clobbering other devices on the same interface.
+ *
+ * Unfortunately, the IDE interface does not generate an interrupt to let
+ * us know when the reset operation has finished, so we must poll for this.
+ * Equally poor, though, is the fact that this may a very long time to complete,
+ * (up to 30 seconds worstcase). So, instead of busy-waiting here for it,
+ * we set a timer to poll at 50ms intervals.
+ */
+static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
+{
+ unsigned int unit;
+ unsigned long flags, timeout;
+ ide_hwif_t *hwif;
+ ide_hwgroup_t *hwgroup;
+ struct ide_io_ports *io_ports;
+ const struct ide_tp_ops *tp_ops;
+ const struct ide_port_ops *port_ops;
+ DEFINE_WAIT(wait);
+
+ spin_lock_irqsave(&ide_lock, flags);
+ hwif = HWIF(drive);
+ hwgroup = HWGROUP(drive);
+
+ io_ports = &hwif->io_ports;
+
+ tp_ops = hwif->tp_ops;
+
+ /* We must not reset with running handlers */
+ BUG_ON(hwgroup->handler != NULL);
+
+ /* For an ATAPI device, first try an ATAPI SRST. */
+ if (drive->media != ide_disk && !do_not_try_atapi) {
+ pre_reset(drive);
+ SELECT_DRIVE(drive);
+ udelay (20);
+ tp_ops->exec_command(hwif, ATA_CMD_DEV_RESET);
+ ndelay(400);
+ hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
+ hwgroup->polling = 1;
+ __ide_set_handler(drive, &atapi_reset_pollfunc, HZ/20, NULL);
+ spin_unlock_irqrestore(&ide_lock, flags);
+ return ide_started;
+ }
+
+ /* We must not disturb devices in the IDE_DFLAG_PARKED state. */
+ do {
+ unsigned long now;
+
+ prepare_to_wait(&ide_park_wq, &wait, TASK_UNINTERRUPTIBLE);
+ timeout = jiffies;
+ for (unit = 0; unit < MAX_DRIVES; unit++) {
+ ide_drive_t *tdrive = &hwif->drives[unit];
+
+ if (tdrive->dev_flags & IDE_DFLAG_PRESENT &&
+ tdrive->dev_flags & IDE_DFLAG_PARKED &&
+ time_after(tdrive->sleep, timeout))
+ timeout = tdrive->sleep;
+ }
+
+ now = jiffies;
+ if (time_before_eq(timeout, now))
+ break;
+
+ spin_unlock_irqrestore(&ide_lock, flags);
+ timeout = schedule_timeout_uninterruptible(timeout - now);
+ spin_lock_irqsave(&ide_lock, flags);
+ } while (timeout);
+ finish_wait(&ide_park_wq, &wait);
+
+ /*
+ * First, reset any device state data we were maintaining
+ * for any of the drives on this interface.
+ */
+ for (unit = 0; unit < MAX_DRIVES; ++unit)
+ pre_reset(&hwif->drives[unit]);
+
+ if (io_ports->ctl_addr == 0) {
+ spin_unlock_irqrestore(&ide_lock, flags);
+ ide_complete_drive_reset(drive, -ENXIO);
+ return ide_stopped;
+ }
+
+ /*
+ * Note that we also set nIEN while resetting the device,
+ * to mask unwanted interrupts from the interface during the reset.
+ * However, due to the design of PC hardware, this will cause an
+ * immediate interrupt due to the edge transition it produces.
+ * This single interrupt gives us a "fast poll" for drives that
+ * recover from reset very quickly, saving us the first 50ms wait time.
+ *
+ * TODO: add ->softreset method and stop abusing ->set_irq
+ */
+ /* set SRST and nIEN */
+ tp_ops->set_irq(hwif, 4);
+ /* more than enough time */
+ udelay(10);
+ /* clear SRST, leave nIEN (unless device is on the quirk list) */
+ tp_ops->set_irq(hwif, drive->quirk_list == 2);
+ /* more than enough time */
+ udelay(10);
+ hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
+ hwgroup->polling = 1;
+ __ide_set_handler(drive, &reset_pollfunc, HZ/20, NULL);
+
+ /*
+ * Some weird controller like resetting themselves to a strange
+ * state when the disks are reset this way. At least, the Winbond
+ * 553 documentation says that
+ */
+ port_ops = hwif->port_ops;
+ if (port_ops && port_ops->resetproc)
+ port_ops->resetproc(drive);
+
+ spin_unlock_irqrestore(&ide_lock, flags);
+ return ide_started;
+}
+
+/*
+ * ide_do_reset() is the entry point to the drive/interface reset code.
+ */
+
+ide_startstop_t ide_do_reset (ide_drive_t *drive)
+{
+ return do_reset1(drive, 0);
+}
+
+EXPORT_SYMBOL(ide_do_reset);
+
+/*
+ * ide_wait_not_busy() waits for the currently selected device on the hwif
+ * to report a non-busy status, see comments in ide_probe_port().
+ */
+int ide_wait_not_busy(ide_hwif_t *hwif, unsigned long timeout)
+{
+ u8 stat = 0;
+
+ while(timeout--) {
+ /*
+ * Turn this into a schedule() sleep once I'm sure
+ * about locking issues (2.5 work ?).
+ */
+ mdelay(1);
+ stat = hwif->tp_ops->read_status(hwif);
+ if ((stat & ATA_BUSY) == 0)
+ return 0;
+ /*
+ * Assume a value of 0xff means nothing is connected to
+ * the interface and it doesn't implement the pull-down
+ * resistor on D7.
+ */
+ if (stat == 0xff)
+ return -ENODEV;
+ touch_softlockup_watchdog();
+ touch_nmi_watchdog();
+ }
+ return -EBUSY;
+}
+
+EXPORT_SYMBOL_GPL(ide_wait_not_busy);
+
diff --git a/drivers/ide/ide-lib.c b/drivers/ide/ide-lib.c
new file mode 100644
index 0000000..9fc4cfb
--- /dev/null
+++ b/drivers/ide/ide-lib.c
@@ -0,0 +1,415 @@
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/ide.h>
+#include <linux/bitops.h>
+
+static const char *udma_str[] =
+ { "UDMA/16", "UDMA/25", "UDMA/33", "UDMA/44",
+ "UDMA/66", "UDMA/100", "UDMA/133", "UDMA7" };
+static const char *mwdma_str[] =
+ { "MWDMA0", "MWDMA1", "MWDMA2" };
+static const char *swdma_str[] =
+ { "SWDMA0", "SWDMA1", "SWDMA2" };
+static const char *pio_str[] =
+ { "PIO0", "PIO1", "PIO2", "PIO3", "PIO4", "PIO5" };
+
+/**
+ * ide_xfer_verbose - return IDE mode names
+ * @mode: transfer mode
+ *
+ * Returns a constant string giving the name of the mode
+ * requested.
+ */
+
+const char *ide_xfer_verbose(u8 mode)
+{
+ const char *s;
+ u8 i = mode & 0xf;
+
+ if (mode >= XFER_UDMA_0 && mode <= XFER_UDMA_7)
+ s = udma_str[i];
+ else if (mode >= XFER_MW_DMA_0 && mode <= XFER_MW_DMA_2)
+ s = mwdma_str[i];
+ else if (mode >= XFER_SW_DMA_0 && mode <= XFER_SW_DMA_2)
+ s = swdma_str[i];
+ else if (mode >= XFER_PIO_0 && mode <= XFER_PIO_5)
+ s = pio_str[i & 0x7];
+ else if (mode == XFER_PIO_SLOW)
+ s = "PIO SLOW";
+ else
+ s = "XFER ERROR";
+
+ return s;
+}
+
+EXPORT_SYMBOL(ide_xfer_verbose);
+
+/**
+ * ide_rate_filter - filter transfer mode
+ * @drive: IDE device
+ * @speed: desired speed
+ *
+ * Given the available transfer modes this function returns
+ * the best available speed at or below the speed requested.
+ *
+ * TODO: check device PIO capabilities
+ */
+
+static u8 ide_rate_filter(ide_drive_t *drive, u8 speed)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ u8 mode = ide_find_dma_mode(drive, speed);
+
+ if (mode == 0) {
+ if (hwif->pio_mask)
+ mode = fls(hwif->pio_mask) - 1 + XFER_PIO_0;
+ else
+ mode = XFER_PIO_4;
+ }
+
+/* printk("%s: mode 0x%02x, speed 0x%02x\n", __func__, mode, speed); */
+
+ return min(speed, mode);
+}
+
+/**
+ * ide_get_best_pio_mode - get PIO mode from drive
+ * @drive: drive to consider
+ * @mode_wanted: preferred mode
+ * @max_mode: highest allowed mode
+ *
+ * This routine returns the recommended PIO settings for a given drive,
+ * based on the drive->id information and the ide_pio_blacklist[].
+ *
+ * Drive PIO mode is auto-selected if 255 is passed as mode_wanted.
+ * This is used by most chipset support modules when "auto-tuning".
+ */
+
+u8 ide_get_best_pio_mode (ide_drive_t *drive, u8 mode_wanted, u8 max_mode)
+{
+ u16 *id = drive->id;
+ int pio_mode = -1, overridden = 0;
+
+ if (mode_wanted != 255)
+ return min_t(u8, mode_wanted, max_mode);
+
+ if ((drive->hwif->host_flags & IDE_HFLAG_PIO_NO_BLACKLIST) == 0)
+ pio_mode = ide_scan_pio_blacklist((char *)&id[ATA_ID_PROD]);
+
+ if (pio_mode != -1) {
+ printk(KERN_INFO "%s: is on PIO blacklist\n", drive->name);
+ } else {
+ pio_mode = id[ATA_ID_OLD_PIO_MODES] >> 8;
+ if (pio_mode > 2) { /* 2 is maximum allowed tPIO value */
+ pio_mode = 2;
+ overridden = 1;
+ }
+
+ if (id[ATA_ID_FIELD_VALID] & 2) { /* ATA2? */
+ if (ata_id_has_iordy(id)) {
+ if (id[ATA_ID_PIO_MODES] & 7) {
+ overridden = 0;
+ if (id[ATA_ID_PIO_MODES] & 4)
+ pio_mode = 5;
+ else if (id[ATA_ID_PIO_MODES] & 2)
+ pio_mode = 4;
+ else
+ pio_mode = 3;
+ }
+ }
+ }
+
+ if (overridden)
+ printk(KERN_INFO "%s: tPIO > 2, assuming tPIO = 2\n",
+ drive->name);
+ }
+
+ if (pio_mode > max_mode)
+ pio_mode = max_mode;
+
+ return pio_mode;
+}
+
+EXPORT_SYMBOL_GPL(ide_get_best_pio_mode);
+
+/* req_pio == "255" for auto-tune */
+void ide_set_pio(ide_drive_t *drive, u8 req_pio)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ const struct ide_port_ops *port_ops = hwif->port_ops;
+ u8 host_pio, pio;
+
+ if (port_ops == NULL || port_ops->set_pio_mode == NULL ||
+ (hwif->host_flags & IDE_HFLAG_NO_SET_MODE))
+ return;
+
+ BUG_ON(hwif->pio_mask == 0x00);
+
+ host_pio = fls(hwif->pio_mask) - 1;
+
+ pio = ide_get_best_pio_mode(drive, req_pio, host_pio);
+
+ /*
+ * TODO:
+ * - report device max PIO mode
+ * - check req_pio != 255 against device max PIO mode
+ */
+ printk(KERN_DEBUG "%s: host max PIO%d wanted PIO%d%s selected PIO%d\n",
+ drive->name, host_pio, req_pio,
+ req_pio == 255 ? "(auto-tune)" : "", pio);
+
+ (void)ide_set_pio_mode(drive, XFER_PIO_0 + pio);
+}
+
+EXPORT_SYMBOL_GPL(ide_set_pio);
+
+/**
+ * ide_toggle_bounce - handle bounce buffering
+ * @drive: drive to update
+ * @on: on/off boolean
+ *
+ * Enable or disable bounce buffering for the device. Drives move
+ * between PIO and DMA and that changes the rules we need.
+ */
+
+void ide_toggle_bounce(ide_drive_t *drive, int on)
+{
+ u64 addr = BLK_BOUNCE_HIGH; /* dma64_addr_t */
+
+ if (!PCI_DMA_BUS_IS_PHYS) {
+ addr = BLK_BOUNCE_ANY;
+ } else if (on && drive->media == ide_disk) {
+ struct device *dev = drive->hwif->dev;
+
+ if (dev && dev->dma_mask)
+ addr = *dev->dma_mask;
+ }
+
+ if (drive->queue)
+ blk_queue_bounce_limit(drive->queue, addr);
+}
+
+int ide_set_pio_mode(ide_drive_t *drive, const u8 mode)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ const struct ide_port_ops *port_ops = hwif->port_ops;
+
+ if (hwif->host_flags & IDE_HFLAG_NO_SET_MODE)
+ return 0;
+
+ if (port_ops == NULL || port_ops->set_pio_mode == NULL)
+ return -1;
+
+ /*
+ * TODO: temporary hack for some legacy host drivers that didn't
+ * set transfer mode on the device in ->set_pio_mode method...
+ */
+ if (port_ops->set_dma_mode == NULL) {
+ port_ops->set_pio_mode(drive, mode - XFER_PIO_0);
+ return 0;
+ }
+
+ if (hwif->host_flags & IDE_HFLAG_POST_SET_MODE) {
+ if (ide_config_drive_speed(drive, mode))
+ return -1;
+ port_ops->set_pio_mode(drive, mode - XFER_PIO_0);
+ return 0;
+ } else {
+ port_ops->set_pio_mode(drive, mode - XFER_PIO_0);
+ return ide_config_drive_speed(drive, mode);
+ }
+}
+
+int ide_set_dma_mode(ide_drive_t *drive, const u8 mode)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ const struct ide_port_ops *port_ops = hwif->port_ops;
+
+ if (hwif->host_flags & IDE_HFLAG_NO_SET_MODE)
+ return 0;
+
+ if (port_ops == NULL || port_ops->set_dma_mode == NULL)
+ return -1;
+
+ if (hwif->host_flags & IDE_HFLAG_POST_SET_MODE) {
+ if (ide_config_drive_speed(drive, mode))
+ return -1;
+ port_ops->set_dma_mode(drive, mode);
+ return 0;
+ } else {
+ port_ops->set_dma_mode(drive, mode);
+ return ide_config_drive_speed(drive, mode);
+ }
+}
+
+EXPORT_SYMBOL_GPL(ide_set_dma_mode);
+
+/**
+ * ide_set_xfer_rate - set transfer rate
+ * @drive: drive to set
+ * @rate: speed to attempt to set
+ *
+ * General helper for setting the speed of an IDE device. This
+ * function knows about user enforced limits from the configuration
+ * which ->set_pio_mode/->set_dma_mode does not.
+ */
+
+int ide_set_xfer_rate(ide_drive_t *drive, u8 rate)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ const struct ide_port_ops *port_ops = hwif->port_ops;
+
+ if (port_ops == NULL || port_ops->set_dma_mode == NULL ||
+ (hwif->host_flags & IDE_HFLAG_NO_SET_MODE))
+ return -1;
+
+ rate = ide_rate_filter(drive, rate);
+
+ BUG_ON(rate < XFER_PIO_0);
+
+ if (rate >= XFER_PIO_0 && rate <= XFER_PIO_5)
+ return ide_set_pio_mode(drive, rate);
+
+ return ide_set_dma_mode(drive, rate);
+}
+
+static void ide_dump_opcode(ide_drive_t *drive)
+{
+ struct request *rq;
+ ide_task_t *task = NULL;
+
+ spin_lock(&ide_lock);
+ rq = NULL;
+ if (HWGROUP(drive))
+ rq = HWGROUP(drive)->rq;
+ spin_unlock(&ide_lock);
+ if (!rq)
+ return;
+
+ if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE)
+ task = rq->special;
+
+ printk("ide: failed opcode was: ");
+ if (task == NULL)
+ printk(KERN_CONT "unknown\n");
+ else
+ printk(KERN_CONT "0x%02x\n", task->tf.command);
+}
+
+u64 ide_get_lba_addr(struct ide_taskfile *tf, int lba48)
+{
+ u32 high, low;
+
+ if (lba48)
+ high = (tf->hob_lbah << 16) | (tf->hob_lbam << 8) |
+ tf->hob_lbal;
+ else
+ high = tf->device & 0xf;
+ low = (tf->lbah << 16) | (tf->lbam << 8) | tf->lbal;
+
+ return ((u64)high << 24) | low;
+}
+EXPORT_SYMBOL_GPL(ide_get_lba_addr);
+
+static void ide_dump_sector(ide_drive_t *drive)
+{
+ ide_task_t task;
+ struct ide_taskfile *tf = &task.tf;
+ u8 lba48 = !!(drive->dev_flags & IDE_DFLAG_LBA48);
+
+ memset(&task, 0, sizeof(task));
+ if (lba48)
+ task.tf_flags = IDE_TFLAG_IN_LBA | IDE_TFLAG_IN_HOB_LBA |
+ IDE_TFLAG_LBA48;
+ else
+ task.tf_flags = IDE_TFLAG_IN_LBA | IDE_TFLAG_IN_DEVICE;
+
+ drive->hwif->tp_ops->tf_read(drive, &task);
+
+ if (lba48 || (tf->device & ATA_LBA))
+ printk(", LBAsect=%llu",
+ (unsigned long long)ide_get_lba_addr(tf, lba48));
+ else
+ printk(", CHS=%d/%d/%d", (tf->lbah << 8) + tf->lbam,
+ tf->device & 0xf, tf->lbal);
+}
+
+static void ide_dump_ata_error(ide_drive_t *drive, u8 err)
+{
+ printk("{ ");
+ if (err & ATA_ABORTED) printk("DriveStatusError ");
+ if (err & ATA_ICRC)
+ printk((err & ATA_ABORTED) ? "BadCRC " : "BadSector ");
+ if (err & ATA_UNC) printk("UncorrectableError ");
+ if (err & ATA_IDNF) printk("SectorIdNotFound ");
+ if (err & ATA_TRK0NF) printk("TrackZeroNotFound ");
+ if (err & ATA_AMNF) printk("AddrMarkNotFound ");
+ printk("}");
+ if ((err & (ATA_BBK | ATA_ABORTED)) == ATA_BBK ||
+ (err & (ATA_UNC | ATA_IDNF | ATA_AMNF))) {
+ ide_dump_sector(drive);
+ if (HWGROUP(drive) && HWGROUP(drive)->rq)
+ printk(", sector=%llu",
+ (unsigned long long)HWGROUP(drive)->rq->sector);
+ }
+ printk("\n");
+}
+
+static void ide_dump_atapi_error(ide_drive_t *drive, u8 err)
+{
+ printk("{ ");
+ if (err & ATAPI_ILI) printk("IllegalLengthIndication ");
+ if (err & ATAPI_EOM) printk("EndOfMedia ");
+ if (err & ATA_ABORTED) printk("AbortedCommand ");
+ if (err & ATA_MCR) printk("MediaChangeRequested ");
+ if (err & ATAPI_LFS) printk("LastFailedSense=0x%02x ",
+ (err & ATAPI_LFS) >> 4);
+ printk("}\n");
+}
+
+/**
+ * ide_dump_status - translate ATA/ATAPI error
+ * @drive: drive that status applies to
+ * @msg: text message to print
+ * @stat: status byte to decode
+ *
+ * Error reporting, in human readable form (luxurious, but a memory hog).
+ * Combines the drive name, message and status byte to provide a
+ * user understandable explanation of the device error.
+ */
+
+u8 ide_dump_status(ide_drive_t *drive, const char *msg, u8 stat)
+{
+ unsigned long flags;
+ u8 err = 0;
+
+ local_irq_save(flags);
+ printk("%s: %s: status=0x%02x { ", drive->name, msg, stat);
+ if (stat & ATA_BUSY)
+ printk("Busy ");
+ else {
+ if (stat & ATA_DRDY) printk("DriveReady ");
+ if (stat & ATA_DF) printk("DeviceFault ");
+ if (stat & ATA_DSC) printk("SeekComplete ");
+ if (stat & ATA_DRQ) printk("DataRequest ");
+ if (stat & ATA_CORR) printk("CorrectedError ");
+ if (stat & ATA_IDX) printk("Index ");
+ if (stat & ATA_ERR) printk("Error ");
+ }
+ printk("}\n");
+ if ((stat & (ATA_BUSY | ATA_ERR)) == ATA_ERR) {
+ err = ide_read_error(drive);
+ printk("%s: %s: error=0x%02x ", drive->name, msg, err);
+ if (drive->media == ide_disk)
+ ide_dump_ata_error(drive, err);
+ else
+ ide_dump_atapi_error(drive, err);
+ }
+ ide_dump_opcode(drive);
+ local_irq_restore(flags);
+ return err;
+}
+
+EXPORT_SYMBOL(ide_dump_status);
diff --git a/drivers/ide/ide-park.c b/drivers/ide/ide-park.c
new file mode 100644
index 0000000..03b00e5
--- /dev/null
+++ b/drivers/ide/ide-park.c
@@ -0,0 +1,121 @@
+#include <linux/kernel.h>
+#include <linux/ide.h>
+#include <linux/jiffies.h>
+#include <linux/blkdev.h>
+
+DECLARE_WAIT_QUEUE_HEAD(ide_park_wq);
+
+static void issue_park_cmd(ide_drive_t *drive, unsigned long timeout)
+{
+ struct request_queue *q = drive->queue;
+ struct request *rq;
+ int rc;
+
+ timeout += jiffies;
+ spin_lock_irq(&ide_lock);
+ if (drive->dev_flags & IDE_DFLAG_PARKED) {
+ ide_hwgroup_t *hwgroup = drive->hwif->hwgroup;
+ int reset_timer;
+
+ reset_timer = time_before(timeout, drive->sleep);
+ drive->sleep = timeout;
+ wake_up_all(&ide_park_wq);
+ if (reset_timer && hwgroup->sleeping &&
+ del_timer(&hwgroup->timer)) {
+ hwgroup->sleeping = 0;
+ hwgroup->busy = 0;
+ blk_start_queueing(q);
+ }
+ spin_unlock_irq(&ide_lock);
+ return;
+ }
+ spin_unlock_irq(&ide_lock);
+
+ rq = blk_get_request(q, READ, __GFP_WAIT);
+ rq->cmd[0] = REQ_PARK_HEADS;
+ rq->cmd_len = 1;
+ rq->cmd_type = REQ_TYPE_SPECIAL;
+ rq->special = &timeout;
+ rc = blk_execute_rq(q, NULL, rq, 1);
+ blk_put_request(rq);
+ if (rc)
+ goto out;
+
+ /*
+ * Make sure that *some* command is sent to the drive after the
+ * timeout has expired, so power management will be reenabled.
+ */
+ rq = blk_get_request(q, READ, GFP_NOWAIT);
+ if (unlikely(!rq))
+ goto out;
+
+ rq->cmd[0] = REQ_UNPARK_HEADS;
+ rq->cmd_len = 1;
+ rq->cmd_type = REQ_TYPE_SPECIAL;
+ elv_add_request(q, rq, ELEVATOR_INSERT_FRONT, 1);
+
+out:
+ return;
+}
+
+ssize_t ide_park_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ ide_drive_t *drive = to_ide_device(dev);
+ unsigned long now;
+ unsigned int msecs;
+
+ if (drive->dev_flags & IDE_DFLAG_NO_UNLOAD)
+ return -EOPNOTSUPP;
+
+ spin_lock_irq(&ide_lock);
+ now = jiffies;
+ if (drive->dev_flags & IDE_DFLAG_PARKED &&
+ time_after(drive->sleep, now))
+ msecs = jiffies_to_msecs(drive->sleep - now);
+ else
+ msecs = 0;
+ spin_unlock_irq(&ide_lock);
+
+ return snprintf(buf, 20, "%u\n", msecs);
+}
+
+ssize_t ide_park_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+#define MAX_PARK_TIMEOUT 30000
+ ide_drive_t *drive = to_ide_device(dev);
+ long int input;
+ int rc;
+
+ rc = strict_strtol(buf, 10, &input);
+ if (rc || input < -2)
+ return -EINVAL;
+ if (input > MAX_PARK_TIMEOUT) {
+ input = MAX_PARK_TIMEOUT;
+ rc = -EOVERFLOW;
+ }
+
+ mutex_lock(&ide_setting_mtx);
+ if (input >= 0) {
+ if (drive->dev_flags & IDE_DFLAG_NO_UNLOAD)
+ rc = -EOPNOTSUPP;
+ else if (input || drive->dev_flags & IDE_DFLAG_PARKED)
+ issue_park_cmd(drive, msecs_to_jiffies(input));
+ } else {
+ if (drive->media == ide_disk)
+ switch (input) {
+ case -1:
+ drive->dev_flags &= ~IDE_DFLAG_NO_UNLOAD;
+ break;
+ case -2:
+ drive->dev_flags |= IDE_DFLAG_NO_UNLOAD;
+ break;
+ }
+ else
+ rc = -EOPNOTSUPP;
+ }
+ mutex_unlock(&ide_setting_mtx);
+
+ return rc ? rc : len;
+}
diff --git a/drivers/ide/ide-pci-generic.c b/drivers/ide/ide-pci-generic.c
new file mode 100644
index 0000000..bddae2b
--- /dev/null
+++ b/drivers/ide/ide-pci-generic.c
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2001-2002 Andre Hedrick <andre@linux-ide.org>
+ * Portions (C) Copyright 2002 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.
+ *
+ * For the avoidance of doubt the "preferred form" of this code is one which
+ * is in an open non patent encumbered format. Where cryptographic key signing
+ * forms part of the process of creating an executable the information
+ * including keys needed to generate an equivalently functional executable
+ * are deemed to be part of the source code.
+ */
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#define DRV_NAME "ide_pci_generic"
+
+static int ide_generic_all; /* Set to claim all devices */
+
+module_param_named(all_generic_ide, ide_generic_all, bool, 0444);
+MODULE_PARM_DESC(all_generic_ide, "IDE generic will claim all unknown PCI IDE storage controllers.");
+
+#define IDE_HFLAGS_UMC (IDE_HFLAG_NO_DMA | IDE_HFLAG_FORCE_LEGACY_IRQS)
+
+#define DECLARE_GENERIC_PCI_DEV(extra_flags) \
+ { \
+ .name = DRV_NAME, \
+ .host_flags = IDE_HFLAG_TRUST_BIOS_FOR_DMA | \
+ extra_flags, \
+ .swdma_mask = ATA_SWDMA2, \
+ .mwdma_mask = ATA_MWDMA2, \
+ .udma_mask = ATA_UDMA6, \
+ }
+
+static const struct ide_port_info generic_chipsets[] __devinitdata = {
+ /* 0: Unknown */
+ DECLARE_GENERIC_PCI_DEV(0),
+
+ { /* 1: NS87410 */
+ .name = DRV_NAME,
+ .enablebits = { {0x43, 0x08, 0x08}, {0x47, 0x08, 0x08} },
+ .host_flags = IDE_HFLAG_TRUST_BIOS_FOR_DMA,
+ .swdma_mask = ATA_SWDMA2,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA6,
+ },
+
+ /* 2: SAMURAI / HT6565 / HINT_IDE */
+ DECLARE_GENERIC_PCI_DEV(0),
+ /* 3: UM8673F / UM8886A / UM8886BF */
+ DECLARE_GENERIC_PCI_DEV(IDE_HFLAGS_UMC),
+ /* 4: VIA_IDE / OPTI621V / Piccolo010{2,3,5} */
+ DECLARE_GENERIC_PCI_DEV(IDE_HFLAG_NO_AUTODMA),
+
+ { /* 5: VIA8237SATA */
+ .name = DRV_NAME,
+ .host_flags = IDE_HFLAG_TRUST_BIOS_FOR_DMA |
+ IDE_HFLAG_OFF_BOARD,
+ .swdma_mask = ATA_SWDMA2,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA6,
+ },
+
+ { /* 6: Revolution */
+ .name = DRV_NAME,
+ .host_flags = IDE_HFLAG_CLEAR_SIMPLEX |
+ IDE_HFLAG_TRUST_BIOS_FOR_DMA |
+ IDE_HFLAG_OFF_BOARD,
+ .swdma_mask = ATA_SWDMA2,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA6,
+ }
+};
+
+/**
+ * generic_init_one - called when a PIIX is found
+ * @dev: the generic device
+ * @id: the matching pci id
+ *
+ * Called when the PCI registration layer (or the IDE initialization)
+ * finds a device matching our IDE device tables.
+ */
+
+static int __devinit generic_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ const struct ide_port_info *d = &generic_chipsets[id->driver_data];
+ int ret = -ENODEV;
+
+ /* Don't use the generic entry unless instructed to do so */
+ if (id->driver_data == 0 && ide_generic_all == 0)
+ goto out;
+
+ switch (dev->vendor) {
+ case PCI_VENDOR_ID_UMC:
+ if (dev->device == PCI_DEVICE_ID_UMC_UM8886A &&
+ !(PCI_FUNC(dev->devfn) & 1))
+ goto out; /* UM8886A/BF pair */
+ break;
+ case PCI_VENDOR_ID_OPTI:
+ if (dev->device == PCI_DEVICE_ID_OPTI_82C558 &&
+ !(PCI_FUNC(dev->devfn) & 1))
+ goto out;
+ break;
+ case PCI_VENDOR_ID_JMICRON:
+ if (dev->device != PCI_DEVICE_ID_JMICRON_JMB368 &&
+ PCI_FUNC(dev->devfn) != 1)
+ goto out;
+ break;
+ case PCI_VENDOR_ID_NS:
+ if (dev->device == PCI_DEVICE_ID_NS_87410 &&
+ (dev->class >> 8) != PCI_CLASS_STORAGE_IDE)
+ goto out;
+ break;
+ }
+
+ if (dev->vendor != PCI_VENDOR_ID_JMICRON) {
+ u16 command;
+ pci_read_config_word(dev, PCI_COMMAND, &command);
+ if (!(command & PCI_COMMAND_IO)) {
+ printk(KERN_INFO "%s %s: skipping disabled "
+ "controller\n", d->name, pci_name(dev));
+ goto out;
+ }
+ }
+ ret = ide_pci_init_one(dev, d, NULL);
+out:
+ return ret;
+}
+
+static const struct pci_device_id generic_pci_tbl[] = {
+ { PCI_VDEVICE(NS, PCI_DEVICE_ID_NS_87410), 1 },
+ { PCI_VDEVICE(PCTECH, PCI_DEVICE_ID_PCTECH_SAMURAI_IDE), 2 },
+ { PCI_VDEVICE(HOLTEK, PCI_DEVICE_ID_HOLTEK_6565), 2 },
+ { PCI_VDEVICE(UMC, PCI_DEVICE_ID_UMC_UM8673F), 3 },
+ { PCI_VDEVICE(UMC, PCI_DEVICE_ID_UMC_UM8886A), 3 },
+ { PCI_VDEVICE(UMC, PCI_DEVICE_ID_UMC_UM8886BF), 3 },
+ { PCI_VDEVICE(HINT, PCI_DEVICE_ID_HINT_VXPROII_IDE), 2 },
+ { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_82C561), 4 },
+ { PCI_VDEVICE(OPTI, PCI_DEVICE_ID_OPTI_82C558), 4 },
+#ifdef CONFIG_BLK_DEV_IDE_SATA
+ { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_8237_SATA), 5 },
+#endif
+ { PCI_VDEVICE(TOSHIBA, PCI_DEVICE_ID_TOSHIBA_PICCOLO), 4 },
+ { PCI_VDEVICE(TOSHIBA, PCI_DEVICE_ID_TOSHIBA_PICCOLO_1), 4 },
+ { PCI_VDEVICE(TOSHIBA, PCI_DEVICE_ID_TOSHIBA_PICCOLO_2), 4 },
+ { PCI_VDEVICE(NETCELL, PCI_DEVICE_ID_REVOLUTION), 6 },
+ /*
+ * Must come last. If you add entries adjust
+ * this table and generic_chipsets[] appropriately.
+ */
+ { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xFFFFFF00UL, 0 },
+ { 0, },
+};
+MODULE_DEVICE_TABLE(pci, generic_pci_tbl);
+
+static struct pci_driver generic_pci_driver = {
+ .name = "PCI_IDE",
+ .id_table = generic_pci_tbl,
+ .probe = generic_init_one,
+ .remove = ide_pci_remove,
+ .suspend = ide_pci_suspend,
+ .resume = ide_pci_resume,
+};
+
+static int __init generic_ide_init(void)
+{
+ return ide_pci_register_driver(&generic_pci_driver);
+}
+
+static void __exit generic_ide_exit(void)
+{
+ pci_unregister_driver(&generic_pci_driver);
+}
+
+module_init(generic_ide_init);
+module_exit(generic_ide_exit);
+
+MODULE_AUTHOR("Andre Hedrick");
+MODULE_DESCRIPTION("PCI driver module for generic PCI IDE");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/ide-pio-blacklist.c b/drivers/ide/ide-pio-blacklist.c
new file mode 100644
index 0000000..a8c2c8f
--- /dev/null
+++ b/drivers/ide/ide-pio-blacklist.c
@@ -0,0 +1,94 @@
+/*
+ * PIO blacklist. Some drives incorrectly report their maximal PIO mode,
+ * at least in respect to CMD640. Here we keep info on some known drives.
+ *
+ * Changes to the ide_pio_blacklist[] should be made with EXTREME CAUTION
+ * to avoid breaking the fragile cmd640.c support.
+ */
+
+#include <linux/string.h>
+
+static struct ide_pio_info {
+ const char *name;
+ int pio;
+} ide_pio_blacklist [] = {
+ { "Conner Peripherals 540MB - CFS540A", 3 },
+
+ { "WDC AC2700", 3 },
+ { "WDC AC2540", 3 },
+ { "WDC AC2420", 3 },
+ { "WDC AC2340", 3 },
+ { "WDC AC2250", 0 },
+ { "WDC AC2200", 0 },
+ { "WDC AC21200", 4 },
+ { "WDC AC2120", 0 },
+ { "WDC AC2850", 3 },
+ { "WDC AC1270", 3 },
+ { "WDC AC1170", 1 },
+ { "WDC AC1210", 1 },
+ { "WDC AC280", 0 },
+ { "WDC AC31000", 3 },
+ { "WDC AC31200", 3 },
+
+ { "Maxtor 7131 AT", 1 },
+ { "Maxtor 7171 AT", 1 },
+ { "Maxtor 7213 AT", 1 },
+ { "Maxtor 7245 AT", 1 },
+ { "Maxtor 7345 AT", 1 },
+ { "Maxtor 7546 AT", 3 },
+ { "Maxtor 7540 AV", 3 },
+
+ { "SAMSUNG SHD-3121A", 1 },
+ { "SAMSUNG SHD-3122A", 1 },
+ { "SAMSUNG SHD-3172A", 1 },
+
+ { "ST5660A", 3 },
+ { "ST3660A", 3 },
+ { "ST3630A", 3 },
+ { "ST3655A", 3 },
+ { "ST3391A", 3 },
+ { "ST3390A", 1 },
+ { "ST3600A", 1 },
+ { "ST3290A", 0 },
+ { "ST3144A", 0 },
+ { "ST3491A", 1 }, /* reports 3, should be 1 or 2 (depending on drive)
+ according to Seagate's FIND-ATA program */
+
+ { "QUANTUM ELS127A", 0 },
+ { "QUANTUM ELS170A", 0 },
+ { "QUANTUM LPS240A", 0 },
+ { "QUANTUM LPS210A", 3 },
+ { "QUANTUM LPS270A", 3 },
+ { "QUANTUM LPS365A", 3 },
+ { "QUANTUM LPS540A", 3 },
+ { "QUANTUM LIGHTNING 540A", 3 },
+ { "QUANTUM LIGHTNING 730A", 3 },
+
+ { "QUANTUM FIREBALL_540", 3 }, /* Older Quantum Fireballs don't work */
+ { "QUANTUM FIREBALL_640", 3 },
+ { "QUANTUM FIREBALL_1080", 3 },
+ { "QUANTUM FIREBALL_1280", 3 },
+ { NULL, 0 }
+};
+
+/**
+ * ide_scan_pio_blacklist - check for a blacklisted drive
+ * @model: Drive model string
+ *
+ * This routine searches the ide_pio_blacklist for an entry
+ * matching the start/whole of the supplied model name.
+ *
+ * Returns -1 if no match found.
+ * Otherwise returns the recommended PIO mode from ide_pio_blacklist[].
+ */
+
+int ide_scan_pio_blacklist(char *model)
+{
+ struct ide_pio_info *p;
+
+ for (p = ide_pio_blacklist; p->name != NULL; p++) {
+ if (strncmp(p->name, model, strlen(p->name)) == 0)
+ return p->pio;
+ }
+ return -1;
+}
diff --git a/drivers/ide/ide-pnp.c b/drivers/ide/ide-pnp.c
new file mode 100644
index 0000000..bac9b39
--- /dev/null
+++ b/drivers/ide/ide-pnp.c
@@ -0,0 +1,107 @@
+/*
+ * This file provides autodetection for ISA PnP IDE interfaces.
+ * It was tested with "ESS ES1868 Plug and Play AudioDrive" IDE interface.
+ *
+ * Copyright (C) 2000 Andrey Panin <pazke@donpac.ru>
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * (for example /usr/src/linux/COPYING); if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/pnp.h>
+#include <linux/ide.h>
+
+#define DRV_NAME "ide-pnp"
+
+/* Add your devices here :)) */
+static struct pnp_device_id idepnp_devices[] = {
+ /* Generic ESDI/IDE/ATA compatible hard disk controller */
+ {.id = "PNP0600", .driver_data = 0},
+ {.id = ""}
+};
+
+static int idepnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
+{
+ struct ide_host *host;
+ unsigned long base, ctl;
+ int rc;
+ hw_regs_t hw, *hws[] = { &hw, NULL, NULL, NULL };
+
+ printk(KERN_INFO DRV_NAME ": generic PnP IDE interface\n");
+
+ if (!(pnp_port_valid(dev, 0) && pnp_port_valid(dev, 1) && pnp_irq_valid(dev, 0)))
+ return -1;
+
+ base = pnp_port_start(dev, 0);
+ ctl = pnp_port_start(dev, 1);
+
+ if (!request_region(base, 8, DRV_NAME)) {
+ printk(KERN_ERR "%s: I/O resource 0x%lX-0x%lX not free.\n",
+ DRV_NAME, base, base + 7);
+ return -EBUSY;
+ }
+
+ if (!request_region(ctl, 1, DRV_NAME)) {
+ printk(KERN_ERR "%s: I/O resource 0x%lX not free.\n",
+ DRV_NAME, ctl);
+ release_region(base, 8);
+ return -EBUSY;
+ }
+
+ memset(&hw, 0, sizeof(hw));
+ ide_std_init_ports(&hw, base, ctl);
+ hw.irq = pnp_irq(dev, 0);
+ hw.chipset = ide_generic;
+
+ rc = ide_host_add(NULL, hws, &host);
+ if (rc)
+ goto out;
+
+ pnp_set_drvdata(dev, host);
+
+ return 0;
+out:
+ release_region(ctl, 1);
+ release_region(base, 8);
+
+ return rc;
+}
+
+static void idepnp_remove(struct pnp_dev *dev)
+{
+ struct ide_host *host = pnp_get_drvdata(dev);
+
+ ide_host_remove(host);
+
+ release_region(pnp_port_start(dev, 1), 1);
+ release_region(pnp_port_start(dev, 0), 8);
+}
+
+static struct pnp_driver idepnp_driver = {
+ .name = "ide",
+ .id_table = idepnp_devices,
+ .probe = idepnp_probe,
+ .remove = idepnp_remove,
+};
+
+static int __init pnpide_init(void)
+{
+ return pnp_register_driver(&idepnp_driver);
+}
+
+static void __exit pnpide_exit(void)
+{
+ pnp_unregister_driver(&idepnp_driver);
+}
+
+module_init(pnpide_init);
+module_exit(pnpide_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c
new file mode 100644
index 0000000..c55bdbd
--- /dev/null
+++ b/drivers/ide/ide-probe.c
@@ -0,0 +1,1852 @@
+/*
+ * Copyright (C) 1994-1998 Linus Torvalds & authors (see below)
+ * Copyright (C) 2005, 2007 Bartlomiej Zolnierkiewicz
+ */
+
+/*
+ * Mostly written by Mark Lord <mlord@pobox.com>
+ * and Gadi Oxman <gadio@netvision.net.il>
+ * and Andre Hedrick <andre@linux-ide.org>
+ *
+ * See linux/MAINTAINERS for address of current maintainer.
+ *
+ * This is the IDE probe module, as evolved from hd.c and ide.c.
+ *
+ * -- increase WAIT_PIDENTIFY to avoid CD-ROM locking at boot
+ * by Andrea Arcangeli
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/major.h>
+#include <linux/errno.h>
+#include <linux/genhd.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/ide.h>
+#include <linux/spinlock.h>
+#include <linux/kmod.h>
+#include <linux/pci.h>
+#include <linux/scatterlist.h>
+
+#include <asm/byteorder.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+/**
+ * generic_id - add a generic drive id
+ * @drive: drive to make an ID block for
+ *
+ * Add a fake id field to the drive we are passed. This allows
+ * use to skip a ton of NULL checks (which people always miss)
+ * and make drive properties unconditional outside of this file
+ */
+
+static void generic_id(ide_drive_t *drive)
+{
+ u16 *id = drive->id;
+
+ id[ATA_ID_CUR_CYLS] = id[ATA_ID_CYLS] = drive->cyl;
+ id[ATA_ID_CUR_HEADS] = id[ATA_ID_HEADS] = drive->head;
+ id[ATA_ID_CUR_SECTORS] = id[ATA_ID_SECTORS] = drive->sect;
+}
+
+static void ide_disk_init_chs(ide_drive_t *drive)
+{
+ u16 *id = drive->id;
+
+ /* Extract geometry if we did not already have one for the drive */
+ if (!drive->cyl || !drive->head || !drive->sect) {
+ drive->cyl = drive->bios_cyl = id[ATA_ID_CYLS];
+ drive->head = drive->bios_head = id[ATA_ID_HEADS];
+ drive->sect = drive->bios_sect = id[ATA_ID_SECTORS];
+ }
+
+ /* Handle logical geometry translation by the drive */
+ if (ata_id_current_chs_valid(id)) {
+ drive->cyl = id[ATA_ID_CUR_CYLS];
+ drive->head = id[ATA_ID_CUR_HEADS];
+ drive->sect = id[ATA_ID_CUR_SECTORS];
+ }
+
+ /* Use physical geometry if what we have still makes no sense */
+ if (drive->head > 16 && id[ATA_ID_HEADS] && id[ATA_ID_HEADS] <= 16) {
+ drive->cyl = id[ATA_ID_CYLS];
+ drive->head = id[ATA_ID_HEADS];
+ drive->sect = id[ATA_ID_SECTORS];
+ }
+}
+
+static void ide_disk_init_mult_count(ide_drive_t *drive)
+{
+ u16 *id = drive->id;
+ u8 max_multsect = id[ATA_ID_MAX_MULTSECT] & 0xff;
+
+ if (max_multsect) {
+ if ((max_multsect / 2) > 1)
+ id[ATA_ID_MULTSECT] = max_multsect | 0x100;
+ else
+ id[ATA_ID_MULTSECT] &= ~0x1ff;
+
+ drive->mult_req = id[ATA_ID_MULTSECT] & 0xff;
+
+ if (drive->mult_req)
+ drive->special.b.set_multmode = 1;
+ }
+}
+
+/**
+ * do_identify - identify a drive
+ * @drive: drive to identify
+ * @cmd: command used
+ *
+ * Called when we have issued a drive identify command to
+ * read and parse the results. This function is run with
+ * interrupts disabled.
+ */
+
+static inline void do_identify (ide_drive_t *drive, u8 cmd)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ u16 *id = drive->id;
+ char *m = (char *)&id[ATA_ID_PROD];
+ int bswap = 1, is_cfa;
+
+ /* read 512 bytes of id info */
+ hwif->tp_ops->input_data(drive, NULL, id, SECTOR_SIZE);
+
+ drive->dev_flags |= IDE_DFLAG_ID_READ;
+
+ local_irq_enable();
+#ifdef DEBUG
+ printk(KERN_INFO "%s: dumping identify data\n", drive->name);
+ ide_dump_identify((u8 *)id);
+#endif
+ ide_fix_driveid(id);
+
+ /*
+ * ATA_CMD_ID_ATA returns little-endian info,
+ * ATA_CMD_ID_ATAPI *usually* returns little-endian info.
+ */
+ if (cmd == ATA_CMD_ID_ATAPI) {
+ if ((m[0] == 'N' && m[1] == 'E') || /* NEC */
+ (m[0] == 'F' && m[1] == 'X') || /* Mitsumi */
+ (m[0] == 'P' && m[1] == 'i')) /* Pioneer */
+ /* Vertos drives may still be weird */
+ bswap ^= 1;
+ }
+
+ ide_fixstring(m, ATA_ID_PROD_LEN, bswap);
+ ide_fixstring((char *)&id[ATA_ID_FW_REV], ATA_ID_FW_REV_LEN, bswap);
+ ide_fixstring((char *)&id[ATA_ID_SERNO], ATA_ID_SERNO_LEN, bswap);
+
+ /* we depend on this a lot! */
+ m[ATA_ID_PROD_LEN - 1] = '\0';
+
+ if (strstr(m, "E X A B Y T E N E S T"))
+ goto err_misc;
+
+ printk(KERN_INFO "%s: %s, ", drive->name, m);
+
+ drive->dev_flags |= IDE_DFLAG_PRESENT;
+ drive->dev_flags &= ~IDE_DFLAG_DEAD;
+
+ /*
+ * Check for an ATAPI device
+ */
+ if (cmd == ATA_CMD_ID_ATAPI) {
+ u8 type = (id[ATA_ID_CONFIG] >> 8) & 0x1f;
+
+ printk(KERN_CONT "ATAPI ");
+ switch (type) {
+ case ide_floppy:
+ if (!strstr(m, "CD-ROM")) {
+ if (!strstr(m, "oppy") &&
+ !strstr(m, "poyp") &&
+ !strstr(m, "ZIP"))
+ printk(KERN_CONT "cdrom or floppy?, assuming ");
+ if (drive->media != ide_cdrom) {
+ printk(KERN_CONT "FLOPPY");
+ drive->dev_flags |= IDE_DFLAG_REMOVABLE;
+ break;
+ }
+ }
+ /* Early cdrom models used zero */
+ type = ide_cdrom;
+ case ide_cdrom:
+ drive->dev_flags |= IDE_DFLAG_REMOVABLE;
+#ifdef CONFIG_PPC
+ /* kludge for Apple PowerBook internal zip */
+ if (!strstr(m, "CD-ROM") && strstr(m, "ZIP")) {
+ printk(KERN_CONT "FLOPPY");
+ type = ide_floppy;
+ break;
+ }
+#endif
+ printk(KERN_CONT "CD/DVD-ROM");
+ break;
+ case ide_tape:
+ printk(KERN_CONT "TAPE");
+ break;
+ case ide_optical:
+ printk(KERN_CONT "OPTICAL");
+ drive->dev_flags |= IDE_DFLAG_REMOVABLE;
+ break;
+ default:
+ printk(KERN_CONT "UNKNOWN (type %d)", type);
+ break;
+ }
+ printk(KERN_CONT " drive\n");
+ drive->media = type;
+ /* an ATAPI device ignores DRDY */
+ drive->ready_stat = 0;
+ if (ata_id_cdb_intr(id))
+ drive->atapi_flags |= IDE_AFLAG_DRQ_INTERRUPT;
+ drive->dev_flags |= IDE_DFLAG_DOORLOCKING;
+ /* we don't do head unloading on ATAPI devices */
+ drive->dev_flags |= IDE_DFLAG_NO_UNLOAD;
+ return;
+ }
+
+ /*
+ * Not an ATAPI device: looks like a "regular" hard disk
+ */
+
+ is_cfa = ata_id_is_cfa(id);
+
+ /* CF devices are *not* removable in Linux definition of the term */
+ if (is_cfa == 0 && (id[ATA_ID_CONFIG] & (1 << 7)))
+ drive->dev_flags |= IDE_DFLAG_REMOVABLE;
+
+ drive->media = ide_disk;
+
+ if (!ata_id_has_unload(drive->id))
+ drive->dev_flags |= IDE_DFLAG_NO_UNLOAD;
+
+ printk(KERN_CONT "%s DISK drive\n", is_cfa ? "CFA" : "ATA");
+
+ return;
+
+err_misc:
+ kfree(id);
+ drive->dev_flags &= ~IDE_DFLAG_PRESENT;
+ return;
+}
+
+/**
+ * actual_try_to_identify - send ata/atapi identify
+ * @drive: drive to identify
+ * @cmd: command to use
+ *
+ * try_to_identify() sends an ATA(PI) IDENTIFY request to a drive
+ * and waits for a response. It also monitors irqs while this is
+ * happening, in hope of automatically determining which one is
+ * being used by the interface.
+ *
+ * Returns: 0 device was identified
+ * 1 device timed-out (no response to identify request)
+ * 2 device aborted the command (refused to identify itself)
+ */
+
+static int actual_try_to_identify (ide_drive_t *drive, u8 cmd)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct ide_io_ports *io_ports = &hwif->io_ports;
+ const struct ide_tp_ops *tp_ops = hwif->tp_ops;
+ int use_altstatus = 0, rc;
+ unsigned long timeout;
+ u8 s = 0, a = 0;
+
+ /* take a deep breath */
+ msleep(50);
+
+ if (io_ports->ctl_addr &&
+ (hwif->host_flags & IDE_HFLAG_BROKEN_ALTSTATUS) == 0) {
+ a = tp_ops->read_altstatus(hwif);
+ s = tp_ops->read_status(hwif);
+ if ((a ^ s) & ~ATA_IDX)
+ /* ancient Seagate drives, broken interfaces */
+ printk(KERN_INFO "%s: probing with STATUS(0x%02x) "
+ "instead of ALTSTATUS(0x%02x)\n",
+ drive->name, s, a);
+ else
+ /* use non-intrusive polling */
+ use_altstatus = 1;
+ }
+
+ /* set features register for atapi
+ * identify command to be sure of reply
+ */
+ if (cmd == ATA_CMD_ID_ATAPI) {
+ ide_task_t task;
+
+ memset(&task, 0, sizeof(task));
+ /* disable DMA & overlap */
+ task.tf_flags = IDE_TFLAG_OUT_FEATURE;
+
+ tp_ops->tf_load(drive, &task);
+ }
+
+ /* ask drive for ID */
+ tp_ops->exec_command(hwif, cmd);
+
+ timeout = ((cmd == ATA_CMD_ID_ATA) ? WAIT_WORSTCASE : WAIT_PIDENTIFY) / 2;
+
+ if (ide_busy_sleep(hwif, timeout, use_altstatus))
+ return 1;
+
+ /* wait for IRQ and ATA_DRQ */
+ msleep(50);
+ s = tp_ops->read_status(hwif);
+
+ if (OK_STAT(s, ATA_DRQ, BAD_R_STAT)) {
+ unsigned long flags;
+
+ /* local CPU only; some systems need this */
+ local_irq_save(flags);
+ /* drive returned ID */
+ do_identify(drive, cmd);
+ /* drive responded with ID */
+ rc = 0;
+ /* clear drive IRQ */
+ (void)tp_ops->read_status(hwif);
+ local_irq_restore(flags);
+ } else {
+ /* drive refused ID */
+ rc = 2;
+ }
+ return rc;
+}
+
+/**
+ * try_to_identify - try to identify a drive
+ * @drive: drive to probe
+ * @cmd: command to use
+ *
+ * Issue the identify command and then do IRQ probing to
+ * complete the identification when needed by finding the
+ * IRQ the drive is attached to
+ */
+
+static int try_to_identify (ide_drive_t *drive, u8 cmd)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ const struct ide_tp_ops *tp_ops = hwif->tp_ops;
+ int retval;
+ int autoprobe = 0;
+ unsigned long cookie = 0;
+
+ /*
+ * Disable device irq unless we need to
+ * probe for it. Otherwise we'll get spurious
+ * interrupts during the identify-phase that
+ * the irq handler isn't expecting.
+ */
+ if (hwif->io_ports.ctl_addr) {
+ if (!hwif->irq) {
+ autoprobe = 1;
+ cookie = probe_irq_on();
+ }
+ tp_ops->set_irq(hwif, autoprobe);
+ }
+
+ retval = actual_try_to_identify(drive, cmd);
+
+ if (autoprobe) {
+ int irq;
+
+ tp_ops->set_irq(hwif, 0);
+ /* clear drive IRQ */
+ (void)tp_ops->read_status(hwif);
+ udelay(5);
+ irq = probe_irq_off(cookie);
+ if (!hwif->irq) {
+ if (irq > 0) {
+ hwif->irq = irq;
+ } else {
+ /* Mmmm.. multiple IRQs..
+ * don't know which was ours
+ */
+ printk(KERN_ERR "%s: IRQ probe failed (0x%lx)\n",
+ drive->name, cookie);
+ }
+ }
+ }
+ return retval;
+}
+
+int ide_busy_sleep(ide_hwif_t *hwif, unsigned long timeout, int altstatus)
+{
+ u8 stat;
+
+ timeout += jiffies;
+
+ do {
+ msleep(50); /* give drive a breather */
+ stat = altstatus ? hwif->tp_ops->read_altstatus(hwif)
+ : hwif->tp_ops->read_status(hwif);
+ if ((stat & ATA_BUSY) == 0)
+ return 0;
+ } while (time_before(jiffies, timeout));
+
+ return 1; /* drive timed-out */
+}
+
+static u8 ide_read_device(ide_drive_t *drive)
+{
+ ide_task_t task;
+
+ memset(&task, 0, sizeof(task));
+ task.tf_flags = IDE_TFLAG_IN_DEVICE;
+
+ drive->hwif->tp_ops->tf_read(drive, &task);
+
+ return task.tf.device;
+}
+
+/**
+ * do_probe - probe an IDE device
+ * @drive: drive to probe
+ * @cmd: command to use
+ *
+ * do_probe() has the difficult job of finding a drive if it exists,
+ * without getting hung up if it doesn't exist, without trampling on
+ * ethernet cards, and without leaving any IRQs dangling to haunt us later.
+ *
+ * If a drive is "known" to exist (from CMOS or kernel parameters),
+ * but does not respond right away, the probe will "hang in there"
+ * for the maximum wait time (about 30 seconds), otherwise it will
+ * exit much more quickly.
+ *
+ * Returns: 0 device was identified
+ * 1 device timed-out (no response to identify request)
+ * 2 device aborted the command (refused to identify itself)
+ * 3 bad status from device (possible for ATAPI drives)
+ * 4 probe was not attempted because failure was obvious
+ */
+
+static int do_probe (ide_drive_t *drive, u8 cmd)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ const struct ide_tp_ops *tp_ops = hwif->tp_ops;
+ int rc;
+ u8 present = !!(drive->dev_flags & IDE_DFLAG_PRESENT), stat;
+
+ /* avoid waiting for inappropriate probes */
+ if (present && drive->media != ide_disk && cmd == ATA_CMD_ID_ATA)
+ return 4;
+
+#ifdef DEBUG
+ printk(KERN_INFO "probing for %s: present=%d, media=%d, probetype=%s\n",
+ drive->name, present, drive->media,
+ (cmd == ATA_CMD_ID_ATA) ? "ATA" : "ATAPI");
+#endif
+
+ /* needed for some systems
+ * (e.g. crw9624 as drive0 with disk as slave)
+ */
+ msleep(50);
+ SELECT_DRIVE(drive);
+ msleep(50);
+
+ if (ide_read_device(drive) != drive->select && present == 0) {
+ if (drive->dn & 1) {
+ /* exit with drive0 selected */
+ SELECT_DRIVE(&hwif->drives[0]);
+ /* allow ATA_BUSY to assert & clear */
+ msleep(50);
+ }
+ /* no i/f present: mmm.. this should be a 4 -ml */
+ return 3;
+ }
+
+ stat = tp_ops->read_status(hwif);
+
+ if (OK_STAT(stat, ATA_DRDY, ATA_BUSY) ||
+ present || cmd == ATA_CMD_ID_ATAPI) {
+ /* send cmd and wait */
+ if ((rc = try_to_identify(drive, cmd))) {
+ /* failed: try again */
+ rc = try_to_identify(drive,cmd);
+ }
+
+ stat = tp_ops->read_status(hwif);
+
+ if (stat == (ATA_BUSY | ATA_DRDY))
+ return 4;
+
+ if (rc == 1 && cmd == ATA_CMD_ID_ATAPI) {
+ printk(KERN_ERR "%s: no response (status = 0x%02x), "
+ "resetting drive\n", drive->name, stat);
+ msleep(50);
+ SELECT_DRIVE(drive);
+ msleep(50);
+ tp_ops->exec_command(hwif, ATA_CMD_DEV_RESET);
+ (void)ide_busy_sleep(hwif, WAIT_WORSTCASE, 0);
+ rc = try_to_identify(drive, cmd);
+ }
+
+ /* ensure drive IRQ is clear */
+ stat = tp_ops->read_status(hwif);
+
+ if (rc == 1)
+ printk(KERN_ERR "%s: no response (status = 0x%02x)\n",
+ drive->name, stat);
+ } else {
+ /* not present or maybe ATAPI */
+ rc = 3;
+ }
+ if (drive->dn & 1) {
+ /* exit with drive0 selected */
+ SELECT_DRIVE(&hwif->drives[0]);
+ msleep(50);
+ /* ensure drive irq is clear */
+ (void)tp_ops->read_status(hwif);
+ }
+ return rc;
+}
+
+/*
+ *
+ */
+static void enable_nest (ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ const struct ide_tp_ops *tp_ops = hwif->tp_ops;
+ u8 stat;
+
+ printk(KERN_INFO "%s: enabling %s -- ",
+ hwif->name, (char *)&drive->id[ATA_ID_PROD]);
+
+ SELECT_DRIVE(drive);
+ msleep(50);
+ tp_ops->exec_command(hwif, ATA_EXABYTE_ENABLE_NEST);
+
+ if (ide_busy_sleep(hwif, WAIT_WORSTCASE, 0)) {
+ printk(KERN_CONT "failed (timeout)\n");
+ return;
+ }
+
+ msleep(50);
+
+ stat = tp_ops->read_status(hwif);
+
+ if (!OK_STAT(stat, 0, BAD_STAT))
+ printk(KERN_CONT "failed (status = 0x%02x)\n", stat);
+ else
+ printk(KERN_CONT "success\n");
+}
+
+/**
+ * probe_for_drives - upper level drive probe
+ * @drive: drive to probe for
+ *
+ * probe_for_drive() tests for existence of a given drive using do_probe()
+ * and presents things to the user as needed.
+ *
+ * Returns: 0 no device was found
+ * 1 device was found
+ * (note: IDE_DFLAG_PRESENT might still be not set)
+ */
+
+static inline u8 probe_for_drive (ide_drive_t *drive)
+{
+ char *m;
+
+ /*
+ * In order to keep things simple we have an id
+ * block for all drives at all times. If the device
+ * is pre ATA or refuses ATA/ATAPI identify we
+ * will add faked data to this.
+ *
+ * Also note that 0 everywhere means "can't do X"
+ */
+
+ drive->dev_flags &= ~IDE_DFLAG_ID_READ;
+
+ drive->id = kzalloc(SECTOR_SIZE, GFP_KERNEL);
+ if (drive->id == NULL) {
+ printk(KERN_ERR "ide: out of memory for id data.\n");
+ return 0;
+ }
+
+ m = (char *)&drive->id[ATA_ID_PROD];
+ strcpy(m, "UNKNOWN");
+
+ /* skip probing? */
+ if ((drive->dev_flags & IDE_DFLAG_NOPROBE) == 0) {
+retry:
+ /* if !(success||timed-out) */
+ if (do_probe(drive, ATA_CMD_ID_ATA) >= 2)
+ /* look for ATAPI device */
+ (void)do_probe(drive, ATA_CMD_ID_ATAPI);
+
+ if ((drive->dev_flags & IDE_DFLAG_PRESENT) == 0)
+ /* drive not found */
+ return 0;
+
+ if (strstr(m, "E X A B Y T E N E S T")) {
+ enable_nest(drive);
+ goto retry;
+ }
+
+ /* identification failed? */
+ if ((drive->dev_flags & IDE_DFLAG_ID_READ) == 0) {
+ if (drive->media == ide_disk) {
+ printk(KERN_INFO "%s: non-IDE drive, CHS=%d/%d/%d\n",
+ drive->name, drive->cyl,
+ drive->head, drive->sect);
+ } else if (drive->media == ide_cdrom) {
+ printk(KERN_INFO "%s: ATAPI cdrom (?)\n", drive->name);
+ } else {
+ /* nuke it */
+ printk(KERN_WARNING "%s: Unknown device on bus refused identification. Ignoring.\n", drive->name);
+ drive->dev_flags &= ~IDE_DFLAG_PRESENT;
+ }
+ }
+ /* drive was found */
+ }
+
+ if ((drive->dev_flags & IDE_DFLAG_PRESENT) == 0)
+ return 0;
+
+ /* The drive wasn't being helpful. Add generic info only */
+ if ((drive->dev_flags & IDE_DFLAG_ID_READ) == 0) {
+ generic_id(drive);
+ return 1;
+ }
+
+ if (drive->media == ide_disk) {
+ ide_disk_init_chs(drive);
+ ide_disk_init_mult_count(drive);
+ }
+
+ return !!(drive->dev_flags & IDE_DFLAG_PRESENT);
+}
+
+static void hwif_release_dev(struct device *dev)
+{
+ ide_hwif_t *hwif = container_of(dev, ide_hwif_t, gendev);
+
+ complete(&hwif->gendev_rel_comp);
+}
+
+static int ide_register_port(ide_hwif_t *hwif)
+{
+ int ret;
+
+ /* register with global device tree */
+ strlcpy(hwif->gendev.bus_id,hwif->name,BUS_ID_SIZE);
+ hwif->gendev.driver_data = hwif;
+ if (hwif->gendev.parent == NULL) {
+ if (hwif->dev)
+ hwif->gendev.parent = hwif->dev;
+ else
+ /* Would like to do = &device_legacy */
+ hwif->gendev.parent = NULL;
+ }
+ hwif->gendev.release = hwif_release_dev;
+ ret = device_register(&hwif->gendev);
+ if (ret < 0) {
+ printk(KERN_WARNING "IDE: %s: device_register error: %d\n",
+ __func__, ret);
+ goto out;
+ }
+
+ hwif->portdev = device_create(ide_port_class, &hwif->gendev,
+ MKDEV(0, 0), hwif, hwif->name);
+ if (IS_ERR(hwif->portdev)) {
+ ret = PTR_ERR(hwif->portdev);
+ device_unregister(&hwif->gendev);
+ }
+out:
+ return ret;
+}
+
+/**
+ * ide_port_wait_ready - wait for port to become ready
+ * @hwif: IDE port
+ *
+ * This is needed on some PPCs and a bunch of BIOS-less embedded
+ * platforms. Typical cases are:
+ *
+ * - The firmware hard reset the disk before booting the kernel,
+ * the drive is still doing it's poweron-reset sequence, that
+ * can take up to 30 seconds.
+ *
+ * - The firmware does nothing (or no firmware), the device is
+ * still in POST state (same as above actually).
+ *
+ * - Some CD/DVD/Writer combo drives tend to drive the bus during
+ * their reset sequence even when they are non-selected slave
+ * devices, thus preventing discovery of the main HD.
+ *
+ * Doing this wait-for-non-busy should not harm any existing
+ * configuration and fix some issues like the above.
+ *
+ * BenH.
+ *
+ * Returns 0 on success, error code (< 0) otherwise.
+ */
+
+static int ide_port_wait_ready(ide_hwif_t *hwif)
+{
+ int unit, rc;
+
+ printk(KERN_DEBUG "Probing IDE interface %s...\n", hwif->name);
+
+ /* Let HW settle down a bit from whatever init state we
+ * come from */
+ mdelay(2);
+
+ /* Wait for BSY bit to go away, spec timeout is 30 seconds,
+ * I know of at least one disk who takes 31 seconds, I use 35
+ * here to be safe
+ */
+ rc = ide_wait_not_busy(hwif, 35000);
+ if (rc)
+ return rc;
+
+ /* Now make sure both master & slave are ready */
+ for (unit = 0; unit < MAX_DRIVES; unit++) {
+ ide_drive_t *drive = &hwif->drives[unit];
+
+ /* Ignore disks that we will not probe for later. */
+ if ((drive->dev_flags & IDE_DFLAG_NOPROBE) == 0 ||
+ (drive->dev_flags & IDE_DFLAG_PRESENT)) {
+ SELECT_DRIVE(drive);
+ hwif->tp_ops->set_irq(hwif, 1);
+ mdelay(2);
+ rc = ide_wait_not_busy(hwif, 35000);
+ if (rc)
+ goto out;
+ } else
+ printk(KERN_DEBUG "%s: ide_wait_not_busy() skipped\n",
+ drive->name);
+ }
+out:
+ /* Exit function with master reselected (let's be sane) */
+ if (unit)
+ SELECT_DRIVE(&hwif->drives[0]);
+
+ return rc;
+}
+
+/**
+ * ide_undecoded_slave - look for bad CF adapters
+ * @dev1: slave device
+ *
+ * Analyse the drives on the interface and attempt to decide if we
+ * have the same drive viewed twice. This occurs with crap CF adapters
+ * and PCMCIA sometimes.
+ */
+
+void ide_undecoded_slave(ide_drive_t *dev1)
+{
+ ide_drive_t *dev0 = &dev1->hwif->drives[0];
+
+ if ((dev1->dn & 1) == 0 || (dev0->dev_flags & IDE_DFLAG_PRESENT) == 0)
+ return;
+
+ /* If the models don't match they are not the same product */
+ if (strcmp((char *)&dev0->id[ATA_ID_PROD],
+ (char *)&dev1->id[ATA_ID_PROD]))
+ return;
+
+ /* Serial numbers do not match */
+ if (strncmp((char *)&dev0->id[ATA_ID_SERNO],
+ (char *)&dev1->id[ATA_ID_SERNO], ATA_ID_SERNO_LEN))
+ return;
+
+ /* No serial number, thankfully very rare for CF */
+ if (*(char *)&dev0->id[ATA_ID_SERNO] == 0)
+ return;
+
+ /* Appears to be an IDE flash adapter with decode bugs */
+ printk(KERN_WARNING "ide-probe: ignoring undecoded slave\n");
+
+ dev1->dev_flags &= ~IDE_DFLAG_PRESENT;
+}
+
+EXPORT_SYMBOL_GPL(ide_undecoded_slave);
+
+static int ide_probe_port(ide_hwif_t *hwif)
+{
+ unsigned long flags;
+ unsigned int irqd;
+ int unit, rc = -ENODEV;
+
+ BUG_ON(hwif->present);
+
+ if ((hwif->drives[0].dev_flags & IDE_DFLAG_NOPROBE) &&
+ (hwif->drives[1].dev_flags & IDE_DFLAG_NOPROBE))
+ return -EACCES;
+
+ /*
+ * We must always disable IRQ, as probe_for_drive will assert IRQ, but
+ * we'll install our IRQ driver much later...
+ */
+ irqd = hwif->irq;
+ if (irqd)
+ disable_irq(hwif->irq);
+
+ local_irq_set(flags);
+
+ if (ide_port_wait_ready(hwif) == -EBUSY)
+ printk(KERN_DEBUG "%s: Wait for ready failed before probe !\n", hwif->name);
+
+ /*
+ * Second drive should only exist if first drive was found,
+ * but a lot of cdrom drives are configured as single slaves.
+ */
+ for (unit = 0; unit < MAX_DRIVES; ++unit) {
+ ide_drive_t *drive = &hwif->drives[unit];
+
+ (void) probe_for_drive(drive);
+ if (drive->dev_flags & IDE_DFLAG_PRESENT)
+ rc = 0;
+ }
+
+ local_irq_restore(flags);
+
+ /*
+ * Use cached IRQ number. It might be (and is...) changed by probe
+ * code above
+ */
+ if (irqd)
+ enable_irq(irqd);
+
+ return rc;
+}
+
+static void ide_port_tune_devices(ide_hwif_t *hwif)
+{
+ const struct ide_port_ops *port_ops = hwif->port_ops;
+ int unit;
+
+ for (unit = 0; unit < MAX_DRIVES; unit++) {
+ ide_drive_t *drive = &hwif->drives[unit];
+
+ if (drive->dev_flags & IDE_DFLAG_PRESENT) {
+ if (port_ops && port_ops->quirkproc)
+ port_ops->quirkproc(drive);
+ }
+ }
+
+ for (unit = 0; unit < MAX_DRIVES; ++unit) {
+ ide_drive_t *drive = &hwif->drives[unit];
+
+ if (drive->dev_flags & IDE_DFLAG_PRESENT) {
+ ide_set_max_pio(drive);
+
+ drive->dev_flags |= IDE_DFLAG_NICE1;
+
+ if (hwif->dma_ops)
+ ide_set_dma(drive);
+ }
+ }
+
+ for (unit = 0; unit < MAX_DRIVES; ++unit) {
+ ide_drive_t *drive = &hwif->drives[unit];
+
+ if ((hwif->host_flags & IDE_HFLAG_NO_IO_32BIT) ||
+ drive->id[ATA_ID_DWORD_IO])
+ drive->dev_flags |= IDE_DFLAG_NO_IO_32BIT;
+ else
+ drive->dev_flags &= ~IDE_DFLAG_NO_IO_32BIT;
+ }
+}
+
+/*
+ * save_match() is used to simplify logic in init_irq() below.
+ *
+ * A loophole here is that we may not know about a particular
+ * hwif's irq until after that hwif is actually probed/initialized..
+ * This could be a problem for the case where an hwif is on a
+ * dual interface that requires serialization (eg. cmd640) and another
+ * hwif using one of the same irqs is initialized beforehand.
+ *
+ * This routine detects and reports such situations, but does not fix them.
+ */
+static void save_match(ide_hwif_t *hwif, ide_hwif_t *new, ide_hwif_t **match)
+{
+ ide_hwif_t *m = *match;
+
+ if (m && m->hwgroup && m->hwgroup != new->hwgroup) {
+ if (!new->hwgroup)
+ return;
+ printk(KERN_WARNING "%s: potential IRQ problem with %s and %s\n",
+ hwif->name, new->name, m->name);
+ }
+ if (!m || m->irq != hwif->irq) /* don't undo a prior perfect match */
+ *match = new;
+}
+
+/*
+ * init request queue
+ */
+static int ide_init_queue(ide_drive_t *drive)
+{
+ struct request_queue *q;
+ ide_hwif_t *hwif = HWIF(drive);
+ int max_sectors = 256;
+ int max_sg_entries = PRD_ENTRIES;
+
+ /*
+ * Our default set up assumes the normal IDE case,
+ * that is 64K segmenting, standard PRD setup
+ * and LBA28. Some drivers then impose their own
+ * limits and LBA48 we could raise it but as yet
+ * do not.
+ */
+
+ q = blk_init_queue_node(do_ide_request, &ide_lock, hwif_to_node(hwif));
+ if (!q)
+ return 1;
+
+ q->queuedata = drive;
+ blk_queue_segment_boundary(q, 0xffff);
+
+ if (hwif->rqsize < max_sectors)
+ max_sectors = hwif->rqsize;
+ blk_queue_max_sectors(q, max_sectors);
+
+#ifdef CONFIG_PCI
+ /* When we have an IOMMU, we may have a problem where pci_map_sg()
+ * creates segments that don't completely match our boundary
+ * requirements and thus need to be broken up again. Because it
+ * doesn't align properly either, we may actually have to break up
+ * to more segments than what was we got in the first place, a max
+ * worst case is twice as many.
+ * This will be fixed once we teach pci_map_sg() about our boundary
+ * requirements, hopefully soon. *FIXME*
+ */
+ if (!PCI_DMA_BUS_IS_PHYS)
+ max_sg_entries >>= 1;
+#endif /* CONFIG_PCI */
+
+ blk_queue_max_hw_segments(q, max_sg_entries);
+ blk_queue_max_phys_segments(q, max_sg_entries);
+
+ /* assign drive queue */
+ drive->queue = q;
+
+ /* needs drive->queue to be set */
+ ide_toggle_bounce(drive, 1);
+
+ return 0;
+}
+
+static void ide_add_drive_to_hwgroup(ide_drive_t *drive)
+{
+ ide_hwgroup_t *hwgroup = drive->hwif->hwgroup;
+
+ spin_lock_irq(&ide_lock);
+ if (!hwgroup->drive) {
+ /* first drive for hwgroup. */
+ drive->next = drive;
+ hwgroup->drive = drive;
+ hwgroup->hwif = HWIF(hwgroup->drive);
+ } else {
+ drive->next = hwgroup->drive->next;
+ hwgroup->drive->next = drive;
+ }
+ spin_unlock_irq(&ide_lock);
+}
+
+/*
+ * For any present drive:
+ * - allocate the block device queue
+ * - link drive into the hwgroup
+ */
+static int ide_port_setup_devices(ide_hwif_t *hwif)
+{
+ int i, j = 0;
+
+ mutex_lock(&ide_cfg_mtx);
+ for (i = 0; i < MAX_DRIVES; i++) {
+ ide_drive_t *drive = &hwif->drives[i];
+
+ if ((drive->dev_flags & IDE_DFLAG_PRESENT) == 0)
+ continue;
+
+ if (ide_init_queue(drive)) {
+ printk(KERN_ERR "ide: failed to init %s\n",
+ drive->name);
+ kfree(drive->id);
+ drive->id = NULL;
+ drive->dev_flags &= ~IDE_DFLAG_PRESENT;
+ continue;
+ }
+
+ j++;
+
+ ide_add_drive_to_hwgroup(drive);
+ }
+ mutex_unlock(&ide_cfg_mtx);
+
+ return j;
+}
+
+static ide_hwif_t *ide_ports[MAX_HWIFS];
+
+void ide_remove_port_from_hwgroup(ide_hwif_t *hwif)
+{
+ ide_hwgroup_t *hwgroup = hwif->hwgroup;
+
+ ide_ports[hwif->index] = NULL;
+
+ spin_lock_irq(&ide_lock);
+ /*
+ * Remove us from the hwgroup, and free
+ * the hwgroup if we were the only member
+ */
+ if (hwif->next == hwif) {
+ BUG_ON(hwgroup->hwif != hwif);
+ kfree(hwgroup);
+ } else {
+ /* There is another interface in hwgroup.
+ * Unlink us, and set hwgroup->drive and ->hwif to
+ * something sane.
+ */
+ ide_hwif_t *g = hwgroup->hwif;
+
+ while (g->next != hwif)
+ g = g->next;
+ g->next = hwif->next;
+ if (hwgroup->hwif == hwif) {
+ /* Chose a random hwif for hwgroup->hwif.
+ * It's guaranteed that there are no drives
+ * left in the hwgroup.
+ */
+ BUG_ON(hwgroup->drive != NULL);
+ hwgroup->hwif = g;
+ }
+ BUG_ON(hwgroup->hwif == hwif);
+ }
+ spin_unlock_irq(&ide_lock);
+}
+
+/*
+ * This routine sets up the irq for an ide interface, and creates a new
+ * hwgroup for the irq/hwif if none was previously assigned.
+ *
+ * Much of the code is for correctly detecting/handling irq sharing
+ * and irq serialization situations. This is somewhat complex because
+ * it handles static as well as dynamic (PCMCIA) IDE interfaces.
+ */
+static int init_irq (ide_hwif_t *hwif)
+{
+ struct ide_io_ports *io_ports = &hwif->io_ports;
+ unsigned int index;
+ ide_hwgroup_t *hwgroup;
+ ide_hwif_t *match = NULL;
+
+ mutex_lock(&ide_cfg_mtx);
+ hwif->hwgroup = NULL;
+
+ /*
+ * Group up with any other hwifs that share our irq(s).
+ */
+ for (index = 0; index < MAX_HWIFS; index++) {
+ ide_hwif_t *h = ide_ports[index];
+
+ if (h && h->hwgroup) { /* scan only initialized ports */
+ if (hwif->irq == h->irq) {
+ hwif->sharing_irq = h->sharing_irq = 1;
+ if (hwif->chipset != ide_pci ||
+ h->chipset != ide_pci) {
+ save_match(hwif, h, &match);
+ }
+ }
+ if (hwif->serialized) {
+ if (hwif->mate && hwif->mate->irq == h->irq)
+ save_match(hwif, h, &match);
+ }
+ if (h->serialized) {
+ if (h->mate && hwif->irq == h->mate->irq)
+ save_match(hwif, h, &match);
+ }
+ }
+ }
+
+ /*
+ * If we are still without a hwgroup, then form a new one
+ */
+ if (match) {
+ hwgroup = match->hwgroup;
+ hwif->hwgroup = hwgroup;
+ /*
+ * Link us into the hwgroup.
+ * This must be done early, do ensure that unexpected_intr
+ * can find the hwif and prevent irq storms.
+ * No drives are attached to the new hwif, choose_drive
+ * can't do anything stupid (yet).
+ * Add ourself as the 2nd entry to the hwgroup->hwif
+ * linked list, the first entry is the hwif that owns
+ * hwgroup->handler - do not change that.
+ */
+ spin_lock_irq(&ide_lock);
+ hwif->next = hwgroup->hwif->next;
+ hwgroup->hwif->next = hwif;
+ BUG_ON(hwif->next == hwif);
+ spin_unlock_irq(&ide_lock);
+ } else {
+ hwgroup = kmalloc_node(sizeof(*hwgroup), GFP_KERNEL|__GFP_ZERO,
+ hwif_to_node(hwif));
+ if (hwgroup == NULL)
+ goto out_up;
+
+ hwif->hwgroup = hwgroup;
+ hwgroup->hwif = hwif->next = hwif;
+
+ init_timer(&hwgroup->timer);
+ hwgroup->timer.function = &ide_timer_expiry;
+ hwgroup->timer.data = (unsigned long) hwgroup;
+ }
+
+ ide_ports[hwif->index] = hwif;
+
+ /*
+ * Allocate the irq, if not already obtained for another hwif
+ */
+ if (!match || match->irq != hwif->irq) {
+ int sa = 0;
+#if defined(__mc68000__)
+ sa = IRQF_SHARED;
+#endif /* __mc68000__ */
+
+ if (hwif->chipset == ide_pci || hwif->chipset == ide_cmd646 ||
+ hwif->chipset == ide_ali14xx)
+ sa = IRQF_SHARED;
+
+ if (io_ports->ctl_addr)
+ hwif->tp_ops->set_irq(hwif, 1);
+
+ if (request_irq(hwif->irq,&ide_intr,sa,hwif->name,hwgroup))
+ goto out_unlink;
+ }
+
+ if (!hwif->rqsize) {
+ if ((hwif->host_flags & IDE_HFLAG_NO_LBA48) ||
+ (hwif->host_flags & IDE_HFLAG_NO_LBA48_DMA))
+ hwif->rqsize = 256;
+ else
+ hwif->rqsize = 65536;
+ }
+
+#if !defined(__mc68000__)
+ printk(KERN_INFO "%s at 0x%03lx-0x%03lx,0x%03lx on irq %d", hwif->name,
+ io_ports->data_addr, io_ports->status_addr,
+ io_ports->ctl_addr, hwif->irq);
+#else
+ printk(KERN_INFO "%s at 0x%08lx on irq %d", hwif->name,
+ io_ports->data_addr, hwif->irq);
+#endif /* __mc68000__ */
+ if (match)
+ printk(KERN_CONT " (%sed with %s)",
+ hwif->sharing_irq ? "shar" : "serializ", match->name);
+ printk(KERN_CONT "\n");
+
+ mutex_unlock(&ide_cfg_mtx);
+ return 0;
+out_unlink:
+ ide_remove_port_from_hwgroup(hwif);
+out_up:
+ mutex_unlock(&ide_cfg_mtx);
+ return 1;
+}
+
+static int ata_lock(dev_t dev, void *data)
+{
+ /* FIXME: we want to pin hwif down */
+ return 0;
+}
+
+static struct kobject *ata_probe(dev_t dev, int *part, void *data)
+{
+ ide_hwif_t *hwif = data;
+ int unit = *part >> PARTN_BITS;
+ ide_drive_t *drive = &hwif->drives[unit];
+
+ if ((drive->dev_flags & IDE_DFLAG_PRESENT) == 0)
+ return NULL;
+
+ if (drive->media == ide_disk)
+ request_module("ide-disk");
+ if (drive->dev_flags & IDE_DFLAG_SCSI)
+ request_module("ide-scsi");
+ if (drive->media == ide_cdrom || drive->media == ide_optical)
+ request_module("ide-cd");
+ if (drive->media == ide_tape)
+ request_module("ide-tape");
+ if (drive->media == ide_floppy)
+ request_module("ide-floppy");
+
+ return NULL;
+}
+
+static struct kobject *exact_match(dev_t dev, int *part, void *data)
+{
+ struct gendisk *p = data;
+ *part &= (1 << PARTN_BITS) - 1;
+ return &disk_to_dev(p)->kobj;
+}
+
+static int exact_lock(dev_t dev, void *data)
+{
+ struct gendisk *p = data;
+
+ if (!get_disk(p))
+ return -1;
+ return 0;
+}
+
+void ide_register_region(struct gendisk *disk)
+{
+ blk_register_region(MKDEV(disk->major, disk->first_minor),
+ disk->minors, NULL, exact_match, exact_lock, disk);
+}
+
+EXPORT_SYMBOL_GPL(ide_register_region);
+
+void ide_unregister_region(struct gendisk *disk)
+{
+ blk_unregister_region(MKDEV(disk->major, disk->first_minor),
+ disk->minors);
+}
+
+EXPORT_SYMBOL_GPL(ide_unregister_region);
+
+void ide_init_disk(struct gendisk *disk, ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ unsigned int unit = drive->dn & 1;
+
+ disk->major = hwif->major;
+ disk->first_minor = unit << PARTN_BITS;
+ sprintf(disk->disk_name, "hd%c", 'a' + hwif->index * MAX_DRIVES + unit);
+ disk->queue = drive->queue;
+}
+
+EXPORT_SYMBOL_GPL(ide_init_disk);
+
+static void ide_remove_drive_from_hwgroup(ide_drive_t *drive)
+{
+ ide_hwgroup_t *hwgroup = drive->hwif->hwgroup;
+
+ if (drive == drive->next) {
+ /* special case: last drive from hwgroup. */
+ BUG_ON(hwgroup->drive != drive);
+ hwgroup->drive = NULL;
+ } else {
+ ide_drive_t *walk;
+
+ walk = hwgroup->drive;
+ while (walk->next != drive)
+ walk = walk->next;
+ walk->next = drive->next;
+ if (hwgroup->drive == drive) {
+ hwgroup->drive = drive->next;
+ hwgroup->hwif = hwgroup->drive->hwif;
+ }
+ }
+ BUG_ON(hwgroup->drive == drive);
+}
+
+static void drive_release_dev (struct device *dev)
+{
+ ide_drive_t *drive = container_of(dev, ide_drive_t, gendev);
+
+ ide_proc_unregister_device(drive);
+
+ spin_lock_irq(&ide_lock);
+ ide_remove_drive_from_hwgroup(drive);
+ kfree(drive->id);
+ drive->id = NULL;
+ drive->dev_flags &= ~IDE_DFLAG_PRESENT;
+ /* Messed up locking ... */
+ spin_unlock_irq(&ide_lock);
+ blk_cleanup_queue(drive->queue);
+ spin_lock_irq(&ide_lock);
+ drive->queue = NULL;
+ spin_unlock_irq(&ide_lock);
+
+ complete(&drive->gendev_rel_comp);
+}
+
+static int hwif_init(ide_hwif_t *hwif)
+{
+ int old_irq;
+
+ if (!hwif->irq) {
+ hwif->irq = __ide_default_irq(hwif->io_ports.data_addr);
+ if (!hwif->irq) {
+ printk(KERN_ERR "%s: disabled, no IRQ\n", hwif->name);
+ return 0;
+ }
+ }
+
+ if (register_blkdev(hwif->major, hwif->name))
+ return 0;
+
+ if (!hwif->sg_max_nents)
+ hwif->sg_max_nents = PRD_ENTRIES;
+
+ hwif->sg_table = kmalloc(sizeof(struct scatterlist)*hwif->sg_max_nents,
+ GFP_KERNEL);
+ if (!hwif->sg_table) {
+ printk(KERN_ERR "%s: unable to allocate SG table.\n", hwif->name);
+ goto out;
+ }
+
+ sg_init_table(hwif->sg_table, hwif->sg_max_nents);
+
+ if (init_irq(hwif) == 0)
+ goto done;
+
+ old_irq = hwif->irq;
+ /*
+ * It failed to initialise. Find the default IRQ for
+ * this port and try that.
+ */
+ hwif->irq = __ide_default_irq(hwif->io_ports.data_addr);
+ if (!hwif->irq) {
+ printk(KERN_ERR "%s: disabled, unable to get IRQ %d\n",
+ hwif->name, old_irq);
+ goto out;
+ }
+ if (init_irq(hwif)) {
+ printk(KERN_ERR "%s: probed IRQ %d and default IRQ %d failed\n",
+ hwif->name, old_irq, hwif->irq);
+ goto out;
+ }
+ printk(KERN_WARNING "%s: probed IRQ %d failed, using default\n",
+ hwif->name, hwif->irq);
+
+done:
+ blk_register_region(MKDEV(hwif->major, 0), MAX_DRIVES << PARTN_BITS,
+ THIS_MODULE, ata_probe, ata_lock, hwif);
+ return 1;
+
+out:
+ unregister_blkdev(hwif->major, hwif->name);
+ return 0;
+}
+
+static void hwif_register_devices(ide_hwif_t *hwif)
+{
+ unsigned int i;
+
+ for (i = 0; i < MAX_DRIVES; i++) {
+ ide_drive_t *drive = &hwif->drives[i];
+ struct device *dev = &drive->gendev;
+ int ret;
+
+ if ((drive->dev_flags & IDE_DFLAG_PRESENT) == 0)
+ continue;
+
+ snprintf(dev->bus_id, BUS_ID_SIZE, "%u.%u", hwif->index, i);
+ dev->parent = &hwif->gendev;
+ dev->bus = &ide_bus_type;
+ dev->driver_data = drive;
+ dev->release = drive_release_dev;
+
+ ret = device_register(dev);
+ if (ret < 0)
+ printk(KERN_WARNING "IDE: %s: device_register error: "
+ "%d\n", __func__, ret);
+ }
+}
+
+static void ide_port_init_devices(ide_hwif_t *hwif)
+{
+ const struct ide_port_ops *port_ops = hwif->port_ops;
+ int i;
+
+ for (i = 0; i < MAX_DRIVES; i++) {
+ ide_drive_t *drive = &hwif->drives[i];
+
+ drive->dn = i + hwif->channel * 2;
+
+ if (hwif->host_flags & IDE_HFLAG_IO_32BIT)
+ drive->io_32bit = 1;
+ if (hwif->host_flags & IDE_HFLAG_UNMASK_IRQS)
+ drive->dev_flags |= IDE_DFLAG_UNMASK;
+ if (hwif->host_flags & IDE_HFLAG_NO_UNMASK_IRQS)
+ drive->dev_flags |= IDE_DFLAG_NO_UNMASK;
+
+ if (port_ops && port_ops->init_dev)
+ port_ops->init_dev(drive);
+ }
+}
+
+static void ide_init_port(ide_hwif_t *hwif, unsigned int port,
+ const struct ide_port_info *d)
+{
+ hwif->channel = port;
+
+ if (d->chipset)
+ hwif->chipset = d->chipset;
+
+ if (d->init_iops)
+ d->init_iops(hwif);
+
+ if ((!hwif->irq && (d->host_flags & IDE_HFLAG_LEGACY_IRQS)) ||
+ (d->host_flags & IDE_HFLAG_FORCE_LEGACY_IRQS))
+ hwif->irq = port ? 15 : 14;
+
+ /* ->host_flags may be set by ->init_iops (or even earlier...) */
+ hwif->host_flags |= d->host_flags;
+ hwif->pio_mask = d->pio_mask;
+
+ if (d->tp_ops)
+ hwif->tp_ops = d->tp_ops;
+
+ /* ->set_pio_mode for DTC2278 is currently limited to port 0 */
+ if (hwif->chipset != ide_dtc2278 || hwif->channel == 0)
+ hwif->port_ops = d->port_ops;
+
+ hwif->swdma_mask = d->swdma_mask;
+ hwif->mwdma_mask = d->mwdma_mask;
+ hwif->ultra_mask = d->udma_mask;
+
+ if ((d->host_flags & IDE_HFLAG_NO_DMA) == 0) {
+ int rc;
+
+ if (d->init_dma)
+ rc = d->init_dma(hwif, d);
+ else
+ rc = ide_hwif_setup_dma(hwif, d);
+
+ if (rc < 0) {
+ printk(KERN_INFO "%s: DMA disabled\n", hwif->name);
+ hwif->dma_base = 0;
+ hwif->swdma_mask = 0;
+ hwif->mwdma_mask = 0;
+ hwif->ultra_mask = 0;
+ } else if (d->dma_ops)
+ hwif->dma_ops = d->dma_ops;
+ }
+
+ if ((d->host_flags & IDE_HFLAG_SERIALIZE) ||
+ ((d->host_flags & IDE_HFLAG_SERIALIZE_DMA) && hwif->dma_base)) {
+ if (hwif->mate)
+ hwif->mate->serialized = hwif->serialized = 1;
+ }
+
+ if (d->host_flags & IDE_HFLAG_RQSIZE_256)
+ hwif->rqsize = 256;
+
+ /* call chipset specific routine for each enabled port */
+ if (d->init_hwif)
+ d->init_hwif(hwif);
+}
+
+static void ide_port_cable_detect(ide_hwif_t *hwif)
+{
+ const struct ide_port_ops *port_ops = hwif->port_ops;
+
+ if (port_ops && port_ops->cable_detect && (hwif->ultra_mask & 0x78)) {
+ if (hwif->cbl != ATA_CBL_PATA40_SHORT)
+ hwif->cbl = port_ops->cable_detect(hwif);
+ }
+}
+
+static ssize_t store_delete_devices(struct device *portdev,
+ struct device_attribute *attr,
+ const char *buf, size_t n)
+{
+ ide_hwif_t *hwif = dev_get_drvdata(portdev);
+
+ if (strncmp(buf, "1", n))
+ return -EINVAL;
+
+ ide_port_unregister_devices(hwif);
+
+ return n;
+};
+
+static DEVICE_ATTR(delete_devices, S_IWUSR, NULL, store_delete_devices);
+
+static ssize_t store_scan(struct device *portdev,
+ struct device_attribute *attr,
+ const char *buf, size_t n)
+{
+ ide_hwif_t *hwif = dev_get_drvdata(portdev);
+
+ if (strncmp(buf, "1", n))
+ return -EINVAL;
+
+ ide_port_unregister_devices(hwif);
+ ide_port_scan(hwif);
+
+ return n;
+};
+
+static DEVICE_ATTR(scan, S_IWUSR, NULL, store_scan);
+
+static struct device_attribute *ide_port_attrs[] = {
+ &dev_attr_delete_devices,
+ &dev_attr_scan,
+ NULL
+};
+
+static int ide_sysfs_register_port(ide_hwif_t *hwif)
+{
+ int i, uninitialized_var(rc);
+
+ for (i = 0; ide_port_attrs[i]; i++) {
+ rc = device_create_file(hwif->portdev, ide_port_attrs[i]);
+ if (rc)
+ break;
+ }
+
+ return rc;
+}
+
+static unsigned int ide_indexes;
+
+/**
+ * ide_find_port_slot - find free port slot
+ * @d: IDE port info
+ *
+ * Return the new port slot index or -ENOENT if we are out of free slots.
+ */
+
+static int ide_find_port_slot(const struct ide_port_info *d)
+{
+ int idx = -ENOENT;
+ u8 bootable = (d && (d->host_flags & IDE_HFLAG_NON_BOOTABLE)) ? 0 : 1;
+ u8 i = (d && (d->host_flags & IDE_HFLAG_QD_2ND_PORT)) ? 1 : 0;;
+
+ /*
+ * Claim an unassigned slot.
+ *
+ * Give preference to claiming other slots before claiming ide0/ide1,
+ * just in case there's another interface yet-to-be-scanned
+ * which uses ports 0x1f0/0x170 (the ide0/ide1 defaults).
+ *
+ * Unless there is a bootable card that does not use the standard
+ * ports 0x1f0/0x170 (the ide0/ide1 defaults).
+ */
+ mutex_lock(&ide_cfg_mtx);
+ if (bootable) {
+ if ((ide_indexes | i) != (1 << MAX_HWIFS) - 1)
+ idx = ffz(ide_indexes | i);
+ } else {
+ if ((ide_indexes | 3) != (1 << MAX_HWIFS) - 1)
+ idx = ffz(ide_indexes | 3);
+ else if ((ide_indexes & 3) != 3)
+ idx = ffz(ide_indexes);
+ }
+ if (idx >= 0)
+ ide_indexes |= (1 << idx);
+ mutex_unlock(&ide_cfg_mtx);
+
+ return idx;
+}
+
+static void ide_free_port_slot(int idx)
+{
+ mutex_lock(&ide_cfg_mtx);
+ ide_indexes &= ~(1 << idx);
+ mutex_unlock(&ide_cfg_mtx);
+}
+
+struct ide_host *ide_host_alloc(const struct ide_port_info *d, hw_regs_t **hws)
+{
+ struct ide_host *host;
+ int i;
+
+ host = kzalloc(sizeof(*host), GFP_KERNEL);
+ if (host == NULL)
+ return NULL;
+
+ for (i = 0; i < MAX_HOST_PORTS; i++) {
+ ide_hwif_t *hwif;
+ int idx;
+
+ if (hws[i] == NULL)
+ continue;
+
+ hwif = kzalloc(sizeof(*hwif), GFP_KERNEL);
+ if (hwif == NULL)
+ continue;
+
+ idx = ide_find_port_slot(d);
+ if (idx < 0) {
+ printk(KERN_ERR "%s: no free slot for interface\n",
+ d ? d->name : "ide");
+ kfree(hwif);
+ continue;
+ }
+
+ ide_init_port_data(hwif, idx);
+
+ hwif->host = host;
+
+ host->ports[i] = hwif;
+ host->n_ports++;
+ }
+
+ if (host->n_ports == 0) {
+ kfree(host);
+ return NULL;
+ }
+
+ if (hws[0])
+ host->dev[0] = hws[0]->dev;
+
+ if (d) {
+ host->init_chipset = d->init_chipset;
+ host->host_flags = d->host_flags;
+ }
+
+ return host;
+}
+EXPORT_SYMBOL_GPL(ide_host_alloc);
+
+int ide_host_register(struct ide_host *host, const struct ide_port_info *d,
+ hw_regs_t **hws)
+{
+ ide_hwif_t *hwif, *mate = NULL;
+ int i, j = 0;
+
+ for (i = 0; i < MAX_HOST_PORTS; i++) {
+ hwif = host->ports[i];
+
+ if (hwif == NULL) {
+ mate = NULL;
+ continue;
+ }
+
+ ide_init_port_hw(hwif, hws[i]);
+ ide_port_apply_params(hwif);
+
+ if (d == NULL) {
+ mate = NULL;
+ } else {
+ if ((i & 1) && mate) {
+ hwif->mate = mate;
+ mate->mate = hwif;
+ }
+
+ mate = (i & 1) ? NULL : hwif;
+
+ ide_init_port(hwif, i & 1, d);
+ ide_port_cable_detect(hwif);
+ }
+
+ ide_port_init_devices(hwif);
+ }
+
+ for (i = 0; i < MAX_HOST_PORTS; i++) {
+ hwif = host->ports[i];
+
+ if (hwif == NULL)
+ continue;
+
+ if (ide_probe_port(hwif) == 0)
+ hwif->present = 1;
+
+ if (hwif->chipset != ide_4drives || !hwif->mate ||
+ !hwif->mate->present)
+ ide_register_port(hwif);
+
+ if (hwif->present)
+ ide_port_tune_devices(hwif);
+ }
+
+ for (i = 0; i < MAX_HOST_PORTS; i++) {
+ hwif = host->ports[i];
+
+ if (hwif == NULL)
+ continue;
+
+ if (hwif_init(hwif) == 0) {
+ printk(KERN_INFO "%s: failed to initialize IDE "
+ "interface\n", hwif->name);
+ hwif->present = 0;
+ continue;
+ }
+
+ if (hwif->present)
+ if (ide_port_setup_devices(hwif) == 0) {
+ hwif->present = 0;
+ continue;
+ }
+
+ j++;
+
+ ide_acpi_init(hwif);
+
+ if (hwif->present)
+ ide_acpi_port_init_devices(hwif);
+ }
+
+ for (i = 0; i < MAX_HOST_PORTS; i++) {
+ hwif = host->ports[i];
+
+ if (hwif == NULL)
+ continue;
+
+ if (hwif->chipset == ide_unknown)
+ hwif->chipset = ide_generic;
+
+ if (hwif->present)
+ hwif_register_devices(hwif);
+ }
+
+ for (i = 0; i < MAX_HOST_PORTS; i++) {
+ hwif = host->ports[i];
+
+ if (hwif == NULL)
+ continue;
+
+ ide_sysfs_register_port(hwif);
+ ide_proc_register_port(hwif);
+
+ if (hwif->present)
+ ide_proc_port_register_devices(hwif);
+ }
+
+ return j ? 0 : -1;
+}
+EXPORT_SYMBOL_GPL(ide_host_register);
+
+int ide_host_add(const struct ide_port_info *d, hw_regs_t **hws,
+ struct ide_host **hostp)
+{
+ struct ide_host *host;
+ int rc;
+
+ host = ide_host_alloc(d, hws);
+ if (host == NULL)
+ return -ENOMEM;
+
+ rc = ide_host_register(host, d, hws);
+ if (rc) {
+ ide_host_free(host);
+ return rc;
+ }
+
+ if (hostp)
+ *hostp = host;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ide_host_add);
+
+void ide_host_free(struct ide_host *host)
+{
+ ide_hwif_t *hwif;
+ int i;
+
+ for (i = 0; i < MAX_HOST_PORTS; i++) {
+ hwif = host->ports[i];
+
+ if (hwif == NULL)
+ continue;
+
+ ide_free_port_slot(hwif->index);
+ kfree(hwif);
+ }
+
+ kfree(host);
+}
+EXPORT_SYMBOL_GPL(ide_host_free);
+
+void ide_host_remove(struct ide_host *host)
+{
+ int i;
+
+ for (i = 0; i < MAX_HOST_PORTS; i++) {
+ if (host->ports[i])
+ ide_unregister(host->ports[i]);
+ }
+
+ ide_host_free(host);
+}
+EXPORT_SYMBOL_GPL(ide_host_remove);
+
+void ide_port_scan(ide_hwif_t *hwif)
+{
+ ide_port_apply_params(hwif);
+ ide_port_cable_detect(hwif);
+ ide_port_init_devices(hwif);
+
+ if (ide_probe_port(hwif) < 0)
+ return;
+
+ hwif->present = 1;
+
+ ide_port_tune_devices(hwif);
+ ide_acpi_port_init_devices(hwif);
+ ide_port_setup_devices(hwif);
+ hwif_register_devices(hwif);
+ ide_proc_port_register_devices(hwif);
+}
+EXPORT_SYMBOL_GPL(ide_port_scan);
+
+static void ide_legacy_init_one(hw_regs_t **hws, hw_regs_t *hw,
+ u8 port_no, const struct ide_port_info *d,
+ unsigned long config)
+{
+ unsigned long base, ctl;
+ int irq;
+
+ if (port_no == 0) {
+ base = 0x1f0;
+ ctl = 0x3f6;
+ irq = 14;
+ } else {
+ base = 0x170;
+ ctl = 0x376;
+ irq = 15;
+ }
+
+ if (!request_region(base, 8, d->name)) {
+ printk(KERN_ERR "%s: I/O resource 0x%lX-0x%lX not free.\n",
+ d->name, base, base + 7);
+ return;
+ }
+
+ if (!request_region(ctl, 1, d->name)) {
+ printk(KERN_ERR "%s: I/O resource 0x%lX not free.\n",
+ d->name, ctl);
+ release_region(base, 8);
+ return;
+ }
+
+ ide_std_init_ports(hw, base, ctl);
+ hw->irq = irq;
+ hw->chipset = d->chipset;
+ hw->config = config;
+
+ hws[port_no] = hw;
+}
+
+int ide_legacy_device_add(const struct ide_port_info *d, unsigned long config)
+{
+ hw_regs_t hw[2], *hws[] = { NULL, NULL, NULL, NULL };
+
+ memset(&hw, 0, sizeof(hw));
+
+ if ((d->host_flags & IDE_HFLAG_QD_2ND_PORT) == 0)
+ ide_legacy_init_one(hws, &hw[0], 0, d, config);
+ ide_legacy_init_one(hws, &hw[1], 1, d, config);
+
+ if (hws[0] == NULL && hws[1] == NULL &&
+ (d->host_flags & IDE_HFLAG_SINGLE))
+ return -ENOENT;
+
+ return ide_host_add(d, hws, NULL);
+}
+EXPORT_SYMBOL_GPL(ide_legacy_device_add);
diff --git a/drivers/ide/ide-proc.c b/drivers/ide/ide-proc.c
new file mode 100644
index 0000000..f3cddd1
--- /dev/null
+++ b/drivers/ide/ide-proc.c
@@ -0,0 +1,723 @@
+/*
+ * Copyright (C) 1997-1998 Mark Lord
+ * Copyright (C) 2003 Red Hat
+ *
+ * Some code was moved here from ide.c, see it for original copyrights.
+ */
+
+/*
+ * This is the /proc/ide/ filesystem implementation.
+ *
+ * Drive/Driver settings can be retrieved by reading the drive's
+ * "settings" files. e.g. "cat /proc/ide0/hda/settings"
+ * To write a new value "val" into a specific setting "name", use:
+ * echo "name:val" >/proc/ide/ide0/hda/settings
+ */
+
+#include <linux/module.h>
+
+#include <asm/uaccess.h>
+#include <linux/errno.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+#include <linux/mm.h>
+#include <linux/pci.h>
+#include <linux/ctype.h>
+#include <linux/ide.h>
+#include <linux/seq_file.h>
+
+#include <asm/io.h>
+
+static struct proc_dir_entry *proc_ide_root;
+
+static int proc_ide_read_imodel
+ (char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ ide_hwif_t *hwif = (ide_hwif_t *) data;
+ int len;
+ const char *name;
+
+ switch (hwif->chipset) {
+ case ide_generic: name = "generic"; break;
+ case ide_pci: name = "pci"; break;
+ case ide_cmd640: name = "cmd640"; break;
+ case ide_dtc2278: name = "dtc2278"; break;
+ case ide_ali14xx: name = "ali14xx"; break;
+ case ide_qd65xx: name = "qd65xx"; break;
+ case ide_umc8672: name = "umc8672"; break;
+ case ide_ht6560b: name = "ht6560b"; break;
+ case ide_rz1000: name = "rz1000"; break;
+ case ide_trm290: name = "trm290"; break;
+ case ide_cmd646: name = "cmd646"; break;
+ case ide_cy82c693: name = "cy82c693"; break;
+ case ide_4drives: name = "4drives"; break;
+ case ide_pmac: name = "mac-io"; break;
+ case ide_au1xxx: name = "au1xxx"; break;
+ case ide_palm3710: name = "palm3710"; break;
+ case ide_acorn: name = "acorn"; break;
+ default: name = "(unknown)"; break;
+ }
+ len = sprintf(page, "%s\n", name);
+ PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
+}
+
+static int proc_ide_read_mate
+ (char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ ide_hwif_t *hwif = (ide_hwif_t *) data;
+ int len;
+
+ if (hwif && hwif->mate)
+ len = sprintf(page, "%s\n", hwif->mate->name);
+ else
+ len = sprintf(page, "(none)\n");
+ PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
+}
+
+static int proc_ide_read_channel
+ (char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ ide_hwif_t *hwif = (ide_hwif_t *) data;
+ int len;
+
+ page[0] = hwif->channel ? '1' : '0';
+ page[1] = '\n';
+ len = 2;
+ PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
+}
+
+static int proc_ide_read_identify
+ (char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ ide_drive_t *drive = (ide_drive_t *)data;
+ int len = 0, i = 0;
+ int err = 0;
+
+ len = sprintf(page, "\n");
+
+ if (drive) {
+ __le16 *val = (__le16 *)page;
+
+ err = taskfile_lib_get_identify(drive, page);
+ if (!err) {
+ char *out = (char *)page + SECTOR_SIZE;
+
+ page = out;
+ do {
+ out += sprintf(out, "%04x%c",
+ le16_to_cpup(val), (++i & 7) ? ' ' : '\n');
+ val += 1;
+ } while (i < SECTOR_SIZE / 2);
+ len = out - page;
+ }
+ }
+ PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
+}
+
+/**
+ * ide_find_setting - find a specific setting
+ * @st: setting table pointer
+ * @name: setting name
+ *
+ * Scan's the setting table for a matching entry and returns
+ * this or NULL if no entry is found. The caller must hold the
+ * setting semaphore
+ */
+
+static
+const struct ide_proc_devset *ide_find_setting(const struct ide_proc_devset *st,
+ char *name)
+{
+ while (st->name) {
+ if (strcmp(st->name, name) == 0)
+ break;
+ st++;
+ }
+ return st->name ? st : NULL;
+}
+
+/**
+ * ide_read_setting - read an IDE setting
+ * @drive: drive to read from
+ * @setting: drive setting
+ *
+ * Read a drive setting and return the value. The caller
+ * must hold the ide_setting_mtx when making this call.
+ *
+ * BUGS: the data return and error are the same return value
+ * so an error -EINVAL and true return of the same value cannot
+ * be told apart
+ */
+
+static int ide_read_setting(ide_drive_t *drive,
+ const struct ide_proc_devset *setting)
+{
+ const struct ide_devset *ds = setting->setting;
+ int val = -EINVAL;
+
+ if (ds->get) {
+ unsigned long flags;
+
+ spin_lock_irqsave(&ide_lock, flags);
+ val = ds->get(drive);
+ spin_unlock_irqrestore(&ide_lock, flags);
+ }
+
+ return val;
+}
+
+/**
+ * ide_write_setting - read an IDE setting
+ * @drive: drive to read from
+ * @setting: drive setting
+ * @val: value
+ *
+ * Write a drive setting if it is possible. The caller
+ * must hold the ide_setting_mtx when making this call.
+ *
+ * BUGS: the data return and error are the same return value
+ * so an error -EINVAL and true return of the same value cannot
+ * be told apart
+ *
+ * FIXME: This should be changed to enqueue a special request
+ * to the driver to change settings, and then wait on a sema for completion.
+ * The current scheme of polling is kludgy, though safe enough.
+ */
+
+static int ide_write_setting(ide_drive_t *drive,
+ const struct ide_proc_devset *setting, int val)
+{
+ const struct ide_devset *ds = setting->setting;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+ if (!ds->set)
+ return -EPERM;
+ if ((ds->flags & DS_SYNC)
+ && (val < setting->min || val > setting->max))
+ return -EINVAL;
+ return ide_devset_execute(drive, ds, val);
+}
+
+ide_devset_get(xfer_rate, current_speed);
+
+static int set_xfer_rate (ide_drive_t *drive, int arg)
+{
+ ide_task_t task;
+ int err;
+
+ if (arg < XFER_PIO_0 || arg > XFER_UDMA_6)
+ return -EINVAL;
+
+ memset(&task, 0, sizeof(task));
+ task.tf.command = ATA_CMD_SET_FEATURES;
+ task.tf.feature = SETFEATURES_XFER;
+ task.tf.nsect = (u8)arg;
+ task.tf_flags = IDE_TFLAG_OUT_FEATURE | IDE_TFLAG_OUT_NSECT |
+ IDE_TFLAG_IN_NSECT;
+
+ err = ide_no_data_taskfile(drive, &task);
+
+ if (!err) {
+ ide_set_xfer_rate(drive, (u8) arg);
+ ide_driveid_update(drive);
+ }
+ return err;
+}
+
+ide_devset_rw(current_speed, xfer_rate);
+ide_devset_rw_field(init_speed, init_speed);
+ide_devset_rw_flag(nice1, IDE_DFLAG_NICE1);
+ide_devset_rw_field(number, dn);
+
+static const struct ide_proc_devset ide_generic_settings[] = {
+ IDE_PROC_DEVSET(current_speed, 0, 70),
+ IDE_PROC_DEVSET(init_speed, 0, 70),
+ IDE_PROC_DEVSET(io_32bit, 0, 1 + (SUPPORT_VLB_SYNC << 1)),
+ IDE_PROC_DEVSET(keepsettings, 0, 1),
+ IDE_PROC_DEVSET(nice1, 0, 1),
+ IDE_PROC_DEVSET(number, 0, 3),
+ IDE_PROC_DEVSET(pio_mode, 0, 255),
+ IDE_PROC_DEVSET(unmaskirq, 0, 1),
+ IDE_PROC_DEVSET(using_dma, 0, 1),
+ { 0 },
+};
+
+static void proc_ide_settings_warn(void)
+{
+ static int warned;
+
+ if (warned)
+ return;
+
+ printk(KERN_WARNING "Warning: /proc/ide/hd?/settings interface is "
+ "obsolete, and will be removed soon!\n");
+ warned = 1;
+}
+
+static int proc_ide_read_settings
+ (char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ const struct ide_proc_devset *setting, *g, *d;
+ const struct ide_devset *ds;
+ ide_drive_t *drive = (ide_drive_t *) data;
+ char *out = page;
+ int len, rc, mul_factor, div_factor;
+
+ proc_ide_settings_warn();
+
+ mutex_lock(&ide_setting_mtx);
+ g = ide_generic_settings;
+ d = drive->settings;
+ out += sprintf(out, "name\t\t\tvalue\t\tmin\t\tmax\t\tmode\n");
+ out += sprintf(out, "----\t\t\t-----\t\t---\t\t---\t\t----\n");
+ while (g->name || (d && d->name)) {
+ /* read settings in the alphabetical order */
+ if (g->name && d && d->name) {
+ if (strcmp(d->name, g->name) < 0)
+ setting = d++;
+ else
+ setting = g++;
+ } else if (d && d->name) {
+ setting = d++;
+ } else
+ setting = g++;
+ mul_factor = setting->mulf ? setting->mulf(drive) : 1;
+ div_factor = setting->divf ? setting->divf(drive) : 1;
+ out += sprintf(out, "%-24s", setting->name);
+ rc = ide_read_setting(drive, setting);
+ if (rc >= 0)
+ out += sprintf(out, "%-16d", rc * mul_factor / div_factor);
+ else
+ out += sprintf(out, "%-16s", "write-only");
+ out += sprintf(out, "%-16d%-16d", (setting->min * mul_factor + div_factor - 1) / div_factor, setting->max * mul_factor / div_factor);
+ ds = setting->setting;
+ if (ds->get)
+ out += sprintf(out, "r");
+ if (ds->set)
+ out += sprintf(out, "w");
+ out += sprintf(out, "\n");
+ }
+ len = out - page;
+ mutex_unlock(&ide_setting_mtx);
+ PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
+}
+
+#define MAX_LEN 30
+
+static int proc_ide_write_settings(struct file *file, const char __user *buffer,
+ unsigned long count, void *data)
+{
+ ide_drive_t *drive = (ide_drive_t *) data;
+ char name[MAX_LEN + 1];
+ int for_real = 0, mul_factor, div_factor;
+ unsigned long n;
+
+ const struct ide_proc_devset *setting;
+ char *buf, *s;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+
+ proc_ide_settings_warn();
+
+ if (count >= PAGE_SIZE)
+ return -EINVAL;
+
+ s = buf = (char *)__get_free_page(GFP_USER);
+ if (!buf)
+ return -ENOMEM;
+
+ if (copy_from_user(buf, buffer, count)) {
+ free_page((unsigned long)buf);
+ return -EFAULT;
+ }
+
+ buf[count] = '\0';
+
+ /*
+ * Skip over leading whitespace
+ */
+ while (count && isspace(*s)) {
+ --count;
+ ++s;
+ }
+ /*
+ * Do one full pass to verify all parameters,
+ * then do another to actually write the new settings.
+ */
+ do {
+ char *p = s;
+ n = count;
+ while (n > 0) {
+ unsigned val;
+ char *q = p;
+
+ while (n > 0 && *p != ':') {
+ --n;
+ p++;
+ }
+ if (*p != ':')
+ goto parse_error;
+ if (p - q > MAX_LEN)
+ goto parse_error;
+ memcpy(name, q, p - q);
+ name[p - q] = 0;
+
+ if (n > 0) {
+ --n;
+ p++;
+ } else
+ goto parse_error;
+
+ val = simple_strtoul(p, &q, 10);
+ n -= q - p;
+ p = q;
+ if (n > 0 && !isspace(*p))
+ goto parse_error;
+ while (n > 0 && isspace(*p)) {
+ --n;
+ ++p;
+ }
+
+ mutex_lock(&ide_setting_mtx);
+ /* generic settings first, then driver specific ones */
+ setting = ide_find_setting(ide_generic_settings, name);
+ if (!setting) {
+ if (drive->settings)
+ setting = ide_find_setting(drive->settings, name);
+ if (!setting) {
+ mutex_unlock(&ide_setting_mtx);
+ goto parse_error;
+ }
+ }
+ if (for_real) {
+ mul_factor = setting->mulf ? setting->mulf(drive) : 1;
+ div_factor = setting->divf ? setting->divf(drive) : 1;
+ ide_write_setting(drive, setting, val * div_factor / mul_factor);
+ }
+ mutex_unlock(&ide_setting_mtx);
+ }
+ } while (!for_real++);
+ free_page((unsigned long)buf);
+ return count;
+parse_error:
+ free_page((unsigned long)buf);
+ printk("proc_ide_write_settings(): parse error\n");
+ return -EINVAL;
+}
+
+int proc_ide_read_capacity
+ (char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ int len = sprintf(page, "%llu\n", (long long)0x7fffffff);
+ PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
+}
+
+EXPORT_SYMBOL_GPL(proc_ide_read_capacity);
+
+int proc_ide_read_geometry
+ (char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ ide_drive_t *drive = (ide_drive_t *) data;
+ char *out = page;
+ int len;
+
+ out += sprintf(out, "physical %d/%d/%d\n",
+ drive->cyl, drive->head, drive->sect);
+ out += sprintf(out, "logical %d/%d/%d\n",
+ drive->bios_cyl, drive->bios_head, drive->bios_sect);
+
+ len = out - page;
+ PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
+}
+
+EXPORT_SYMBOL(proc_ide_read_geometry);
+
+static int proc_ide_read_dmodel
+ (char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ ide_drive_t *drive = (ide_drive_t *) data;
+ char *m = (char *)&drive->id[ATA_ID_PROD];
+ int len;
+
+ len = sprintf(page, "%.40s\n", m[0] ? m : "(none)");
+ PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
+}
+
+static int proc_ide_read_driver
+ (char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ ide_drive_t *drive = (ide_drive_t *) data;
+ struct device *dev = &drive->gendev;
+ ide_driver_t *ide_drv;
+ int len;
+
+ if (dev->driver) {
+ ide_drv = container_of(dev->driver, ide_driver_t, gen_driver);
+ len = sprintf(page, "%s version %s\n",
+ dev->driver->name, ide_drv->version);
+ } else
+ len = sprintf(page, "ide-default version 0.9.newide\n");
+ PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
+}
+
+static int ide_replace_subdriver(ide_drive_t *drive, const char *driver)
+{
+ struct device *dev = &drive->gendev;
+ int ret = 1;
+ int err;
+
+ device_release_driver(dev);
+ /* FIXME: device can still be in use by previous driver */
+ strlcpy(drive->driver_req, driver, sizeof(drive->driver_req));
+ err = device_attach(dev);
+ if (err < 0)
+ printk(KERN_WARNING "IDE: %s: device_attach error: %d\n",
+ __func__, err);
+ drive->driver_req[0] = 0;
+ if (dev->driver == NULL) {
+ err = device_attach(dev);
+ if (err < 0)
+ printk(KERN_WARNING
+ "IDE: %s: device_attach(2) error: %d\n",
+ __func__, err);
+ }
+ if (dev->driver && !strcmp(dev->driver->name, driver))
+ ret = 0;
+
+ return ret;
+}
+
+static int proc_ide_write_driver
+ (struct file *file, const char __user *buffer, unsigned long count, void *data)
+{
+ ide_drive_t *drive = (ide_drive_t *) data;
+ char name[32];
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+ if (count > 31)
+ count = 31;
+ if (copy_from_user(name, buffer, count))
+ return -EFAULT;
+ name[count] = '\0';
+ if (ide_replace_subdriver(drive, name))
+ return -EINVAL;
+ return count;
+}
+
+static int proc_ide_read_media
+ (char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ ide_drive_t *drive = (ide_drive_t *) data;
+ const char *media;
+ int len;
+
+ switch (drive->media) {
+ case ide_disk: media = "disk\n"; break;
+ case ide_cdrom: media = "cdrom\n"; break;
+ case ide_tape: media = "tape\n"; break;
+ case ide_floppy: media = "floppy\n"; break;
+ case ide_optical: media = "optical\n"; break;
+ default: media = "UNKNOWN\n"; break;
+ }
+ strcpy(page, media);
+ len = strlen(media);
+ PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
+}
+
+static ide_proc_entry_t generic_drive_entries[] = {
+ { "driver", S_IFREG|S_IRUGO, proc_ide_read_driver,
+ proc_ide_write_driver },
+ { "identify", S_IFREG|S_IRUSR, proc_ide_read_identify, NULL },
+ { "media", S_IFREG|S_IRUGO, proc_ide_read_media, NULL },
+ { "model", S_IFREG|S_IRUGO, proc_ide_read_dmodel, NULL },
+ { "settings", S_IFREG|S_IRUSR|S_IWUSR, proc_ide_read_settings,
+ proc_ide_write_settings },
+ { NULL, 0, NULL, NULL }
+};
+
+static void ide_add_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p, void *data)
+{
+ struct proc_dir_entry *ent;
+
+ if (!dir || !p)
+ return;
+ while (p->name != NULL) {
+ ent = create_proc_entry(p->name, p->mode, dir);
+ if (!ent) return;
+ ent->data = data;
+ ent->read_proc = p->read_proc;
+ ent->write_proc = p->write_proc;
+ p++;
+ }
+}
+
+static void ide_remove_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p)
+{
+ if (!dir || !p)
+ return;
+ while (p->name != NULL) {
+ remove_proc_entry(p->name, dir);
+ p++;
+ }
+}
+
+void ide_proc_register_driver(ide_drive_t *drive, ide_driver_t *driver)
+{
+ mutex_lock(&ide_setting_mtx);
+ drive->settings = driver->proc_devsets(drive);
+ mutex_unlock(&ide_setting_mtx);
+
+ ide_add_proc_entries(drive->proc, driver->proc_entries(drive), drive);
+}
+
+EXPORT_SYMBOL(ide_proc_register_driver);
+
+/**
+ * ide_proc_unregister_driver - remove driver specific data
+ * @drive: drive
+ * @driver: driver
+ *
+ * Clean up the driver specific /proc files and IDE settings
+ * for a given drive.
+ *
+ * Takes ide_setting_mtx and ide_lock.
+ * Caller must hold none of the locks.
+ */
+
+void ide_proc_unregister_driver(ide_drive_t *drive, ide_driver_t *driver)
+{
+ unsigned long flags;
+
+ ide_remove_proc_entries(drive->proc, driver->proc_entries(drive));
+
+ mutex_lock(&ide_setting_mtx);
+ spin_lock_irqsave(&ide_lock, flags);
+ /*
+ * ide_setting_mtx protects the settings list
+ * ide_lock protects the use of settings
+ *
+ * so we need to hold both, ide_settings_sem because we want to
+ * modify the settings list, and ide_lock because we cannot take
+ * a setting out that is being used.
+ *
+ * OTOH both ide_{read,write}_setting are only ever used under
+ * ide_setting_mtx.
+ */
+ drive->settings = NULL;
+ spin_unlock_irqrestore(&ide_lock, flags);
+ mutex_unlock(&ide_setting_mtx);
+}
+EXPORT_SYMBOL(ide_proc_unregister_driver);
+
+void ide_proc_port_register_devices(ide_hwif_t *hwif)
+{
+ int d;
+ struct proc_dir_entry *ent;
+ struct proc_dir_entry *parent = hwif->proc;
+ char name[64];
+
+ for (d = 0; d < MAX_DRIVES; d++) {
+ ide_drive_t *drive = &hwif->drives[d];
+
+ if ((drive->dev_flags & IDE_DFLAG_PRESENT) == 0 || drive->proc)
+ continue;
+
+ drive->proc = proc_mkdir(drive->name, parent);
+ if (drive->proc)
+ ide_add_proc_entries(drive->proc, generic_drive_entries, drive);
+ sprintf(name, "ide%d/%s", (drive->name[2]-'a')/2, drive->name);
+ ent = proc_symlink(drive->name, proc_ide_root, name);
+ if (!ent) return;
+ }
+}
+
+void ide_proc_unregister_device(ide_drive_t *drive)
+{
+ if (drive->proc) {
+ ide_remove_proc_entries(drive->proc, generic_drive_entries);
+ remove_proc_entry(drive->name, proc_ide_root);
+ remove_proc_entry(drive->name, drive->hwif->proc);
+ drive->proc = NULL;
+ }
+}
+
+static ide_proc_entry_t hwif_entries[] = {
+ { "channel", S_IFREG|S_IRUGO, proc_ide_read_channel, NULL },
+ { "mate", S_IFREG|S_IRUGO, proc_ide_read_mate, NULL },
+ { "model", S_IFREG|S_IRUGO, proc_ide_read_imodel, NULL },
+ { NULL, 0, NULL, NULL }
+};
+
+void ide_proc_register_port(ide_hwif_t *hwif)
+{
+ if (!hwif->proc) {
+ hwif->proc = proc_mkdir(hwif->name, proc_ide_root);
+
+ if (!hwif->proc)
+ return;
+
+ ide_add_proc_entries(hwif->proc, hwif_entries, hwif);
+ }
+}
+
+void ide_proc_unregister_port(ide_hwif_t *hwif)
+{
+ if (hwif->proc) {
+ ide_remove_proc_entries(hwif->proc, hwif_entries);
+ remove_proc_entry(hwif->name, proc_ide_root);
+ hwif->proc = NULL;
+ }
+}
+
+static int proc_print_driver(struct device_driver *drv, void *data)
+{
+ ide_driver_t *ide_drv = container_of(drv, ide_driver_t, gen_driver);
+ struct seq_file *s = data;
+
+ seq_printf(s, "%s version %s\n", drv->name, ide_drv->version);
+
+ return 0;
+}
+
+static int ide_drivers_show(struct seq_file *s, void *p)
+{
+ int err;
+
+ err = bus_for_each_drv(&ide_bus_type, NULL, s, proc_print_driver);
+ if (err < 0)
+ printk(KERN_WARNING "IDE: %s: bus_for_each_drv error: %d\n",
+ __func__, err);
+ return 0;
+}
+
+static int ide_drivers_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, &ide_drivers_show, NULL);
+}
+
+static const struct file_operations ide_drivers_operations = {
+ .owner = THIS_MODULE,
+ .open = ide_drivers_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+void proc_ide_create(void)
+{
+ proc_ide_root = proc_mkdir("ide", NULL);
+
+ if (!proc_ide_root)
+ return;
+
+ proc_create("drivers", 0, proc_ide_root, &ide_drivers_operations);
+}
+
+void proc_ide_destroy(void)
+{
+ remove_proc_entry("drivers", proc_ide_root);
+ remove_proc_entry("ide", NULL);
+}
diff --git a/drivers/ide/ide-scan-pci.c b/drivers/ide/ide-scan-pci.c
new file mode 100644
index 0000000..0e79eff
--- /dev/null
+++ b/drivers/ide/ide-scan-pci.c
@@ -0,0 +1,111 @@
+/*
+ * support for probing IDE PCI devices in the PCI bus order
+ *
+ * Copyright (c) 1998-2000 Andre Hedrick <andre@linux-ide.org>
+ * Copyright (c) 1995-1998 Mark Lord
+ *
+ * May be copied or modified under the terms of the GNU General Public License
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/ide.h>
+
+/*
+ * Module interfaces
+ */
+
+static int pre_init = 1; /* Before first ordered IDE scan */
+static LIST_HEAD(ide_pci_drivers);
+
+/*
+ * __ide_pci_register_driver - attach IDE driver
+ * @driver: pci driver
+ * @module: owner module of the driver
+ *
+ * Registers a driver with the IDE layer. The IDE layer arranges that
+ * boot time setup is done in the expected device order and then
+ * hands the controllers off to the core PCI code to do the rest of
+ * the work.
+ *
+ * Returns are the same as for pci_register_driver
+ */
+
+int __ide_pci_register_driver(struct pci_driver *driver, struct module *module,
+ const char *mod_name)
+{
+ if (!pre_init)
+ return __pci_register_driver(driver, module, mod_name);
+ driver->driver.owner = module;
+ list_add_tail(&driver->node, &ide_pci_drivers);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(__ide_pci_register_driver);
+
+/**
+ * ide_scan_pcidev - find an IDE driver for a device
+ * @dev: PCI device to check
+ *
+ * Look for an IDE driver to handle the device we are considering.
+ * This is only used during boot up to get the ordering correct. After
+ * boot up the pci layer takes over the job.
+ */
+
+static int __init ide_scan_pcidev(struct pci_dev *dev)
+{
+ struct list_head *l;
+ struct pci_driver *d;
+
+ list_for_each(l, &ide_pci_drivers) {
+ d = list_entry(l, struct pci_driver, node);
+ if (d->id_table) {
+ const struct pci_device_id *id =
+ pci_match_id(d->id_table, dev);
+
+ if (id != NULL && d->probe(dev, id) >= 0) {
+ dev->driver = d;
+ pci_dev_get(dev);
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+/**
+ * ide_scan_pcibus - perform the initial IDE driver scan
+ *
+ * Perform the initial bus rather than driver ordered scan of the
+ * PCI drivers. After this all IDE pci handling becomes standard
+ * module ordering not traditionally ordered.
+ */
+
+static int __init ide_scan_pcibus(void)
+{
+ struct pci_dev *dev = NULL;
+ struct pci_driver *d;
+ struct list_head *l, *n;
+
+ pre_init = 0;
+ while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)))
+ ide_scan_pcidev(dev);
+
+ /*
+ * Hand the drivers over to the PCI layer now we
+ * are post init.
+ */
+
+ list_for_each_safe(l, n, &ide_pci_drivers) {
+ list_del(l);
+ d = list_entry(l, struct pci_driver, node);
+ if (__pci_register_driver(d, d->driver.owner,
+ d->driver.mod_name))
+ printk(KERN_ERR "%s: failed to register %s driver\n",
+ __func__, d->driver.mod_name);
+ }
+
+ return 0;
+}
+
+module_init(ide_scan_pcibus);
diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c
new file mode 100644
index 0000000..a2d470e
--- /dev/null
+++ b/drivers/ide/ide-tape.c
@@ -0,0 +1,2489 @@
+/*
+ * IDE ATAPI streaming tape driver.
+ *
+ * Copyright (C) 1995-1999 Gadi Oxman <gadio@netvision.net.il>
+ * Copyright (C) 2003-2005 Bartlomiej Zolnierkiewicz
+ *
+ * This driver was constructed as a student project in the software laboratory
+ * of the faculty of electrical engineering in the Technion - Israel's
+ * Institute Of Technology, with the guide of Avner Lottem and Dr. Ilana David.
+ *
+ * It is hereby placed under the terms of the GNU general public license.
+ * (See linux/COPYING).
+ *
+ * For a historical changelog see
+ * Documentation/ide/ChangeLog.ide-tape.1995-2002
+ */
+
+#define DRV_NAME "ide-tape"
+
+#define IDETAPE_VERSION "1.20"
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/jiffies.h>
+#include <linux/major.h>
+#include <linux/errno.h>
+#include <linux/genhd.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+#include <linux/smp_lock.h>
+#include <linux/completion.h>
+#include <linux/bitops.h>
+#include <linux/mutex.h>
+#include <scsi/scsi.h>
+
+#include <asm/byteorder.h>
+#include <linux/irq.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+#include <asm/unaligned.h>
+#include <linux/mtio.h>
+
+enum {
+ /* output errors only */
+ DBG_ERR = (1 << 0),
+ /* output all sense key/asc */
+ DBG_SENSE = (1 << 1),
+ /* info regarding all chrdev-related procedures */
+ DBG_CHRDEV = (1 << 2),
+ /* all remaining procedures */
+ DBG_PROCS = (1 << 3),
+};
+
+/* define to see debug info */
+#define IDETAPE_DEBUG_LOG 0
+
+#if IDETAPE_DEBUG_LOG
+#define debug_log(lvl, fmt, args...) \
+{ \
+ if (tape->debug_mask & lvl) \
+ printk(KERN_INFO "ide-tape: " fmt, ## args); \
+}
+#else
+#define debug_log(lvl, fmt, args...) do {} while (0)
+#endif
+
+/**************************** Tunable parameters *****************************/
+/*
+ * After each failed packet command we issue a request sense command and retry
+ * the packet command IDETAPE_MAX_PC_RETRIES times.
+ *
+ * Setting IDETAPE_MAX_PC_RETRIES to 0 will disable retries.
+ */
+#define IDETAPE_MAX_PC_RETRIES 3
+
+/*
+ * The following parameter is used to select the point in the internal tape fifo
+ * in which we will start to refill the buffer. Decreasing the following
+ * parameter will improve the system's latency and interactive response, while
+ * using a high value might improve system throughput.
+ */
+#define IDETAPE_FIFO_THRESHOLD 2
+
+/*
+ * DSC polling parameters.
+ *
+ * Polling for DSC (a single bit in the status register) is a very important
+ * function in ide-tape. There are two cases in which we poll for DSC:
+ *
+ * 1. Before a read/write packet command, to ensure that we can transfer data
+ * from/to the tape's data buffers, without causing an actual media access.
+ * In case the tape is not ready yet, we take out our request from the device
+ * request queue, so that ide.c could service requests from the other device
+ * on the same interface in the meantime.
+ *
+ * 2. After the successful initialization of a "media access packet command",
+ * which is a command that can take a long time to complete (the interval can
+ * range from several seconds to even an hour). Again, we postpone our request
+ * in the middle to free the bus for the other device. The polling frequency
+ * here should be lower than the read/write frequency since those media access
+ * commands are slow. We start from a "fast" frequency - IDETAPE_DSC_MA_FAST
+ * (1 second), and if we don't receive DSC after IDETAPE_DSC_MA_THRESHOLD
+ * (5 min), we switch it to a lower frequency - IDETAPE_DSC_MA_SLOW (1 min).
+ *
+ * We also set a timeout for the timer, in case something goes wrong. The
+ * timeout should be longer then the maximum execution time of a tape operation.
+ */
+
+/* DSC timings. */
+#define IDETAPE_DSC_RW_MIN 5*HZ/100 /* 50 msec */
+#define IDETAPE_DSC_RW_MAX 40*HZ/100 /* 400 msec */
+#define IDETAPE_DSC_RW_TIMEOUT 2*60*HZ /* 2 minutes */
+#define IDETAPE_DSC_MA_FAST 2*HZ /* 2 seconds */
+#define IDETAPE_DSC_MA_THRESHOLD 5*60*HZ /* 5 minutes */
+#define IDETAPE_DSC_MA_SLOW 30*HZ /* 30 seconds */
+#define IDETAPE_DSC_MA_TIMEOUT 2*60*60*HZ /* 2 hours */
+
+/*************************** End of tunable parameters ***********************/
+
+/* tape directions */
+enum {
+ IDETAPE_DIR_NONE = (1 << 0),
+ IDETAPE_DIR_READ = (1 << 1),
+ IDETAPE_DIR_WRITE = (1 << 2),
+};
+
+struct idetape_bh {
+ u32 b_size;
+ atomic_t b_count;
+ struct idetape_bh *b_reqnext;
+ char *b_data;
+};
+
+/* Tape door status */
+#define DOOR_UNLOCKED 0
+#define DOOR_LOCKED 1
+#define DOOR_EXPLICITLY_LOCKED 2
+
+/* Some defines for the SPACE command */
+#define IDETAPE_SPACE_OVER_FILEMARK 1
+#define IDETAPE_SPACE_TO_EOD 3
+
+/* Some defines for the LOAD UNLOAD command */
+#define IDETAPE_LU_LOAD_MASK 1
+#define IDETAPE_LU_RETENSION_MASK 2
+#define IDETAPE_LU_EOT_MASK 4
+
+/* Error codes returned in rq->errors to the higher part of the driver. */
+#define IDETAPE_ERROR_GENERAL 101
+#define IDETAPE_ERROR_FILEMARK 102
+#define IDETAPE_ERROR_EOD 103
+
+/* Structures related to the SELECT SENSE / MODE SENSE packet commands. */
+#define IDETAPE_BLOCK_DESCRIPTOR 0
+#define IDETAPE_CAPABILITIES_PAGE 0x2a
+
+/*
+ * Most of our global data which we need to save even as we leave the driver due
+ * to an interrupt or a timer event is stored in the struct defined below.
+ */
+typedef struct ide_tape_obj {
+ ide_drive_t *drive;
+ ide_driver_t *driver;
+ struct gendisk *disk;
+ struct kref kref;
+
+ /*
+ * failed_pc points to the last failed packet command, or contains
+ * NULL if we do not need to retry any packet command. This is
+ * required since an additional packet command is needed before the
+ * retry, to get detailed information on what went wrong.
+ */
+ /* Last failed packet command */
+ struct ide_atapi_pc *failed_pc;
+ /* used by REQ_IDETAPE_{READ,WRITE} requests */
+ struct ide_atapi_pc queued_pc;
+
+ /*
+ * DSC polling variables.
+ *
+ * While polling for DSC we use postponed_rq to postpone the current
+ * request so that ide.c will be able to service pending requests on the
+ * other device. Note that at most we will have only one DSC (usually
+ * data transfer) request in the device request queue.
+ */
+ struct request *postponed_rq;
+ /* The time in which we started polling for DSC */
+ unsigned long dsc_polling_start;
+ /* Timer used to poll for dsc */
+ struct timer_list dsc_timer;
+ /* Read/Write dsc polling frequency */
+ unsigned long best_dsc_rw_freq;
+ unsigned long dsc_poll_freq;
+ unsigned long dsc_timeout;
+
+ /* Read position information */
+ u8 partition;
+ /* Current block */
+ unsigned int first_frame;
+
+ /* Last error information */
+ u8 sense_key, asc, ascq;
+
+ /* Character device operation */
+ unsigned int minor;
+ /* device name */
+ char name[4];
+ /* Current character device data transfer direction */
+ u8 chrdev_dir;
+
+ /* tape block size, usually 512 or 1024 bytes */
+ unsigned short blk_size;
+ int user_bs_factor;
+
+ /* Copy of the tape's Capabilities and Mechanical Page */
+ u8 caps[20];
+
+ /*
+ * Active data transfer request parameters.
+ *
+ * At most, there is only one ide-tape originated data transfer request
+ * in the device request queue. This allows ide.c to easily service
+ * requests from the other device when we postpone our active request.
+ */
+
+ /* Data buffer size chosen based on the tape's recommendation */
+ int buffer_size;
+ /* merge buffer */
+ struct idetape_bh *merge_bh;
+ /* size of the merge buffer */
+ int merge_bh_size;
+ /* pointer to current buffer head within the merge buffer */
+ struct idetape_bh *bh;
+ char *b_data;
+ int b_count;
+
+ int pages_per_buffer;
+ /* Wasted space in each stage */
+ int excess_bh_size;
+
+ /* protects the ide-tape queue */
+ spinlock_t lock;
+
+ /* Measures average tape speed */
+ unsigned long avg_time;
+ int avg_size;
+ int avg_speed;
+
+ /* the door is currently locked */
+ int door_locked;
+ /* the tape hardware is write protected */
+ char drv_write_prot;
+ /* the tape is write protected (hardware or opened as read-only) */
+ char write_prot;
+
+ u32 debug_mask;
+} idetape_tape_t;
+
+static DEFINE_MUTEX(idetape_ref_mutex);
+
+static struct class *idetape_sysfs_class;
+
+static void ide_tape_release(struct kref *);
+
+static struct ide_tape_obj *ide_tape_get(struct gendisk *disk)
+{
+ struct ide_tape_obj *tape = NULL;
+
+ mutex_lock(&idetape_ref_mutex);
+ tape = ide_drv_g(disk, ide_tape_obj);
+ if (tape) {
+ if (ide_device_get(tape->drive))
+ tape = NULL;
+ else
+ kref_get(&tape->kref);
+ }
+ mutex_unlock(&idetape_ref_mutex);
+ return tape;
+}
+
+static void ide_tape_put(struct ide_tape_obj *tape)
+{
+ ide_drive_t *drive = tape->drive;
+
+ mutex_lock(&idetape_ref_mutex);
+ kref_put(&tape->kref, ide_tape_release);
+ ide_device_put(drive);
+ mutex_unlock(&idetape_ref_mutex);
+}
+
+/*
+ * The variables below are used for the character device interface. Additional
+ * state variables are defined in our ide_drive_t structure.
+ */
+static struct ide_tape_obj *idetape_devs[MAX_HWIFS * MAX_DRIVES];
+
+static struct ide_tape_obj *ide_tape_chrdev_get(unsigned int i)
+{
+ struct ide_tape_obj *tape = NULL;
+
+ mutex_lock(&idetape_ref_mutex);
+ tape = idetape_devs[i];
+ if (tape)
+ kref_get(&tape->kref);
+ mutex_unlock(&idetape_ref_mutex);
+ return tape;
+}
+
+static void idetape_input_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc,
+ unsigned int bcount)
+{
+ struct idetape_bh *bh = pc->bh;
+ int count;
+
+ while (bcount) {
+ if (bh == NULL) {
+ printk(KERN_ERR "ide-tape: bh == NULL in "
+ "idetape_input_buffers\n");
+ ide_pad_transfer(drive, 0, bcount);
+ return;
+ }
+ count = min(
+ (unsigned int)(bh->b_size - atomic_read(&bh->b_count)),
+ bcount);
+ drive->hwif->tp_ops->input_data(drive, NULL, bh->b_data +
+ atomic_read(&bh->b_count), count);
+ bcount -= count;
+ atomic_add(count, &bh->b_count);
+ if (atomic_read(&bh->b_count) == bh->b_size) {
+ bh = bh->b_reqnext;
+ if (bh)
+ atomic_set(&bh->b_count, 0);
+ }
+ }
+ pc->bh = bh;
+}
+
+static void idetape_output_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc,
+ unsigned int bcount)
+{
+ struct idetape_bh *bh = pc->bh;
+ int count;
+
+ while (bcount) {
+ if (bh == NULL) {
+ printk(KERN_ERR "ide-tape: bh == NULL in %s\n",
+ __func__);
+ return;
+ }
+ count = min((unsigned int)pc->b_count, (unsigned int)bcount);
+ drive->hwif->tp_ops->output_data(drive, NULL, pc->b_data, count);
+ bcount -= count;
+ pc->b_data += count;
+ pc->b_count -= count;
+ if (!pc->b_count) {
+ bh = bh->b_reqnext;
+ pc->bh = bh;
+ if (bh) {
+ pc->b_data = bh->b_data;
+ pc->b_count = atomic_read(&bh->b_count);
+ }
+ }
+ }
+}
+
+static void idetape_update_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc)
+{
+ struct idetape_bh *bh = pc->bh;
+ int count;
+ unsigned int bcount = pc->xferred;
+
+ if (pc->flags & PC_FLAG_WRITING)
+ return;
+ while (bcount) {
+ if (bh == NULL) {
+ printk(KERN_ERR "ide-tape: bh == NULL in %s\n",
+ __func__);
+ return;
+ }
+ count = min((unsigned int)bh->b_size, (unsigned int)bcount);
+ atomic_set(&bh->b_count, count);
+ if (atomic_read(&bh->b_count) == bh->b_size)
+ bh = bh->b_reqnext;
+ bcount -= count;
+ }
+ pc->bh = bh;
+}
+
+/*
+ * called on each failed packet command retry to analyze the request sense. We
+ * currently do not utilize this information.
+ */
+static void idetape_analyze_error(ide_drive_t *drive, u8 *sense)
+{
+ idetape_tape_t *tape = drive->driver_data;
+ struct ide_atapi_pc *pc = tape->failed_pc;
+
+ tape->sense_key = sense[2] & 0xF;
+ tape->asc = sense[12];
+ tape->ascq = sense[13];
+
+ debug_log(DBG_ERR, "pc = %x, sense key = %x, asc = %x, ascq = %x\n",
+ pc->c[0], tape->sense_key, tape->asc, tape->ascq);
+
+ /* Correct pc->xferred by asking the tape. */
+ if (pc->flags & PC_FLAG_DMA_ERROR) {
+ pc->xferred = pc->req_xfer -
+ tape->blk_size *
+ get_unaligned_be32(&sense[3]);
+ idetape_update_buffers(drive, pc);
+ }
+
+ /*
+ * If error was the result of a zero-length read or write command,
+ * with sense key=5, asc=0x22, ascq=0, let it slide. Some drives
+ * (i.e. Seagate STT3401A Travan) don't support 0-length read/writes.
+ */
+ if ((pc->c[0] == READ_6 || pc->c[0] == WRITE_6)
+ /* length == 0 */
+ && pc->c[4] == 0 && pc->c[3] == 0 && pc->c[2] == 0) {
+ if (tape->sense_key == 5) {
+ /* don't report an error, everything's ok */
+ pc->error = 0;
+ /* don't retry read/write */
+ pc->flags |= PC_FLAG_ABORT;
+ }
+ }
+ if (pc->c[0] == READ_6 && (sense[2] & 0x80)) {
+ pc->error = IDETAPE_ERROR_FILEMARK;
+ pc->flags |= PC_FLAG_ABORT;
+ }
+ if (pc->c[0] == WRITE_6) {
+ if ((sense[2] & 0x40) || (tape->sense_key == 0xd
+ && tape->asc == 0x0 && tape->ascq == 0x2)) {
+ pc->error = IDETAPE_ERROR_EOD;
+ pc->flags |= PC_FLAG_ABORT;
+ }
+ }
+ if (pc->c[0] == READ_6 || pc->c[0] == WRITE_6) {
+ if (tape->sense_key == 8) {
+ pc->error = IDETAPE_ERROR_EOD;
+ pc->flags |= PC_FLAG_ABORT;
+ }
+ if (!(pc->flags & PC_FLAG_ABORT) &&
+ pc->xferred)
+ pc->retries = IDETAPE_MAX_PC_RETRIES + 1;
+ }
+}
+
+/* Free data buffers completely. */
+static void ide_tape_kfree_buffer(idetape_tape_t *tape)
+{
+ struct idetape_bh *prev_bh, *bh = tape->merge_bh;
+
+ while (bh) {
+ u32 size = bh->b_size;
+
+ while (size) {
+ unsigned int order = fls(size >> PAGE_SHIFT)-1;
+
+ if (bh->b_data)
+ free_pages((unsigned long)bh->b_data, order);
+
+ size &= (order-1);
+ bh->b_data += (1 << order) * PAGE_SIZE;
+ }
+ prev_bh = bh;
+ bh = bh->b_reqnext;
+ kfree(prev_bh);
+ }
+}
+
+static int idetape_end_request(ide_drive_t *drive, int uptodate, int nr_sects)
+{
+ struct request *rq = HWGROUP(drive)->rq;
+ idetape_tape_t *tape = drive->driver_data;
+ unsigned long flags;
+ int error;
+
+ debug_log(DBG_PROCS, "Enter %s\n", __func__);
+
+ switch (uptodate) {
+ case 0: error = IDETAPE_ERROR_GENERAL; break;
+ case 1: error = 0; break;
+ default: error = uptodate;
+ }
+ rq->errors = error;
+ if (error)
+ tape->failed_pc = NULL;
+
+ if (!blk_special_request(rq)) {
+ ide_end_request(drive, uptodate, nr_sects);
+ return 0;
+ }
+
+ spin_lock_irqsave(&tape->lock, flags);
+
+ ide_end_drive_cmd(drive, 0, 0);
+
+ spin_unlock_irqrestore(&tape->lock, flags);
+ return 0;
+}
+
+static void ide_tape_handle_dsc(ide_drive_t *);
+
+static void ide_tape_callback(ide_drive_t *drive, int dsc)
+{
+ idetape_tape_t *tape = drive->driver_data;
+ struct ide_atapi_pc *pc = drive->pc;
+ int uptodate = pc->error ? 0 : 1;
+
+ debug_log(DBG_PROCS, "Enter %s\n", __func__);
+
+ if (dsc)
+ ide_tape_handle_dsc(drive);
+
+ if (tape->failed_pc == pc)
+ tape->failed_pc = NULL;
+
+ if (pc->c[0] == REQUEST_SENSE) {
+ if (uptodate)
+ idetape_analyze_error(drive, pc->buf);
+ else
+ printk(KERN_ERR "ide-tape: Error in REQUEST SENSE "
+ "itself - Aborting request!\n");
+ } else if (pc->c[0] == READ_6 || pc->c[0] == WRITE_6) {
+ struct request *rq = drive->hwif->hwgroup->rq;
+ int blocks = pc->xferred / tape->blk_size;
+
+ tape->avg_size += blocks * tape->blk_size;
+
+ if (time_after_eq(jiffies, tape->avg_time + HZ)) {
+ tape->avg_speed = tape->avg_size * HZ /
+ (jiffies - tape->avg_time) / 1024;
+ tape->avg_size = 0;
+ tape->avg_time = jiffies;
+ }
+
+ tape->first_frame += blocks;
+ rq->current_nr_sectors -= blocks;
+
+ if (pc->error)
+ uptodate = pc->error;
+ } else if (pc->c[0] == READ_POSITION && uptodate) {
+ u8 *readpos = pc->buf;
+
+ debug_log(DBG_SENSE, "BOP - %s\n",
+ (readpos[0] & 0x80) ? "Yes" : "No");
+ debug_log(DBG_SENSE, "EOP - %s\n",
+ (readpos[0] & 0x40) ? "Yes" : "No");
+
+ if (readpos[0] & 0x4) {
+ printk(KERN_INFO "ide-tape: Block location is unknown"
+ "to the tape\n");
+ clear_bit(IDE_AFLAG_ADDRESS_VALID, &drive->atapi_flags);
+ uptodate = 0;
+ } else {
+ debug_log(DBG_SENSE, "Block Location - %u\n",
+ be32_to_cpup((__be32 *)&readpos[4]));
+
+ tape->partition = readpos[1];
+ tape->first_frame = be32_to_cpup((__be32 *)&readpos[4]);
+ set_bit(IDE_AFLAG_ADDRESS_VALID, &drive->atapi_flags);
+ }
+ }
+
+ idetape_end_request(drive, uptodate, 0);
+}
+
+/*
+ * Postpone the current request so that ide.c will be able to service requests
+ * from another device on the same hwgroup while we are polling for DSC.
+ */
+static void idetape_postpone_request(ide_drive_t *drive)
+{
+ idetape_tape_t *tape = drive->driver_data;
+
+ debug_log(DBG_PROCS, "Enter %s\n", __func__);
+
+ tape->postponed_rq = HWGROUP(drive)->rq;
+ ide_stall_queue(drive, tape->dsc_poll_freq);
+}
+
+static void ide_tape_handle_dsc(ide_drive_t *drive)
+{
+ idetape_tape_t *tape = drive->driver_data;
+
+ /* Media access command */
+ tape->dsc_polling_start = jiffies;
+ tape->dsc_poll_freq = IDETAPE_DSC_MA_FAST;
+ tape->dsc_timeout = jiffies + IDETAPE_DSC_MA_TIMEOUT;
+ /* Allow ide.c to handle other requests */
+ idetape_postpone_request(drive);
+}
+
+static int ide_tape_io_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc,
+ unsigned int bcount, int write)
+{
+ if (write)
+ idetape_output_buffers(drive, pc, bcount);
+ else
+ idetape_input_buffers(drive, pc, bcount);
+
+ return bcount;
+}
+
+/*
+ * Packet Command Interface
+ *
+ * The current Packet Command is available in drive->pc, and will not change
+ * until we finish handling it. Each packet command is associated with a
+ * callback function that will be called when the command is finished.
+ *
+ * The handling will be done in three stages:
+ *
+ * 1. idetape_issue_pc will send the packet command to the drive, and will set
+ * the interrupt handler to ide_pc_intr.
+ *
+ * 2. On each interrupt, ide_pc_intr will be called. This step will be
+ * repeated until the device signals us that no more interrupts will be issued.
+ *
+ * 3. ATAPI Tape media access commands have immediate status with a delayed
+ * process. In case of a successful initiation of a media access packet command,
+ * the DSC bit will be set when the actual execution of the command is finished.
+ * Since the tape drive will not issue an interrupt, we have to poll for this
+ * event. In this case, we define the request as "low priority request" by
+ * setting rq_status to IDETAPE_RQ_POSTPONED, set a timer to poll for DSC and
+ * exit the driver.
+ *
+ * ide.c will then give higher priority to requests which originate from the
+ * other device, until will change rq_status to RQ_ACTIVE.
+ *
+ * 4. When the packet command is finished, it will be checked for errors.
+ *
+ * 5. In case an error was found, we queue a request sense packet command in
+ * front of the request queue and retry the operation up to
+ * IDETAPE_MAX_PC_RETRIES times.
+ *
+ * 6. In case no error was found, or we decided to give up and not to retry
+ * again, the callback function will be called and then we will handle the next
+ * request.
+ */
+
+static ide_startstop_t idetape_issue_pc(ide_drive_t *drive,
+ struct ide_atapi_pc *pc)
+{
+ idetape_tape_t *tape = drive->driver_data;
+
+ if (drive->pc->c[0] == REQUEST_SENSE &&
+ pc->c[0] == REQUEST_SENSE) {
+ printk(KERN_ERR "ide-tape: possible ide-tape.c bug - "
+ "Two request sense in serial were issued\n");
+ }
+
+ if (tape->failed_pc == NULL && pc->c[0] != REQUEST_SENSE)
+ tape->failed_pc = pc;
+
+ /* Set the current packet command */
+ drive->pc = pc;
+
+ if (pc->retries > IDETAPE_MAX_PC_RETRIES ||
+ (pc->flags & PC_FLAG_ABORT)) {
+ /*
+ * We will "abort" retrying a packet command in case legitimate
+ * error code was received (crossing a filemark, or end of the
+ * media, for example).
+ */
+ if (!(pc->flags & PC_FLAG_ABORT)) {
+ if (!(pc->c[0] == TEST_UNIT_READY &&
+ tape->sense_key == 2 && tape->asc == 4 &&
+ (tape->ascq == 1 || tape->ascq == 8))) {
+ printk(KERN_ERR "ide-tape: %s: I/O error, "
+ "pc = %2x, key = %2x, "
+ "asc = %2x, ascq = %2x\n",
+ tape->name, pc->c[0],
+ tape->sense_key, tape->asc,
+ tape->ascq);
+ }
+ /* Giving up */
+ pc->error = IDETAPE_ERROR_GENERAL;
+ }
+ tape->failed_pc = NULL;
+ drive->pc_callback(drive, 0);
+ return ide_stopped;
+ }
+ debug_log(DBG_SENSE, "Retry #%d, cmd = %02X\n", pc->retries, pc->c[0]);
+
+ pc->retries++;
+
+ return ide_issue_pc(drive, WAIT_TAPE_CMD, NULL);
+}
+
+/* A mode sense command is used to "sense" tape parameters. */
+static void idetape_create_mode_sense_cmd(struct ide_atapi_pc *pc, u8 page_code)
+{
+ ide_init_pc(pc);
+ pc->c[0] = MODE_SENSE;
+ if (page_code != IDETAPE_BLOCK_DESCRIPTOR)
+ /* DBD = 1 - Don't return block descriptors */
+ pc->c[1] = 8;
+ pc->c[2] = page_code;
+ /*
+ * Changed pc->c[3] to 0 (255 will at best return unused info).
+ *
+ * For SCSI this byte is defined as subpage instead of high byte
+ * of length and some IDE drives seem to interpret it this way
+ * and return an error when 255 is used.
+ */
+ pc->c[3] = 0;
+ /* We will just discard data in that case */
+ pc->c[4] = 255;
+ if (page_code == IDETAPE_BLOCK_DESCRIPTOR)
+ pc->req_xfer = 12;
+ else if (page_code == IDETAPE_CAPABILITIES_PAGE)
+ pc->req_xfer = 24;
+ else
+ pc->req_xfer = 50;
+}
+
+static ide_startstop_t idetape_media_access_finished(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ idetape_tape_t *tape = drive->driver_data;
+ struct ide_atapi_pc *pc = drive->pc;
+ u8 stat;
+
+ stat = hwif->tp_ops->read_status(hwif);
+
+ if (stat & ATA_DSC) {
+ if (stat & ATA_ERR) {
+ /* Error detected */
+ if (pc->c[0] != TEST_UNIT_READY)
+ printk(KERN_ERR "ide-tape: %s: I/O error, ",
+ tape->name);
+ /* Retry operation */
+ ide_retry_pc(drive, tape->disk);
+ return ide_stopped;
+ }
+ pc->error = 0;
+ } else {
+ pc->error = IDETAPE_ERROR_GENERAL;
+ tape->failed_pc = NULL;
+ }
+ drive->pc_callback(drive, 0);
+ return ide_stopped;
+}
+
+static void ide_tape_create_rw_cmd(idetape_tape_t *tape,
+ struct ide_atapi_pc *pc, struct request *rq,
+ u8 opcode)
+{
+ struct idetape_bh *bh = (struct idetape_bh *)rq->special;
+ unsigned int length = rq->current_nr_sectors;
+
+ ide_init_pc(pc);
+ put_unaligned(cpu_to_be32(length), (unsigned int *) &pc->c[1]);
+ pc->c[1] = 1;
+ pc->bh = bh;
+ pc->buf = NULL;
+ pc->buf_size = length * tape->blk_size;
+ pc->req_xfer = pc->buf_size;
+ if (pc->req_xfer == tape->buffer_size)
+ pc->flags |= PC_FLAG_DMA_OK;
+
+ if (opcode == READ_6) {
+ pc->c[0] = READ_6;
+ atomic_set(&bh->b_count, 0);
+ } else if (opcode == WRITE_6) {
+ pc->c[0] = WRITE_6;
+ pc->flags |= PC_FLAG_WRITING;
+ pc->b_data = bh->b_data;
+ pc->b_count = atomic_read(&bh->b_count);
+ }
+
+ memcpy(rq->cmd, pc->c, 12);
+}
+
+static ide_startstop_t idetape_do_request(ide_drive_t *drive,
+ struct request *rq, sector_t block)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ idetape_tape_t *tape = drive->driver_data;
+ struct ide_atapi_pc *pc = NULL;
+ struct request *postponed_rq = tape->postponed_rq;
+ u8 stat;
+
+ debug_log(DBG_SENSE, "sector: %llu, nr_sectors: %lu,"
+ " current_nr_sectors: %u\n",
+ (unsigned long long)rq->sector, rq->nr_sectors,
+ rq->current_nr_sectors);
+
+ if (!blk_special_request(rq)) {
+ /* We do not support buffer cache originated requests. */
+ printk(KERN_NOTICE "ide-tape: %s: Unsupported request in "
+ "request queue (%d)\n", drive->name, rq->cmd_type);
+ ide_end_request(drive, 0, 0);
+ return ide_stopped;
+ }
+
+ /* Retry a failed packet command */
+ if (tape->failed_pc && drive->pc->c[0] == REQUEST_SENSE) {
+ pc = tape->failed_pc;
+ goto out;
+ }
+
+ if (postponed_rq != NULL)
+ if (rq != postponed_rq) {
+ printk(KERN_ERR "ide-tape: ide-tape.c bug - "
+ "Two DSC requests were queued\n");
+ idetape_end_request(drive, 0, 0);
+ return ide_stopped;
+ }
+
+ tape->postponed_rq = NULL;
+
+ /*
+ * If the tape is still busy, postpone our request and service
+ * the other device meanwhile.
+ */
+ stat = hwif->tp_ops->read_status(hwif);
+
+ if ((drive->dev_flags & IDE_DFLAG_DSC_OVERLAP) == 0 &&
+ (rq->cmd[13] & REQ_IDETAPE_PC2) == 0)
+ set_bit(IDE_AFLAG_IGNORE_DSC, &drive->atapi_flags);
+
+ if (drive->dev_flags & IDE_DFLAG_POST_RESET) {
+ set_bit(IDE_AFLAG_IGNORE_DSC, &drive->atapi_flags);
+ drive->dev_flags &= ~IDE_DFLAG_POST_RESET;
+ }
+
+ if (!test_and_clear_bit(IDE_AFLAG_IGNORE_DSC, &drive->atapi_flags) &&
+ (stat & ATA_DSC) == 0) {
+ if (postponed_rq == NULL) {
+ tape->dsc_polling_start = jiffies;
+ tape->dsc_poll_freq = tape->best_dsc_rw_freq;
+ tape->dsc_timeout = jiffies + IDETAPE_DSC_RW_TIMEOUT;
+ } else if (time_after(jiffies, tape->dsc_timeout)) {
+ printk(KERN_ERR "ide-tape: %s: DSC timeout\n",
+ tape->name);
+ if (rq->cmd[13] & REQ_IDETAPE_PC2) {
+ idetape_media_access_finished(drive);
+ return ide_stopped;
+ } else {
+ return ide_do_reset(drive);
+ }
+ } else if (time_after(jiffies,
+ tape->dsc_polling_start +
+ IDETAPE_DSC_MA_THRESHOLD))
+ tape->dsc_poll_freq = IDETAPE_DSC_MA_SLOW;
+ idetape_postpone_request(drive);
+ return ide_stopped;
+ }
+ if (rq->cmd[13] & REQ_IDETAPE_READ) {
+ pc = &tape->queued_pc;
+ ide_tape_create_rw_cmd(tape, pc, rq, READ_6);
+ goto out;
+ }
+ if (rq->cmd[13] & REQ_IDETAPE_WRITE) {
+ pc = &tape->queued_pc;
+ ide_tape_create_rw_cmd(tape, pc, rq, WRITE_6);
+ goto out;
+ }
+ if (rq->cmd[13] & REQ_IDETAPE_PC1) {
+ pc = (struct ide_atapi_pc *) rq->buffer;
+ rq->cmd[13] &= ~(REQ_IDETAPE_PC1);
+ rq->cmd[13] |= REQ_IDETAPE_PC2;
+ goto out;
+ }
+ if (rq->cmd[13] & REQ_IDETAPE_PC2) {
+ idetape_media_access_finished(drive);
+ return ide_stopped;
+ }
+ BUG();
+
+out:
+ return idetape_issue_pc(drive, pc);
+}
+
+/*
+ * The function below uses __get_free_pages to allocate a data buffer of size
+ * tape->buffer_size (or a bit more). We attempt to combine sequential pages as
+ * much as possible.
+ *
+ * It returns a pointer to the newly allocated buffer, or NULL in case of
+ * failure.
+ */
+static struct idetape_bh *ide_tape_kmalloc_buffer(idetape_tape_t *tape,
+ int full, int clear)
+{
+ struct idetape_bh *prev_bh, *bh, *merge_bh;
+ int pages = tape->pages_per_buffer;
+ unsigned int order, b_allocd;
+ char *b_data = NULL;
+
+ merge_bh = kmalloc(sizeof(struct idetape_bh), GFP_KERNEL);
+ bh = merge_bh;
+ if (bh == NULL)
+ goto abort;
+
+ order = fls(pages) - 1;
+ bh->b_data = (char *) __get_free_pages(GFP_KERNEL, order);
+ if (!bh->b_data)
+ goto abort;
+ b_allocd = (1 << order) * PAGE_SIZE;
+ pages &= (order-1);
+
+ if (clear)
+ memset(bh->b_data, 0, b_allocd);
+ bh->b_reqnext = NULL;
+ bh->b_size = b_allocd;
+ atomic_set(&bh->b_count, full ? bh->b_size : 0);
+
+ while (pages) {
+ order = fls(pages) - 1;
+ b_data = (char *) __get_free_pages(GFP_KERNEL, order);
+ if (!b_data)
+ goto abort;
+ b_allocd = (1 << order) * PAGE_SIZE;
+
+ if (clear)
+ memset(b_data, 0, b_allocd);
+
+ /* newly allocated page frames below buffer header or ...*/
+ if (bh->b_data == b_data + b_allocd) {
+ bh->b_size += b_allocd;
+ bh->b_data -= b_allocd;
+ if (full)
+ atomic_add(b_allocd, &bh->b_count);
+ continue;
+ }
+ /* they are above the header */
+ if (b_data == bh->b_data + bh->b_size) {
+ bh->b_size += b_allocd;
+ if (full)
+ atomic_add(b_allocd, &bh->b_count);
+ continue;
+ }
+ prev_bh = bh;
+ bh = kmalloc(sizeof(struct idetape_bh), GFP_KERNEL);
+ if (!bh) {
+ free_pages((unsigned long) b_data, order);
+ goto abort;
+ }
+ bh->b_reqnext = NULL;
+ bh->b_data = b_data;
+ bh->b_size = b_allocd;
+ atomic_set(&bh->b_count, full ? bh->b_size : 0);
+ prev_bh->b_reqnext = bh;
+
+ pages &= (order-1);
+ }
+
+ bh->b_size -= tape->excess_bh_size;
+ if (full)
+ atomic_sub(tape->excess_bh_size, &bh->b_count);
+ return merge_bh;
+abort:
+ ide_tape_kfree_buffer(tape);
+ return NULL;
+}
+
+static int idetape_copy_stage_from_user(idetape_tape_t *tape,
+ const char __user *buf, int n)
+{
+ struct idetape_bh *bh = tape->bh;
+ int count;
+ int ret = 0;
+
+ while (n) {
+ if (bh == NULL) {
+ printk(KERN_ERR "ide-tape: bh == NULL in %s\n",
+ __func__);
+ return 1;
+ }
+ count = min((unsigned int)
+ (bh->b_size - atomic_read(&bh->b_count)),
+ (unsigned int)n);
+ if (copy_from_user(bh->b_data + atomic_read(&bh->b_count), buf,
+ count))
+ ret = 1;
+ n -= count;
+ atomic_add(count, &bh->b_count);
+ buf += count;
+ if (atomic_read(&bh->b_count) == bh->b_size) {
+ bh = bh->b_reqnext;
+ if (bh)
+ atomic_set(&bh->b_count, 0);
+ }
+ }
+ tape->bh = bh;
+ return ret;
+}
+
+static int idetape_copy_stage_to_user(idetape_tape_t *tape, char __user *buf,
+ int n)
+{
+ struct idetape_bh *bh = tape->bh;
+ int count;
+ int ret = 0;
+
+ while (n) {
+ if (bh == NULL) {
+ printk(KERN_ERR "ide-tape: bh == NULL in %s\n",
+ __func__);
+ return 1;
+ }
+ count = min(tape->b_count, n);
+ if (copy_to_user(buf, tape->b_data, count))
+ ret = 1;
+ n -= count;
+ tape->b_data += count;
+ tape->b_count -= count;
+ buf += count;
+ if (!tape->b_count) {
+ bh = bh->b_reqnext;
+ tape->bh = bh;
+ if (bh) {
+ tape->b_data = bh->b_data;
+ tape->b_count = atomic_read(&bh->b_count);
+ }
+ }
+ }
+ return ret;
+}
+
+static void idetape_init_merge_buffer(idetape_tape_t *tape)
+{
+ struct idetape_bh *bh = tape->merge_bh;
+ tape->bh = tape->merge_bh;
+
+ if (tape->chrdev_dir == IDETAPE_DIR_WRITE)
+ atomic_set(&bh->b_count, 0);
+ else {
+ tape->b_data = bh->b_data;
+ tape->b_count = atomic_read(&bh->b_count);
+ }
+}
+
+/*
+ * Write a filemark if write_filemark=1. Flush the device buffers without
+ * writing a filemark otherwise.
+ */
+static void idetape_create_write_filemark_cmd(ide_drive_t *drive,
+ struct ide_atapi_pc *pc, int write_filemark)
+{
+ ide_init_pc(pc);
+ pc->c[0] = WRITE_FILEMARKS;
+ pc->c[4] = write_filemark;
+ pc->flags |= PC_FLAG_WAIT_FOR_DSC;
+}
+
+static int idetape_wait_ready(ide_drive_t *drive, unsigned long timeout)
+{
+ idetape_tape_t *tape = drive->driver_data;
+ struct gendisk *disk = tape->disk;
+ int load_attempted = 0;
+
+ /* Wait for the tape to become ready */
+ set_bit(IDE_AFLAG_MEDIUM_PRESENT, &drive->atapi_flags);
+ timeout += jiffies;
+ while (time_before(jiffies, timeout)) {
+ if (ide_do_test_unit_ready(drive, disk) == 0)
+ return 0;
+ if ((tape->sense_key == 2 && tape->asc == 4 && tape->ascq == 2)
+ || (tape->asc == 0x3A)) {
+ /* no media */
+ if (load_attempted)
+ return -ENOMEDIUM;
+ ide_do_start_stop(drive, disk, IDETAPE_LU_LOAD_MASK);
+ load_attempted = 1;
+ /* not about to be ready */
+ } else if (!(tape->sense_key == 2 && tape->asc == 4 &&
+ (tape->ascq == 1 || tape->ascq == 8)))
+ return -EIO;
+ msleep(100);
+ }
+ return -EIO;
+}
+
+static int idetape_flush_tape_buffers(ide_drive_t *drive)
+{
+ struct ide_tape_obj *tape = drive->driver_data;
+ struct ide_atapi_pc pc;
+ int rc;
+
+ idetape_create_write_filemark_cmd(drive, &pc, 0);
+ rc = ide_queue_pc_tail(drive, tape->disk, &pc);
+ if (rc)
+ return rc;
+ idetape_wait_ready(drive, 60 * 5 * HZ);
+ return 0;
+}
+
+static void idetape_create_read_position_cmd(struct ide_atapi_pc *pc)
+{
+ ide_init_pc(pc);
+ pc->c[0] = READ_POSITION;
+ pc->req_xfer = 20;
+}
+
+static int idetape_read_position(ide_drive_t *drive)
+{
+ idetape_tape_t *tape = drive->driver_data;
+ struct ide_atapi_pc pc;
+ int position;
+
+ debug_log(DBG_PROCS, "Enter %s\n", __func__);
+
+ idetape_create_read_position_cmd(&pc);
+ if (ide_queue_pc_tail(drive, tape->disk, &pc))
+ return -1;
+ position = tape->first_frame;
+ return position;
+}
+
+static void idetape_create_locate_cmd(ide_drive_t *drive,
+ struct ide_atapi_pc *pc,
+ unsigned int block, u8 partition, int skip)
+{
+ ide_init_pc(pc);
+ pc->c[0] = POSITION_TO_ELEMENT;
+ pc->c[1] = 2;
+ put_unaligned(cpu_to_be32(block), (unsigned int *) &pc->c[3]);
+ pc->c[8] = partition;
+ pc->flags |= PC_FLAG_WAIT_FOR_DSC;
+}
+
+static void __ide_tape_discard_merge_buffer(ide_drive_t *drive)
+{
+ idetape_tape_t *tape = drive->driver_data;
+
+ if (tape->chrdev_dir != IDETAPE_DIR_READ)
+ return;
+
+ clear_bit(IDE_AFLAG_FILEMARK, &drive->atapi_flags);
+ tape->merge_bh_size = 0;
+ if (tape->merge_bh != NULL) {
+ ide_tape_kfree_buffer(tape);
+ tape->merge_bh = NULL;
+ }
+
+ tape->chrdev_dir = IDETAPE_DIR_NONE;
+}
+
+/*
+ * Position the tape to the requested block using the LOCATE packet command.
+ * A READ POSITION command is then issued to check where we are positioned. Like
+ * all higher level operations, we queue the commands at the tail of the request
+ * queue and wait for their completion.
+ */
+static int idetape_position_tape(ide_drive_t *drive, unsigned int block,
+ u8 partition, int skip)
+{
+ idetape_tape_t *tape = drive->driver_data;
+ struct gendisk *disk = tape->disk;
+ int retval;
+ struct ide_atapi_pc pc;
+
+ if (tape->chrdev_dir == IDETAPE_DIR_READ)
+ __ide_tape_discard_merge_buffer(drive);
+ idetape_wait_ready(drive, 60 * 5 * HZ);
+ idetape_create_locate_cmd(drive, &pc, block, partition, skip);
+ retval = ide_queue_pc_tail(drive, disk, &pc);
+ if (retval)
+ return (retval);
+
+ idetape_create_read_position_cmd(&pc);
+ return ide_queue_pc_tail(drive, disk, &pc);
+}
+
+static void ide_tape_discard_merge_buffer(ide_drive_t *drive,
+ int restore_position)
+{
+ idetape_tape_t *tape = drive->driver_data;
+ int seek, position;
+
+ __ide_tape_discard_merge_buffer(drive);
+ if (restore_position) {
+ position = idetape_read_position(drive);
+ seek = position > 0 ? position : 0;
+ if (idetape_position_tape(drive, seek, 0, 0)) {
+ printk(KERN_INFO "ide-tape: %s: position_tape failed in"
+ " %s\n", tape->name, __func__);
+ return;
+ }
+ }
+}
+
+/*
+ * Generate a read/write request for the block device interface and wait for it
+ * to be serviced.
+ */
+static int idetape_queue_rw_tail(ide_drive_t *drive, int cmd, int blocks,
+ struct idetape_bh *bh)
+{
+ idetape_tape_t *tape = drive->driver_data;
+ struct request *rq;
+ int ret, errors;
+
+ debug_log(DBG_SENSE, "%s: cmd=%d\n", __func__, cmd);
+
+ rq = blk_get_request(drive->queue, READ, __GFP_WAIT);
+ rq->cmd_type = REQ_TYPE_SPECIAL;
+ rq->cmd[13] = cmd;
+ rq->rq_disk = tape->disk;
+ rq->special = (void *)bh;
+ rq->sector = tape->first_frame;
+ rq->nr_sectors = blocks;
+ rq->current_nr_sectors = blocks;
+ blk_execute_rq(drive->queue, tape->disk, rq, 0);
+
+ errors = rq->errors;
+ ret = tape->blk_size * (blocks - rq->current_nr_sectors);
+ blk_put_request(rq);
+
+ if ((cmd & (REQ_IDETAPE_READ | REQ_IDETAPE_WRITE)) == 0)
+ return 0;
+
+ if (tape->merge_bh)
+ idetape_init_merge_buffer(tape);
+ if (errors == IDETAPE_ERROR_GENERAL)
+ return -EIO;
+ return ret;
+}
+
+static void idetape_create_inquiry_cmd(struct ide_atapi_pc *pc)
+{
+ ide_init_pc(pc);
+ pc->c[0] = INQUIRY;
+ pc->c[4] = 254;
+ pc->req_xfer = 254;
+}
+
+static void idetape_create_rewind_cmd(ide_drive_t *drive,
+ struct ide_atapi_pc *pc)
+{
+ ide_init_pc(pc);
+ pc->c[0] = REZERO_UNIT;
+ pc->flags |= PC_FLAG_WAIT_FOR_DSC;
+}
+
+static void idetape_create_erase_cmd(struct ide_atapi_pc *pc)
+{
+ ide_init_pc(pc);
+ pc->c[0] = ERASE;
+ pc->c[1] = 1;
+ pc->flags |= PC_FLAG_WAIT_FOR_DSC;
+}
+
+static void idetape_create_space_cmd(struct ide_atapi_pc *pc, int count, u8 cmd)
+{
+ ide_init_pc(pc);
+ pc->c[0] = SPACE;
+ put_unaligned(cpu_to_be32(count), (unsigned int *) &pc->c[1]);
+ pc->c[1] = cmd;
+ pc->flags |= PC_FLAG_WAIT_FOR_DSC;
+}
+
+/* Queue up a character device originated write request. */
+static int idetape_add_chrdev_write_request(ide_drive_t *drive, int blocks)
+{
+ idetape_tape_t *tape = drive->driver_data;
+
+ debug_log(DBG_CHRDEV, "Enter %s\n", __func__);
+
+ return idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE,
+ blocks, tape->merge_bh);
+}
+
+static void ide_tape_flush_merge_buffer(ide_drive_t *drive)
+{
+ idetape_tape_t *tape = drive->driver_data;
+ int blocks, min;
+ struct idetape_bh *bh;
+
+ if (tape->chrdev_dir != IDETAPE_DIR_WRITE) {
+ printk(KERN_ERR "ide-tape: bug: Trying to empty merge buffer"
+ " but we are not writing.\n");
+ return;
+ }
+ if (tape->merge_bh_size > tape->buffer_size) {
+ printk(KERN_ERR "ide-tape: bug: merge_buffer too big\n");
+ tape->merge_bh_size = tape->buffer_size;
+ }
+ if (tape->merge_bh_size) {
+ blocks = tape->merge_bh_size / tape->blk_size;
+ if (tape->merge_bh_size % tape->blk_size) {
+ unsigned int i;
+
+ blocks++;
+ i = tape->blk_size - tape->merge_bh_size %
+ tape->blk_size;
+ bh = tape->bh->b_reqnext;
+ while (bh) {
+ atomic_set(&bh->b_count, 0);
+ bh = bh->b_reqnext;
+ }
+ bh = tape->bh;
+ while (i) {
+ if (bh == NULL) {
+ printk(KERN_INFO "ide-tape: bug,"
+ " bh NULL\n");
+ break;
+ }
+ min = min(i, (unsigned int)(bh->b_size -
+ atomic_read(&bh->b_count)));
+ memset(bh->b_data + atomic_read(&bh->b_count),
+ 0, min);
+ atomic_add(min, &bh->b_count);
+ i -= min;
+ bh = bh->b_reqnext;
+ }
+ }
+ (void) idetape_add_chrdev_write_request(drive, blocks);
+ tape->merge_bh_size = 0;
+ }
+ if (tape->merge_bh != NULL) {
+ ide_tape_kfree_buffer(tape);
+ tape->merge_bh = NULL;
+ }
+ tape->chrdev_dir = IDETAPE_DIR_NONE;
+}
+
+static int idetape_init_read(ide_drive_t *drive)
+{
+ idetape_tape_t *tape = drive->driver_data;
+ int bytes_read;
+
+ /* Initialize read operation */
+ if (tape->chrdev_dir != IDETAPE_DIR_READ) {
+ if (tape->chrdev_dir == IDETAPE_DIR_WRITE) {
+ ide_tape_flush_merge_buffer(drive);
+ idetape_flush_tape_buffers(drive);
+ }
+ if (tape->merge_bh || tape->merge_bh_size) {
+ printk(KERN_ERR "ide-tape: merge_bh_size should be"
+ " 0 now\n");
+ tape->merge_bh_size = 0;
+ }
+ tape->merge_bh = ide_tape_kmalloc_buffer(tape, 0, 0);
+ if (!tape->merge_bh)
+ return -ENOMEM;
+ tape->chrdev_dir = IDETAPE_DIR_READ;
+
+ /*
+ * Issue a read 0 command to ensure that DSC handshake is
+ * switched from completion mode to buffer available mode.
+ * No point in issuing this if DSC overlap isn't supported, some
+ * drives (Seagate STT3401A) will return an error.
+ */
+ if (drive->dev_flags & IDE_DFLAG_DSC_OVERLAP) {
+ bytes_read = idetape_queue_rw_tail(drive,
+ REQ_IDETAPE_READ, 0,
+ tape->merge_bh);
+ if (bytes_read < 0) {
+ ide_tape_kfree_buffer(tape);
+ tape->merge_bh = NULL;
+ tape->chrdev_dir = IDETAPE_DIR_NONE;
+ return bytes_read;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/* called from idetape_chrdev_read() to service a chrdev read request. */
+static int idetape_add_chrdev_read_request(ide_drive_t *drive, int blocks)
+{
+ idetape_tape_t *tape = drive->driver_data;
+
+ debug_log(DBG_PROCS, "Enter %s, %d blocks\n", __func__, blocks);
+
+ /* If we are at a filemark, return a read length of 0 */
+ if (test_bit(IDE_AFLAG_FILEMARK, &drive->atapi_flags))
+ return 0;
+
+ idetape_init_read(drive);
+
+ return idetape_queue_rw_tail(drive, REQ_IDETAPE_READ, blocks,
+ tape->merge_bh);
+}
+
+static void idetape_pad_zeros(ide_drive_t *drive, int bcount)
+{
+ idetape_tape_t *tape = drive->driver_data;
+ struct idetape_bh *bh;
+ int blocks;
+
+ while (bcount) {
+ unsigned int count;
+
+ bh = tape->merge_bh;
+ count = min(tape->buffer_size, bcount);
+ bcount -= count;
+ blocks = count / tape->blk_size;
+ while (count) {
+ atomic_set(&bh->b_count,
+ min(count, (unsigned int)bh->b_size));
+ memset(bh->b_data, 0, atomic_read(&bh->b_count));
+ count -= atomic_read(&bh->b_count);
+ bh = bh->b_reqnext;
+ }
+ idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE, blocks,
+ tape->merge_bh);
+ }
+}
+
+/*
+ * Rewinds the tape to the Beginning Of the current Partition (BOP). We
+ * currently support only one partition.
+ */
+static int idetape_rewind_tape(ide_drive_t *drive)
+{
+ struct ide_tape_obj *tape = drive->driver_data;
+ struct gendisk *disk = tape->disk;
+ int retval;
+ struct ide_atapi_pc pc;
+
+ debug_log(DBG_SENSE, "Enter %s\n", __func__);
+
+ idetape_create_rewind_cmd(drive, &pc);
+ retval = ide_queue_pc_tail(drive, disk, &pc);
+ if (retval)
+ return retval;
+
+ idetape_create_read_position_cmd(&pc);
+ retval = ide_queue_pc_tail(drive, disk, &pc);
+ if (retval)
+ return retval;
+ return 0;
+}
+
+/* mtio.h compatible commands should be issued to the chrdev interface. */
+static int idetape_blkdev_ioctl(ide_drive_t *drive, unsigned int cmd,
+ unsigned long arg)
+{
+ idetape_tape_t *tape = drive->driver_data;
+ void __user *argp = (void __user *)arg;
+
+ struct idetape_config {
+ int dsc_rw_frequency;
+ int dsc_media_access_frequency;
+ int nr_stages;
+ } config;
+
+ debug_log(DBG_PROCS, "Enter %s\n", __func__);
+
+ switch (cmd) {
+ case 0x0340:
+ if (copy_from_user(&config, argp, sizeof(config)))
+ return -EFAULT;
+ tape->best_dsc_rw_freq = config.dsc_rw_frequency;
+ break;
+ case 0x0350:
+ config.dsc_rw_frequency = (int) tape->best_dsc_rw_freq;
+ config.nr_stages = 1;
+ if (copy_to_user(argp, &config, sizeof(config)))
+ return -EFAULT;
+ break;
+ default:
+ return -EIO;
+ }
+ return 0;
+}
+
+static int idetape_space_over_filemarks(ide_drive_t *drive, short mt_op,
+ int mt_count)
+{
+ idetape_tape_t *tape = drive->driver_data;
+ struct gendisk *disk = tape->disk;
+ struct ide_atapi_pc pc;
+ int retval, count = 0;
+ int sprev = !!(tape->caps[4] & 0x20);
+
+ if (mt_count == 0)
+ return 0;
+ if (MTBSF == mt_op || MTBSFM == mt_op) {
+ if (!sprev)
+ return -EIO;
+ mt_count = -mt_count;
+ }
+
+ if (tape->chrdev_dir == IDETAPE_DIR_READ) {
+ tape->merge_bh_size = 0;
+ if (test_and_clear_bit(IDE_AFLAG_FILEMARK, &drive->atapi_flags))
+ ++count;
+ ide_tape_discard_merge_buffer(drive, 0);
+ }
+
+ switch (mt_op) {
+ case MTFSF:
+ case MTBSF:
+ idetape_create_space_cmd(&pc, mt_count - count,
+ IDETAPE_SPACE_OVER_FILEMARK);
+ return ide_queue_pc_tail(drive, disk, &pc);
+ case MTFSFM:
+ case MTBSFM:
+ if (!sprev)
+ return -EIO;
+ retval = idetape_space_over_filemarks(drive, MTFSF,
+ mt_count - count);
+ if (retval)
+ return retval;
+ count = (MTBSFM == mt_op ? 1 : -1);
+ return idetape_space_over_filemarks(drive, MTFSF, count);
+ default:
+ printk(KERN_ERR "ide-tape: MTIO operation %d not supported\n",
+ mt_op);
+ return -EIO;
+ }
+}
+
+/*
+ * Our character device read / write functions.
+ *
+ * The tape is optimized to maximize throughput when it is transferring an
+ * integral number of the "continuous transfer limit", which is a parameter of
+ * the specific tape (26kB on my particular tape, 32kB for Onstream).
+ *
+ * As of version 1.3 of the driver, the character device provides an abstract
+ * continuous view of the media - any mix of block sizes (even 1 byte) on the
+ * same backup/restore procedure is supported. The driver will internally
+ * convert the requests to the recommended transfer unit, so that an unmatch
+ * between the user's block size to the recommended size will only result in a
+ * (slightly) increased driver overhead, but will no longer hit performance.
+ * This is not applicable to Onstream.
+ */
+static ssize_t idetape_chrdev_read(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct ide_tape_obj *tape = file->private_data;
+ ide_drive_t *drive = tape->drive;
+ ssize_t bytes_read, temp, actually_read = 0, rc;
+ ssize_t ret = 0;
+ u16 ctl = *(u16 *)&tape->caps[12];
+
+ debug_log(DBG_CHRDEV, "Enter %s, count %Zd\n", __func__, count);
+
+ if (tape->chrdev_dir != IDETAPE_DIR_READ) {
+ if (test_bit(IDE_AFLAG_DETECT_BS, &drive->atapi_flags))
+ if (count > tape->blk_size &&
+ (count % tape->blk_size) == 0)
+ tape->user_bs_factor = count / tape->blk_size;
+ }
+ rc = idetape_init_read(drive);
+ if (rc < 0)
+ return rc;
+ if (count == 0)
+ return (0);
+ if (tape->merge_bh_size) {
+ actually_read = min((unsigned int)(tape->merge_bh_size),
+ (unsigned int)count);
+ if (idetape_copy_stage_to_user(tape, buf, actually_read))
+ ret = -EFAULT;
+ buf += actually_read;
+ tape->merge_bh_size -= actually_read;
+ count -= actually_read;
+ }
+ while (count >= tape->buffer_size) {
+ bytes_read = idetape_add_chrdev_read_request(drive, ctl);
+ if (bytes_read <= 0)
+ goto finish;
+ if (idetape_copy_stage_to_user(tape, buf, bytes_read))
+ ret = -EFAULT;
+ buf += bytes_read;
+ count -= bytes_read;
+ actually_read += bytes_read;
+ }
+ if (count) {
+ bytes_read = idetape_add_chrdev_read_request(drive, ctl);
+ if (bytes_read <= 0)
+ goto finish;
+ temp = min((unsigned long)count, (unsigned long)bytes_read);
+ if (idetape_copy_stage_to_user(tape, buf, temp))
+ ret = -EFAULT;
+ actually_read += temp;
+ tape->merge_bh_size = bytes_read-temp;
+ }
+finish:
+ if (!actually_read && test_bit(IDE_AFLAG_FILEMARK, &drive->atapi_flags)) {
+ debug_log(DBG_SENSE, "%s: spacing over filemark\n", tape->name);
+
+ idetape_space_over_filemarks(drive, MTFSF, 1);
+ return 0;
+ }
+
+ return ret ? ret : actually_read;
+}
+
+static ssize_t idetape_chrdev_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct ide_tape_obj *tape = file->private_data;
+ ide_drive_t *drive = tape->drive;
+ ssize_t actually_written = 0;
+ ssize_t ret = 0;
+ u16 ctl = *(u16 *)&tape->caps[12];
+
+ /* The drive is write protected. */
+ if (tape->write_prot)
+ return -EACCES;
+
+ debug_log(DBG_CHRDEV, "Enter %s, count %Zd\n", __func__, count);
+
+ /* Initialize write operation */
+ if (tape->chrdev_dir != IDETAPE_DIR_WRITE) {
+ if (tape->chrdev_dir == IDETAPE_DIR_READ)
+ ide_tape_discard_merge_buffer(drive, 1);
+ if (tape->merge_bh || tape->merge_bh_size) {
+ printk(KERN_ERR "ide-tape: merge_bh_size "
+ "should be 0 now\n");
+ tape->merge_bh_size = 0;
+ }
+ tape->merge_bh = ide_tape_kmalloc_buffer(tape, 0, 0);
+ if (!tape->merge_bh)
+ return -ENOMEM;
+ tape->chrdev_dir = IDETAPE_DIR_WRITE;
+ idetape_init_merge_buffer(tape);
+
+ /*
+ * Issue a write 0 command to ensure that DSC handshake is
+ * switched from completion mode to buffer available mode. No
+ * point in issuing this if DSC overlap isn't supported, some
+ * drives (Seagate STT3401A) will return an error.
+ */
+ if (drive->dev_flags & IDE_DFLAG_DSC_OVERLAP) {
+ ssize_t retval = idetape_queue_rw_tail(drive,
+ REQ_IDETAPE_WRITE, 0,
+ tape->merge_bh);
+ if (retval < 0) {
+ ide_tape_kfree_buffer(tape);
+ tape->merge_bh = NULL;
+ tape->chrdev_dir = IDETAPE_DIR_NONE;
+ return retval;
+ }
+ }
+ }
+ if (count == 0)
+ return (0);
+ if (tape->merge_bh_size) {
+ if (tape->merge_bh_size >= tape->buffer_size) {
+ printk(KERN_ERR "ide-tape: bug: merge buf too big\n");
+ tape->merge_bh_size = 0;
+ }
+ actually_written = min((unsigned int)
+ (tape->buffer_size - tape->merge_bh_size),
+ (unsigned int)count);
+ if (idetape_copy_stage_from_user(tape, buf, actually_written))
+ ret = -EFAULT;
+ buf += actually_written;
+ tape->merge_bh_size += actually_written;
+ count -= actually_written;
+
+ if (tape->merge_bh_size == tape->buffer_size) {
+ ssize_t retval;
+ tape->merge_bh_size = 0;
+ retval = idetape_add_chrdev_write_request(drive, ctl);
+ if (retval <= 0)
+ return (retval);
+ }
+ }
+ while (count >= tape->buffer_size) {
+ ssize_t retval;
+ if (idetape_copy_stage_from_user(tape, buf, tape->buffer_size))
+ ret = -EFAULT;
+ buf += tape->buffer_size;
+ count -= tape->buffer_size;
+ retval = idetape_add_chrdev_write_request(drive, ctl);
+ actually_written += tape->buffer_size;
+ if (retval <= 0)
+ return (retval);
+ }
+ if (count) {
+ actually_written += count;
+ if (idetape_copy_stage_from_user(tape, buf, count))
+ ret = -EFAULT;
+ tape->merge_bh_size += count;
+ }
+ return ret ? ret : actually_written;
+}
+
+static int idetape_write_filemark(ide_drive_t *drive)
+{
+ struct ide_tape_obj *tape = drive->driver_data;
+ struct ide_atapi_pc pc;
+
+ /* Write a filemark */
+ idetape_create_write_filemark_cmd(drive, &pc, 1);
+ if (ide_queue_pc_tail(drive, tape->disk, &pc)) {
+ printk(KERN_ERR "ide-tape: Couldn't write a filemark\n");
+ return -EIO;
+ }
+ return 0;
+}
+
+/*
+ * Called from idetape_chrdev_ioctl when the general mtio MTIOCTOP ioctl is
+ * requested.
+ *
+ * Note: MTBSF and MTBSFM are not supported when the tape doesn't support
+ * spacing over filemarks in the reverse direction. In this case, MTFSFM is also
+ * usually not supported.
+ *
+ * The following commands are currently not supported:
+ *
+ * MTFSS, MTBSS, MTWSM, MTSETDENSITY, MTSETDRVBUFFER, MT_ST_BOOLEANS,
+ * MT_ST_WRITE_THRESHOLD.
+ */
+static int idetape_mtioctop(ide_drive_t *drive, short mt_op, int mt_count)
+{
+ idetape_tape_t *tape = drive->driver_data;
+ struct gendisk *disk = tape->disk;
+ struct ide_atapi_pc pc;
+ int i, retval;
+
+ debug_log(DBG_ERR, "Handling MTIOCTOP ioctl: mt_op=%d, mt_count=%d\n",
+ mt_op, mt_count);
+
+ switch (mt_op) {
+ case MTFSF:
+ case MTFSFM:
+ case MTBSF:
+ case MTBSFM:
+ if (!mt_count)
+ return 0;
+ return idetape_space_over_filemarks(drive, mt_op, mt_count);
+ default:
+ break;
+ }
+
+ switch (mt_op) {
+ case MTWEOF:
+ if (tape->write_prot)
+ return -EACCES;
+ ide_tape_discard_merge_buffer(drive, 1);
+ for (i = 0; i < mt_count; i++) {
+ retval = idetape_write_filemark(drive);
+ if (retval)
+ return retval;
+ }
+ return 0;
+ case MTREW:
+ ide_tape_discard_merge_buffer(drive, 0);
+ if (idetape_rewind_tape(drive))
+ return -EIO;
+ return 0;
+ case MTLOAD:
+ ide_tape_discard_merge_buffer(drive, 0);
+ return ide_do_start_stop(drive, disk, IDETAPE_LU_LOAD_MASK);
+ case MTUNLOAD:
+ case MTOFFL:
+ /*
+ * If door is locked, attempt to unlock before
+ * attempting to eject.
+ */
+ if (tape->door_locked) {
+ if (!ide_set_media_lock(drive, disk, 0))
+ tape->door_locked = DOOR_UNLOCKED;
+ }
+ ide_tape_discard_merge_buffer(drive, 0);
+ retval = ide_do_start_stop(drive, disk, !IDETAPE_LU_LOAD_MASK);
+ if (!retval)
+ clear_bit(IDE_AFLAG_MEDIUM_PRESENT, &drive->atapi_flags);
+ return retval;
+ case MTNOP:
+ ide_tape_discard_merge_buffer(drive, 0);
+ return idetape_flush_tape_buffers(drive);
+ case MTRETEN:
+ ide_tape_discard_merge_buffer(drive, 0);
+ return ide_do_start_stop(drive, disk,
+ IDETAPE_LU_RETENSION_MASK | IDETAPE_LU_LOAD_MASK);
+ case MTEOM:
+ idetape_create_space_cmd(&pc, 0, IDETAPE_SPACE_TO_EOD);
+ return ide_queue_pc_tail(drive, disk, &pc);
+ case MTERASE:
+ (void)idetape_rewind_tape(drive);
+ idetape_create_erase_cmd(&pc);
+ return ide_queue_pc_tail(drive, disk, &pc);
+ case MTSETBLK:
+ if (mt_count) {
+ if (mt_count < tape->blk_size ||
+ mt_count % tape->blk_size)
+ return -EIO;
+ tape->user_bs_factor = mt_count / tape->blk_size;
+ clear_bit(IDE_AFLAG_DETECT_BS, &drive->atapi_flags);
+ } else
+ set_bit(IDE_AFLAG_DETECT_BS, &drive->atapi_flags);
+ return 0;
+ case MTSEEK:
+ ide_tape_discard_merge_buffer(drive, 0);
+ return idetape_position_tape(drive,
+ mt_count * tape->user_bs_factor, tape->partition, 0);
+ case MTSETPART:
+ ide_tape_discard_merge_buffer(drive, 0);
+ return idetape_position_tape(drive, 0, mt_count, 0);
+ case MTFSR:
+ case MTBSR:
+ case MTLOCK:
+ retval = ide_set_media_lock(drive, disk, 1);
+ if (retval)
+ return retval;
+ tape->door_locked = DOOR_EXPLICITLY_LOCKED;
+ return 0;
+ case MTUNLOCK:
+ retval = ide_set_media_lock(drive, disk, 0);
+ if (retval)
+ return retval;
+ tape->door_locked = DOOR_UNLOCKED;
+ return 0;
+ default:
+ printk(KERN_ERR "ide-tape: MTIO operation %d not supported\n",
+ mt_op);
+ return -EIO;
+ }
+}
+
+/*
+ * Our character device ioctls. General mtio.h magnetic io commands are
+ * supported here, and not in the corresponding block interface. Our own
+ * ide-tape ioctls are supported on both interfaces.
+ */
+static int idetape_chrdev_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct ide_tape_obj *tape = file->private_data;
+ ide_drive_t *drive = tape->drive;
+ struct mtop mtop;
+ struct mtget mtget;
+ struct mtpos mtpos;
+ int block_offset = 0, position = tape->first_frame;
+ void __user *argp = (void __user *)arg;
+
+ debug_log(DBG_CHRDEV, "Enter %s, cmd=%u\n", __func__, cmd);
+
+ if (tape->chrdev_dir == IDETAPE_DIR_WRITE) {
+ ide_tape_flush_merge_buffer(drive);
+ idetape_flush_tape_buffers(drive);
+ }
+ if (cmd == MTIOCGET || cmd == MTIOCPOS) {
+ block_offset = tape->merge_bh_size /
+ (tape->blk_size * tape->user_bs_factor);
+ position = idetape_read_position(drive);
+ if (position < 0)
+ return -EIO;
+ }
+ switch (cmd) {
+ case MTIOCTOP:
+ if (copy_from_user(&mtop, argp, sizeof(struct mtop)))
+ return -EFAULT;
+ return idetape_mtioctop(drive, mtop.mt_op, mtop.mt_count);
+ case MTIOCGET:
+ memset(&mtget, 0, sizeof(struct mtget));
+ mtget.mt_type = MT_ISSCSI2;
+ mtget.mt_blkno = position / tape->user_bs_factor - block_offset;
+ mtget.mt_dsreg =
+ ((tape->blk_size * tape->user_bs_factor)
+ << MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK;
+
+ if (tape->drv_write_prot)
+ mtget.mt_gstat |= GMT_WR_PROT(0xffffffff);
+
+ if (copy_to_user(argp, &mtget, sizeof(struct mtget)))
+ return -EFAULT;
+ return 0;
+ case MTIOCPOS:
+ mtpos.mt_blkno = position / tape->user_bs_factor - block_offset;
+ if (copy_to_user(argp, &mtpos, sizeof(struct mtpos)))
+ return -EFAULT;
+ return 0;
+ default:
+ if (tape->chrdev_dir == IDETAPE_DIR_READ)
+ ide_tape_discard_merge_buffer(drive, 1);
+ return idetape_blkdev_ioctl(drive, cmd, arg);
+ }
+}
+
+/*
+ * Do a mode sense page 0 with block descriptor and if it succeeds set the tape
+ * block size with the reported value.
+ */
+static void ide_tape_get_bsize_from_bdesc(ide_drive_t *drive)
+{
+ idetape_tape_t *tape = drive->driver_data;
+ struct ide_atapi_pc pc;
+
+ idetape_create_mode_sense_cmd(&pc, IDETAPE_BLOCK_DESCRIPTOR);
+ if (ide_queue_pc_tail(drive, tape->disk, &pc)) {
+ printk(KERN_ERR "ide-tape: Can't get block descriptor\n");
+ if (tape->blk_size == 0) {
+ printk(KERN_WARNING "ide-tape: Cannot deal with zero "
+ "block size, assuming 32k\n");
+ tape->blk_size = 32768;
+ }
+ return;
+ }
+ tape->blk_size = (pc.buf[4 + 5] << 16) +
+ (pc.buf[4 + 6] << 8) +
+ pc.buf[4 + 7];
+ tape->drv_write_prot = (pc.buf[2] & 0x80) >> 7;
+}
+
+static int idetape_chrdev_open(struct inode *inode, struct file *filp)
+{
+ unsigned int minor = iminor(inode), i = minor & ~0xc0;
+ ide_drive_t *drive;
+ idetape_tape_t *tape;
+ int retval;
+
+ if (i >= MAX_HWIFS * MAX_DRIVES)
+ return -ENXIO;
+
+ lock_kernel();
+ tape = ide_tape_chrdev_get(i);
+ if (!tape) {
+ unlock_kernel();
+ return -ENXIO;
+ }
+
+ debug_log(DBG_CHRDEV, "Enter %s\n", __func__);
+
+ /*
+ * We really want to do nonseekable_open(inode, filp); here, but some
+ * versions of tar incorrectly call lseek on tapes and bail out if that
+ * fails. So we disallow pread() and pwrite(), but permit lseeks.
+ */
+ filp->f_mode &= ~(FMODE_PREAD | FMODE_PWRITE);
+
+ drive = tape->drive;
+
+ filp->private_data = tape;
+
+ if (test_and_set_bit(IDE_AFLAG_BUSY, &drive->atapi_flags)) {
+ retval = -EBUSY;
+ goto out_put_tape;
+ }
+
+ retval = idetape_wait_ready(drive, 60 * HZ);
+ if (retval) {
+ clear_bit(IDE_AFLAG_BUSY, &drive->atapi_flags);
+ printk(KERN_ERR "ide-tape: %s: drive not ready\n", tape->name);
+ goto out_put_tape;
+ }
+
+ idetape_read_position(drive);
+ if (!test_bit(IDE_AFLAG_ADDRESS_VALID, &drive->atapi_flags))
+ (void)idetape_rewind_tape(drive);
+
+ /* Read block size and write protect status from drive. */
+ ide_tape_get_bsize_from_bdesc(drive);
+
+ /* Set write protect flag if device is opened as read-only. */
+ if ((filp->f_flags & O_ACCMODE) == O_RDONLY)
+ tape->write_prot = 1;
+ else
+ tape->write_prot = tape->drv_write_prot;
+
+ /* Make sure drive isn't write protected if user wants to write. */
+ if (tape->write_prot) {
+ if ((filp->f_flags & O_ACCMODE) == O_WRONLY ||
+ (filp->f_flags & O_ACCMODE) == O_RDWR) {
+ clear_bit(IDE_AFLAG_BUSY, &drive->atapi_flags);
+ retval = -EROFS;
+ goto out_put_tape;
+ }
+ }
+
+ /* Lock the tape drive door so user can't eject. */
+ if (tape->chrdev_dir == IDETAPE_DIR_NONE) {
+ if (!ide_set_media_lock(drive, tape->disk, 1)) {
+ if (tape->door_locked != DOOR_EXPLICITLY_LOCKED)
+ tape->door_locked = DOOR_LOCKED;
+ }
+ }
+ unlock_kernel();
+ return 0;
+
+out_put_tape:
+ ide_tape_put(tape);
+ unlock_kernel();
+ return retval;
+}
+
+static void idetape_write_release(ide_drive_t *drive, unsigned int minor)
+{
+ idetape_tape_t *tape = drive->driver_data;
+
+ ide_tape_flush_merge_buffer(drive);
+ tape->merge_bh = ide_tape_kmalloc_buffer(tape, 1, 0);
+ if (tape->merge_bh != NULL) {
+ idetape_pad_zeros(drive, tape->blk_size *
+ (tape->user_bs_factor - 1));
+ ide_tape_kfree_buffer(tape);
+ tape->merge_bh = NULL;
+ }
+ idetape_write_filemark(drive);
+ idetape_flush_tape_buffers(drive);
+ idetape_flush_tape_buffers(drive);
+}
+
+static int idetape_chrdev_release(struct inode *inode, struct file *filp)
+{
+ struct ide_tape_obj *tape = filp->private_data;
+ ide_drive_t *drive = tape->drive;
+ unsigned int minor = iminor(inode);
+
+ lock_kernel();
+ tape = drive->driver_data;
+
+ debug_log(DBG_CHRDEV, "Enter %s\n", __func__);
+
+ if (tape->chrdev_dir == IDETAPE_DIR_WRITE)
+ idetape_write_release(drive, minor);
+ if (tape->chrdev_dir == IDETAPE_DIR_READ) {
+ if (minor < 128)
+ ide_tape_discard_merge_buffer(drive, 1);
+ }
+
+ if (minor < 128 && test_bit(IDE_AFLAG_MEDIUM_PRESENT, &drive->atapi_flags))
+ (void) idetape_rewind_tape(drive);
+ if (tape->chrdev_dir == IDETAPE_DIR_NONE) {
+ if (tape->door_locked == DOOR_LOCKED) {
+ if (!ide_set_media_lock(drive, tape->disk, 0))
+ tape->door_locked = DOOR_UNLOCKED;
+ }
+ }
+ clear_bit(IDE_AFLAG_BUSY, &drive->atapi_flags);
+ ide_tape_put(tape);
+ unlock_kernel();
+ return 0;
+}
+
+static void idetape_get_inquiry_results(ide_drive_t *drive)
+{
+ idetape_tape_t *tape = drive->driver_data;
+ struct ide_atapi_pc pc;
+ char fw_rev[4], vendor_id[8], product_id[16];
+
+ idetape_create_inquiry_cmd(&pc);
+ if (ide_queue_pc_tail(drive, tape->disk, &pc)) {
+ printk(KERN_ERR "ide-tape: %s: can't get INQUIRY results\n",
+ tape->name);
+ return;
+ }
+ memcpy(vendor_id, &pc.buf[8], 8);
+ memcpy(product_id, &pc.buf[16], 16);
+ memcpy(fw_rev, &pc.buf[32], 4);
+
+ ide_fixstring(vendor_id, 8, 0);
+ ide_fixstring(product_id, 16, 0);
+ ide_fixstring(fw_rev, 4, 0);
+
+ printk(KERN_INFO "ide-tape: %s <-> %s: %.8s %.16s rev %.4s\n",
+ drive->name, tape->name, vendor_id, product_id, fw_rev);
+}
+
+/*
+ * Ask the tape about its various parameters. In particular, we will adjust our
+ * data transfer buffer size to the recommended value as returned by the tape.
+ */
+static void idetape_get_mode_sense_results(ide_drive_t *drive)
+{
+ idetape_tape_t *tape = drive->driver_data;
+ struct ide_atapi_pc pc;
+ u8 *caps;
+ u8 speed, max_speed;
+
+ idetape_create_mode_sense_cmd(&pc, IDETAPE_CAPABILITIES_PAGE);
+ if (ide_queue_pc_tail(drive, tape->disk, &pc)) {
+ printk(KERN_ERR "ide-tape: Can't get tape parameters - assuming"
+ " some default values\n");
+ tape->blk_size = 512;
+ put_unaligned(52, (u16 *)&tape->caps[12]);
+ put_unaligned(540, (u16 *)&tape->caps[14]);
+ put_unaligned(6*52, (u16 *)&tape->caps[16]);
+ return;
+ }
+ caps = pc.buf + 4 + pc.buf[3];
+
+ /* convert to host order and save for later use */
+ speed = be16_to_cpup((__be16 *)&caps[14]);
+ max_speed = be16_to_cpup((__be16 *)&caps[8]);
+
+ *(u16 *)&caps[8] = max_speed;
+ *(u16 *)&caps[12] = be16_to_cpup((__be16 *)&caps[12]);
+ *(u16 *)&caps[14] = speed;
+ *(u16 *)&caps[16] = be16_to_cpup((__be16 *)&caps[16]);
+
+ if (!speed) {
+ printk(KERN_INFO "ide-tape: %s: invalid tape speed "
+ "(assuming 650KB/sec)\n", drive->name);
+ *(u16 *)&caps[14] = 650;
+ }
+ if (!max_speed) {
+ printk(KERN_INFO "ide-tape: %s: invalid max_speed "
+ "(assuming 650KB/sec)\n", drive->name);
+ *(u16 *)&caps[8] = 650;
+ }
+
+ memcpy(&tape->caps, caps, 20);
+
+ /* device lacks locking support according to capabilities page */
+ if ((caps[6] & 1) == 0)
+ drive->dev_flags &= ~IDE_DFLAG_DOORLOCKING;
+
+ if (caps[7] & 0x02)
+ tape->blk_size = 512;
+ else if (caps[7] & 0x04)
+ tape->blk_size = 1024;
+}
+
+#ifdef CONFIG_IDE_PROC_FS
+#define ide_tape_devset_get(name, field) \
+static int get_##name(ide_drive_t *drive) \
+{ \
+ idetape_tape_t *tape = drive->driver_data; \
+ return tape->field; \
+}
+
+#define ide_tape_devset_set(name, field) \
+static int set_##name(ide_drive_t *drive, int arg) \
+{ \
+ idetape_tape_t *tape = drive->driver_data; \
+ tape->field = arg; \
+ return 0; \
+}
+
+#define ide_tape_devset_rw_field(_name, _field) \
+ide_tape_devset_get(_name, _field) \
+ide_tape_devset_set(_name, _field) \
+IDE_DEVSET(_name, DS_SYNC, get_##_name, set_##_name)
+
+#define ide_tape_devset_r_field(_name, _field) \
+ide_tape_devset_get(_name, _field) \
+IDE_DEVSET(_name, 0, get_##_name, NULL)
+
+static int mulf_tdsc(ide_drive_t *drive) { return 1000; }
+static int divf_tdsc(ide_drive_t *drive) { return HZ; }
+static int divf_buffer(ide_drive_t *drive) { return 2; }
+static int divf_buffer_size(ide_drive_t *drive) { return 1024; }
+
+ide_devset_rw_flag(dsc_overlap, IDE_DFLAG_DSC_OVERLAP);
+
+ide_tape_devset_rw_field(debug_mask, debug_mask);
+ide_tape_devset_rw_field(tdsc, best_dsc_rw_freq);
+
+ide_tape_devset_r_field(avg_speed, avg_speed);
+ide_tape_devset_r_field(speed, caps[14]);
+ide_tape_devset_r_field(buffer, caps[16]);
+ide_tape_devset_r_field(buffer_size, buffer_size);
+
+static const struct ide_proc_devset idetape_settings[] = {
+ __IDE_PROC_DEVSET(avg_speed, 0, 0xffff, NULL, NULL),
+ __IDE_PROC_DEVSET(buffer, 0, 0xffff, NULL, divf_buffer),
+ __IDE_PROC_DEVSET(buffer_size, 0, 0xffff, NULL, divf_buffer_size),
+ __IDE_PROC_DEVSET(debug_mask, 0, 0xffff, NULL, NULL),
+ __IDE_PROC_DEVSET(dsc_overlap, 0, 1, NULL, NULL),
+ __IDE_PROC_DEVSET(speed, 0, 0xffff, NULL, NULL),
+ __IDE_PROC_DEVSET(tdsc, IDETAPE_DSC_RW_MIN, IDETAPE_DSC_RW_MAX,
+ mulf_tdsc, divf_tdsc),
+ { 0 },
+};
+#endif
+
+/*
+ * The function below is called to:
+ *
+ * 1. Initialize our various state variables.
+ * 2. Ask the tape for its capabilities.
+ * 3. Allocate a buffer which will be used for data transfer. The buffer size
+ * is chosen based on the recommendation which we received in step 2.
+ *
+ * Note that at this point ide.c already assigned us an irq, so that we can
+ * queue requests here and wait for their completion.
+ */
+static void idetape_setup(ide_drive_t *drive, idetape_tape_t *tape, int minor)
+{
+ unsigned long t;
+ int speed;
+ int buffer_size;
+ u16 *ctl = (u16 *)&tape->caps[12];
+
+ drive->pc_callback = ide_tape_callback;
+ drive->pc_update_buffers = idetape_update_buffers;
+ drive->pc_io_buffers = ide_tape_io_buffers;
+
+ spin_lock_init(&tape->lock);
+
+ drive->dev_flags |= IDE_DFLAG_DSC_OVERLAP;
+
+ if (drive->hwif->host_flags & IDE_HFLAG_NO_DSC) {
+ printk(KERN_INFO "ide-tape: %s: disabling DSC overlap\n",
+ tape->name);
+ drive->dev_flags &= ~IDE_DFLAG_DSC_OVERLAP;
+ }
+
+ /* Seagate Travan drives do not support DSC overlap. */
+ if (strstr((char *)&drive->id[ATA_ID_PROD], "Seagate STT3401"))
+ drive->dev_flags &= ~IDE_DFLAG_DSC_OVERLAP;
+
+ tape->minor = minor;
+ tape->name[0] = 'h';
+ tape->name[1] = 't';
+ tape->name[2] = '0' + minor;
+ tape->chrdev_dir = IDETAPE_DIR_NONE;
+
+ idetape_get_inquiry_results(drive);
+ idetape_get_mode_sense_results(drive);
+ ide_tape_get_bsize_from_bdesc(drive);
+ tape->user_bs_factor = 1;
+ tape->buffer_size = *ctl * tape->blk_size;
+ while (tape->buffer_size > 0xffff) {
+ printk(KERN_NOTICE "ide-tape: decreasing stage size\n");
+ *ctl /= 2;
+ tape->buffer_size = *ctl * tape->blk_size;
+ }
+ buffer_size = tape->buffer_size;
+ tape->pages_per_buffer = buffer_size / PAGE_SIZE;
+ if (buffer_size % PAGE_SIZE) {
+ tape->pages_per_buffer++;
+ tape->excess_bh_size = PAGE_SIZE - buffer_size % PAGE_SIZE;
+ }
+
+ /* select the "best" DSC read/write polling freq */
+ speed = max(*(u16 *)&tape->caps[14], *(u16 *)&tape->caps[8]);
+
+ t = (IDETAPE_FIFO_THRESHOLD * tape->buffer_size * HZ) / (speed * 1000);
+
+ /*
+ * Ensure that the number we got makes sense; limit it within
+ * IDETAPE_DSC_RW_MIN and IDETAPE_DSC_RW_MAX.
+ */
+ tape->best_dsc_rw_freq = clamp_t(unsigned long, t, IDETAPE_DSC_RW_MIN,
+ IDETAPE_DSC_RW_MAX);
+ printk(KERN_INFO "ide-tape: %s <-> %s: %dKBps, %d*%dkB buffer, "
+ "%lums tDSC%s\n",
+ drive->name, tape->name, *(u16 *)&tape->caps[14],
+ (*(u16 *)&tape->caps[16] * 512) / tape->buffer_size,
+ tape->buffer_size / 1024,
+ tape->best_dsc_rw_freq * 1000 / HZ,
+ (drive->dev_flags & IDE_DFLAG_USING_DMA) ? ", DMA" : "");
+
+ ide_proc_register_driver(drive, tape->driver);
+}
+
+static void ide_tape_remove(ide_drive_t *drive)
+{
+ idetape_tape_t *tape = drive->driver_data;
+
+ ide_proc_unregister_driver(drive, tape->driver);
+
+ ide_unregister_region(tape->disk);
+
+ ide_tape_put(tape);
+}
+
+static void ide_tape_release(struct kref *kref)
+{
+ struct ide_tape_obj *tape = to_ide_drv(kref, ide_tape_obj);
+ ide_drive_t *drive = tape->drive;
+ struct gendisk *g = tape->disk;
+
+ BUG_ON(tape->merge_bh_size);
+
+ drive->dev_flags &= ~IDE_DFLAG_DSC_OVERLAP;
+ drive->driver_data = NULL;
+ device_destroy(idetape_sysfs_class, MKDEV(IDETAPE_MAJOR, tape->minor));
+ device_destroy(idetape_sysfs_class,
+ MKDEV(IDETAPE_MAJOR, tape->minor + 128));
+ idetape_devs[tape->minor] = NULL;
+ g->private_data = NULL;
+ put_disk(g);
+ kfree(tape);
+}
+
+#ifdef CONFIG_IDE_PROC_FS
+static int proc_idetape_read_name
+ (char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ ide_drive_t *drive = (ide_drive_t *) data;
+ idetape_tape_t *tape = drive->driver_data;
+ char *out = page;
+ int len;
+
+ len = sprintf(out, "%s\n", tape->name);
+ PROC_IDE_READ_RETURN(page, start, off, count, eof, len);
+}
+
+static ide_proc_entry_t idetape_proc[] = {
+ { "capacity", S_IFREG|S_IRUGO, proc_ide_read_capacity, NULL },
+ { "name", S_IFREG|S_IRUGO, proc_idetape_read_name, NULL },
+ { NULL, 0, NULL, NULL }
+};
+
+static ide_proc_entry_t *ide_tape_proc_entries(ide_drive_t *drive)
+{
+ return idetape_proc;
+}
+
+static const struct ide_proc_devset *ide_tape_proc_devsets(ide_drive_t *drive)
+{
+ return idetape_settings;
+}
+#endif
+
+static int ide_tape_probe(ide_drive_t *);
+
+static ide_driver_t idetape_driver = {
+ .gen_driver = {
+ .owner = THIS_MODULE,
+ .name = "ide-tape",
+ .bus = &ide_bus_type,
+ },
+ .probe = ide_tape_probe,
+ .remove = ide_tape_remove,
+ .version = IDETAPE_VERSION,
+ .do_request = idetape_do_request,
+ .end_request = idetape_end_request,
+ .error = __ide_error,
+#ifdef CONFIG_IDE_PROC_FS
+ .proc_entries = ide_tape_proc_entries,
+ .proc_devsets = ide_tape_proc_devsets,
+#endif
+};
+
+/* Our character device supporting functions, passed to register_chrdev. */
+static const struct file_operations idetape_fops = {
+ .owner = THIS_MODULE,
+ .read = idetape_chrdev_read,
+ .write = idetape_chrdev_write,
+ .ioctl = idetape_chrdev_ioctl,
+ .open = idetape_chrdev_open,
+ .release = idetape_chrdev_release,
+};
+
+static int idetape_open(struct block_device *bdev, fmode_t mode)
+{
+ struct ide_tape_obj *tape = ide_tape_get(bdev->bd_disk);
+
+ if (!tape)
+ return -ENXIO;
+
+ return 0;
+}
+
+static int idetape_release(struct gendisk *disk, fmode_t mode)
+{
+ struct ide_tape_obj *tape = ide_drv_g(disk, ide_tape_obj);
+
+ ide_tape_put(tape);
+ return 0;
+}
+
+static int idetape_ioctl(struct block_device *bdev, fmode_t mode,
+ unsigned int cmd, unsigned long arg)
+{
+ struct ide_tape_obj *tape = ide_drv_g(bdev->bd_disk, ide_tape_obj);
+ ide_drive_t *drive = tape->drive;
+ int err = generic_ide_ioctl(drive, bdev, cmd, arg);
+ if (err == -EINVAL)
+ err = idetape_blkdev_ioctl(drive, cmd, arg);
+ return err;
+}
+
+static struct block_device_operations idetape_block_ops = {
+ .owner = THIS_MODULE,
+ .open = idetape_open,
+ .release = idetape_release,
+ .locked_ioctl = idetape_ioctl,
+};
+
+static int ide_tape_probe(ide_drive_t *drive)
+{
+ idetape_tape_t *tape;
+ struct gendisk *g;
+ int minor;
+
+ if (!strstr("ide-tape", drive->driver_req))
+ goto failed;
+
+ if (drive->media != ide_tape)
+ goto failed;
+
+ if ((drive->dev_flags & IDE_DFLAG_ID_READ) &&
+ ide_check_atapi_device(drive, DRV_NAME) == 0) {
+ printk(KERN_ERR "ide-tape: %s: not supported by this version of"
+ " the driver\n", drive->name);
+ goto failed;
+ }
+ tape = kzalloc(sizeof(idetape_tape_t), GFP_KERNEL);
+ if (tape == NULL) {
+ printk(KERN_ERR "ide-tape: %s: Can't allocate a tape struct\n",
+ drive->name);
+ goto failed;
+ }
+
+ g = alloc_disk(1 << PARTN_BITS);
+ if (!g)
+ goto out_free_tape;
+
+ ide_init_disk(g, drive);
+
+ kref_init(&tape->kref);
+
+ tape->drive = drive;
+ tape->driver = &idetape_driver;
+ tape->disk = g;
+
+ g->private_data = &tape->driver;
+
+ drive->driver_data = tape;
+
+ mutex_lock(&idetape_ref_mutex);
+ for (minor = 0; idetape_devs[minor]; minor++)
+ ;
+ idetape_devs[minor] = tape;
+ mutex_unlock(&idetape_ref_mutex);
+
+ idetape_setup(drive, tape, minor);
+
+ device_create(idetape_sysfs_class, &drive->gendev,
+ MKDEV(IDETAPE_MAJOR, minor), NULL, "%s", tape->name);
+ device_create(idetape_sysfs_class, &drive->gendev,
+ MKDEV(IDETAPE_MAJOR, minor + 128), NULL,
+ "n%s", tape->name);
+
+ g->fops = &idetape_block_ops;
+ ide_register_region(g);
+
+ return 0;
+
+out_free_tape:
+ kfree(tape);
+failed:
+ return -ENODEV;
+}
+
+static void __exit idetape_exit(void)
+{
+ driver_unregister(&idetape_driver.gen_driver);
+ class_destroy(idetape_sysfs_class);
+ unregister_chrdev(IDETAPE_MAJOR, "ht");
+}
+
+static int __init idetape_init(void)
+{
+ int error = 1;
+ idetape_sysfs_class = class_create(THIS_MODULE, "ide_tape");
+ if (IS_ERR(idetape_sysfs_class)) {
+ idetape_sysfs_class = NULL;
+ printk(KERN_ERR "Unable to create sysfs class for ide tapes\n");
+ error = -EBUSY;
+ goto out;
+ }
+
+ if (register_chrdev(IDETAPE_MAJOR, "ht", &idetape_fops)) {
+ printk(KERN_ERR "ide-tape: Failed to register chrdev"
+ " interface\n");
+ error = -EBUSY;
+ goto out_free_class;
+ }
+
+ error = driver_register(&idetape_driver.gen_driver);
+ if (error)
+ goto out_free_driver;
+
+ return 0;
+
+out_free_driver:
+ driver_unregister(&idetape_driver.gen_driver);
+out_free_class:
+ class_destroy(idetape_sysfs_class);
+out:
+ return error;
+}
+
+MODULE_ALIAS("ide:*m-tape*");
+module_init(idetape_init);
+module_exit(idetape_exit);
+MODULE_ALIAS_CHARDEV_MAJOR(IDETAPE_MAJOR);
+MODULE_DESCRIPTION("ATAPI Streaming TAPE Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c
new file mode 100644
index 0000000..bf4fb9d
--- /dev/null
+++ b/drivers/ide/ide-taskfile.c
@@ -0,0 +1,682 @@
+/*
+ * Copyright (C) 2000-2002 Michael Cornwell <cornwell@acm.org>
+ * Copyright (C) 2000-2002 Andre Hedrick <andre@linux-ide.org>
+ * Copyright (C) 2001-2002 Klaus Smolin
+ * IBM Storage Technology Division
+ * Copyright (C) 2003-2004, 2007 Bartlomiej Zolnierkiewicz
+ *
+ * The big the bad and the ugly.
+ */
+
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/scatterlist.h>
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+void ide_tf_dump(const char *s, struct ide_taskfile *tf)
+{
+#ifdef DEBUG
+ printk("%s: tf: feat 0x%02x nsect 0x%02x lbal 0x%02x "
+ "lbam 0x%02x lbah 0x%02x dev 0x%02x cmd 0x%02x\n",
+ s, tf->feature, tf->nsect, tf->lbal,
+ tf->lbam, tf->lbah, tf->device, tf->command);
+ printk("%s: hob: nsect 0x%02x lbal 0x%02x "
+ "lbam 0x%02x lbah 0x%02x\n",
+ s, tf->hob_nsect, tf->hob_lbal,
+ tf->hob_lbam, tf->hob_lbah);
+#endif
+}
+
+int taskfile_lib_get_identify (ide_drive_t *drive, u8 *buf)
+{
+ ide_task_t args;
+
+ memset(&args, 0, sizeof(ide_task_t));
+ args.tf.nsect = 0x01;
+ if (drive->media == ide_disk)
+ args.tf.command = ATA_CMD_ID_ATA;
+ else
+ args.tf.command = ATA_CMD_ID_ATAPI;
+ args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
+ args.data_phase = TASKFILE_IN;
+ return ide_raw_taskfile(drive, &args, buf, 1);
+}
+
+static ide_startstop_t task_no_data_intr(ide_drive_t *);
+static ide_startstop_t pre_task_out_intr(ide_drive_t *, struct request *);
+static ide_startstop_t task_in_intr(ide_drive_t *);
+
+ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct ide_taskfile *tf = &task->tf;
+ ide_handler_t *handler = NULL;
+ const struct ide_tp_ops *tp_ops = hwif->tp_ops;
+ const struct ide_dma_ops *dma_ops = hwif->dma_ops;
+
+ if (task->data_phase == TASKFILE_MULTI_IN ||
+ task->data_phase == TASKFILE_MULTI_OUT) {
+ if (!drive->mult_count) {
+ printk(KERN_ERR "%s: multimode not set!\n",
+ drive->name);
+ return ide_stopped;
+ }
+ }
+
+ if (task->tf_flags & IDE_TFLAG_FLAGGED)
+ task->tf_flags |= IDE_TFLAG_FLAGGED_SET_IN_FLAGS;
+
+ memcpy(&hwif->task, task, sizeof(*task));
+
+ if ((task->tf_flags & IDE_TFLAG_DMA_PIO_FALLBACK) == 0) {
+ ide_tf_dump(drive->name, tf);
+ tp_ops->set_irq(hwif, 1);
+ SELECT_MASK(drive, 0);
+ tp_ops->tf_load(drive, task);
+ }
+
+ switch (task->data_phase) {
+ case TASKFILE_MULTI_OUT:
+ case TASKFILE_OUT:
+ tp_ops->exec_command(hwif, tf->command);
+ ndelay(400); /* FIXME */
+ return pre_task_out_intr(drive, task->rq);
+ case TASKFILE_MULTI_IN:
+ case TASKFILE_IN:
+ handler = task_in_intr;
+ /* fall-through */
+ case TASKFILE_NO_DATA:
+ if (handler == NULL)
+ handler = task_no_data_intr;
+ ide_execute_command(drive, tf->command, handler,
+ WAIT_WORSTCASE, NULL);
+ return ide_started;
+ default:
+ if ((drive->dev_flags & IDE_DFLAG_USING_DMA) == 0 ||
+ dma_ops->dma_setup(drive))
+ return ide_stopped;
+ dma_ops->dma_exec_cmd(drive, tf->command);
+ dma_ops->dma_start(drive);
+ return ide_started;
+ }
+}
+EXPORT_SYMBOL_GPL(do_rw_taskfile);
+
+/*
+ * Handler for commands without a data phase
+ */
+static ide_startstop_t task_no_data_intr(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ ide_task_t *task = &hwif->task;
+ struct ide_taskfile *tf = &task->tf;
+ int custom = (task->tf_flags & IDE_TFLAG_CUSTOM_HANDLER) ? 1 : 0;
+ int retries = (custom && tf->command == ATA_CMD_INIT_DEV_PARAMS) ? 5 : 1;
+ u8 stat;
+
+ local_irq_enable_in_hardirq();
+
+ while (1) {
+ stat = hwif->tp_ops->read_status(hwif);
+ if ((stat & ATA_BUSY) == 0 || retries-- == 0)
+ break;
+ udelay(10);
+ };
+
+ if (!OK_STAT(stat, ATA_DRDY, BAD_STAT)) {
+ if (custom && tf->command == ATA_CMD_SET_MULTI) {
+ drive->mult_req = drive->mult_count = 0;
+ drive->special.b.recalibrate = 1;
+ (void)ide_dump_status(drive, __func__, stat);
+ return ide_stopped;
+ } else if (custom && tf->command == ATA_CMD_INIT_DEV_PARAMS) {
+ if ((stat & (ATA_ERR | ATA_DRQ)) == 0) {
+ ide_set_handler(drive, &task_no_data_intr,
+ WAIT_WORSTCASE, NULL);
+ return ide_started;
+ }
+ }
+ return ide_error(drive, "task_no_data_intr", stat);
+ /* calls ide_end_drive_cmd */
+ }
+
+ if (!custom)
+ ide_end_drive_cmd(drive, stat, ide_read_error(drive));
+ else if (tf->command == ATA_CMD_IDLEIMMEDIATE) {
+ hwif->tp_ops->tf_read(drive, task);
+ if (tf->lbal != 0xc4) {
+ printk(KERN_ERR "%s: head unload failed!\n",
+ drive->name);
+ ide_tf_dump(drive->name, tf);
+ } else
+ drive->dev_flags |= IDE_DFLAG_PARKED;
+ ide_end_drive_cmd(drive, stat, ide_read_error(drive));
+ } else if (tf->command == ATA_CMD_SET_MULTI)
+ drive->mult_count = drive->mult_req;
+
+ return ide_stopped;
+}
+
+static u8 wait_drive_not_busy(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ int retries;
+ u8 stat;
+
+ /*
+ * Last sector was transfered, wait until device is ready. This can
+ * take up to 6 ms on some ATAPI devices, so we will wait max 10 ms.
+ */
+ for (retries = 0; retries < 1000; retries++) {
+ stat = hwif->tp_ops->read_status(hwif);
+
+ if (stat & ATA_BUSY)
+ udelay(10);
+ else
+ break;
+ }
+
+ if (stat & ATA_BUSY)
+ printk(KERN_ERR "%s: drive still BUSY!\n", drive->name);
+
+ return stat;
+}
+
+static void ide_pio_sector(ide_drive_t *drive, struct request *rq,
+ unsigned int write)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ struct scatterlist *sg = hwif->sg_table;
+ struct scatterlist *cursg = hwif->cursg;
+ struct page *page;
+#ifdef CONFIG_HIGHMEM
+ unsigned long flags;
+#endif
+ unsigned int offset;
+ u8 *buf;
+
+ cursg = hwif->cursg;
+ if (!cursg) {
+ cursg = sg;
+ hwif->cursg = sg;
+ }
+
+ page = sg_page(cursg);
+ offset = cursg->offset + hwif->cursg_ofs * SECTOR_SIZE;
+
+ /* get the current page and offset */
+ page = nth_page(page, (offset >> PAGE_SHIFT));
+ offset %= PAGE_SIZE;
+
+#ifdef CONFIG_HIGHMEM
+ local_irq_save(flags);
+#endif
+ buf = kmap_atomic(page, KM_BIO_SRC_IRQ) + offset;
+
+ hwif->nleft--;
+ hwif->cursg_ofs++;
+
+ if ((hwif->cursg_ofs * SECTOR_SIZE) == cursg->length) {
+ hwif->cursg = sg_next(hwif->cursg);
+ hwif->cursg_ofs = 0;
+ }
+
+ /* do the actual data transfer */
+ if (write)
+ hwif->tp_ops->output_data(drive, rq, buf, SECTOR_SIZE);
+ else
+ hwif->tp_ops->input_data(drive, rq, buf, SECTOR_SIZE);
+
+ kunmap_atomic(buf, KM_BIO_SRC_IRQ);
+#ifdef CONFIG_HIGHMEM
+ local_irq_restore(flags);
+#endif
+}
+
+static void ide_pio_multi(ide_drive_t *drive, struct request *rq,
+ unsigned int write)
+{
+ unsigned int nsect;
+
+ nsect = min_t(unsigned int, drive->hwif->nleft, drive->mult_count);
+ while (nsect--)
+ ide_pio_sector(drive, rq, write);
+}
+
+static void ide_pio_datablock(ide_drive_t *drive, struct request *rq,
+ unsigned int write)
+{
+ u8 saved_io_32bit = drive->io_32bit;
+
+ if (rq->bio) /* fs request */
+ rq->errors = 0;
+
+ if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) {
+ ide_task_t *task = rq->special;
+
+ if (task->tf_flags & IDE_TFLAG_IO_16BIT)
+ drive->io_32bit = 0;
+ }
+
+ touch_softlockup_watchdog();
+
+ switch (drive->hwif->data_phase) {
+ case TASKFILE_MULTI_IN:
+ case TASKFILE_MULTI_OUT:
+ ide_pio_multi(drive, rq, write);
+ break;
+ default:
+ ide_pio_sector(drive, rq, write);
+ break;
+ }
+
+ drive->io_32bit = saved_io_32bit;
+}
+
+static ide_startstop_t task_error(ide_drive_t *drive, struct request *rq,
+ const char *s, u8 stat)
+{
+ if (rq->bio) {
+ ide_hwif_t *hwif = drive->hwif;
+ int sectors = hwif->nsect - hwif->nleft;
+
+ switch (hwif->data_phase) {
+ case TASKFILE_IN:
+ if (hwif->nleft)
+ break;
+ /* fall through */
+ case TASKFILE_OUT:
+ sectors--;
+ break;
+ case TASKFILE_MULTI_IN:
+ if (hwif->nleft)
+ break;
+ /* fall through */
+ case TASKFILE_MULTI_OUT:
+ sectors -= drive->mult_count;
+ default:
+ break;
+ }
+
+ if (sectors > 0) {
+ ide_driver_t *drv;
+
+ drv = *(ide_driver_t **)rq->rq_disk->private_data;
+ drv->end_request(drive, 1, sectors);
+ }
+ }
+ return ide_error(drive, s, stat);
+}
+
+void task_end_request(ide_drive_t *drive, struct request *rq, u8 stat)
+{
+ if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) {
+ u8 err = ide_read_error(drive);
+
+ ide_end_drive_cmd(drive, stat, err);
+ return;
+ }
+
+ if (rq->rq_disk) {
+ ide_driver_t *drv;
+
+ drv = *(ide_driver_t **)rq->rq_disk->private_data;;
+ drv->end_request(drive, 1, rq->nr_sectors);
+ } else
+ ide_end_request(drive, 1, rq->nr_sectors);
+}
+
+/*
+ * We got an interrupt on a task_in case, but no errors and no DRQ.
+ *
+ * It might be a spurious irq (shared irq), but it might be a
+ * command that had no output.
+ */
+static ide_startstop_t task_in_unexpected(ide_drive_t *drive, struct request *rq, u8 stat)
+{
+ /* Command all done? */
+ if (OK_STAT(stat, ATA_DRDY, ATA_BUSY)) {
+ task_end_request(drive, rq, stat);
+ return ide_stopped;
+ }
+
+ /* Assume it was a spurious irq */
+ ide_set_handler(drive, &task_in_intr, WAIT_WORSTCASE, NULL);
+ return ide_started;
+}
+
+/*
+ * Handler for command with PIO data-in phase (Read/Read Multiple).
+ */
+static ide_startstop_t task_in_intr(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ struct request *rq = hwif->hwgroup->rq;
+ u8 stat = hwif->tp_ops->read_status(hwif);
+
+ /* Error? */
+ if (stat & ATA_ERR)
+ return task_error(drive, rq, __func__, stat);
+
+ /* Didn't want any data? Odd. */
+ if ((stat & ATA_DRQ) == 0)
+ return task_in_unexpected(drive, rq, stat);
+
+ ide_pio_datablock(drive, rq, 0);
+
+ /* Are we done? Check status and finish transfer. */
+ if (!hwif->nleft) {
+ stat = wait_drive_not_busy(drive);
+ if (!OK_STAT(stat, 0, BAD_STAT))
+ return task_error(drive, rq, __func__, stat);
+ task_end_request(drive, rq, stat);
+ return ide_stopped;
+ }
+
+ /* Still data left to transfer. */
+ ide_set_handler(drive, &task_in_intr, WAIT_WORSTCASE, NULL);
+
+ return ide_started;
+}
+
+/*
+ * Handler for command with PIO data-out phase (Write/Write Multiple).
+ */
+static ide_startstop_t task_out_intr (ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ struct request *rq = HWGROUP(drive)->rq;
+ u8 stat = hwif->tp_ops->read_status(hwif);
+
+ if (!OK_STAT(stat, DRIVE_READY, drive->bad_wstat))
+ return task_error(drive, rq, __func__, stat);
+
+ /* Deal with unexpected ATA data phase. */
+ if (((stat & ATA_DRQ) == 0) ^ !hwif->nleft)
+ return task_error(drive, rq, __func__, stat);
+
+ if (!hwif->nleft) {
+ task_end_request(drive, rq, stat);
+ return ide_stopped;
+ }
+
+ /* Still data left to transfer. */
+ ide_pio_datablock(drive, rq, 1);
+ ide_set_handler(drive, &task_out_intr, WAIT_WORSTCASE, NULL);
+
+ return ide_started;
+}
+
+static ide_startstop_t pre_task_out_intr(ide_drive_t *drive, struct request *rq)
+{
+ ide_startstop_t startstop;
+
+ if (ide_wait_stat(&startstop, drive, ATA_DRQ,
+ drive->bad_wstat, WAIT_DRQ)) {
+ printk(KERN_ERR "%s: no DRQ after issuing %sWRITE%s\n",
+ drive->name, drive->hwif->data_phase ? "MULT" : "",
+ (drive->dev_flags & IDE_DFLAG_LBA48) ? "_EXT" : "");
+ return startstop;
+ }
+
+ if ((drive->dev_flags & IDE_DFLAG_UNMASK) == 0)
+ local_irq_disable();
+
+ ide_set_handler(drive, &task_out_intr, WAIT_WORSTCASE, NULL);
+ ide_pio_datablock(drive, rq, 1);
+
+ return ide_started;
+}
+
+int ide_raw_taskfile(ide_drive_t *drive, ide_task_t *task, u8 *buf, u16 nsect)
+{
+ struct request *rq;
+ int error;
+
+ rq = blk_get_request(drive->queue, READ, __GFP_WAIT);
+ rq->cmd_type = REQ_TYPE_ATA_TASKFILE;
+ rq->buffer = buf;
+
+ /*
+ * (ks) We transfer currently only whole sectors.
+ * This is suffient for now. But, it would be great,
+ * if we would find a solution to transfer any size.
+ * To support special commands like READ LONG.
+ */
+ rq->hard_nr_sectors = rq->nr_sectors = nsect;
+ rq->hard_cur_sectors = rq->current_nr_sectors = nsect;
+
+ if (task->tf_flags & IDE_TFLAG_WRITE)
+ rq->cmd_flags |= REQ_RW;
+
+ rq->special = task;
+ task->rq = rq;
+
+ error = blk_execute_rq(drive->queue, NULL, rq, 0);
+ blk_put_request(rq);
+
+ return error;
+}
+
+EXPORT_SYMBOL(ide_raw_taskfile);
+
+int ide_no_data_taskfile(ide_drive_t *drive, ide_task_t *task)
+{
+ task->data_phase = TASKFILE_NO_DATA;
+
+ return ide_raw_taskfile(drive, task, NULL, 0);
+}
+EXPORT_SYMBOL_GPL(ide_no_data_taskfile);
+
+#ifdef CONFIG_IDE_TASK_IOCTL
+int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
+{
+ ide_task_request_t *req_task;
+ ide_task_t args;
+ u8 *outbuf = NULL;
+ u8 *inbuf = NULL;
+ u8 *data_buf = NULL;
+ int err = 0;
+ int tasksize = sizeof(struct ide_task_request_s);
+ unsigned int taskin = 0;
+ unsigned int taskout = 0;
+ u16 nsect = 0;
+ char __user *buf = (char __user *)arg;
+
+// printk("IDE Taskfile ...\n");
+
+ req_task = kzalloc(tasksize, GFP_KERNEL);
+ if (req_task == NULL) return -ENOMEM;
+ if (copy_from_user(req_task, buf, tasksize)) {
+ kfree(req_task);
+ return -EFAULT;
+ }
+
+ taskout = req_task->out_size;
+ taskin = req_task->in_size;
+
+ if (taskin > 65536 || taskout > 65536) {
+ err = -EINVAL;
+ goto abort;
+ }
+
+ if (taskout) {
+ int outtotal = tasksize;
+ outbuf = kzalloc(taskout, GFP_KERNEL);
+ if (outbuf == NULL) {
+ err = -ENOMEM;
+ goto abort;
+ }
+ if (copy_from_user(outbuf, buf + outtotal, taskout)) {
+ err = -EFAULT;
+ goto abort;
+ }
+ }
+
+ if (taskin) {
+ int intotal = tasksize + taskout;
+ inbuf = kzalloc(taskin, GFP_KERNEL);
+ if (inbuf == NULL) {
+ err = -ENOMEM;
+ goto abort;
+ }
+ if (copy_from_user(inbuf, buf + intotal, taskin)) {
+ err = -EFAULT;
+ goto abort;
+ }
+ }
+
+ memset(&args, 0, sizeof(ide_task_t));
+
+ memcpy(&args.tf_array[0], req_task->hob_ports, HDIO_DRIVE_HOB_HDR_SIZE - 2);
+ memcpy(&args.tf_array[6], req_task->io_ports, HDIO_DRIVE_TASK_HDR_SIZE);
+
+ args.data_phase = req_task->data_phase;
+
+ args.tf_flags = IDE_TFLAG_IO_16BIT | IDE_TFLAG_DEVICE |
+ IDE_TFLAG_IN_TF;
+ if (drive->dev_flags & IDE_DFLAG_LBA48)
+ args.tf_flags |= (IDE_TFLAG_LBA48 | IDE_TFLAG_IN_HOB);
+
+ if (req_task->out_flags.all) {
+ args.tf_flags |= IDE_TFLAG_FLAGGED;
+
+ if (req_task->out_flags.b.data)
+ args.tf_flags |= IDE_TFLAG_OUT_DATA;
+
+ if (req_task->out_flags.b.nsector_hob)
+ args.tf_flags |= IDE_TFLAG_OUT_HOB_NSECT;
+ if (req_task->out_flags.b.sector_hob)
+ args.tf_flags |= IDE_TFLAG_OUT_HOB_LBAL;
+ if (req_task->out_flags.b.lcyl_hob)
+ args.tf_flags |= IDE_TFLAG_OUT_HOB_LBAM;
+ if (req_task->out_flags.b.hcyl_hob)
+ args.tf_flags |= IDE_TFLAG_OUT_HOB_LBAH;
+
+ if (req_task->out_flags.b.error_feature)
+ args.tf_flags |= IDE_TFLAG_OUT_FEATURE;
+ if (req_task->out_flags.b.nsector)
+ args.tf_flags |= IDE_TFLAG_OUT_NSECT;
+ if (req_task->out_flags.b.sector)
+ args.tf_flags |= IDE_TFLAG_OUT_LBAL;
+ if (req_task->out_flags.b.lcyl)
+ args.tf_flags |= IDE_TFLAG_OUT_LBAM;
+ if (req_task->out_flags.b.hcyl)
+ args.tf_flags |= IDE_TFLAG_OUT_LBAH;
+ } else {
+ args.tf_flags |= IDE_TFLAG_OUT_TF;
+ if (args.tf_flags & IDE_TFLAG_LBA48)
+ args.tf_flags |= IDE_TFLAG_OUT_HOB;
+ }
+
+ if (req_task->in_flags.b.data)
+ args.tf_flags |= IDE_TFLAG_IN_DATA;
+
+ switch(req_task->data_phase) {
+ case TASKFILE_MULTI_OUT:
+ if (!drive->mult_count) {
+ /* (hs): give up if multcount is not set */
+ printk(KERN_ERR "%s: %s Multimode Write " \
+ "multcount is not set\n",
+ drive->name, __func__);
+ err = -EPERM;
+ goto abort;
+ }
+ /* fall through */
+ case TASKFILE_OUT:
+ /* fall through */
+ case TASKFILE_OUT_DMAQ:
+ case TASKFILE_OUT_DMA:
+ nsect = taskout / SECTOR_SIZE;
+ data_buf = outbuf;
+ break;
+ case TASKFILE_MULTI_IN:
+ if (!drive->mult_count) {
+ /* (hs): give up if multcount is not set */
+ printk(KERN_ERR "%s: %s Multimode Read failure " \
+ "multcount is not set\n",
+ drive->name, __func__);
+ err = -EPERM;
+ goto abort;
+ }
+ /* fall through */
+ case TASKFILE_IN:
+ /* fall through */
+ case TASKFILE_IN_DMAQ:
+ case TASKFILE_IN_DMA:
+ nsect = taskin / SECTOR_SIZE;
+ data_buf = inbuf;
+ break;
+ case TASKFILE_NO_DATA:
+ break;
+ default:
+ err = -EFAULT;
+ goto abort;
+ }
+
+ if (req_task->req_cmd == IDE_DRIVE_TASK_NO_DATA)
+ nsect = 0;
+ else if (!nsect) {
+ nsect = (args.tf.hob_nsect << 8) | args.tf.nsect;
+
+ if (!nsect) {
+ printk(KERN_ERR "%s: in/out command without data\n",
+ drive->name);
+ err = -EFAULT;
+ goto abort;
+ }
+ }
+
+ if (req_task->req_cmd == IDE_DRIVE_TASK_RAW_WRITE)
+ args.tf_flags |= IDE_TFLAG_WRITE;
+
+ err = ide_raw_taskfile(drive, &args, data_buf, nsect);
+
+ memcpy(req_task->hob_ports, &args.tf_array[0], HDIO_DRIVE_HOB_HDR_SIZE - 2);
+ memcpy(req_task->io_ports, &args.tf_array[6], HDIO_DRIVE_TASK_HDR_SIZE);
+
+ if ((args.tf_flags & IDE_TFLAG_FLAGGED_SET_IN_FLAGS) &&
+ req_task->in_flags.all == 0) {
+ req_task->in_flags.all = IDE_TASKFILE_STD_IN_FLAGS;
+ if (drive->dev_flags & IDE_DFLAG_LBA48)
+ req_task->in_flags.all |= (IDE_HOB_STD_IN_FLAGS << 8);
+ }
+
+ if (copy_to_user(buf, req_task, tasksize)) {
+ err = -EFAULT;
+ goto abort;
+ }
+ if (taskout) {
+ int outtotal = tasksize;
+ if (copy_to_user(buf + outtotal, outbuf, taskout)) {
+ err = -EFAULT;
+ goto abort;
+ }
+ }
+ if (taskin) {
+ int intotal = tasksize + taskout;
+ if (copy_to_user(buf + intotal, inbuf, taskin)) {
+ err = -EFAULT;
+ goto abort;
+ }
+ }
+abort:
+ kfree(req_task);
+ kfree(outbuf);
+ kfree(inbuf);
+
+// printk("IDE Taskfile ioctl ended. rc = %i\n", err);
+
+ return err;
+}
+#endif
diff --git a/drivers/ide/ide-timings.c b/drivers/ide/ide-timings.c
new file mode 100644
index 0000000..81f527a
--- /dev/null
+++ b/drivers/ide/ide-timings.c
@@ -0,0 +1,203 @@
+/*
+ * Copyright (c) 1999-2001 Vojtech Pavlik
+ * Copyright (c) 2007-2008 Bartlomiej Zolnierkiewicz
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/kernel.h>
+#include <linux/ide.h>
+#include <linux/module.h>
+
+/*
+ * PIO 0-5, MWDMA 0-2 and UDMA 0-6 timings (in nanoseconds).
+ * These were taken from ATA/ATAPI-6 standard, rev 0a, except
+ * for PIO 5, which is a nonstandard extension and UDMA6, which
+ * is currently supported only by Maxtor drives.
+ */
+
+static struct ide_timing ide_timing[] = {
+
+ { XFER_UDMA_6, 0, 0, 0, 0, 0, 0, 0, 15 },
+ { XFER_UDMA_5, 0, 0, 0, 0, 0, 0, 0, 20 },
+ { XFER_UDMA_4, 0, 0, 0, 0, 0, 0, 0, 30 },
+ { XFER_UDMA_3, 0, 0, 0, 0, 0, 0, 0, 45 },
+
+ { XFER_UDMA_2, 0, 0, 0, 0, 0, 0, 0, 60 },
+ { XFER_UDMA_1, 0, 0, 0, 0, 0, 0, 0, 80 },
+ { XFER_UDMA_0, 0, 0, 0, 0, 0, 0, 0, 120 },
+
+ { XFER_MW_DMA_2, 25, 0, 0, 0, 70, 25, 120, 0 },
+ { XFER_MW_DMA_1, 45, 0, 0, 0, 80, 50, 150, 0 },
+ { XFER_MW_DMA_0, 60, 0, 0, 0, 215, 215, 480, 0 },
+
+ { XFER_SW_DMA_2, 60, 0, 0, 0, 120, 120, 240, 0 },
+ { XFER_SW_DMA_1, 90, 0, 0, 0, 240, 240, 480, 0 },
+ { XFER_SW_DMA_0, 120, 0, 0, 0, 480, 480, 960, 0 },
+
+ { XFER_PIO_5, 20, 50, 30, 100, 50, 30, 100, 0 },
+ { XFER_PIO_4, 25, 70, 25, 120, 70, 25, 120, 0 },
+ { XFER_PIO_3, 30, 80, 70, 180, 80, 70, 180, 0 },
+
+ { XFER_PIO_2, 30, 290, 40, 330, 100, 90, 240, 0 },
+ { XFER_PIO_1, 50, 290, 93, 383, 125, 100, 383, 0 },
+ { XFER_PIO_0, 70, 290, 240, 600, 165, 150, 600, 0 },
+
+ { XFER_PIO_SLOW, 120, 290, 240, 960, 290, 240, 960, 0 },
+
+ { 0xff }
+};
+
+struct ide_timing *ide_timing_find_mode(u8 speed)
+{
+ struct ide_timing *t;
+
+ for (t = ide_timing; t->mode != speed; t++)
+ if (t->mode == 0xff)
+ return NULL;
+ return t;
+}
+EXPORT_SYMBOL_GPL(ide_timing_find_mode);
+
+u16 ide_pio_cycle_time(ide_drive_t *drive, u8 pio)
+{
+ u16 *id = drive->id;
+ struct ide_timing *t = ide_timing_find_mode(XFER_PIO_0 + pio);
+ u16 cycle = 0;
+
+ if (id[ATA_ID_FIELD_VALID] & 2) {
+ if (ata_id_has_iordy(drive->id))
+ cycle = id[ATA_ID_EIDE_PIO_IORDY];
+ else
+ cycle = id[ATA_ID_EIDE_PIO];
+
+ /* conservative "downgrade" for all pre-ATA2 drives */
+ if (pio < 3 && cycle < t->cycle)
+ cycle = 0; /* use standard timing */
+ }
+
+ return cycle ? cycle : t->cycle;
+}
+EXPORT_SYMBOL_GPL(ide_pio_cycle_time);
+
+#define ENOUGH(v, unit) (((v) - 1) / (unit) + 1)
+#define EZ(v, unit) ((v) ? ENOUGH(v, unit) : 0)
+
+static void ide_timing_quantize(struct ide_timing *t, struct ide_timing *q,
+ int T, int UT)
+{
+ q->setup = EZ(t->setup * 1000, T);
+ q->act8b = EZ(t->act8b * 1000, T);
+ q->rec8b = EZ(t->rec8b * 1000, T);
+ q->cyc8b = EZ(t->cyc8b * 1000, T);
+ q->active = EZ(t->active * 1000, T);
+ q->recover = EZ(t->recover * 1000, T);
+ q->cycle = EZ(t->cycle * 1000, T);
+ q->udma = EZ(t->udma * 1000, UT);
+}
+
+void ide_timing_merge(struct ide_timing *a, struct ide_timing *b,
+ struct ide_timing *m, unsigned int what)
+{
+ if (what & IDE_TIMING_SETUP)
+ m->setup = max(a->setup, b->setup);
+ if (what & IDE_TIMING_ACT8B)
+ m->act8b = max(a->act8b, b->act8b);
+ if (what & IDE_TIMING_REC8B)
+ m->rec8b = max(a->rec8b, b->rec8b);
+ if (what & IDE_TIMING_CYC8B)
+ m->cyc8b = max(a->cyc8b, b->cyc8b);
+ if (what & IDE_TIMING_ACTIVE)
+ m->active = max(a->active, b->active);
+ if (what & IDE_TIMING_RECOVER)
+ m->recover = max(a->recover, b->recover);
+ if (what & IDE_TIMING_CYCLE)
+ m->cycle = max(a->cycle, b->cycle);
+ if (what & IDE_TIMING_UDMA)
+ m->udma = max(a->udma, b->udma);
+}
+EXPORT_SYMBOL_GPL(ide_timing_merge);
+
+int ide_timing_compute(ide_drive_t *drive, u8 speed,
+ struct ide_timing *t, int T, int UT)
+{
+ u16 *id = drive->id;
+ struct ide_timing *s, p;
+
+ /*
+ * Find the mode.
+ */
+ s = ide_timing_find_mode(speed);
+ if (s == NULL)
+ return -EINVAL;
+
+ /*
+ * Copy the timing from the table.
+ */
+ *t = *s;
+
+ /*
+ * If the drive is an EIDE drive, it can tell us it needs extended
+ * PIO/MWDMA cycle timing.
+ */
+ if (id[ATA_ID_FIELD_VALID] & 2) { /* EIDE drive */
+ memset(&p, 0, sizeof(p));
+
+ if (speed <= XFER_PIO_2)
+ p.cycle = p.cyc8b = id[ATA_ID_EIDE_PIO];
+ else if (speed <= XFER_PIO_5)
+ p.cycle = p.cyc8b = id[ATA_ID_EIDE_PIO_IORDY];
+ else if (speed >= XFER_MW_DMA_0 && speed <= XFER_MW_DMA_2)
+ p.cycle = id[ATA_ID_EIDE_DMA_MIN];
+
+ ide_timing_merge(&p, t, t, IDE_TIMING_CYCLE | IDE_TIMING_CYC8B);
+ }
+
+ /*
+ * Convert the timing to bus clock counts.
+ */
+ ide_timing_quantize(t, t, T, UT);
+
+ /*
+ * Even in DMA/UDMA modes we still use PIO access for IDENTIFY,
+ * S.M.A.R.T and some other commands. We have to ensure that the
+ * DMA cycle timing is slower/equal than the fastest PIO timing.
+ */
+ if (speed >= XFER_SW_DMA_0) {
+ u8 pio = ide_get_best_pio_mode(drive, 255, 5);
+ ide_timing_compute(drive, XFER_PIO_0 + pio, &p, T, UT);
+ ide_timing_merge(&p, t, t, IDE_TIMING_ALL);
+ }
+
+ /*
+ * Lengthen active & recovery time so that cycle time is correct.
+ */
+ if (t->act8b + t->rec8b < t->cyc8b) {
+ t->act8b += (t->cyc8b - (t->act8b + t->rec8b)) / 2;
+ t->rec8b = t->cyc8b - t->act8b;
+ }
+
+ if (t->active + t->recover < t->cycle) {
+ t->active += (t->cycle - (t->active + t->recover)) / 2;
+ t->recover = t->cycle - t->active;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ide_timing_compute);
diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c
new file mode 100644
index 0000000..04f8f13
--- /dev/null
+++ b/drivers/ide/ide.c
@@ -0,0 +1,869 @@
+/*
+ * Copyright (C) 1994-1998 Linus Torvalds & authors (see below)
+ * Copyright (C) 2003-2005, 2007 Bartlomiej Zolnierkiewicz
+ */
+
+/*
+ * Mostly written by Mark Lord <mlord@pobox.com>
+ * and Gadi Oxman <gadio@netvision.net.il>
+ * and Andre Hedrick <andre@linux-ide.org>
+ *
+ * See linux/MAINTAINERS for address of current maintainer.
+ *
+ * This is the multiple IDE interface driver, as evolved from hd.c.
+ * It supports up to MAX_HWIFS IDE interfaces, on one or more IRQs
+ * (usually 14 & 15).
+ * There can be up to two drives per interface, as per the ATA-2 spec.
+ *
+ * ...
+ *
+ * From hd.c:
+ * |
+ * | It traverses the request-list, using interrupts to jump between functions.
+ * | As nearly all functions can be called within interrupts, we may not sleep.
+ * | Special care is recommended. Have Fun!
+ * |
+ * | modified by Drew Eckhardt to check nr of hd's from the CMOS.
+ * |
+ * | Thanks to Branko Lankester, lankeste@fwi.uva.nl, who found a bug
+ * | in the early extended-partition checks and added DM partitions.
+ * |
+ * | Early work on error handling by Mika Liljeberg (liljeber@cs.Helsinki.FI).
+ * |
+ * | IRQ-unmask, drive-id, multiple-mode, support for ">16 heads",
+ * | and general streamlining by Mark Lord (mlord@pobox.com).
+ *
+ * October, 1994 -- Complete line-by-line overhaul for linux 1.1.x, by:
+ *
+ * Mark Lord (mlord@pobox.com) (IDE Perf.Pkg)
+ * Delman Lee (delman@ieee.org) ("Mr. atdisk2")
+ * Scott Snyder (snyder@fnald0.fnal.gov) (ATAPI IDE cd-rom)
+ *
+ * This was a rewrite of just about everything from hd.c, though some original
+ * code is still sprinkled about. Think of it as a major evolution, with
+ * inspiration from lots of linux users, esp. hamish@zot.apana.org.au
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/major.h>
+#include <linux/errno.h>
+#include <linux/genhd.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+#include <linux/hdreg.h>
+#include <linux/completion.h>
+#include <linux/device.h>
+
+
+/* default maximum number of failures */
+#define IDE_DEFAULT_MAX_FAILURES 1
+
+struct class *ide_port_class;
+
+static const u8 ide_hwif_to_major[] = { IDE0_MAJOR, IDE1_MAJOR,
+ IDE2_MAJOR, IDE3_MAJOR,
+ IDE4_MAJOR, IDE5_MAJOR,
+ IDE6_MAJOR, IDE7_MAJOR,
+ IDE8_MAJOR, IDE9_MAJOR };
+
+DEFINE_MUTEX(ide_cfg_mtx);
+
+__cacheline_aligned_in_smp DEFINE_SPINLOCK(ide_lock);
+EXPORT_SYMBOL(ide_lock);
+
+static void ide_port_init_devices_data(ide_hwif_t *);
+
+/*
+ * Do not even *think* about calling this!
+ */
+void ide_init_port_data(ide_hwif_t *hwif, unsigned int index)
+{
+ /* bulk initialize hwif & drive info with zeros */
+ memset(hwif, 0, sizeof(ide_hwif_t));
+
+ /* fill in any non-zero initial values */
+ hwif->index = index;
+ hwif->major = ide_hwif_to_major[index];
+
+ hwif->name[0] = 'i';
+ hwif->name[1] = 'd';
+ hwif->name[2] = 'e';
+ hwif->name[3] = '0' + index;
+
+ init_completion(&hwif->gendev_rel_comp);
+
+ hwif->tp_ops = &default_tp_ops;
+
+ ide_port_init_devices_data(hwif);
+}
+
+static void ide_port_init_devices_data(ide_hwif_t *hwif)
+{
+ int unit;
+
+ for (unit = 0; unit < MAX_DRIVES; ++unit) {
+ ide_drive_t *drive = &hwif->drives[unit];
+ u8 j = (hwif->index * MAX_DRIVES) + unit;
+
+ memset(drive, 0, sizeof(*drive));
+
+ drive->media = ide_disk;
+ drive->select = (unit << 4) | ATA_DEVICE_OBS;
+ drive->hwif = hwif;
+ drive->ready_stat = ATA_DRDY;
+ drive->bad_wstat = BAD_W_STAT;
+ drive->special.b.recalibrate = 1;
+ drive->special.b.set_geometry = 1;
+ drive->name[0] = 'h';
+ drive->name[1] = 'd';
+ drive->name[2] = 'a' + j;
+ drive->max_failures = IDE_DEFAULT_MAX_FAILURES;
+
+ INIT_LIST_HEAD(&drive->list);
+ init_completion(&drive->gendev_rel_comp);
+ }
+}
+
+/* Called with ide_lock held. */
+static void __ide_port_unregister_devices(ide_hwif_t *hwif)
+{
+ int i;
+
+ for (i = 0; i < MAX_DRIVES; i++) {
+ ide_drive_t *drive = &hwif->drives[i];
+
+ if (drive->dev_flags & IDE_DFLAG_PRESENT) {
+ spin_unlock_irq(&ide_lock);
+ device_unregister(&drive->gendev);
+ wait_for_completion(&drive->gendev_rel_comp);
+ spin_lock_irq(&ide_lock);
+ }
+ }
+}
+
+void ide_port_unregister_devices(ide_hwif_t *hwif)
+{
+ mutex_lock(&ide_cfg_mtx);
+ spin_lock_irq(&ide_lock);
+ __ide_port_unregister_devices(hwif);
+ hwif->present = 0;
+ ide_port_init_devices_data(hwif);
+ spin_unlock_irq(&ide_lock);
+ mutex_unlock(&ide_cfg_mtx);
+}
+EXPORT_SYMBOL_GPL(ide_port_unregister_devices);
+
+/**
+ * ide_unregister - free an IDE interface
+ * @hwif: IDE interface
+ *
+ * Perform the final unregister of an IDE interface. At the moment
+ * we don't refcount interfaces so this will also get split up.
+ *
+ * Locking:
+ * The caller must not hold the IDE locks
+ * The drive present/vanishing is not yet properly locked
+ * Take care with the callbacks. These have been split to avoid
+ * deadlocking the IDE layer. The shutdown callback is called
+ * before we take the lock and free resources. It is up to the
+ * caller to be sure there is no pending I/O here, and that
+ * the interface will not be reopened (present/vanishing locking
+ * isn't yet done BTW). After we commit to the final kill we
+ * call the cleanup callback with the ide locks held.
+ *
+ * Unregister restores the hwif structures to the default state.
+ * This is raving bonkers.
+ */
+
+void ide_unregister(ide_hwif_t *hwif)
+{
+ ide_hwif_t *g;
+ ide_hwgroup_t *hwgroup;
+ int irq_count = 0;
+
+ BUG_ON(in_interrupt());
+ BUG_ON(irqs_disabled());
+
+ mutex_lock(&ide_cfg_mtx);
+
+ spin_lock_irq(&ide_lock);
+ if (hwif->present) {
+ __ide_port_unregister_devices(hwif);
+ hwif->present = 0;
+ }
+ spin_unlock_irq(&ide_lock);
+
+ ide_proc_unregister_port(hwif);
+
+ hwgroup = hwif->hwgroup;
+ /*
+ * free the irq if we were the only hwif using it
+ */
+ g = hwgroup->hwif;
+ do {
+ if (g->irq == hwif->irq)
+ ++irq_count;
+ g = g->next;
+ } while (g != hwgroup->hwif);
+ if (irq_count == 1)
+ free_irq(hwif->irq, hwgroup);
+
+ ide_remove_port_from_hwgroup(hwif);
+
+ device_unregister(hwif->portdev);
+ device_unregister(&hwif->gendev);
+ wait_for_completion(&hwif->gendev_rel_comp);
+
+ /*
+ * Remove us from the kernel's knowledge
+ */
+ blk_unregister_region(MKDEV(hwif->major, 0), MAX_DRIVES<<PARTN_BITS);
+ kfree(hwif->sg_table);
+ unregister_blkdev(hwif->major, hwif->name);
+
+ ide_release_dma_engine(hwif);
+
+ mutex_unlock(&ide_cfg_mtx);
+}
+
+void ide_init_port_hw(ide_hwif_t *hwif, hw_regs_t *hw)
+{
+ memcpy(&hwif->io_ports, &hw->io_ports, sizeof(hwif->io_ports));
+ hwif->irq = hw->irq;
+ hwif->chipset = hw->chipset;
+ hwif->dev = hw->dev;
+ hwif->gendev.parent = hw->parent ? hw->parent : hw->dev;
+ hwif->ack_intr = hw->ack_intr;
+ hwif->config_data = hw->config;
+}
+
+/*
+ * Locks for IDE setting functionality
+ */
+
+DEFINE_MUTEX(ide_setting_mtx);
+
+ide_devset_get(io_32bit, io_32bit);
+
+static int set_io_32bit(ide_drive_t *drive, int arg)
+{
+ if (drive->dev_flags & IDE_DFLAG_NO_IO_32BIT)
+ return -EPERM;
+
+ if (arg < 0 || arg > 1 + (SUPPORT_VLB_SYNC << 1))
+ return -EINVAL;
+
+ drive->io_32bit = arg;
+
+ return 0;
+}
+
+ide_devset_get_flag(ksettings, IDE_DFLAG_KEEP_SETTINGS);
+
+static int set_ksettings(ide_drive_t *drive, int arg)
+{
+ if (arg < 0 || arg > 1)
+ return -EINVAL;
+
+ if (arg)
+ drive->dev_flags |= IDE_DFLAG_KEEP_SETTINGS;
+ else
+ drive->dev_flags &= ~IDE_DFLAG_KEEP_SETTINGS;
+
+ return 0;
+}
+
+ide_devset_get_flag(using_dma, IDE_DFLAG_USING_DMA);
+
+static int set_using_dma(ide_drive_t *drive, int arg)
+{
+#ifdef CONFIG_BLK_DEV_IDEDMA
+ int err = -EPERM;
+
+ if (arg < 0 || arg > 1)
+ return -EINVAL;
+
+ if (ata_id_has_dma(drive->id) == 0)
+ goto out;
+
+ if (drive->hwif->dma_ops == NULL)
+ goto out;
+
+ err = 0;
+
+ if (arg) {
+ if (ide_set_dma(drive))
+ err = -EIO;
+ } else
+ ide_dma_off(drive);
+
+out:
+ return err;
+#else
+ if (arg < 0 || arg > 1)
+ return -EINVAL;
+
+ return -EPERM;
+#endif
+}
+
+/*
+ * handle HDIO_SET_PIO_MODE ioctl abusers here, eventually it will go away
+ */
+static int set_pio_mode_abuse(ide_hwif_t *hwif, u8 req_pio)
+{
+ switch (req_pio) {
+ case 202:
+ case 201:
+ case 200:
+ case 102:
+ case 101:
+ case 100:
+ return (hwif->host_flags & IDE_HFLAG_ABUSE_DMA_MODES) ? 1 : 0;
+ case 9:
+ case 8:
+ return (hwif->host_flags & IDE_HFLAG_ABUSE_PREFETCH) ? 1 : 0;
+ case 7:
+ case 6:
+ return (hwif->host_flags & IDE_HFLAG_ABUSE_FAST_DEVSEL) ? 1 : 0;
+ default:
+ return 0;
+ }
+}
+
+static int set_pio_mode(ide_drive_t *drive, int arg)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ const struct ide_port_ops *port_ops = hwif->port_ops;
+
+ if (arg < 0 || arg > 255)
+ return -EINVAL;
+
+ if (port_ops == NULL || port_ops->set_pio_mode == NULL ||
+ (hwif->host_flags & IDE_HFLAG_NO_SET_MODE))
+ return -ENOSYS;
+
+ if (set_pio_mode_abuse(drive->hwif, arg)) {
+ if (arg == 8 || arg == 9) {
+ unsigned long flags;
+
+ /* take lock for IDE_DFLAG_[NO_]UNMASK/[NO_]IO_32BIT */
+ spin_lock_irqsave(&ide_lock, flags);
+ port_ops->set_pio_mode(drive, arg);
+ spin_unlock_irqrestore(&ide_lock, flags);
+ } else
+ port_ops->set_pio_mode(drive, arg);
+ } else {
+ int keep_dma = !!(drive->dev_flags & IDE_DFLAG_USING_DMA);
+
+ ide_set_pio(drive, arg);
+
+ if (hwif->host_flags & IDE_HFLAG_SET_PIO_MODE_KEEP_DMA) {
+ if (keep_dma)
+ ide_dma_on(drive);
+ }
+ }
+
+ return 0;
+}
+
+ide_devset_get_flag(unmaskirq, IDE_DFLAG_UNMASK);
+
+static int set_unmaskirq(ide_drive_t *drive, int arg)
+{
+ if (drive->dev_flags & IDE_DFLAG_NO_UNMASK)
+ return -EPERM;
+
+ if (arg < 0 || arg > 1)
+ return -EINVAL;
+
+ if (arg)
+ drive->dev_flags |= IDE_DFLAG_UNMASK;
+ else
+ drive->dev_flags &= ~IDE_DFLAG_UNMASK;
+
+ return 0;
+}
+
+ide_ext_devset_rw_sync(io_32bit, io_32bit);
+ide_ext_devset_rw_sync(keepsettings, ksettings);
+ide_ext_devset_rw_sync(unmaskirq, unmaskirq);
+ide_ext_devset_rw_sync(using_dma, using_dma);
+__IDE_DEVSET(pio_mode, DS_SYNC, NULL, set_pio_mode);
+
+static int generic_ide_suspend(struct device *dev, pm_message_t mesg)
+{
+ ide_drive_t *drive = dev->driver_data, *pair = ide_get_pair_dev(drive);
+ ide_hwif_t *hwif = HWIF(drive);
+ struct request *rq;
+ struct request_pm_state rqpm;
+ ide_task_t args;
+ int ret;
+
+ /* call ACPI _GTM only once */
+ if ((drive->dn & 1) == 0 || pair == NULL)
+ ide_acpi_get_timing(hwif);
+
+ memset(&rqpm, 0, sizeof(rqpm));
+ memset(&args, 0, sizeof(args));
+ rq = blk_get_request(drive->queue, READ, __GFP_WAIT);
+ rq->cmd_type = REQ_TYPE_PM_SUSPEND;
+ rq->special = &args;
+ rq->data = &rqpm;
+ rqpm.pm_step = IDE_PM_START_SUSPEND;
+ if (mesg.event == PM_EVENT_PRETHAW)
+ mesg.event = PM_EVENT_FREEZE;
+ rqpm.pm_state = mesg.event;
+
+ ret = blk_execute_rq(drive->queue, NULL, rq, 0);
+ blk_put_request(rq);
+
+ /* call ACPI _PS3 only after both devices are suspended */
+ if (ret == 0 && ((drive->dn & 1) || pair == NULL))
+ ide_acpi_set_state(hwif, 0);
+
+ return ret;
+}
+
+static int generic_ide_resume(struct device *dev)
+{
+ ide_drive_t *drive = dev->driver_data, *pair = ide_get_pair_dev(drive);
+ ide_hwif_t *hwif = HWIF(drive);
+ struct request *rq;
+ struct request_pm_state rqpm;
+ ide_task_t args;
+ int err;
+
+ /* call ACPI _PS0 / _STM only once */
+ if ((drive->dn & 1) == 0 || pair == NULL) {
+ ide_acpi_set_state(hwif, 1);
+ ide_acpi_push_timing(hwif);
+ }
+
+ ide_acpi_exec_tfs(drive);
+
+ memset(&rqpm, 0, sizeof(rqpm));
+ memset(&args, 0, sizeof(args));
+ rq = blk_get_request(drive->queue, READ, __GFP_WAIT);
+ rq->cmd_type = REQ_TYPE_PM_RESUME;
+ rq->cmd_flags |= REQ_PREEMPT;
+ rq->special = &args;
+ rq->data = &rqpm;
+ rqpm.pm_step = IDE_PM_START_RESUME;
+ rqpm.pm_state = PM_EVENT_ON;
+
+ err = blk_execute_rq(drive->queue, NULL, rq, 1);
+ blk_put_request(rq);
+
+ if (err == 0 && dev->driver) {
+ ide_driver_t *drv = to_ide_driver(dev->driver);
+
+ if (drv->resume)
+ drv->resume(drive);
+ }
+
+ return err;
+}
+
+/**
+ * ide_device_get - get an additional reference to a ide_drive_t
+ * @drive: device to get a reference to
+ *
+ * Gets a reference to the ide_drive_t and increments the use count of the
+ * underlying LLDD module.
+ */
+int ide_device_get(ide_drive_t *drive)
+{
+ struct device *host_dev;
+ struct module *module;
+
+ if (!get_device(&drive->gendev))
+ return -ENXIO;
+
+ host_dev = drive->hwif->host->dev[0];
+ module = host_dev ? host_dev->driver->owner : NULL;
+
+ if (module && !try_module_get(module)) {
+ put_device(&drive->gendev);
+ return -ENXIO;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ide_device_get);
+
+/**
+ * ide_device_put - release a reference to a ide_drive_t
+ * @drive: device to release a reference on
+ *
+ * Release a reference to the ide_drive_t and decrements the use count of
+ * the underlying LLDD module.
+ */
+void ide_device_put(ide_drive_t *drive)
+{
+#ifdef CONFIG_MODULE_UNLOAD
+ struct device *host_dev = drive->hwif->host->dev[0];
+ struct module *module = host_dev ? host_dev->driver->owner : NULL;
+
+ if (module)
+ module_put(module);
+#endif
+ put_device(&drive->gendev);
+}
+EXPORT_SYMBOL_GPL(ide_device_put);
+
+static int ide_bus_match(struct device *dev, struct device_driver *drv)
+{
+ return 1;
+}
+
+static char *media_string(ide_drive_t *drive)
+{
+ switch (drive->media) {
+ case ide_disk:
+ return "disk";
+ case ide_cdrom:
+ return "cdrom";
+ case ide_tape:
+ return "tape";
+ case ide_floppy:
+ return "floppy";
+ case ide_optical:
+ return "optical";
+ default:
+ return "UNKNOWN";
+ }
+}
+
+static ssize_t media_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ ide_drive_t *drive = to_ide_device(dev);
+ return sprintf(buf, "%s\n", media_string(drive));
+}
+
+static ssize_t drivename_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ ide_drive_t *drive = to_ide_device(dev);
+ return sprintf(buf, "%s\n", drive->name);
+}
+
+static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ ide_drive_t *drive = to_ide_device(dev);
+ return sprintf(buf, "ide:m-%s\n", media_string(drive));
+}
+
+static ssize_t model_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ ide_drive_t *drive = to_ide_device(dev);
+ return sprintf(buf, "%s\n", (char *)&drive->id[ATA_ID_PROD]);
+}
+
+static ssize_t firmware_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ ide_drive_t *drive = to_ide_device(dev);
+ return sprintf(buf, "%s\n", (char *)&drive->id[ATA_ID_FW_REV]);
+}
+
+static ssize_t serial_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ ide_drive_t *drive = to_ide_device(dev);
+ return sprintf(buf, "%s\n", (char *)&drive->id[ATA_ID_SERNO]);
+}
+
+static struct device_attribute ide_dev_attrs[] = {
+ __ATTR_RO(media),
+ __ATTR_RO(drivename),
+ __ATTR_RO(modalias),
+ __ATTR_RO(model),
+ __ATTR_RO(firmware),
+ __ATTR(serial, 0400, serial_show, NULL),
+ __ATTR(unload_heads, 0644, ide_park_show, ide_park_store),
+ __ATTR_NULL
+};
+
+static int ide_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+ ide_drive_t *drive = to_ide_device(dev);
+
+ add_uevent_var(env, "MEDIA=%s", media_string(drive));
+ add_uevent_var(env, "DRIVENAME=%s", drive->name);
+ add_uevent_var(env, "MODALIAS=ide:m-%s", media_string(drive));
+ return 0;
+}
+
+static int generic_ide_probe(struct device *dev)
+{
+ ide_drive_t *drive = to_ide_device(dev);
+ ide_driver_t *drv = to_ide_driver(dev->driver);
+
+ return drv->probe ? drv->probe(drive) : -ENODEV;
+}
+
+static int generic_ide_remove(struct device *dev)
+{
+ ide_drive_t *drive = to_ide_device(dev);
+ ide_driver_t *drv = to_ide_driver(dev->driver);
+
+ if (drv->remove)
+ drv->remove(drive);
+
+ return 0;
+}
+
+static void generic_ide_shutdown(struct device *dev)
+{
+ ide_drive_t *drive = to_ide_device(dev);
+ ide_driver_t *drv = to_ide_driver(dev->driver);
+
+ if (dev->driver && drv->shutdown)
+ drv->shutdown(drive);
+}
+
+struct bus_type ide_bus_type = {
+ .name = "ide",
+ .match = ide_bus_match,
+ .uevent = ide_uevent,
+ .probe = generic_ide_probe,
+ .remove = generic_ide_remove,
+ .shutdown = generic_ide_shutdown,
+ .dev_attrs = ide_dev_attrs,
+ .suspend = generic_ide_suspend,
+ .resume = generic_ide_resume,
+};
+
+EXPORT_SYMBOL_GPL(ide_bus_type);
+
+int ide_vlb_clk;
+EXPORT_SYMBOL_GPL(ide_vlb_clk);
+
+module_param_named(vlb_clock, ide_vlb_clk, int, 0);
+MODULE_PARM_DESC(vlb_clock, "VLB clock frequency (in MHz)");
+
+int ide_pci_clk;
+EXPORT_SYMBOL_GPL(ide_pci_clk);
+
+module_param_named(pci_clock, ide_pci_clk, int, 0);
+MODULE_PARM_DESC(pci_clock, "PCI bus clock frequency (in MHz)");
+
+static int ide_set_dev_param_mask(const char *s, struct kernel_param *kp)
+{
+ int a, b, i, j = 1;
+ unsigned int *dev_param_mask = (unsigned int *)kp->arg;
+
+ if (sscanf(s, "%d.%d:%d", &a, &b, &j) != 3 &&
+ sscanf(s, "%d.%d", &a, &b) != 2)
+ return -EINVAL;
+
+ i = a * MAX_DRIVES + b;
+
+ if (i >= MAX_HWIFS * MAX_DRIVES || j < 0 || j > 1)
+ return -EINVAL;
+
+ if (j)
+ *dev_param_mask |= (1 << i);
+ else
+ *dev_param_mask &= (1 << i);
+
+ return 0;
+}
+
+static unsigned int ide_nodma;
+
+module_param_call(nodma, ide_set_dev_param_mask, NULL, &ide_nodma, 0);
+MODULE_PARM_DESC(nodma, "disallow DMA for a device");
+
+static unsigned int ide_noflush;
+
+module_param_call(noflush, ide_set_dev_param_mask, NULL, &ide_noflush, 0);
+MODULE_PARM_DESC(noflush, "disable flush requests for a device");
+
+static unsigned int ide_noprobe;
+
+module_param_call(noprobe, ide_set_dev_param_mask, NULL, &ide_noprobe, 0);
+MODULE_PARM_DESC(noprobe, "skip probing for a device");
+
+static unsigned int ide_nowerr;
+
+module_param_call(nowerr, ide_set_dev_param_mask, NULL, &ide_nowerr, 0);
+MODULE_PARM_DESC(nowerr, "ignore the ATA_DF bit for a device");
+
+static unsigned int ide_cdroms;
+
+module_param_call(cdrom, ide_set_dev_param_mask, NULL, &ide_cdroms, 0);
+MODULE_PARM_DESC(cdrom, "force device as a CD-ROM");
+
+struct chs_geom {
+ unsigned int cyl;
+ u8 head;
+ u8 sect;
+};
+
+static unsigned int ide_disks;
+static struct chs_geom ide_disks_chs[MAX_HWIFS * MAX_DRIVES];
+
+static int ide_set_disk_chs(const char *str, struct kernel_param *kp)
+{
+ int a, b, c = 0, h = 0, s = 0, i, j = 1;
+
+ if (sscanf(str, "%d.%d:%d,%d,%d", &a, &b, &c, &h, &s) != 5 &&
+ sscanf(str, "%d.%d:%d", &a, &b, &j) != 3)
+ return -EINVAL;
+
+ i = a * MAX_DRIVES + b;
+
+ if (i >= MAX_HWIFS * MAX_DRIVES || j < 0 || j > 1)
+ return -EINVAL;
+
+ if (c > INT_MAX || h > 255 || s > 255)
+ return -EINVAL;
+
+ if (j)
+ ide_disks |= (1 << i);
+ else
+ ide_disks &= (1 << i);
+
+ ide_disks_chs[i].cyl = c;
+ ide_disks_chs[i].head = h;
+ ide_disks_chs[i].sect = s;
+
+ return 0;
+}
+
+module_param_call(chs, ide_set_disk_chs, NULL, NULL, 0);
+MODULE_PARM_DESC(chs, "force device as a disk (using CHS)");
+
+static void ide_dev_apply_params(ide_drive_t *drive, u8 unit)
+{
+ int i = drive->hwif->index * MAX_DRIVES + unit;
+
+ if (ide_nodma & (1 << i)) {
+ printk(KERN_INFO "ide: disallowing DMA for %s\n", drive->name);
+ drive->dev_flags |= IDE_DFLAG_NODMA;
+ }
+ if (ide_noflush & (1 << i)) {
+ printk(KERN_INFO "ide: disabling flush requests for %s\n",
+ drive->name);
+ drive->dev_flags |= IDE_DFLAG_NOFLUSH;
+ }
+ if (ide_noprobe & (1 << i)) {
+ printk(KERN_INFO "ide: skipping probe for %s\n", drive->name);
+ drive->dev_flags |= IDE_DFLAG_NOPROBE;
+ }
+ if (ide_nowerr & (1 << i)) {
+ printk(KERN_INFO "ide: ignoring the ATA_DF bit for %s\n",
+ drive->name);
+ drive->bad_wstat = BAD_R_STAT;
+ }
+ if (ide_cdroms & (1 << i)) {
+ printk(KERN_INFO "ide: forcing %s as a CD-ROM\n", drive->name);
+ drive->dev_flags |= IDE_DFLAG_PRESENT;
+ drive->media = ide_cdrom;
+ /* an ATAPI device ignores DRDY */
+ drive->ready_stat = 0;
+ }
+ if (ide_disks & (1 << i)) {
+ drive->cyl = drive->bios_cyl = ide_disks_chs[i].cyl;
+ drive->head = drive->bios_head = ide_disks_chs[i].head;
+ drive->sect = drive->bios_sect = ide_disks_chs[i].sect;
+
+ printk(KERN_INFO "ide: forcing %s as a disk (%d/%d/%d)\n",
+ drive->name,
+ drive->cyl, drive->head, drive->sect);
+
+ drive->dev_flags |= IDE_DFLAG_FORCED_GEOM | IDE_DFLAG_PRESENT;
+ drive->media = ide_disk;
+ drive->ready_stat = ATA_DRDY;
+ }
+}
+
+static unsigned int ide_ignore_cable;
+
+static int ide_set_ignore_cable(const char *s, struct kernel_param *kp)
+{
+ int i, j = 1;
+
+ if (sscanf(s, "%d:%d", &i, &j) != 2 && sscanf(s, "%d", &i) != 1)
+ return -EINVAL;
+
+ if (i >= MAX_HWIFS || j < 0 || j > 1)
+ return -EINVAL;
+
+ if (j)
+ ide_ignore_cable |= (1 << i);
+ else
+ ide_ignore_cable &= (1 << i);
+
+ return 0;
+}
+
+module_param_call(ignore_cable, ide_set_ignore_cable, NULL, NULL, 0);
+MODULE_PARM_DESC(ignore_cable, "ignore cable detection");
+
+void ide_port_apply_params(ide_hwif_t *hwif)
+{
+ int i;
+
+ if (ide_ignore_cable & (1 << hwif->index)) {
+ printk(KERN_INFO "ide: ignoring cable detection for %s\n",
+ hwif->name);
+ hwif->cbl = ATA_CBL_PATA40_SHORT;
+ }
+
+ for (i = 0; i < MAX_DRIVES; i++)
+ ide_dev_apply_params(&hwif->drives[i], i);
+}
+
+/*
+ * This is gets invoked once during initialization, to set *everything* up
+ */
+static int __init ide_init(void)
+{
+ int ret;
+
+ printk(KERN_INFO "Uniform Multi-Platform E-IDE driver\n");
+
+ ret = bus_register(&ide_bus_type);
+ if (ret < 0) {
+ printk(KERN_WARNING "IDE: bus_register error: %d\n", ret);
+ return ret;
+ }
+
+ ide_port_class = class_create(THIS_MODULE, "ide_port");
+ if (IS_ERR(ide_port_class)) {
+ ret = PTR_ERR(ide_port_class);
+ goto out_port_class;
+ }
+
+ proc_ide_create();
+
+ return 0;
+
+out_port_class:
+ bus_unregister(&ide_bus_type);
+
+ return ret;
+}
+
+static void __exit ide_exit(void)
+{
+ proc_ide_destroy();
+
+ class_destroy(ide_port_class);
+
+ bus_unregister(&ide_bus_type);
+}
+
+module_init(ide_init);
+module_exit(ide_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/ide_arm.c b/drivers/ide/ide_arm.c
new file mode 100644
index 0000000..f728f29
--- /dev/null
+++ b/drivers/ide/ide_arm.c
@@ -0,0 +1,56 @@
+/*
+ * ARM default IDE host driver
+ *
+ * Copyright (C) 2004 Bartlomiej Zolnierkiewicz
+ * Based on code by: Russell King, Ian Molton and Alexander Schulz.
+ *
+ * May be copied or modified under the terms of the GNU General Public License.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/ide.h>
+
+#include <asm/irq.h>
+
+#define DRV_NAME "ide_arm"
+
+#ifdef CONFIG_ARCH_CLPS7500
+# include <mach/hardware.h>
+#
+# define IDE_ARM_IO (ISASLOT_IO + 0x1f0)
+# define IDE_ARM_IRQ IRQ_ISA_14
+#else
+# define IDE_ARM_IO 0x1f0
+# define IDE_ARM_IRQ IRQ_HARDDISK
+#endif
+
+static int __init ide_arm_init(void)
+{
+ unsigned long base = IDE_ARM_IO, ctl = IDE_ARM_IO + 0x206;
+ hw_regs_t hw, *hws[] = { &hw, NULL, NULL, NULL };
+
+ if (!request_region(base, 8, DRV_NAME)) {
+ printk(KERN_ERR "%s: I/O resource 0x%lX-0x%lX not free.\n",
+ DRV_NAME, base, base + 7);
+ return -EBUSY;
+ }
+
+ if (!request_region(ctl, 1, DRV_NAME)) {
+ printk(KERN_ERR "%s: I/O resource 0x%lX not free.\n",
+ DRV_NAME, ctl);
+ release_region(base, 8);
+ return -EBUSY;
+ }
+
+ memset(&hw, 0, sizeof(hw));
+ ide_std_init_ports(&hw, base, ctl);
+ hw.irq = IDE_ARM_IRQ;
+ hw.chipset = ide_generic;
+
+ return ide_host_add(NULL, hws, NULL);
+}
+
+module_init(ide_arm_init);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/ide_platform.c b/drivers/ide/ide_platform.c
new file mode 100644
index 0000000..051b4ab
--- /dev/null
+++ b/drivers/ide/ide_platform.c
@@ -0,0 +1,147 @@
+/*
+ * Platform IDE driver
+ *
+ * Copyright (C) 2007 MontaVista Software
+ *
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/ide.h>
+#include <linux/ioport.h>
+#include <linux/module.h>
+#include <linux/ata_platform.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+static void __devinit plat_ide_setup_ports(hw_regs_t *hw,
+ void __iomem *base,
+ void __iomem *ctrl,
+ struct pata_platform_info *pdata,
+ int irq)
+{
+ unsigned long port = (unsigned long)base;
+ int i;
+
+ hw->io_ports.data_addr = port;
+
+ port += (1 << pdata->ioport_shift);
+ for (i = 1; i <= 7;
+ i++, port += (1 << pdata->ioport_shift))
+ hw->io_ports_array[i] = port;
+
+ hw->io_ports.ctl_addr = (unsigned long)ctrl;
+
+ hw->irq = irq;
+
+ hw->chipset = ide_generic;
+}
+
+static const struct ide_port_info platform_ide_port_info = {
+ .host_flags = IDE_HFLAG_NO_DMA,
+};
+
+static int __devinit plat_ide_probe(struct platform_device *pdev)
+{
+ struct resource *res_base, *res_alt, *res_irq;
+ void __iomem *base, *alt_base;
+ struct pata_platform_info *pdata;
+ struct ide_host *host;
+ int ret = 0, mmio = 0;
+ hw_regs_t hw, *hws[] = { &hw, NULL, NULL, NULL };
+ struct ide_port_info d = platform_ide_port_info;
+
+ pdata = pdev->dev.platform_data;
+
+ /* get a pointer to the register memory */
+ res_base = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ res_alt = platform_get_resource(pdev, IORESOURCE_IO, 1);
+
+ if (!res_base || !res_alt) {
+ res_base = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ res_alt = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (!res_base || !res_alt) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ mmio = 1;
+ }
+
+ res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res_irq) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (mmio) {
+ base = devm_ioremap(&pdev->dev,
+ res_base->start, res_base->end - res_base->start + 1);
+ alt_base = devm_ioremap(&pdev->dev,
+ res_alt->start, res_alt->end - res_alt->start + 1);
+ } else {
+ base = devm_ioport_map(&pdev->dev,
+ res_base->start, res_base->end - res_base->start + 1);
+ alt_base = devm_ioport_map(&pdev->dev,
+ res_alt->start, res_alt->end - res_alt->start + 1);
+ }
+
+ memset(&hw, 0, sizeof(hw));
+ plat_ide_setup_ports(&hw, base, alt_base, pdata, res_irq->start);
+ hw.dev = &pdev->dev;
+
+ if (mmio)
+ d.host_flags |= IDE_HFLAG_MMIO;
+
+ ret = ide_host_add(&d, hws, &host);
+ if (ret)
+ goto out;
+
+ platform_set_drvdata(pdev, host);
+
+ return 0;
+
+out:
+ return ret;
+}
+
+static int __devexit plat_ide_remove(struct platform_device *pdev)
+{
+ struct ide_host *host = pdev->dev.driver_data;
+
+ ide_host_remove(host);
+
+ return 0;
+}
+
+static struct platform_driver platform_ide_driver = {
+ .driver = {
+ .name = "pata_platform",
+ .owner = THIS_MODULE,
+ },
+ .probe = plat_ide_probe,
+ .remove = __devexit_p(plat_ide_remove),
+};
+
+static int __init platform_ide_init(void)
+{
+ return platform_driver_register(&platform_ide_driver);
+}
+
+static void __exit platform_ide_exit(void)
+{
+ platform_driver_unregister(&platform_ide_driver);
+}
+
+MODULE_DESCRIPTION("Platform IDE driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pata_platform");
+
+module_init(platform_ide_init);
+module_exit(platform_ide_exit);
diff --git a/drivers/ide/it8213.c b/drivers/ide/it8213.c
new file mode 100644
index 0000000..7c2feeb
--- /dev/null
+++ b/drivers/ide/it8213.c
@@ -0,0 +1,216 @@
+/*
+ * ITE 8213 IDE driver
+ *
+ * Copyright (C) 2006 Jack Lee
+ * Copyright (C) 2006 Alan Cox
+ * Copyright (C) 2007 Bartlomiej Zolnierkiewicz
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#define DRV_NAME "it8213"
+
+/**
+ * it8213_set_pio_mode - set host controller for PIO mode
+ * @drive: drive
+ * @pio: PIO mode number
+ *
+ * Set the interface PIO mode.
+ */
+
+static void it8213_set_pio_mode(ide_drive_t *drive, const u8 pio)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+ int is_slave = drive->dn & 1;
+ int master_port = 0x40;
+ int slave_port = 0x44;
+ unsigned long flags;
+ u16 master_data;
+ u8 slave_data;
+ static DEFINE_SPINLOCK(tune_lock);
+ int control = 0;
+
+ static const u8 timings[][2] = {
+ { 0, 0 },
+ { 0, 0 },
+ { 1, 0 },
+ { 2, 1 },
+ { 2, 3 }, };
+
+ spin_lock_irqsave(&tune_lock, flags);
+ pci_read_config_word(dev, master_port, &master_data);
+
+ if (pio > 1)
+ control |= 1; /* Programmable timing on */
+ if (drive->media != ide_disk)
+ control |= 4; /* ATAPI */
+ if (pio > 2)
+ control |= 2; /* IORDY */
+ if (is_slave) {
+ master_data |= 0x4000;
+ master_data &= ~0x0070;
+ if (pio > 1)
+ master_data = master_data | (control << 4);
+ pci_read_config_byte(dev, slave_port, &slave_data);
+ slave_data = slave_data & 0xf0;
+ slave_data = slave_data | (timings[pio][0] << 2) | timings[pio][1];
+ } else {
+ master_data &= ~0x3307;
+ if (pio > 1)
+ master_data = master_data | control;
+ master_data = master_data | (timings[pio][0] << 12) | (timings[pio][1] << 8);
+ }
+ pci_write_config_word(dev, master_port, master_data);
+ if (is_slave)
+ pci_write_config_byte(dev, slave_port, slave_data);
+ spin_unlock_irqrestore(&tune_lock, flags);
+}
+
+/**
+ * it8213_set_dma_mode - set host controller for DMA mode
+ * @drive: drive
+ * @speed: DMA mode
+ *
+ * Tune the ITE chipset for the DMA mode.
+ */
+
+static void it8213_set_dma_mode(ide_drive_t *drive, const u8 speed)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+ u8 maslave = 0x40;
+ int a_speed = 3 << (drive->dn * 4);
+ int u_flag = 1 << drive->dn;
+ int v_flag = 0x01 << drive->dn;
+ int w_flag = 0x10 << drive->dn;
+ int u_speed = 0;
+ u16 reg4042, reg4a;
+ u8 reg48, reg54, reg55;
+
+ pci_read_config_word(dev, maslave, &reg4042);
+ pci_read_config_byte(dev, 0x48, &reg48);
+ pci_read_config_word(dev, 0x4a, &reg4a);
+ pci_read_config_byte(dev, 0x54, &reg54);
+ pci_read_config_byte(dev, 0x55, &reg55);
+
+ if (speed >= XFER_UDMA_0) {
+ u8 udma = speed - XFER_UDMA_0;
+
+ u_speed = min_t(u8, 2 - (udma & 1), udma) << (drive->dn * 4);
+
+ if (!(reg48 & u_flag))
+ pci_write_config_byte(dev, 0x48, reg48 | u_flag);
+ if (speed >= XFER_UDMA_5)
+ pci_write_config_byte(dev, 0x55, (u8) reg55|w_flag);
+ else
+ pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag);
+
+ if ((reg4a & a_speed) != u_speed)
+ pci_write_config_word(dev, 0x4a, (reg4a & ~a_speed) | u_speed);
+ if (speed > XFER_UDMA_2) {
+ if (!(reg54 & v_flag))
+ pci_write_config_byte(dev, 0x54, reg54 | v_flag);
+ } else
+ pci_write_config_byte(dev, 0x54, reg54 & ~v_flag);
+ } else {
+ const u8 mwdma_to_pio[] = { 0, 3, 4 };
+ u8 pio;
+
+ if (reg48 & u_flag)
+ pci_write_config_byte(dev, 0x48, reg48 & ~u_flag);
+ if (reg4a & a_speed)
+ pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
+ if (reg54 & v_flag)
+ pci_write_config_byte(dev, 0x54, reg54 & ~v_flag);
+ if (reg55 & w_flag)
+ pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag);
+
+ if (speed >= XFER_MW_DMA_0)
+ pio = mwdma_to_pio[speed - XFER_MW_DMA_0];
+ else
+ pio = 2; /* only SWDMA2 is allowed */
+
+ it8213_set_pio_mode(drive, pio);
+ }
+}
+
+static u8 it8213_cable_detect(ide_hwif_t *hwif)
+{
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+ u8 reg42h = 0;
+
+ pci_read_config_byte(dev, 0x42, &reg42h);
+
+ return (reg42h & 0x02) ? ATA_CBL_PATA40 : ATA_CBL_PATA80;
+}
+
+static const struct ide_port_ops it8213_port_ops = {
+ .set_pio_mode = it8213_set_pio_mode,
+ .set_dma_mode = it8213_set_dma_mode,
+ .cable_detect = it8213_cable_detect,
+};
+
+static const struct ide_port_info it8213_chipset __devinitdata = {
+ .name = DRV_NAME,
+ .enablebits = { {0x41, 0x80, 0x80} },
+ .port_ops = &it8213_port_ops,
+ .host_flags = IDE_HFLAG_SINGLE,
+ .pio_mask = ATA_PIO4,
+ .swdma_mask = ATA_SWDMA2_ONLY,
+ .mwdma_mask = ATA_MWDMA12_ONLY,
+ .udma_mask = ATA_UDMA6,
+};
+
+/**
+ * it8213_init_one - pci layer discovery entry
+ * @dev: PCI device
+ * @id: ident table entry
+ *
+ * Called by the PCI code when it finds an ITE8213 controller. As
+ * this device follows the standard interfaces we can use the
+ * standard helper functions to do almost all the work for us.
+ */
+
+static int __devinit it8213_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ return ide_pci_init_one(dev, &it8213_chipset, NULL);
+}
+
+static const struct pci_device_id it8213_pci_tbl[] = {
+ { PCI_VDEVICE(ITE, PCI_DEVICE_ID_ITE_8213), 0 },
+ { 0, },
+};
+
+MODULE_DEVICE_TABLE(pci, it8213_pci_tbl);
+
+static struct pci_driver it8213_pci_driver = {
+ .name = "ITE8213_IDE",
+ .id_table = it8213_pci_tbl,
+ .probe = it8213_init_one,
+ .remove = ide_pci_remove,
+ .suspend = ide_pci_suspend,
+ .resume = ide_pci_resume,
+};
+
+static int __init it8213_ide_init(void)
+{
+ return ide_pci_register_driver(&it8213_pci_driver);
+}
+
+static void __exit it8213_ide_exit(void)
+{
+ pci_unregister_driver(&it8213_pci_driver);
+}
+
+module_init(it8213_ide_init);
+module_exit(it8213_ide_exit);
+
+MODULE_AUTHOR("Jack Lee, Alan Cox");
+MODULE_DESCRIPTION("PCI driver module for the ITE 8213");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/it821x.c b/drivers/ide/it821x.c
new file mode 100644
index 0000000..011e6d6
--- /dev/null
+++ b/drivers/ide/it821x.c
@@ -0,0 +1,718 @@
+/*
+ * Copyright (C) 2004 Red Hat
+ * Copyright (C) 2007 Bartlomiej Zolnierkiewicz
+ *
+ * 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 UDMA is ok but not MWDMA it seems
+ * - RAID configuration ioctls
+ * - Move to libata once it grows up
+ */
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#define DRV_NAME "it821x"
+
+#define QUIRK_VORTEX86 1
+
+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 quirks;
+};
+
+#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 necessary right now
+ * for embedded platforms that cannot run a PC BIOS but are using this
+ * device.
+ */
+
+static int it8212_noraid;
+
+/**
+ * it821x_program - program the PIO/MWDMA registers
+ * @drive: drive to tune
+ * @timing: timing info
+ *
+ * Program the PIO/MWDMA timing for this channel according to the
+ * current clock.
+ */
+
+static void it821x_program(ide_drive_t *drive, u16 timing)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+ struct it821x_dev *itdev = ide_get_hwifdata(hwif);
+ int channel = hwif->channel;
+ u8 conf;
+
+ /* Program PIO/MWDMA timing bits */
+ if(itdev->clock_mode == ATA_66)
+ conf = timing >> 8;
+ else
+ conf = timing & 0xFF;
+
+ pci_write_config_byte(dev, 0x54 + 4 * channel, conf);
+}
+
+/**
+ * it821x_program_udma - program the UDMA registers
+ * @drive: drive to tune
+ * @timing: timing info
+ *
+ * Program the UDMA timing for this drive according to the
+ * current clock.
+ */
+
+static void it821x_program_udma(ide_drive_t *drive, u16 timing)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+ struct it821x_dev *itdev = ide_get_hwifdata(hwif);
+ int channel = hwif->channel;
+ u8 unit = drive->dn & 1, 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(dev, 0x56 + 4 * channel + unit, conf);
+ else {
+ pci_write_config_byte(dev, 0x56 + 4 * channel, conf);
+ pci_write_config_byte(dev, 0x56 + 4 * channel + 1, conf);
+ }
+}
+
+/**
+ * it821x_clock_strategy
+ * @drive: drive to set up
+ *
+ * Select between the 50 and 66Mhz base clocks to get the best
+ * results for this interface.
+ */
+
+static void it821x_clock_strategy(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+ struct it821x_dev *itdev = ide_get_hwifdata(hwif);
+ ide_drive_t *pair;
+ int clock, altclock, sel = 0;
+ u8 unit = drive->dn & 1, v;
+
+ pair = &hwif->drives[1 - unit];
+
+ 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];
+ }
+
+ /*
+ * if both clocks can be used for the mode with the higher priority
+ * use the clock needed by the mode with the lower priority
+ */
+ 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(dev, 0x50, &v);
+ v &= ~(1 << (1 + hwif->channel));
+ v |= sel << (1 + hwif->channel);
+ pci_write_config_byte(dev, 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(pair, itdev->udma[1-unit]);
+ it821x_program(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(drive, itdev->udma[unit]);
+ it821x_program(drive, itdev->pio[unit]);
+ }
+}
+
+/**
+ * it821x_set_pio_mode - set host controller for PIO mode
+ * @drive: drive
+ * @pio: PIO mode number
+ *
+ * Tune the host to the desired PIO mode taking into the consideration
+ * the maximum PIO mode supported by the other device on the cable.
+ */
+
+static void it821x_set_pio_mode(ide_drive_t *drive, const u8 pio)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ struct it821x_dev *itdev = ide_get_hwifdata(hwif);
+ ide_drive_t *pair;
+ u8 unit = drive->dn & 1, set_pio = pio;
+
+ /* Spec says 89 ref driver uses 88 */
+ static u16 pio_timings[]= { 0xAA88, 0xA382, 0xA181, 0x3332, 0x3121 };
+ static u8 pio_want[] = { ATA_66, ATA_66, ATA_66, ATA_66, ATA_ANY };
+
+ pair = &hwif->drives[1 - unit];
+
+ /*
+ * Compute the best PIO mode we can for a given device. We must
+ * pick a speed that does not cause problems with the other device
+ * on the cable.
+ */
+ if (pair) {
+ u8 pair_pio = ide_get_best_pio_mode(pair, 255, 4);
+ /* trim PIO to the slowest of the master/slave */
+ if (pair_pio < set_pio)
+ set_pio = pair_pio;
+ }
+
+ /* We prefer 66Mhz clock for PIO 0-3, don't care for PIO4 */
+ itdev->want[unit][1] = pio_want[set_pio];
+ itdev->want[unit][0] = 1; /* PIO is lowest priority */
+ itdev->pio[unit] = pio_timings[set_pio];
+ it821x_clock_strategy(drive);
+ it821x_program(drive, itdev->pio[unit]);
+}
+
+/**
+ * it821x_tune_mwdma - tune a channel for MWDMA
+ * @drive: drive to set up
+ * @mode_wanted: the target operating mode
+ *
+ * Load the timing settings for this device mode into the
+ * controller when doing MWDMA in pass through mode. The caller
+ * must manage the whole lack of per device MWDMA/PIO timings and
+ * the shared MWDMA/PIO timing register.
+ */
+
+static void it821x_tune_mwdma (ide_drive_t *drive, byte mode_wanted)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+ struct it821x_dev *itdev = (void *)ide_get_hwifdata(hwif);
+ u8 unit = drive->dn & 1, channel = hwif->channel, conf;
+
+ static u16 dma[] = { 0x8866, 0x3222, 0x3121 };
+ static u8 mwdma_want[] = { ATA_ANY, ATA_66, ATA_ANY };
+
+ 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(dev, 0x50, &conf);
+ if (itdev->timing10)
+ conf |= channel ? 0x60: 0x18;
+ else
+ conf |= 1 << (3 + 2 * channel + unit);
+ pci_write_config_byte(dev, 0x50, conf);
+
+ it821x_clock_strategy(drive);
+ /* FIXME: do we need to program this ? */
+ /* it821x_program(drive, itdev->mwdma[unit]); */
+}
+
+/**
+ * it821x_tune_udma - tune a channel for UDMA
+ * @drive: drive to set up
+ * @mode_wanted: the target operating mode
+ *
+ * Load the timing settings for this device mode into the
+ * controller when doing UDMA modes in pass through.
+ */
+
+static void it821x_tune_udma (ide_drive_t *drive, byte mode_wanted)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+ struct it821x_dev *itdev = ide_get_hwifdata(hwif);
+ u8 unit = drive->dn & 1, channel = hwif->channel, conf;
+
+ static u16 udma[] = { 0x4433, 0x4231, 0x3121, 0x2121, 0x1111, 0x2211, 0x1111 };
+ static u8 udma_want[] = { ATA_ANY, ATA_50, ATA_ANY, ATA_66, ATA_66, ATA_50, ATA_66 };
+
+ 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(dev, 0x50, &conf);
+ if (itdev->timing10)
+ conf &= channel ? 0x9F: 0xE7;
+ else
+ conf &= ~ (1 << (3 + 2 * channel + unit));
+ pci_write_config_byte(dev, 0x50, conf);
+
+ it821x_clock_strategy(drive);
+ it821x_program_udma(drive, itdev->udma[unit]);
+
+}
+
+/**
+ * it821x_dma_read - DMA hook
+ * @drive: drive for DMA
+ *
+ * The IT821x has a single timing register for MWDMA and for PIO
+ * operations. As we flip back and forth we have to reload the
+ * clock. In addition the rev 0x10 device only works if the same
+ * timing value is loaded into the master and slave UDMA clock
+ * so we must also reload that.
+ *
+ * FIXME: we could figure out in advance if we need to do reloads
+ */
+
+static void it821x_dma_start(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ struct it821x_dev *itdev = ide_get_hwifdata(hwif);
+ u8 unit = drive->dn & 1;
+
+ if(itdev->mwdma[unit] != MWDMA_OFF)
+ it821x_program(drive, itdev->mwdma[unit]);
+ else if(itdev->udma[unit] != UDMA_OFF && itdev->timing10)
+ it821x_program_udma(drive, itdev->udma[unit]);
+ ide_dma_start(drive);
+}
+
+/**
+ * it821x_dma_write - DMA hook
+ * @drive: drive for DMA stop
+ *
+ * The IT821x has a single timing register for MWDMA and for PIO
+ * operations. As we flip back and forth we have to reload the
+ * clock.
+ */
+
+static int it821x_dma_end(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ struct it821x_dev *itdev = ide_get_hwifdata(hwif);
+ int ret = ide_dma_end(drive);
+ u8 unit = drive->dn & 1;
+
+ if(itdev->mwdma[unit] != MWDMA_OFF)
+ it821x_program(drive, itdev->pio[unit]);
+ return ret;
+}
+
+/**
+ * it821x_set_dma_mode - set host controller for DMA mode
+ * @drive: drive
+ * @speed: DMA mode
+ *
+ * Tune the ITE chipset for the desired DMA mode.
+ */
+
+static void it821x_set_dma_mode(ide_drive_t *drive, const u8 speed)
+{
+ /*
+ * MWDMA tuning is really hard because our MWDMA and PIO
+ * timings are kept in the same place. We can switch in the
+ * host dma on/off callbacks.
+ */
+ if (speed >= XFER_UDMA_0 && speed <= XFER_UDMA_6)
+ it821x_tune_udma(drive, speed - XFER_UDMA_0);
+ else if (speed >= XFER_MW_DMA_0 && speed <= XFER_MW_DMA_2)
+ it821x_tune_mwdma(drive, speed - XFER_MW_DMA_0);
+}
+
+/**
+ * it821x_cable_detect - cable detection
+ * @hwif: interface to check
+ *
+ * Check for the presence of an ATA66 capable cable on the
+ * interface. Problematic as it seems some cards don't have
+ * the needed logic onboard.
+ */
+
+static u8 it821x_cable_detect(ide_hwif_t *hwif)
+{
+ /* The reference driver also only does disk side */
+ return ATA_CBL_PATA80;
+}
+
+/**
+ * it821x_quirkproc - post init callback
+ * @drive: drive
+ *
+ * This callback is run after the drive has been probed but
+ * before anything gets attached. It allows drivers to do any
+ * final tuning that is needed, or fixups to work around bugs.
+ */
+
+static void it821x_quirkproc(ide_drive_t *drive)
+{
+ struct it821x_dev *itdev = ide_get_hwifdata(drive->hwif);
+ u16 *id = drive->id;
+
+ if (!itdev->smart) {
+ /*
+ * If we are in pass through mode then not much
+ * needs to be done, but we do bother to clear the
+ * IRQ mask as we may well be in PIO (eg rev 0x10)
+ * for now and we know unmasking is safe on this chipset.
+ */
+ drive->dev_flags |= IDE_DFLAG_UNMASK;
+ } else {
+ /*
+ * Perform fixups on smart mode. We need to "lose" some
+ * capabilities the firmware lacks but does not filter, and
+ * also patch up some capability bits that it forgets to set
+ * in RAID mode.
+ */
+
+ /* Check for RAID v native */
+ if (strstr((char *)&id[ATA_ID_PROD],
+ "Integrated Technology Express")) {
+ /* In raid mode the ident block is slightly buggy
+ We need to set the bits so that the IDE layer knows
+ LBA28. LBA48 and DMA ar valid */
+ id[ATA_ID_CAPABILITY] |= (3 << 8); /* LBA28, DMA */
+ id[ATA_ID_COMMAND_SET_2] |= 0x0400; /* LBA48 valid */
+ id[ATA_ID_CFS_ENABLE_2] |= 0x0400; /* LBA48 on */
+ /* Reporting logic */
+ printk(KERN_INFO "%s: IT8212 %sRAID %d volume",
+ drive->name, id[147] ? "Bootable " : "",
+ id[ATA_ID_CSFO]);
+ if (id[ATA_ID_CSFO] != 1)
+ printk(KERN_CONT "(%dK stripe)", id[146]);
+ printk(KERN_CONT ".\n");
+ } else {
+ /* Non RAID volume. Fixups to stop the core code
+ doing unsupported things */
+ id[ATA_ID_FIELD_VALID] &= 3;
+ id[ATA_ID_QUEUE_DEPTH] = 0;
+ id[ATA_ID_COMMAND_SET_1] = 0;
+ id[ATA_ID_COMMAND_SET_2] &= 0xC400;
+ id[ATA_ID_CFSSE] &= 0xC000;
+ id[ATA_ID_CFS_ENABLE_1] = 0;
+ id[ATA_ID_CFS_ENABLE_2] &= 0xC400;
+ id[ATA_ID_CSF_DEFAULT] &= 0xC000;
+ id[127] = 0;
+ id[ATA_ID_DLF] = 0;
+ id[ATA_ID_CSFO] = 0;
+ id[ATA_ID_CFA_POWER] = 0;
+ printk(KERN_INFO "%s: Performing identify fixups.\n",
+ drive->name);
+ }
+
+ /*
+ * Set MWDMA0 mode as enabled/support - just to tell
+ * IDE core that DMA is supported (it821x hardware
+ * takes care of DMA mode programming).
+ */
+ if (ata_id_has_dma(id)) {
+ id[ATA_ID_MWDMA_MODES] |= 0x0101;
+ drive->current_speed = XFER_MW_DMA_0;
+ }
+ }
+
+}
+
+static struct ide_dma_ops it821x_pass_through_dma_ops = {
+ .dma_host_set = ide_dma_host_set,
+ .dma_setup = ide_dma_setup,
+ .dma_exec_cmd = ide_dma_exec_cmd,
+ .dma_start = it821x_dma_start,
+ .dma_end = it821x_dma_end,
+ .dma_test_irq = ide_dma_test_irq,
+ .dma_timeout = ide_dma_timeout,
+ .dma_lost_irq = ide_dma_lost_irq,
+};
+
+/**
+ * init_hwif_it821x - set up hwif structs
+ * @hwif: interface to set up
+ *
+ * We do the basic set up of the interface structure. The IT8212
+ * requires several custom handlers so we override the default
+ * ide DMA handlers appropriately
+ */
+
+static void __devinit init_hwif_it821x(ide_hwif_t *hwif)
+{
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+ struct ide_host *host = pci_get_drvdata(dev);
+ struct it821x_dev *itdevs = host->host_priv;
+ struct it821x_dev *idev = itdevs + hwif->channel;
+ u8 conf;
+
+ ide_set_hwifdata(hwif, idev);
+
+ pci_read_config_byte(dev, 0x50, &conf);
+ if (conf & 1) {
+ idev->smart = 1;
+ hwif->host_flags |= IDE_HFLAG_NO_ATAPI_DMA;
+ /* Long I/O's although allowed in LBA48 space cause the
+ onboard firmware to enter the twighlight zone */
+ hwif->rqsize = 256;
+ }
+
+ /* Pull the current clocks from 0x50 also */
+ if (conf & (1 << (1 + hwif->channel)))
+ idev->clock_mode = ATA_50;
+ else
+ idev->clock_mode = ATA_66;
+
+ idev->want[0][1] = ATA_ANY;
+ idev->want[1][1] = ATA_ANY;
+
+ /*
+ * Not in the docs but according to the reference driver
+ * this is necessary.
+ */
+
+ pci_read_config_byte(dev, 0x08, &conf);
+ if (conf == 0x10) {
+ idev->timing10 = 1;
+ hwif->host_flags |= IDE_HFLAG_NO_ATAPI_DMA;
+ if (idev->smart == 0)
+ printk(KERN_WARNING DRV_NAME " %s: revision 0x10, "
+ "workarounds activated\n", pci_name(dev));
+ }
+
+ if (idev->smart == 0) {
+ /* MWDMA/PIO clock switching for pass through mode */
+ hwif->dma_ops = &it821x_pass_through_dma_ops;
+ } else
+ hwif->host_flags |= IDE_HFLAG_NO_SET_MODE;
+
+ if (hwif->dma_base == 0)
+ return;
+
+ hwif->ultra_mask = ATA_UDMA6;
+ hwif->mwdma_mask = ATA_MWDMA2;
+
+ /* Vortex86SX quirk: prevent Ultra-DMA mode to fix BadCRC issue */
+ if (idev->quirks & QUIRK_VORTEX86) {
+ if (dev->revision == 0x11)
+ hwif->ultra_mask = 0;
+ }
+}
+
+static void it8212_disable_raid(struct pci_dev *dev)
+{
+ /* Reset local CPU, and set BIOS not ready */
+ pci_write_config_byte(dev, 0x5E, 0x01);
+
+ /* Set to bypass mode, and reset PCI bus */
+ pci_write_config_byte(dev, 0x50, 0x00);
+ pci_write_config_word(dev, PCI_COMMAND,
+ PCI_COMMAND_PARITY | PCI_COMMAND_IO |
+ PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
+ pci_write_config_word(dev, 0x40, 0xA0F3);
+
+ pci_write_config_dword(dev,0x4C, 0x02040204);
+ pci_write_config_byte(dev, 0x42, 0x36);
+ pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x20);
+}
+
+static unsigned int init_chipset_it821x(struct pci_dev *dev)
+{
+ u8 conf;
+ static char *mode[2] = { "pass through", "smart" };
+
+ /* Force the card into bypass mode if so requested */
+ if (it8212_noraid) {
+ printk(KERN_INFO DRV_NAME " %s: forcing bypass mode\n",
+ pci_name(dev));
+ it8212_disable_raid(dev);
+ }
+ pci_read_config_byte(dev, 0x50, &conf);
+ printk(KERN_INFO DRV_NAME " %s: controller in %s mode\n",
+ pci_name(dev), mode[conf & 1]);
+ return 0;
+}
+
+static const struct ide_port_ops it821x_port_ops = {
+ /* it821x_set_{pio,dma}_mode() are only used in pass-through mode */
+ .set_pio_mode = it821x_set_pio_mode,
+ .set_dma_mode = it821x_set_dma_mode,
+ .quirkproc = it821x_quirkproc,
+ .cable_detect = it821x_cable_detect,
+};
+
+static const struct ide_port_info it821x_chipset __devinitdata = {
+ .name = DRV_NAME,
+ .init_chipset = init_chipset_it821x,
+ .init_hwif = init_hwif_it821x,
+ .port_ops = &it821x_port_ops,
+ .pio_mask = ATA_PIO4,
+};
+
+/**
+ * it821x_init_one - pci layer discovery entry
+ * @dev: PCI device
+ * @id: ident table entry
+ *
+ * Called by the PCI code when it finds an ITE821x controller.
+ * We then use the IDE PCI generic helper to do most of the work.
+ */
+
+static int __devinit it821x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ struct it821x_dev *itdevs;
+ int rc;
+
+ itdevs = kzalloc(2 * sizeof(*itdevs), GFP_KERNEL);
+ if (itdevs == NULL) {
+ printk(KERN_ERR DRV_NAME " %s: out of memory\n", pci_name(dev));
+ return -ENOMEM;
+ }
+
+ itdevs->quirks = id->driver_data;
+
+ rc = ide_pci_init_one(dev, &it821x_chipset, itdevs);
+ if (rc)
+ kfree(itdevs);
+
+ return rc;
+}
+
+static void __devexit it821x_remove(struct pci_dev *dev)
+{
+ struct ide_host *host = pci_get_drvdata(dev);
+ struct it821x_dev *itdevs = host->host_priv;
+
+ ide_pci_remove(dev);
+ kfree(itdevs);
+}
+
+static const struct pci_device_id it821x_pci_tbl[] = {
+ { PCI_VDEVICE(ITE, PCI_DEVICE_ID_ITE_8211), 0 },
+ { PCI_VDEVICE(ITE, PCI_DEVICE_ID_ITE_8212), 0 },
+ { PCI_VDEVICE(RDC, PCI_DEVICE_ID_RDC_D1010), QUIRK_VORTEX86 },
+ { 0, },
+};
+
+MODULE_DEVICE_TABLE(pci, it821x_pci_tbl);
+
+static struct pci_driver it821x_pci_driver = {
+ .name = "ITE821x IDE",
+ .id_table = it821x_pci_tbl,
+ .probe = it821x_init_one,
+ .remove = __devexit_p(it821x_remove),
+ .suspend = ide_pci_suspend,
+ .resume = ide_pci_resume,
+};
+
+static int __init it821x_ide_init(void)
+{
+ return ide_pci_register_driver(&it821x_pci_driver);
+}
+
+static void __exit it821x_ide_exit(void)
+{
+ pci_unregister_driver(&it821x_pci_driver);
+}
+
+module_init(it821x_ide_init);
+module_exit(it821x_ide_exit);
+
+module_param_named(noraid, it8212_noraid, int, S_IRUGO);
+MODULE_PARM_DESC(noraid, "Force card into bypass mode");
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("PCI driver module for the ITE 821x");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/jmicron.c b/drivers/ide/jmicron.c
new file mode 100644
index 0000000..bf2be64
--- /dev/null
+++ b/drivers/ide/jmicron.c
@@ -0,0 +1,176 @@
+
+/*
+ * Copyright (C) 2006 Red Hat
+ *
+ * May be copied or modified under the terms of the GNU General Public License
+ */
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#define DRV_NAME "jmicron"
+
+typedef enum {
+ PORT_PATA0 = 0,
+ PORT_PATA1 = 1,
+ PORT_SATA = 2,
+} port_type;
+
+/**
+ * jmicron_cable_detect - cable detection
+ * @hwif: IDE port
+ *
+ * Returns the cable type.
+ */
+
+static u8 jmicron_cable_detect(ide_hwif_t *hwif)
+{
+ struct pci_dev *pdev = to_pci_dev(hwif->dev);
+
+ u32 control;
+ u32 control5;
+
+ int port = hwif->channel;
+ port_type port_map[2];
+
+ pci_read_config_dword(pdev, 0x40, &control);
+
+ /* 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 << 3)) /* 40/80 pin primary */
+ return ATA_CBL_PATA40;
+ return ATA_CBL_PATA80;
+ case PORT_PATA1:
+ if (control5 & (1 << 19)) /* 40/80 pin secondary */
+ return ATA_CBL_PATA40;
+ return ATA_CBL_PATA80;
+ case PORT_SATA:
+ break;
+ }
+ /* Avoid bogus "control reaches end of non-void function" */
+ return ATA_CBL_PATA80;
+}
+
+static void jmicron_set_pio_mode(ide_drive_t *drive, const u8 pio)
+{
+}
+
+/**
+ * jmicron_set_dma_mode - set host controller for DMA mode
+ * @drive: drive
+ * @mode: DMA mode
+ *
+ * As the JMicron snoops for timings we don't need to do anything here.
+ */
+
+static void jmicron_set_dma_mode(ide_drive_t *drive, const u8 mode)
+{
+}
+
+static const struct ide_port_ops jmicron_port_ops = {
+ .set_pio_mode = jmicron_set_pio_mode,
+ .set_dma_mode = jmicron_set_dma_mode,
+ .cable_detect = jmicron_cable_detect,
+};
+
+static const struct ide_port_info jmicron_chipset __devinitdata = {
+ .name = DRV_NAME,
+ .enablebits = { { 0x40, 0x01, 0x01 }, { 0x40, 0x10, 0x10 } },
+ .port_ops = &jmicron_port_ops,
+ .pio_mask = ATA_PIO5,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA6,
+};
+
+/**
+ * jmicron_init_one - pci layer discovery entry
+ * @dev: PCI device
+ * @id: ident table entry
+ *
+ * Called by the PCI code when it finds a Jmicron controller.
+ * We then use the IDE PCI generic helper to do most of the work.
+ */
+
+static int __devinit jmicron_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ return ide_pci_init_one(dev, &jmicron_chipset, NULL);
+}
+
+/* All JMB PATA controllers have and will continue to have the same
+ * interface. Matching vendor and device class is enough for all
+ * current and future controllers if the controller is programmed
+ * properly.
+ *
+ * If libata is configured, jmicron PCI quirk programs the controller
+ * into the correct mode. If libata isn't configured, match known
+ * device IDs too to maintain backward compatibility.
+ */
+static struct pci_device_id jmicron_pci_tbl[] = {
+#if !defined(CONFIG_ATA) && !defined(CONFIG_ATA_MODULE)
+ { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB361) },
+ { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB363) },
+ { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB365) },
+ { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB366) },
+ { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB368) },
+#endif
+ { PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
+ PCI_CLASS_STORAGE_IDE << 8, 0xffff00, 0 },
+ { 0, },
+};
+
+MODULE_DEVICE_TABLE(pci, jmicron_pci_tbl);
+
+static struct pci_driver jmicron_pci_driver = {
+ .name = "JMicron IDE",
+ .id_table = jmicron_pci_tbl,
+ .probe = jmicron_init_one,
+ .remove = ide_pci_remove,
+ .suspend = ide_pci_suspend,
+ .resume = ide_pci_resume,
+};
+
+static int __init jmicron_ide_init(void)
+{
+ return ide_pci_register_driver(&jmicron_pci_driver);
+}
+
+static void __exit jmicron_ide_exit(void)
+{
+ pci_unregister_driver(&jmicron_pci_driver);
+}
+
+module_init(jmicron_ide_init);
+module_exit(jmicron_ide_exit);
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("PCI driver module for the JMicron in legacy modes");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/macide.c b/drivers/ide/macide.c
new file mode 100644
index 0000000..43f97cc
--- /dev/null
+++ b/drivers/ide/macide.c
@@ -0,0 +1,131 @@
+/*
+ * Macintosh IDE Driver
+ *
+ * Copyright (C) 1998 by Michael Schmitz
+ *
+ * This driver was written based on information obtained from the MacOS IDE
+ * driver binary by Mikael Forselius
+ *
+ * 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/types.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/ide.h>
+
+#include <asm/machw.h>
+#include <asm/macintosh.h>
+#include <asm/macints.h>
+#include <asm/mac_baboon.h>
+
+#define IDE_BASE 0x50F1A000 /* Base address of IDE controller */
+
+/*
+ * Generic IDE registers as offsets from the base
+ * These match MkLinux so they should be correct.
+ */
+
+#define IDE_CONTROL 0x38 /* control/altstatus */
+
+/*
+ * Mac-specific registers
+ */
+
+/*
+ * this register is odd; it doesn't seem to do much and it's
+ * not word-aligned like virtually every other hardware register
+ * on the Mac...
+ */
+
+#define IDE_IFR 0x101 /* (0x101) IDE interrupt flags on Quadra:
+ *
+ * Bit 0+1: some interrupt flags
+ * Bit 2+3: some interrupt enable
+ * Bit 4: ??
+ * Bit 5: IDE interrupt flag (any hwif)
+ * Bit 6: maybe IDE interrupt enable (any hwif) ??
+ * Bit 7: Any interrupt condition
+ */
+
+volatile unsigned char *ide_ifr = (unsigned char *) (IDE_BASE + IDE_IFR);
+
+int macide_ack_intr(ide_hwif_t* hwif)
+{
+ if (*ide_ifr & 0x20) {
+ *ide_ifr &= ~0x20;
+ return 1;
+ }
+ return 0;
+}
+
+static void __init macide_setup_ports(hw_regs_t *hw, unsigned long base,
+ int irq, ide_ack_intr_t *ack_intr)
+{
+ int i;
+
+ memset(hw, 0, sizeof(*hw));
+
+ for (i = 0; i < 8; i++)
+ hw->io_ports_array[i] = base + i * 4;
+
+ hw->io_ports.ctl_addr = base + IDE_CONTROL;
+
+ hw->irq = irq;
+ hw->ack_intr = ack_intr;
+
+ hw->chipset = ide_generic;
+}
+
+static const char *mac_ide_name[] =
+ { "Quadra", "Powerbook", "Powerbook Baboon" };
+
+/*
+ * Probe for a Macintosh IDE interface
+ */
+
+static int __init macide_init(void)
+{
+ ide_ack_intr_t *ack_intr;
+ unsigned long base;
+ int irq;
+ hw_regs_t hw, *hws[] = { &hw, NULL, NULL, NULL };
+
+ if (!MACH_IS_MAC)
+ return -ENODEV;
+
+ switch (macintosh_config->ide_type) {
+ case MAC_IDE_QUADRA:
+ base = IDE_BASE;
+ ack_intr = macide_ack_intr;
+ irq = IRQ_NUBUS_F;
+ break;
+ case MAC_IDE_PB:
+ base = IDE_BASE;
+ ack_intr = macide_ack_intr;
+ irq = IRQ_NUBUS_C;
+ break;
+ case MAC_IDE_BABOON:
+ base = BABOON_BASE;
+ ack_intr = NULL;
+ irq = IRQ_BABOON_1;
+ break;
+ default:
+ return -ENODEV;
+ }
+
+ printk(KERN_INFO "ide: Macintosh %s IDE controller\n",
+ mac_ide_name[macintosh_config->ide_type - 1]);
+
+ macide_setup_ports(&hw, base, irq, ack_intr);
+
+ return ide_host_add(NULL, hws, NULL);
+}
+
+module_init(macide_init);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/ns87415.c b/drivers/ide/ns87415.c
new file mode 100644
index 0000000..1378906
--- /dev/null
+++ b/drivers/ide/ns87415.c
@@ -0,0 +1,366 @@
+/*
+ * Copyright (C) 1997-1998 Mark Lord <mlord@pobox.com>
+ * Copyright (C) 1998 Eddie C. Dost <ecd@skynet.be>
+ * Copyright (C) 1999-2000 Andre Hedrick <andre@linux-ide.org>
+ * Copyright (C) 2004 Grant Grundler <grundler at parisc-linux.org>
+ *
+ * Inspired by an earlier effort from David S. Miller <davem@redhat.com>
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#define DRV_NAME "ns87415"
+
+#ifdef CONFIG_SUPERIO
+/* SUPERIO 87560 is a PoS chip that NatSem denies exists.
+ * Unfortunately, it's built-in on all Astro-based PA-RISC workstations
+ * which use the integrated NS87514 cell for CD-ROM support.
+ * i.e we have to support for CD-ROM installs.
+ * See drivers/parisc/superio.c for more gory details.
+ */
+#include <asm/superio.h>
+
+#define SUPERIO_IDE_MAX_RETRIES 25
+
+/* Because of a defect in Super I/O, all reads of the PCI DMA status
+ * registers, IDE status register and the IDE select register need to be
+ * retried
+ */
+static u8 superio_ide_inb (unsigned long port)
+{
+ u8 tmp;
+ int retries = SUPERIO_IDE_MAX_RETRIES;
+
+ /* printk(" [ reading port 0x%x with retry ] ", port); */
+
+ do {
+ tmp = inb(port);
+ if (tmp == 0)
+ udelay(50);
+ } while (tmp == 0 && retries-- > 0);
+
+ return tmp;
+}
+
+static u8 superio_read_status(ide_hwif_t *hwif)
+{
+ return superio_ide_inb(hwif->io_ports.status_addr);
+}
+
+static u8 superio_read_sff_dma_status(ide_hwif_t *hwif)
+{
+ return superio_ide_inb(hwif->dma_base + ATA_DMA_STATUS);
+}
+
+static void superio_tf_read(ide_drive_t *drive, ide_task_t *task)
+{
+ struct ide_io_ports *io_ports = &drive->hwif->io_ports;
+ struct ide_taskfile *tf = &task->tf;
+
+ if (task->tf_flags & IDE_TFLAG_IN_DATA) {
+ u16 data = inw(io_ports->data_addr);
+
+ tf->data = data & 0xff;
+ tf->hob_data = (data >> 8) & 0xff;
+ }
+
+ /* be sure we're looking at the low order bits */
+ outb(ATA_DEVCTL_OBS & ~0x80, io_ports->ctl_addr);
+
+ if (task->tf_flags & IDE_TFLAG_IN_FEATURE)
+ tf->feature = inb(io_ports->feature_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_NSECT)
+ tf->nsect = inb(io_ports->nsect_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_LBAL)
+ tf->lbal = inb(io_ports->lbal_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_LBAM)
+ tf->lbam = inb(io_ports->lbam_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_LBAH)
+ tf->lbah = inb(io_ports->lbah_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_DEVICE)
+ tf->device = superio_ide_inb(io_ports->device_addr);
+
+ if (task->tf_flags & IDE_TFLAG_LBA48) {
+ outb(ATA_DEVCTL_OBS | 0x80, io_ports->ctl_addr);
+
+ if (task->tf_flags & IDE_TFLAG_IN_HOB_FEATURE)
+ tf->hob_feature = inb(io_ports->feature_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_HOB_NSECT)
+ tf->hob_nsect = inb(io_ports->nsect_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAL)
+ tf->hob_lbal = inb(io_ports->lbal_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAM)
+ tf->hob_lbam = inb(io_ports->lbam_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAH)
+ tf->hob_lbah = inb(io_ports->lbah_addr);
+ }
+}
+
+static const struct ide_tp_ops superio_tp_ops = {
+ .exec_command = ide_exec_command,
+ .read_status = superio_read_status,
+ .read_altstatus = ide_read_altstatus,
+ .read_sff_dma_status = superio_read_sff_dma_status,
+
+ .set_irq = ide_set_irq,
+
+ .tf_load = ide_tf_load,
+ .tf_read = superio_tf_read,
+
+ .input_data = ide_input_data,
+ .output_data = ide_output_data,
+};
+
+static void __devinit superio_init_iops(struct hwif_s *hwif)
+{
+ struct pci_dev *pdev = to_pci_dev(hwif->dev);
+ u32 dma_stat;
+ u8 port = hwif->channel, tmp;
+
+ dma_stat = (pci_resource_start(pdev, 4) & ~3) + (!port ? 2 : 0xa);
+
+ /* Clear error/interrupt, enable dma */
+ tmp = superio_ide_inb(dma_stat);
+ outb(tmp | 0x66, dma_stat);
+}
+#endif
+
+static unsigned int ns87415_count = 0, ns87415_control[MAX_HWIFS] = { 0 };
+
+/*
+ * This routine either enables/disables (according to IDE_DFLAG_PRESENT)
+ * the IRQ associated with the port (HWIF(drive)),
+ * and selects either PIO or DMA handshaking for the next I/O operation.
+ */
+static void ns87415_prepare_drive (ide_drive_t *drive, unsigned int use_dma)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+ unsigned int bit, other, new, *old = (unsigned int *) hwif->select_data;
+ unsigned long flags;
+
+ local_irq_save(flags);
+ new = *old;
+
+ /* Adjust IRQ enable bit */
+ bit = 1 << (8 + hwif->channel);
+
+ if (drive->dev_flags & IDE_DFLAG_PRESENT)
+ new &= ~bit;
+ else
+ new |= bit;
+
+ /* Select PIO or DMA, DMA may only be selected for one drive/channel. */
+ bit = 1 << (20 + (drive->dn & 1) + (hwif->channel << 1));
+ other = 1 << (20 + (1 - (drive->dn & 1)) + (hwif->channel << 1));
+ new = use_dma ? ((new & ~other) | bit) : (new & ~bit);
+
+ if (new != *old) {
+ unsigned char stat;
+
+ /*
+ * Don't change DMA engine settings while Write Buffers
+ * are busy.
+ */
+ (void) pci_read_config_byte(dev, 0x43, &stat);
+ while (stat & 0x03) {
+ udelay(1);
+ (void) pci_read_config_byte(dev, 0x43, &stat);
+ }
+
+ *old = new;
+ (void) pci_write_config_dword(dev, 0x40, new);
+
+ /*
+ * And let things settle...
+ */
+ udelay(10);
+ }
+
+ local_irq_restore(flags);
+}
+
+static void ns87415_selectproc (ide_drive_t *drive)
+{
+ ns87415_prepare_drive(drive,
+ !!(drive->dev_flags & IDE_DFLAG_USING_DMA));
+}
+
+static int ns87415_dma_end(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ u8 dma_stat = 0, dma_cmd = 0;
+
+ drive->waiting_for_dma = 0;
+ dma_stat = hwif->tp_ops->read_sff_dma_status(hwif);
+ /* get DMA command mode */
+ dma_cmd = inb(hwif->dma_base + ATA_DMA_CMD);
+ /* stop DMA */
+ outb(dma_cmd & ~1, hwif->dma_base + ATA_DMA_CMD);
+ /* from ERRATA: clear the INTR & ERROR bits */
+ dma_cmd = inb(hwif->dma_base + ATA_DMA_CMD);
+ outb(dma_cmd | 6, hwif->dma_base + ATA_DMA_CMD);
+ /* and free any DMA resources */
+ ide_destroy_dmatable(drive);
+ /* verify good DMA status */
+ return (dma_stat & 7) != 4;
+}
+
+static int ns87415_dma_setup(ide_drive_t *drive)
+{
+ /* select DMA xfer */
+ ns87415_prepare_drive(drive, 1);
+ if (!ide_dma_setup(drive))
+ return 0;
+ /* DMA failed: select PIO xfer */
+ ns87415_prepare_drive(drive, 0);
+ return 1;
+}
+
+static void __devinit init_hwif_ns87415 (ide_hwif_t *hwif)
+{
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+ unsigned int ctrl, using_inta;
+ u8 progif;
+#ifdef __sparc_v9__
+ int timeout;
+ u8 stat;
+#endif
+
+ /*
+ * We cannot probe for IRQ: both ports share common IRQ on INTA.
+ * Also, leave IRQ masked during drive probing, to prevent infinite
+ * interrupts from a potentially floating INTA..
+ *
+ * IRQs get unmasked in selectproc when drive is first used.
+ */
+ (void) pci_read_config_dword(dev, 0x40, &ctrl);
+ (void) pci_read_config_byte(dev, 0x09, &progif);
+ /* is irq in "native" mode? */
+ using_inta = progif & (1 << (hwif->channel << 1));
+ if (!using_inta)
+ using_inta = ctrl & (1 << (4 + hwif->channel));
+ if (hwif->mate) {
+ hwif->select_data = hwif->mate->select_data;
+ } else {
+ hwif->select_data = (unsigned long)
+ &ns87415_control[ns87415_count++];
+ ctrl |= (1 << 8) | (1 << 9); /* mask both IRQs */
+ if (using_inta)
+ ctrl &= ~(1 << 6); /* unmask INTA */
+ *((unsigned int *)hwif->select_data) = ctrl;
+ (void) pci_write_config_dword(dev, 0x40, ctrl);
+
+ /*
+ * Set prefetch size to 512 bytes for both ports,
+ * but don't turn on/off prefetching here.
+ */
+ pci_write_config_byte(dev, 0x55, 0xee);
+
+#ifdef __sparc_v9__
+ /*
+ * XXX: Reset the device, if we don't it will not respond to
+ * SELECT_DRIVE() properly during first ide_probe_port().
+ */
+ timeout = 10000;
+ outb(12, hwif->io_ports.ctl_addr);
+ udelay(10);
+ outb(8, hwif->io_ports.ctl_addr);
+ do {
+ udelay(50);
+ stat = hwif->tp_ops->read_status(hwif);
+ if (stat == 0xff)
+ break;
+ } while ((stat & ATA_BUSY) && --timeout);
+#endif
+ }
+
+ if (!using_inta)
+ hwif->irq = __ide_default_irq(hwif->io_ports.data_addr);
+ else if (!hwif->irq && hwif->mate && hwif->mate->irq)
+ hwif->irq = hwif->mate->irq; /* share IRQ with mate */
+
+ if (!hwif->dma_base)
+ return;
+
+ outb(0x60, hwif->dma_base + ATA_DMA_STATUS);
+}
+
+static const struct ide_port_ops ns87415_port_ops = {
+ .selectproc = ns87415_selectproc,
+};
+
+static const struct ide_dma_ops ns87415_dma_ops = {
+ .dma_host_set = ide_dma_host_set,
+ .dma_setup = ns87415_dma_setup,
+ .dma_exec_cmd = ide_dma_exec_cmd,
+ .dma_start = ide_dma_start,
+ .dma_end = ns87415_dma_end,
+ .dma_test_irq = ide_dma_test_irq,
+ .dma_lost_irq = ide_dma_lost_irq,
+ .dma_timeout = ide_dma_timeout,
+};
+
+static const struct ide_port_info ns87415_chipset __devinitdata = {
+ .name = DRV_NAME,
+ .init_hwif = init_hwif_ns87415,
+ .port_ops = &ns87415_port_ops,
+ .dma_ops = &ns87415_dma_ops,
+ .host_flags = IDE_HFLAG_TRUST_BIOS_FOR_DMA |
+ IDE_HFLAG_NO_ATAPI_DMA,
+};
+
+static int __devinit ns87415_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ struct ide_port_info d = ns87415_chipset;
+
+#ifdef CONFIG_SUPERIO
+ if (PCI_SLOT(dev->devfn) == 0xE) {
+ /* Built-in - assume it's under superio. */
+ d.init_iops = superio_init_iops;
+ d.tp_ops = &superio_tp_ops;
+ }
+#endif
+ return ide_pci_init_one(dev, &d, NULL);
+}
+
+static const struct pci_device_id ns87415_pci_tbl[] = {
+ { PCI_VDEVICE(NS, PCI_DEVICE_ID_NS_87415), 0 },
+ { 0, },
+};
+MODULE_DEVICE_TABLE(pci, ns87415_pci_tbl);
+
+static struct pci_driver ns87415_pci_driver = {
+ .name = "NS87415_IDE",
+ .id_table = ns87415_pci_tbl,
+ .probe = ns87415_init_one,
+ .remove = ide_pci_remove,
+ .suspend = ide_pci_suspend,
+ .resume = ide_pci_resume,
+};
+
+static int __init ns87415_ide_init(void)
+{
+ return ide_pci_register_driver(&ns87415_pci_driver);
+}
+
+static void __exit ns87415_ide_exit(void)
+{
+ pci_unregister_driver(&ns87415_pci_driver);
+}
+
+module_init(ns87415_ide_init);
+module_exit(ns87415_ide_exit);
+
+MODULE_AUTHOR("Mark Lord, Eddie Dost, Andre Hedrick");
+MODULE_DESCRIPTION("PCI driver module for NS87415 IDE");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/opti621.c b/drivers/ide/opti621.c
new file mode 100644
index 0000000..6048eda
--- /dev/null
+++ b/drivers/ide/opti621.c
@@ -0,0 +1,247 @@
+/*
+ * 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.
+ *
+ * OPTi is trademark of OPTi, Octek is trademark of Octek.
+ *
+ * I used docs from OPTi databook, from ftp.opti.com, file 9123-0002.ps
+ * and disassembled/traced setupvic.exe (DOS program).
+ * It increases kernel code about 2 kB.
+ * I don't have this card no more, but I hope I can get some in case
+ * of needed development.
+ * My card is Octek PIDE 1.01 (on card) or OPTiViC (program).
+ * It has a place for a secondary connector in circuit, but nothing
+ * is there. Also BIOS says no address for
+ * secondary controller (see bellow in ide_init_opti621).
+ * I've only tested this on my system, which only has one disk.
+ * It's Western Digital WDAC2850, with PIO mode 3. The PCI bus
+ * is at 20 MHz (I have DX2/80, I tried PCI at 40, but I got random
+ * lockups). I tried the OCTEK double speed CD-ROM and
+ * it does not work! But I can't boot DOS also, so it's probably
+ * hardware fault. I have connected Conner 80MB, the Seagate 850MB (no
+ * problems) and Seagate 1GB (as slave, WD as master). My experiences
+ * with the third, 1GB drive: I got 3MB/s (hdparm), but sometimes
+ * it slows to about 100kB/s! I don't know why and I have
+ * not this drive now, so I can't try it again.
+ * I write this driver because I lost the paper ("manual") with
+ * settings of jumpers on the card and I have to boot Linux with
+ * Loadlin except LILO, cause I have to run the setupvic.exe program
+ * already or I get disk errors (my test: rpm -Vf
+ * /usr/X11R6/bin/XF86_SVGA - or any big file).
+ * Some numbers from hdparm -t /dev/hda:
+ * Timing buffer-cache reads: 32 MB in 3.02 seconds =10.60 MB/sec
+ * Timing buffered disk reads: 16 MB in 5.52 seconds = 2.90 MB/sec
+ * I have 4 Megs/s before, but I don't know why (maybe changes
+ * in hdparm test).
+ * After release of 0.1, I got some successful reports, so it might work.
+ *
+ * The main problem with OPTi is that some timings for master
+ * and slave must be the same. For example, if you have master
+ * PIO 3 and slave PIO 0, driver have to set some timings of
+ * master for PIO 0. Second problem is that opti621_set_pio_mode
+ * got only one drive to set, but have to set both drives.
+ * This is solved in compute_pios. If you don't set
+ * the second drive, compute_pios use ide_get_best_pio_mode
+ * for autoselect mode (you can change it to PIO 0, if you want).
+ * If you then set the second drive to another PIO, the old value
+ * (automatically selected) will be overrided by yours.
+ * There is a 25/33MHz switch in configuration
+ * register, but driver is written for use at any frequency.
+ *
+ * Version 0.1, Nov 8, 1996
+ * by Jaromir Koutek, for 2.1.8.
+ * Initial version of driver.
+ *
+ * Version 0.2
+ * Number 0.2 skipped.
+ *
+ * Version 0.3, Nov 29, 1997
+ * by Mark Lord (probably), for 2.1.68
+ * Updates for use with new IDE block driver.
+ *
+ * Version 0.4, Dec 14, 1997
+ * by Jan Harkes
+ * Fixed some errors and cleaned the code.
+ *
+ * Version 0.5, Jan 2, 1998
+ * by Jaromir Koutek
+ * Updates for use with (again) new IDE block driver.
+ * Update of documentation.
+ *
+ * Version 0.6, Jan 2, 1999
+ * by Jaromir Koutek
+ * Reversed to version 0.3 of the driver, because
+ * 0.5 doesn't work.
+ */
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+
+#define DRV_NAME "opti621"
+
+#define READ_REG 0 /* index of Read cycle timing register */
+#define WRITE_REG 1 /* index of Write cycle timing register */
+#define CNTRL_REG 3 /* index of Control register */
+#define STRAP_REG 5 /* index of Strap register */
+#define MISC_REG 6 /* index of Miscellaneous register */
+
+static int reg_base;
+
+static DEFINE_SPINLOCK(opti621_lock);
+
+/* Write value to register reg, base of register
+ * is at reg_base (0x1f0 primary, 0x170 secondary,
+ * if not changed by PCI configuration).
+ * This is from setupvic.exe program.
+ */
+static void write_reg(u8 value, int reg)
+{
+ inw(reg_base + 1);
+ inw(reg_base + 1);
+ outb(3, reg_base + 2);
+ outb(value, reg_base + reg);
+ outb(0x83, reg_base + 2);
+}
+
+/* Read value from register reg, base of register
+ * is at reg_base (0x1f0 primary, 0x170 secondary,
+ * if not changed by PCI configuration).
+ * This is from setupvic.exe program.
+ */
+static u8 read_reg(int reg)
+{
+ u8 ret = 0;
+
+ inw(reg_base + 1);
+ inw(reg_base + 1);
+ outb(3, reg_base + 2);
+ ret = inb(reg_base + reg);
+ outb(0x83, reg_base + 2);
+
+ return ret;
+}
+
+static void opti621_set_pio_mode(ide_drive_t *drive, const u8 pio)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ ide_drive_t *pair = ide_get_pair_dev(drive);
+ unsigned long flags;
+ u8 tim, misc, addr_pio = pio, clk;
+
+ /* DRDY is default 2 (by OPTi Databook) */
+ static const u8 addr_timings[2][5] = {
+ { 0x20, 0x10, 0x00, 0x00, 0x00 }, /* 33 MHz */
+ { 0x10, 0x10, 0x00, 0x00, 0x00 }, /* 25 MHz */
+ };
+ static const u8 data_rec_timings[2][5] = {
+ { 0x5b, 0x45, 0x32, 0x21, 0x20 }, /* 33 MHz */
+ { 0x48, 0x34, 0x21, 0x10, 0x10 } /* 25 MHz */
+ };
+
+ drive->drive_data = XFER_PIO_0 + pio;
+
+ if (pair) {
+ if (pair->drive_data && pair->drive_data < drive->drive_data)
+ addr_pio = pair->drive_data - XFER_PIO_0;
+ }
+
+ spin_lock_irqsave(&opti621_lock, flags);
+
+ reg_base = hwif->io_ports.data_addr;
+
+ /* allow Register-B */
+ outb(0xc0, reg_base + CNTRL_REG);
+ /* hmm, setupvic.exe does this ;-) */
+ outb(0xff, reg_base + 5);
+ /* if reads 0xff, adapter not exist? */
+ (void)inb(reg_base + CNTRL_REG);
+ /* if reads 0xc0, no interface exist? */
+ read_reg(CNTRL_REG);
+
+ /* check CLK speed */
+ clk = read_reg(STRAP_REG) & 1;
+
+ printk(KERN_INFO "%s: CLK = %d MHz\n", hwif->name, clk ? 25 : 33);
+
+ tim = data_rec_timings[clk][pio];
+ misc = addr_timings[clk][addr_pio];
+
+ /* select Index-0/1 for Register-A/B */
+ write_reg(drive->dn & 1, MISC_REG);
+ /* set read cycle timings */
+ write_reg(tim, READ_REG);
+ /* set write cycle timings */
+ write_reg(tim, WRITE_REG);
+
+ /* use Register-A for drive 0 */
+ /* use Register-B for drive 1 */
+ write_reg(0x85, CNTRL_REG);
+
+ /* set address setup, DRDY timings, */
+ /* and read prefetch for both drives */
+ write_reg(misc, MISC_REG);
+
+ spin_unlock_irqrestore(&opti621_lock, flags);
+}
+
+static const struct ide_port_ops opti621_port_ops = {
+ .set_pio_mode = opti621_set_pio_mode,
+};
+
+static const struct ide_port_info opti621_chipset __devinitdata = {
+ .name = DRV_NAME,
+ .enablebits = { {0x45, 0x80, 0x00}, {0x40, 0x08, 0x00} },
+ .port_ops = &opti621_port_ops,
+ .host_flags = IDE_HFLAG_NO_DMA,
+ .pio_mask = ATA_PIO4,
+};
+
+static int __devinit opti621_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ return ide_pci_init_one(dev, &opti621_chipset, NULL);
+}
+
+static const struct pci_device_id opti621_pci_tbl[] = {
+ { PCI_VDEVICE(OPTI, PCI_DEVICE_ID_OPTI_82C621), 0 },
+ { PCI_VDEVICE(OPTI, PCI_DEVICE_ID_OPTI_82C825), 0 },
+ { 0, },
+};
+MODULE_DEVICE_TABLE(pci, opti621_pci_tbl);
+
+static struct pci_driver opti621_pci_driver = {
+ .name = "Opti621_IDE",
+ .id_table = opti621_pci_tbl,
+ .probe = opti621_init_one,
+ .remove = ide_pci_remove,
+ .suspend = ide_pci_suspend,
+ .resume = ide_pci_resume,
+};
+
+static int __init opti621_ide_init(void)
+{
+ return ide_pci_register_driver(&opti621_pci_driver);
+}
+
+static void __exit opti621_ide_exit(void)
+{
+ pci_unregister_driver(&opti621_pci_driver);
+}
+
+module_init(opti621_ide_init);
+module_exit(opti621_ide_exit);
+
+MODULE_AUTHOR("Jaromir Koutek, Jan Harkes, Mark Lord");
+MODULE_DESCRIPTION("PCI driver module for Opti621 IDE");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/palm_bk3710.c b/drivers/ide/palm_bk3710.c
new file mode 100644
index 0000000..122ed3c
--- /dev/null
+++ b/drivers/ide/palm_bk3710.c
@@ -0,0 +1,424 @@
+/*
+ * Palmchip bk3710 IDE controller
+ *
+ * Copyright (C) 2006 Texas Instruments.
+ * Copyright (C) 2007 MontaVista Software, Inc., <source@mvista.com>
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * ----------------------------------------------------------------------------
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/ide.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+
+/* Offset of the primary interface registers */
+#define IDE_PALM_ATA_PRI_REG_OFFSET 0x1F0
+
+/* Primary Control Offset */
+#define IDE_PALM_ATA_PRI_CTL_OFFSET 0x3F6
+
+/*
+ * PalmChip 3710 IDE Controller UDMA timing structure Definition
+ */
+struct palm_bk3710_udmatiming {
+ unsigned int rptime; /* Ready to pause time */
+ unsigned int cycletime; /* Cycle Time */
+};
+
+#define BK3710_BMICP 0x00
+#define BK3710_BMISP 0x02
+#define BK3710_BMIDTP 0x04
+#define BK3710_BMICS 0x08
+#define BK3710_BMISS 0x0A
+#define BK3710_BMIDTS 0x0C
+#define BK3710_IDETIMP 0x40
+#define BK3710_IDETIMS 0x42
+#define BK3710_SIDETIM 0x44
+#define BK3710_SLEWCTL 0x45
+#define BK3710_IDESTATUS 0x47
+#define BK3710_UDMACTL 0x48
+#define BK3710_UDMATIM 0x4A
+#define BK3710_MISCCTL 0x50
+#define BK3710_REGSTB 0x54
+#define BK3710_REGRCVR 0x58
+#define BK3710_DATSTB 0x5C
+#define BK3710_DATRCVR 0x60
+#define BK3710_DMASTB 0x64
+#define BK3710_DMARCVR 0x68
+#define BK3710_UDMASTB 0x6C
+#define BK3710_UDMATRP 0x70
+#define BK3710_UDMAENV 0x74
+#define BK3710_IORDYTMP 0x78
+#define BK3710_IORDYTMS 0x7C
+
+static unsigned ideclk_period; /* in nanoseconds */
+
+static const struct palm_bk3710_udmatiming palm_bk3710_udmatimings[6] = {
+ {160, 240}, /* UDMA Mode 0 */
+ {125, 160}, /* UDMA Mode 1 */
+ {100, 120}, /* UDMA Mode 2 */
+ {100, 90}, /* UDMA Mode 3 */
+ {100, 60}, /* UDMA Mode 4 */
+ {85, 40}, /* UDMA Mode 5 */
+};
+
+static void palm_bk3710_setudmamode(void __iomem *base, unsigned int dev,
+ unsigned int mode)
+{
+ u8 tenv, trp, t0;
+ u32 val32;
+ u16 val16;
+
+ /* DMA Data Setup */
+ t0 = DIV_ROUND_UP(palm_bk3710_udmatimings[mode].cycletime,
+ ideclk_period) - 1;
+ tenv = DIV_ROUND_UP(20, ideclk_period) - 1;
+ trp = DIV_ROUND_UP(palm_bk3710_udmatimings[mode].rptime,
+ ideclk_period) - 1;
+
+ /* udmatim Register */
+ val16 = readw(base + BK3710_UDMATIM) & (dev ? 0xFF0F : 0xFFF0);
+ val16 |= (mode << (dev ? 4 : 0));
+ writew(val16, base + BK3710_UDMATIM);
+
+ /* udmastb Ultra DMA Access Strobe Width */
+ val32 = readl(base + BK3710_UDMASTB) & (0xFF << (dev ? 0 : 8));
+ val32 |= (t0 << (dev ? 8 : 0));
+ writel(val32, base + BK3710_UDMASTB);
+
+ /* udmatrp Ultra DMA Ready to Pause Time */
+ val32 = readl(base + BK3710_UDMATRP) & (0xFF << (dev ? 0 : 8));
+ val32 |= (trp << (dev ? 8 : 0));
+ writel(val32, base + BK3710_UDMATRP);
+
+ /* udmaenv Ultra DMA envelop Time */
+ val32 = readl(base + BK3710_UDMAENV) & (0xFF << (dev ? 0 : 8));
+ val32 |= (tenv << (dev ? 8 : 0));
+ writel(val32, base + BK3710_UDMAENV);
+
+ /* Enable UDMA for Device */
+ val16 = readw(base + BK3710_UDMACTL) | (1 << dev);
+ writew(val16, base + BK3710_UDMACTL);
+}
+
+static void palm_bk3710_setdmamode(void __iomem *base, unsigned int dev,
+ unsigned short min_cycle,
+ unsigned int mode)
+{
+ u8 td, tkw, t0;
+ u32 val32;
+ u16 val16;
+ struct ide_timing *t;
+ int cycletime;
+
+ t = ide_timing_find_mode(mode);
+ cycletime = max_t(int, t->cycle, min_cycle);
+
+ /* DMA Data Setup */
+ t0 = DIV_ROUND_UP(cycletime, ideclk_period);
+ td = DIV_ROUND_UP(t->active, ideclk_period);
+ tkw = t0 - td - 1;
+ td -= 1;
+
+ val32 = readl(base + BK3710_DMASTB) & (0xFF << (dev ? 0 : 8));
+ val32 |= (td << (dev ? 8 : 0));
+ writel(val32, base + BK3710_DMASTB);
+
+ val32 = readl(base + BK3710_DMARCVR) & (0xFF << (dev ? 0 : 8));
+ val32 |= (tkw << (dev ? 8 : 0));
+ writel(val32, base + BK3710_DMARCVR);
+
+ /* Disable UDMA for Device */
+ val16 = readw(base + BK3710_UDMACTL) & ~(1 << dev);
+ writew(val16, base + BK3710_UDMACTL);
+}
+
+static void palm_bk3710_setpiomode(void __iomem *base, ide_drive_t *mate,
+ unsigned int dev, unsigned int cycletime,
+ unsigned int mode)
+{
+ u8 t2, t2i, t0;
+ u32 val32;
+ struct ide_timing *t;
+
+ /* PIO Data Setup */
+ t0 = DIV_ROUND_UP(cycletime, ideclk_period);
+ t2 = DIV_ROUND_UP(ide_timing_find_mode(XFER_PIO_0 + mode)->active,
+ ideclk_period);
+
+ t2i = t0 - t2 - 1;
+ t2 -= 1;
+
+ val32 = readl(base + BK3710_DATSTB) & (0xFF << (dev ? 0 : 8));
+ val32 |= (t2 << (dev ? 8 : 0));
+ writel(val32, base + BK3710_DATSTB);
+
+ val32 = readl(base + BK3710_DATRCVR) & (0xFF << (dev ? 0 : 8));
+ val32 |= (t2i << (dev ? 8 : 0));
+ writel(val32, base + BK3710_DATRCVR);
+
+ if (mate) {
+ u8 mode2 = ide_get_best_pio_mode(mate, 255, 4);
+
+ if (mode2 < mode)
+ mode = mode2;
+ }
+
+ /* TASKFILE Setup */
+ t = ide_timing_find_mode(XFER_PIO_0 + mode);
+ t0 = DIV_ROUND_UP(t->cyc8b, ideclk_period);
+ t2 = DIV_ROUND_UP(t->act8b, ideclk_period);
+
+ t2i = t0 - t2 - 1;
+ t2 -= 1;
+
+ val32 = readl(base + BK3710_REGSTB) & (0xFF << (dev ? 0 : 8));
+ val32 |= (t2 << (dev ? 8 : 0));
+ writel(val32, base + BK3710_REGSTB);
+
+ val32 = readl(base + BK3710_REGRCVR) & (0xFF << (dev ? 0 : 8));
+ val32 |= (t2i << (dev ? 8 : 0));
+ writel(val32, base + BK3710_REGRCVR);
+}
+
+static void palm_bk3710_set_dma_mode(ide_drive_t *drive, u8 xferspeed)
+{
+ int is_slave = drive->dn & 1;
+ void __iomem *base = (void *)drive->hwif->dma_base;
+
+ if (xferspeed >= XFER_UDMA_0) {
+ palm_bk3710_setudmamode(base, is_slave,
+ xferspeed - XFER_UDMA_0);
+ } else {
+ palm_bk3710_setdmamode(base, is_slave,
+ drive->id[ATA_ID_EIDE_DMA_MIN],
+ xferspeed);
+ }
+}
+
+static void palm_bk3710_set_pio_mode(ide_drive_t *drive, u8 pio)
+{
+ unsigned int cycle_time;
+ int is_slave = drive->dn & 1;
+ ide_drive_t *mate;
+ void __iomem *base = (void *)drive->hwif->dma_base;
+
+ /*
+ * Obtain the drive PIO data for tuning the Palm Chip registers
+ */
+ cycle_time = ide_pio_cycle_time(drive, pio);
+ mate = ide_get_pair_dev(drive);
+ palm_bk3710_setpiomode(base, mate, is_slave, cycle_time, pio);
+}
+
+static void __devinit palm_bk3710_chipinit(void __iomem *base)
+{
+ /*
+ * enable the reset_en of ATA controller so that when ata signals
+ * are brought out, by writing into device config. at that
+ * time por_n signal should not be 'Z' and have a stable value.
+ */
+ writel(0x0300, base + BK3710_MISCCTL);
+
+ /* wait for some time and deassert the reset of ATA Device. */
+ mdelay(100);
+
+ /* Deassert the Reset */
+ writel(0x0200, base + BK3710_MISCCTL);
+
+ /*
+ * Program the IDETIMP Register Value based on the following assumptions
+ *
+ * (ATA_IDETIMP_IDEEN , ENABLE ) |
+ * (ATA_IDETIMP_SLVTIMEN , DISABLE) |
+ * (ATA_IDETIMP_RDYSMPL , 70NS) |
+ * (ATA_IDETIMP_RDYRCVRY , 50NS) |
+ * (ATA_IDETIMP_DMAFTIM1 , PIOCOMP) |
+ * (ATA_IDETIMP_PREPOST1 , DISABLE) |
+ * (ATA_IDETIMP_RDYSEN1 , DISABLE) |
+ * (ATA_IDETIMP_PIOFTIM1 , DISABLE) |
+ * (ATA_IDETIMP_DMAFTIM0 , PIOCOMP) |
+ * (ATA_IDETIMP_PREPOST0 , DISABLE) |
+ * (ATA_IDETIMP_RDYSEN0 , DISABLE) |
+ * (ATA_IDETIMP_PIOFTIM0 , DISABLE)
+ */
+ writew(0xB388, base + BK3710_IDETIMP);
+
+ /*
+ * Configure SIDETIM Register
+ * (ATA_SIDETIM_RDYSMPS1 ,120NS ) |
+ * (ATA_SIDETIM_RDYRCYS1 ,120NS )
+ */
+ writeb(0, base + BK3710_SIDETIM);
+
+ /*
+ * UDMACTL Ultra-ATA DMA Control
+ * (ATA_UDMACTL_UDMAP1 , 0 ) |
+ * (ATA_UDMACTL_UDMAP0 , 0 )
+ *
+ */
+ writew(0, base + BK3710_UDMACTL);
+
+ /*
+ * MISCCTL Miscellaneous Conrol Register
+ * (ATA_MISCCTL_RSTMODEP , 1) |
+ * (ATA_MISCCTL_RESETP , 0) |
+ * (ATA_MISCCTL_TIMORIDE , 1)
+ */
+ writel(0x201, base + BK3710_MISCCTL);
+
+ /*
+ * IORDYTMP IORDY Timer for Primary Register
+ * (ATA_IORDYTMP_IORDYTMP , 0xffff )
+ */
+ writel(0xFFFF, base + BK3710_IORDYTMP);
+
+ /*
+ * Configure BMISP Register
+ * (ATA_BMISP_DMAEN1 , DISABLE ) |
+ * (ATA_BMISP_DMAEN0 , DISABLE ) |
+ * (ATA_BMISP_IORDYINT , CLEAR) |
+ * (ATA_BMISP_INTRSTAT , CLEAR) |
+ * (ATA_BMISP_DMAERROR , CLEAR)
+ */
+ writew(0, base + BK3710_BMISP);
+
+ palm_bk3710_setpiomode(base, NULL, 0, 600, 0);
+ palm_bk3710_setpiomode(base, NULL, 1, 600, 0);
+}
+
+static u8 palm_bk3710_cable_detect(ide_hwif_t *hwif)
+{
+ return ATA_CBL_PATA80;
+}
+
+static int __devinit palm_bk3710_init_dma(ide_hwif_t *hwif,
+ const struct ide_port_info *d)
+{
+ printk(KERN_INFO " %s: MMIO-DMA\n", hwif->name);
+
+ if (ide_allocate_dma_engine(hwif))
+ return -1;
+
+ hwif->dma_base = hwif->io_ports.data_addr - IDE_PALM_ATA_PRI_REG_OFFSET;
+
+ hwif->dma_ops = &sff_dma_ops;
+
+ return 0;
+}
+
+static const struct ide_port_ops palm_bk3710_ports_ops = {
+ .set_pio_mode = palm_bk3710_set_pio_mode,
+ .set_dma_mode = palm_bk3710_set_dma_mode,
+ .cable_detect = palm_bk3710_cable_detect,
+};
+
+static struct ide_port_info __devinitdata palm_bk3710_port_info = {
+ .init_dma = palm_bk3710_init_dma,
+ .port_ops = &palm_bk3710_ports_ops,
+ .host_flags = IDE_HFLAG_MMIO,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+};
+
+static int __init palm_bk3710_probe(struct platform_device *pdev)
+{
+ struct clk *clk;
+ struct resource *mem, *irq;
+ unsigned long base, rate;
+ int i, rc;
+ hw_regs_t hw, *hws[] = { &hw, NULL, NULL, NULL };
+
+ clk = clk_get(&pdev->dev, "IDECLK");
+ if (IS_ERR(clk))
+ return -ENODEV;
+
+ clk_enable(clk);
+ rate = clk_get_rate(clk);
+ ideclk_period = 1000000000UL / rate;
+
+ /* Register the IDE interface with Linux ATA Interface */
+ memset(&hw, 0, sizeof(hw));
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (mem == NULL) {
+ printk(KERN_ERR "failed to get memory region resource\n");
+ return -ENODEV;
+ }
+
+ irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (irq == NULL) {
+ printk(KERN_ERR "failed to get IRQ resource\n");
+ return -ENODEV;
+ }
+
+ if (request_mem_region(mem->start, mem->end - mem->start + 1,
+ "palm_bk3710") == NULL) {
+ printk(KERN_ERR "failed to request memory region\n");
+ return -EBUSY;
+ }
+
+ base = IO_ADDRESS(mem->start);
+
+ /* Configure the Palm Chip controller */
+ palm_bk3710_chipinit((void __iomem *)base);
+
+ for (i = 0; i < IDE_NR_PORTS - 2; i++)
+ hw.io_ports_array[i] = base + IDE_PALM_ATA_PRI_REG_OFFSET + i;
+ hw.io_ports.ctl_addr = base + IDE_PALM_ATA_PRI_CTL_OFFSET;
+ hw.irq = irq->start;
+ hw.dev = &pdev->dev;
+ hw.chipset = ide_palm3710;
+
+ palm_bk3710_port_info.udma_mask = rate < 100000000 ? ATA_UDMA4 :
+ ATA_UDMA5;
+
+ rc = ide_host_add(&palm_bk3710_port_info, hws, NULL);
+ if (rc)
+ goto out;
+
+ return 0;
+out:
+ printk(KERN_WARNING "Palm Chip BK3710 IDE Register Fail\n");
+ return rc;
+}
+
+/* work with hotplug and coldplug */
+MODULE_ALIAS("platform:palm_bk3710");
+
+static struct platform_driver platform_bk_driver = {
+ .driver = {
+ .name = "palm_bk3710",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init palm_bk3710_init(void)
+{
+ return platform_driver_probe(&platform_bk_driver, palm_bk3710_probe);
+}
+
+module_init(palm_bk3710_init);
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/pdc202xx_new.c b/drivers/ide/pdc202xx_new.c
new file mode 100644
index 0000000..211ae46
--- /dev/null
+++ b/drivers/ide/pdc202xx_new.c
@@ -0,0 +1,588 @@
+/*
+ * Promise TX2/TX4/TX2000/133 IDE driver
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Split from:
+ * linux/drivers/ide/pdc202xx.c Version 0.35 Mar. 30, 2002
+ * Copyright (C) 1998-2002 Andre Hedrick <andre@linux-ide.org>
+ * Copyright (C) 2005-2007 MontaVista Software, Inc.
+ * Portions Copyright (C) 1999 Promise Technology, Inc.
+ * Author: Frank Tiernan (frankt@promise.com)
+ * Released under terms of General Public License
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+
+#ifdef CONFIG_PPC_PMAC
+#include <asm/prom.h>
+#include <asm/pci-bridge.h>
+#endif
+
+#define DRV_NAME "pdc202xx_new"
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(fmt, args...) printk("%s: " fmt, __func__, ## args)
+#else
+#define DBG(fmt, args...)
+#endif
+
+static const char *pdc_quirk_drives[] = {
+ "QUANTUM FIREBALLlct08 08",
+ "QUANTUM FIREBALLP KA6.4",
+ "QUANTUM FIREBALLP KA9.1",
+ "QUANTUM FIREBALLP LM20.4",
+ "QUANTUM FIREBALLP KX13.6",
+ "QUANTUM FIREBALLP KX20.5",
+ "QUANTUM FIREBALLP KX27.3",
+ "QUANTUM FIREBALLP LM20.5",
+ NULL
+};
+
+static u8 max_dma_rate(struct pci_dev *pdev)
+{
+ u8 mode;
+
+ switch(pdev->device) {
+ case PCI_DEVICE_ID_PROMISE_20277:
+ case PCI_DEVICE_ID_PROMISE_20276:
+ case PCI_DEVICE_ID_PROMISE_20275:
+ case PCI_DEVICE_ID_PROMISE_20271:
+ case PCI_DEVICE_ID_PROMISE_20269:
+ mode = 4;
+ break;
+ case PCI_DEVICE_ID_PROMISE_20270:
+ case PCI_DEVICE_ID_PROMISE_20268:
+ mode = 3;
+ break;
+ default:
+ return 0;
+ }
+
+ return mode;
+}
+
+/**
+ * get_indexed_reg - Get indexed register
+ * @hwif: for the port address
+ * @index: index of the indexed register
+ */
+static u8 get_indexed_reg(ide_hwif_t *hwif, u8 index)
+{
+ u8 value;
+
+ outb(index, hwif->dma_base + 1);
+ value = inb(hwif->dma_base + 3);
+
+ DBG("index[%02X] value[%02X]\n", index, value);
+ return value;
+}
+
+/**
+ * set_indexed_reg - Set indexed register
+ * @hwif: for the port address
+ * @index: index of the indexed register
+ */
+static void set_indexed_reg(ide_hwif_t *hwif, u8 index, u8 value)
+{
+ outb(index, hwif->dma_base + 1);
+ outb(value, hwif->dma_base + 3);
+ DBG("index[%02X] value[%02X]\n", index, value);
+}
+
+/*
+ * ATA Timing Tables based on 133 MHz PLL output clock.
+ *
+ * If the PLL outputs 100 MHz clock, the ASIC hardware will set
+ * the timing registers automatically when "set features" command is
+ * issued to the device. However, if the PLL output clock is 133 MHz,
+ * the following tables must be used.
+ */
+static struct pio_timing {
+ u8 reg0c, reg0d, reg13;
+} pio_timings [] = {
+ { 0xfb, 0x2b, 0xac }, /* PIO mode 0, IORDY off, Prefetch off */
+ { 0x46, 0x29, 0xa4 }, /* PIO mode 1, IORDY off, Prefetch off */
+ { 0x23, 0x26, 0x64 }, /* PIO mode 2, IORDY off, Prefetch off */
+ { 0x27, 0x0d, 0x35 }, /* PIO mode 3, IORDY on, Prefetch off */
+ { 0x23, 0x09, 0x25 }, /* PIO mode 4, IORDY on, Prefetch off */
+};
+
+static struct mwdma_timing {
+ u8 reg0e, reg0f;
+} mwdma_timings [] = {
+ { 0xdf, 0x5f }, /* MWDMA mode 0 */
+ { 0x6b, 0x27 }, /* MWDMA mode 1 */
+ { 0x69, 0x25 }, /* MWDMA mode 2 */
+};
+
+static struct udma_timing {
+ u8 reg10, reg11, reg12;
+} udma_timings [] = {
+ { 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 void pdcnew_set_dma_mode(ide_drive_t *drive, const u8 speed)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+ u8 adj = (drive->dn & 1) ? 0x08 : 0x00;
+
+ /*
+ * IDE core issues SETFEATURES_XFER to the drive first (thanks to
+ * IDE_HFLAG_POST_SET_MODE in ->host_flags). PDC202xx hardware will
+ * automatically set the timing registers based on 100 MHz PLL output.
+ *
+ * As we set up the PLL to output 133 MHz for UltraDMA/133 capable
+ * chips, we must override the default register settings...
+ */
+ if (max_dma_rate(dev) == 4) {
+ u8 mode = speed & 0x07;
+
+ if (speed >= XFER_UDMA_0) {
+ set_indexed_reg(hwif, 0x10 + adj,
+ udma_timings[mode].reg10);
+ set_indexed_reg(hwif, 0x11 + adj,
+ udma_timings[mode].reg11);
+ set_indexed_reg(hwif, 0x12 + adj,
+ udma_timings[mode].reg12);
+ } else {
+ set_indexed_reg(hwif, 0x0e + adj,
+ mwdma_timings[mode].reg0e);
+ set_indexed_reg(hwif, 0x0f + adj,
+ mwdma_timings[mode].reg0f);
+ }
+ } else if (speed == XFER_UDMA_2) {
+ /* Set tHOLD bit to 0 if using UDMA mode 2 */
+ u8 tmp = get_indexed_reg(hwif, 0x10 + adj);
+
+ set_indexed_reg(hwif, 0x10 + adj, tmp & 0x7f);
+ }
+}
+
+static void pdcnew_set_pio_mode(ide_drive_t *drive, const u8 pio)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+ u8 adj = (drive->dn & 1) ? 0x08 : 0x00;
+
+ if (max_dma_rate(dev) == 4) {
+ set_indexed_reg(hwif, 0x0c + adj, pio_timings[pio].reg0c);
+ set_indexed_reg(hwif, 0x0d + adj, pio_timings[pio].reg0d);
+ set_indexed_reg(hwif, 0x13 + adj, pio_timings[pio].reg13);
+ }
+}
+
+static u8 pdcnew_cable_detect(ide_hwif_t *hwif)
+{
+ if (get_indexed_reg(hwif, 0x0b) & 0x04)
+ return ATA_CBL_PATA40;
+ else
+ return ATA_CBL_PATA80;
+}
+
+static void pdcnew_quirkproc(ide_drive_t *drive)
+{
+ const char **list, *m = (char *)&drive->id[ATA_ID_PROD];
+
+ for (list = pdc_quirk_drives; *list != NULL; list++)
+ if (strstr(m, *list) != NULL) {
+ drive->quirk_list = 2;
+ return;
+ }
+
+ drive->quirk_list = 0;
+}
+
+static void pdcnew_reset(ide_drive_t *drive)
+{
+ /*
+ * Deleted this because it is redundant from the caller.
+ */
+ printk(KERN_WARNING "pdc202xx_new: %s channel reset.\n",
+ HWIF(drive)->channel ? "Secondary" : "Primary");
+}
+
+/**
+ * read_counter - Read the byte count registers
+ * @dma_base: for the port address
+ */
+static long read_counter(u32 dma_base)
+{
+ u32 pri_dma_base = dma_base, sec_dma_base = dma_base + 0x08;
+ u8 cnt0, cnt1, cnt2, cnt3;
+ long count = 0, last;
+ int retry = 3;
+
+ do {
+ last = count;
+
+ /* Read the current count */
+ outb(0x20, pri_dma_base + 0x01);
+ cnt0 = inb(pri_dma_base + 0x03);
+ outb(0x21, pri_dma_base + 0x01);
+ cnt1 = inb(pri_dma_base + 0x03);
+ outb(0x20, sec_dma_base + 0x01);
+ cnt2 = inb(sec_dma_base + 0x03);
+ outb(0x21, sec_dma_base + 0x01);
+ cnt3 = inb(sec_dma_base + 0x03);
+
+ count = (cnt3 << 23) | (cnt2 << 15) | (cnt1 << 8) | cnt0;
+
+ /*
+ * The 30-bit decrementing counter is read in 4 pieces.
+ * Incorrect value may be read when the most significant bytes
+ * are changing...
+ */
+ } while (retry-- && (((last ^ count) & 0x3fff8000) || last < count));
+
+ DBG("cnt0[%02X] cnt1[%02X] cnt2[%02X] cnt3[%02X]\n",
+ cnt0, cnt1, cnt2, cnt3);
+
+ return count;
+}
+
+/**
+ * detect_pll_input_clock - Detect the PLL input clock in Hz.
+ * @dma_base: for the port address
+ * E.g. 16949000 on 33 MHz PCI bus, i.e. half of the PCI clock.
+ */
+static long detect_pll_input_clock(unsigned long dma_base)
+{
+ struct timeval start_time, end_time;
+ long start_count, end_count;
+ long pll_input, usec_elapsed;
+ u8 scr1;
+
+ start_count = read_counter(dma_base);
+ do_gettimeofday(&start_time);
+
+ /* Start the test mode */
+ outb(0x01, dma_base + 0x01);
+ scr1 = inb(dma_base + 0x03);
+ DBG("scr1[%02X]\n", scr1);
+ outb(scr1 | 0x40, dma_base + 0x03);
+
+ /* Let the counter run for 10 ms. */
+ mdelay(10);
+
+ end_count = read_counter(dma_base);
+ do_gettimeofday(&end_time);
+
+ /* Stop the test mode */
+ outb(0x01, dma_base + 0x01);
+ scr1 = inb(dma_base + 0x03);
+ DBG("scr1[%02X]\n", scr1);
+ outb(scr1 & ~0x40, dma_base + 0x03);
+
+ /*
+ * Calculate the input clock in Hz
+ * (the clock counter is 30 bit wide and counts down)
+ */
+ usec_elapsed = (end_time.tv_sec - start_time.tv_sec) * 1000000 +
+ (end_time.tv_usec - start_time.tv_usec);
+ pll_input = ((start_count - end_count) & 0x3fffffff) / 10 *
+ (10000000 / usec_elapsed);
+
+ DBG("start[%ld] end[%ld]\n", start_count, end_count);
+
+ return pll_input;
+}
+
+#ifdef CONFIG_PPC_PMAC
+static void apple_kiwi_init(struct pci_dev *pdev)
+{
+ struct device_node *np = pci_device_to_OF_node(pdev);
+ u8 conf;
+
+ if (np == NULL || !of_device_is_compatible(np, "kiwi-root"))
+ return;
+
+ if (pdev->revision >= 0x03) {
+ /* Setup chip magic config stuff (from darwin) */
+ pci_read_config_byte (pdev, 0x40, &conf);
+ pci_write_config_byte(pdev, 0x40, (conf | 0x01));
+ }
+}
+#endif /* CONFIG_PPC_PMAC */
+
+static unsigned int init_chipset_pdcnew(struct pci_dev *dev)
+{
+ const char *name = DRV_NAME;
+ unsigned long dma_base = pci_resource_start(dev, 4);
+ unsigned long sec_dma_base = dma_base + 0x08;
+ long pll_input, pll_output, ratio;
+ int f, r;
+ u8 pll_ctl0, pll_ctl1;
+
+ if (dma_base == 0)
+ return -EFAULT;
+
+#ifdef CONFIG_PPC_PMAC
+ apple_kiwi_init(dev);
+#endif
+
+ /* Calculate the required PLL output frequency */
+ switch(max_dma_rate(dev)) {
+ case 4: /* it's 133 MHz for Ultra133 chips */
+ pll_output = 133333333;
+ break;
+ case 3: /* and 100 MHz for Ultra100 chips */
+ default:
+ pll_output = 100000000;
+ break;
+ }
+
+ /*
+ * Detect PLL input clock.
+ * On some systems, where PCI bus is running at non-standard clock rate
+ * (e.g. 25 or 40 MHz), we have to adjust the cycle time.
+ * PDC20268 and newer chips employ PLL circuit to help correct timing
+ * registers setting.
+ */
+ pll_input = detect_pll_input_clock(dma_base);
+ printk(KERN_INFO "%s %s: PLL input clock is %ld kHz\n",
+ name, pci_name(dev), pll_input / 1000);
+
+ /* Sanity check */
+ if (unlikely(pll_input < 5000000L || pll_input > 70000000L)) {
+ printk(KERN_ERR "%s %s: Bad PLL input clock %ld Hz, giving up!"
+ "\n", name, pci_name(dev), pll_input);
+ goto out;
+ }
+
+#ifdef DEBUG
+ DBG("pll_output is %ld Hz\n", pll_output);
+
+ /* Show the current clock value of PLL control register
+ * (maybe already configured by the BIOS)
+ */
+ outb(0x02, sec_dma_base + 0x01);
+ pll_ctl0 = inb(sec_dma_base + 0x03);
+ outb(0x03, sec_dma_base + 0x01);
+ pll_ctl1 = inb(sec_dma_base + 0x03);
+
+ DBG("pll_ctl[%02X][%02X]\n", pll_ctl0, pll_ctl1);
+#endif
+
+ /*
+ * Calculate the ratio of F, R and NO
+ * POUT = (F + 2) / (( R + 2) * NO)
+ */
+ ratio = pll_output / (pll_input / 1000);
+ 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 "%s %s: Bad ratio %ld, giving up!\n",
+ name, pci_name(dev), ratio);
+ goto out;
+ }
+
+ f = (ratio * (r + 2)) / 1000 - 2;
+
+ DBG("F[%d] R[%d] ratio*1000[%ld]\n", f, r, ratio);
+
+ if (unlikely(f < 0 || f > 127)) {
+ /* Invalid F */
+ printk(KERN_ERR "%s %s: F[%d] invalid!\n",
+ name, pci_name(dev), f);
+ goto out;
+ }
+
+ pll_ctl0 = (u8) f;
+ pll_ctl1 = (u8) r;
+
+ DBG("Writing pll_ctl[%02X][%02X]\n", pll_ctl0, pll_ctl1);
+
+ outb(0x02, sec_dma_base + 0x01);
+ outb(pll_ctl0, sec_dma_base + 0x03);
+ outb(0x03, sec_dma_base + 0x01);
+ outb(pll_ctl1, sec_dma_base + 0x03);
+
+ /* Wait the PLL circuit to be stable */
+ mdelay(30);
+
+#ifdef DEBUG
+ /*
+ * Show the current clock value of PLL control register
+ */
+ outb(0x02, sec_dma_base + 0x01);
+ pll_ctl0 = inb(sec_dma_base + 0x03);
+ outb(0x03, sec_dma_base + 0x01);
+ pll_ctl1 = inb(sec_dma_base + 0x03);
+
+ DBG("pll_ctl[%02X][%02X]\n", pll_ctl0, pll_ctl1);
+#endif
+
+ out:
+ return dev->irq;
+}
+
+static struct pci_dev * __devinit pdc20270_get_dev2(struct pci_dev *dev)
+{
+ struct pci_dev *dev2;
+
+ dev2 = pci_get_slot(dev->bus, PCI_DEVFN(PCI_SLOT(dev->devfn) + 1,
+ PCI_FUNC(dev->devfn)));
+
+ if (dev2 &&
+ dev2->vendor == dev->vendor &&
+ dev2->device == dev->device) {
+
+ if (dev2->irq != dev->irq) {
+ dev2->irq = dev->irq;
+ printk(KERN_INFO DRV_NAME " %s: PCI config space "
+ "interrupt fixed\n", pci_name(dev));
+ }
+
+ return dev2;
+ }
+
+ return NULL;
+}
+
+static const struct ide_port_ops pdcnew_port_ops = {
+ .set_pio_mode = pdcnew_set_pio_mode,
+ .set_dma_mode = pdcnew_set_dma_mode,
+ .quirkproc = pdcnew_quirkproc,
+ .resetproc = pdcnew_reset,
+ .cable_detect = pdcnew_cable_detect,
+};
+
+#define DECLARE_PDCNEW_DEV(udma) \
+ { \
+ .name = DRV_NAME, \
+ .init_chipset = init_chipset_pdcnew, \
+ .port_ops = &pdcnew_port_ops, \
+ .host_flags = IDE_HFLAG_POST_SET_MODE | \
+ IDE_HFLAG_ERROR_STOPS_FIFO | \
+ IDE_HFLAG_OFF_BOARD, \
+ .pio_mask = ATA_PIO4, \
+ .mwdma_mask = ATA_MWDMA2, \
+ .udma_mask = udma, \
+ }
+
+static const struct ide_port_info pdcnew_chipsets[] __devinitdata = {
+ /* 0: PDC202{68,70} */ DECLARE_PDCNEW_DEV(ATA_UDMA5),
+ /* 1: PDC202{69,71,75,76,77} */ DECLARE_PDCNEW_DEV(ATA_UDMA6),
+};
+
+/**
+ * pdc202new_init_one - called when a pdc202xx is found
+ * @dev: the pdc202new device
+ * @id: the matching pci id
+ *
+ * Called when the PCI registration layer (or the IDE initialization)
+ * finds a device matching our IDE device tables.
+ */
+
+static int __devinit pdc202new_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ const struct ide_port_info *d = &pdcnew_chipsets[id->driver_data];
+ struct pci_dev *bridge = dev->bus->self;
+
+ if (dev->device == PCI_DEVICE_ID_PROMISE_20270 && bridge &&
+ bridge->vendor == PCI_VENDOR_ID_DEC &&
+ bridge->device == PCI_DEVICE_ID_DEC_21150) {
+ struct pci_dev *dev2;
+
+ if (PCI_SLOT(dev->devfn) & 2)
+ return -ENODEV;
+
+ dev2 = pdc20270_get_dev2(dev);
+
+ if (dev2) {
+ int ret = ide_pci_init_two(dev, dev2, d, NULL);
+ if (ret < 0)
+ pci_dev_put(dev2);
+ return ret;
+ }
+ }
+
+ if (dev->device == PCI_DEVICE_ID_PROMISE_20276 && bridge &&
+ bridge->vendor == PCI_VENDOR_ID_INTEL &&
+ (bridge->device == PCI_DEVICE_ID_INTEL_I960 ||
+ bridge->device == PCI_DEVICE_ID_INTEL_I960RM)) {
+ printk(KERN_INFO DRV_NAME " %s: attached to I2O RAID controller,"
+ " skipping\n", pci_name(dev));
+ return -ENODEV;
+ }
+
+ return ide_pci_init_one(dev, d, NULL);
+}
+
+static void __devexit pdc202new_remove(struct pci_dev *dev)
+{
+ struct ide_host *host = pci_get_drvdata(dev);
+ struct pci_dev *dev2 = host->dev[1] ? to_pci_dev(host->dev[1]) : NULL;
+
+ ide_pci_remove(dev);
+ pci_dev_put(dev2);
+}
+
+static const struct pci_device_id pdc202new_pci_tbl[] = {
+ { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20268), 0 },
+ { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20269), 1 },
+ { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20270), 0 },
+ { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20271), 1 },
+ { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20275), 1 },
+ { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20276), 1 },
+ { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20277), 1 },
+ { 0, },
+};
+MODULE_DEVICE_TABLE(pci, pdc202new_pci_tbl);
+
+static struct pci_driver pdc202new_pci_driver = {
+ .name = "Promise_IDE",
+ .id_table = pdc202new_pci_tbl,
+ .probe = pdc202new_init_one,
+ .remove = __devexit_p(pdc202new_remove),
+ .suspend = ide_pci_suspend,
+ .resume = ide_pci_resume,
+};
+
+static int __init pdc202new_ide_init(void)
+{
+ return ide_pci_register_driver(&pdc202new_pci_driver);
+}
+
+static void __exit pdc202new_ide_exit(void)
+{
+ pci_unregister_driver(&pdc202new_pci_driver);
+}
+
+module_init(pdc202new_ide_init);
+module_exit(pdc202new_ide_exit);
+
+MODULE_AUTHOR("Andre Hedrick, Frank Tiernan");
+MODULE_DESCRIPTION("PCI driver module for Promise PDC20268 and higher");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/pdc202xx_old.c b/drivers/ide/pdc202xx_old.c
new file mode 100644
index 0000000..799557c
--- /dev/null
+++ b/drivers/ide/pdc202xx_old.c
@@ -0,0 +1,453 @@
+/*
+ * Copyright (C) 1998-2002 Andre Hedrick <andre@linux-ide.org>
+ * Copyright (C) 2006-2007 MontaVista Software, Inc.
+ * Copyright (C) 2007 Bartlomiej Zolnierkiewicz
+ *
+ * Portions Copyright (C) 1999 Promise Technology, Inc.
+ * Author: Frank Tiernan (frankt@promise.com)
+ * Released under terms of General Public License
+ */
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/blkdev.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+
+#define DRV_NAME "pdc202xx_old"
+
+#define PDC202XX_DEBUG_DRIVE_INFO 0
+
+static const char *pdc_quirk_drives[] = {
+ "QUANTUM FIREBALLlct08 08",
+ "QUANTUM FIREBALLP KA6.4",
+ "QUANTUM FIREBALLP KA9.1",
+ "QUANTUM FIREBALLP LM20.4",
+ "QUANTUM FIREBALLP KX13.6",
+ "QUANTUM FIREBALLP KX20.5",
+ "QUANTUM FIREBALLP KX27.3",
+ "QUANTUM FIREBALLP LM20.5",
+ NULL
+};
+
+static void pdc_old_disable_66MHz_clock(ide_hwif_t *);
+
+static void pdc202xx_set_mode(ide_drive_t *drive, const u8 speed)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+ u8 drive_pci = 0x60 + (drive->dn << 2);
+
+ u8 AP = 0, BP = 0, CP = 0;
+ u8 TA = 0, TB = 0, TC = 0;
+
+#if PDC202XX_DEBUG_DRIVE_INFO
+ u32 drive_conf = 0;
+ pci_read_config_dword(dev, drive_pci, &drive_conf);
+#endif
+
+ /*
+ * TODO: do this once per channel
+ */
+ if (dev->device != PCI_DEVICE_ID_PROMISE_20246)
+ pdc_old_disable_66MHz_clock(hwif);
+
+ pci_read_config_byte(dev, drive_pci, &AP);
+ pci_read_config_byte(dev, drive_pci + 1, &BP);
+ pci_read_config_byte(dev, drive_pci + 2, &CP);
+
+ switch(speed) {
+ case XFER_UDMA_5:
+ case XFER_UDMA_4: TB = 0x20; TC = 0x01; break;
+ case XFER_UDMA_2: TB = 0x20; TC = 0x01; break;
+ case XFER_UDMA_3:
+ case XFER_UDMA_1: TB = 0x40; TC = 0x02; break;
+ case XFER_UDMA_0:
+ case XFER_MW_DMA_2: TB = 0x60; TC = 0x03; break;
+ case XFER_MW_DMA_1: TB = 0x60; TC = 0x04; break;
+ case XFER_MW_DMA_0: TB = 0xE0; TC = 0x0F; break;
+ case XFER_PIO_4: TA = 0x01; TB = 0x04; break;
+ case XFER_PIO_3: TA = 0x02; TB = 0x06; break;
+ case XFER_PIO_2: TA = 0x03; TB = 0x08; break;
+ case XFER_PIO_1: TA = 0x05; TB = 0x0C; break;
+ case XFER_PIO_0:
+ default: TA = 0x09; TB = 0x13; break;
+ }
+
+ if (speed < XFER_SW_DMA_0) {
+ /*
+ * preserve SYNC_INT / ERDDY_EN bits while clearing
+ * Prefetch_EN / IORDY_EN / PA[3:0] bits of register A
+ */
+ AP &= ~0x3f;
+ if (ata_id_iordy_disable(drive->id))
+ AP |= 0x20; /* set IORDY_EN bit */
+ if (drive->media == ide_disk)
+ AP |= 0x10; /* set Prefetch_EN bit */
+ /* clear PB[4:0] bits of register B */
+ BP &= ~0x1f;
+ pci_write_config_byte(dev, drive_pci, AP | TA);
+ pci_write_config_byte(dev, drive_pci + 1, BP | TB);
+ } else {
+ /* clear MB[2:0] bits of register B */
+ BP &= ~0xe0;
+ /* clear MC[3:0] bits of register C */
+ CP &= ~0x0f;
+ pci_write_config_byte(dev, drive_pci + 1, BP | TB);
+ pci_write_config_byte(dev, drive_pci + 2, CP | TC);
+ }
+
+#if PDC202XX_DEBUG_DRIVE_INFO
+ printk(KERN_DEBUG "%s: %s drive%d 0x%08x ",
+ drive->name, ide_xfer_verbose(speed),
+ drive->dn, drive_conf);
+ pci_read_config_dword(dev, drive_pci, &drive_conf);
+ printk("0x%08x\n", drive_conf);
+#endif
+}
+
+static void pdc202xx_set_pio_mode(ide_drive_t *drive, const u8 pio)
+{
+ pdc202xx_set_mode(drive, XFER_PIO_0 + pio);
+}
+
+static u8 pdc2026x_cable_detect(ide_hwif_t *hwif)
+{
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+ u16 CIS, mask = hwif->channel ? (1 << 11) : (1 << 10);
+
+ pci_read_config_word(dev, 0x50, &CIS);
+
+ return (CIS & mask) ? ATA_CBL_PATA40 : ATA_CBL_PATA80;
+}
+
+/*
+ * Set the control register to use the 66MHz system
+ * clock for UDMA 3/4/5 mode operation when necessary.
+ *
+ * FIXME: this register is shared by both channels, some locking is needed
+ *
+ * It may also be possible to leave the 66MHz clock on
+ * and readjust the timing parameters.
+ */
+static void pdc_old_enable_66MHz_clock(ide_hwif_t *hwif)
+{
+ unsigned long clock_reg = hwif->extra_base + 0x01;
+ u8 clock = inb(clock_reg);
+
+ outb(clock | (hwif->channel ? 0x08 : 0x02), clock_reg);
+}
+
+static void pdc_old_disable_66MHz_clock(ide_hwif_t *hwif)
+{
+ unsigned long clock_reg = hwif->extra_base + 0x01;
+ u8 clock = inb(clock_reg);
+
+ outb(clock & ~(hwif->channel ? 0x08 : 0x02), clock_reg);
+}
+
+static void pdc202xx_quirkproc(ide_drive_t *drive)
+{
+ const char **list, *m = (char *)&drive->id[ATA_ID_PROD];
+
+ for (list = pdc_quirk_drives; *list != NULL; list++)
+ if (strstr(m, *list) != NULL) {
+ drive->quirk_list = 2;
+ return;
+ }
+
+ drive->quirk_list = 0;
+}
+
+static void pdc202xx_dma_start(ide_drive_t *drive)
+{
+ if (drive->current_speed > XFER_UDMA_2)
+ pdc_old_enable_66MHz_clock(drive->hwif);
+ if (drive->media != ide_disk || (drive->dev_flags & IDE_DFLAG_LBA48)) {
+ struct request *rq = HWGROUP(drive)->rq;
+ ide_hwif_t *hwif = HWIF(drive);
+ unsigned long high_16 = hwif->extra_base - 16;
+ unsigned long atapi_reg = high_16 + (hwif->channel ? 0x24 : 0x20);
+ u32 word_count = 0;
+ u8 clock = inb(high_16 + 0x11);
+
+ outb(clock | (hwif->channel ? 0x08 : 0x02), high_16 + 0x11);
+ word_count = (rq->nr_sectors << 8);
+ word_count = (rq_data_dir(rq) == READ) ?
+ word_count | 0x05000000 :
+ word_count | 0x06000000;
+ outl(word_count, atapi_reg);
+ }
+ ide_dma_start(drive);
+}
+
+static int pdc202xx_dma_end(ide_drive_t *drive)
+{
+ if (drive->media != ide_disk || (drive->dev_flags & IDE_DFLAG_LBA48)) {
+ ide_hwif_t *hwif = HWIF(drive);
+ unsigned long high_16 = hwif->extra_base - 16;
+ unsigned long atapi_reg = high_16 + (hwif->channel ? 0x24 : 0x20);
+ u8 clock = 0;
+
+ outl(0, atapi_reg); /* zero out extra */
+ clock = inb(high_16 + 0x11);
+ outb(clock & ~(hwif->channel ? 0x08:0x02), high_16 + 0x11);
+ }
+ if (drive->current_speed > XFER_UDMA_2)
+ pdc_old_disable_66MHz_clock(drive->hwif);
+ return ide_dma_end(drive);
+}
+
+static int pdc202xx_dma_test_irq(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ unsigned long high_16 = hwif->extra_base - 16;
+ u8 dma_stat = inb(hwif->dma_base + ATA_DMA_STATUS);
+ u8 sc1d = inb(high_16 + 0x001d);
+
+ if (hwif->channel) {
+ /* bit7: Error, bit6: Interrupting, bit5: FIFO Full, bit4: FIFO Empty */
+ if ((sc1d & 0x50) == 0x50)
+ goto somebody_else;
+ else if ((sc1d & 0x40) == 0x40)
+ return (dma_stat & 4) == 4;
+ } else {
+ /* bit3: Error, bit2: Interrupting, bit1: FIFO Full, bit0: FIFO Empty */
+ if ((sc1d & 0x05) == 0x05)
+ goto somebody_else;
+ else if ((sc1d & 0x04) == 0x04)
+ return (dma_stat & 4) == 4;
+ }
+somebody_else:
+ return (dma_stat & 4) == 4; /* return 1 if INTR asserted */
+}
+
+static void pdc202xx_reset_host (ide_hwif_t *hwif)
+{
+ unsigned long high_16 = hwif->extra_base - 16;
+ u8 udma_speed_flag = inb(high_16 | 0x001f);
+
+ outb(udma_speed_flag | 0x10, high_16 | 0x001f);
+ mdelay(100);
+ outb(udma_speed_flag & ~0x10, high_16 | 0x001f);
+ mdelay(2000); /* 2 seconds ?! */
+
+ printk(KERN_WARNING "PDC202XX: %s channel reset.\n",
+ hwif->channel ? "Secondary" : "Primary");
+}
+
+static void pdc202xx_reset (ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ ide_hwif_t *mate = hwif->mate;
+
+ pdc202xx_reset_host(hwif);
+ pdc202xx_reset_host(mate);
+
+ ide_set_max_pio(drive);
+}
+
+static void pdc202xx_dma_lost_irq(ide_drive_t *drive)
+{
+ pdc202xx_reset(drive);
+ ide_dma_lost_irq(drive);
+}
+
+static void pdc202xx_dma_timeout(ide_drive_t *drive)
+{
+ pdc202xx_reset(drive);
+ ide_dma_timeout(drive);
+}
+
+static unsigned int init_chipset_pdc202xx(struct pci_dev *dev)
+{
+ unsigned long dmabase = pci_resource_start(dev, 4);
+ u8 udma_speed_flag = 0, primary_mode = 0, secondary_mode = 0;
+
+ if (dmabase == 0)
+ goto out;
+
+ udma_speed_flag = inb(dmabase | 0x1f);
+ primary_mode = inb(dmabase | 0x1a);
+ secondary_mode = inb(dmabase | 0x1b);
+ printk(KERN_INFO "%s: (U)DMA Burst Bit %sABLED " \
+ "Primary %s Mode " \
+ "Secondary %s Mode.\n", pci_name(dev),
+ (udma_speed_flag & 1) ? "EN" : "DIS",
+ (primary_mode & 1) ? "MASTER" : "PCI",
+ (secondary_mode & 1) ? "MASTER" : "PCI" );
+
+ if (!(udma_speed_flag & 1)) {
+ printk(KERN_INFO "%s: FORCING BURST BIT 0x%02x->0x%02x ",
+ pci_name(dev), udma_speed_flag,
+ (udma_speed_flag|1));
+ outb(udma_speed_flag | 1, dmabase | 0x1f);
+ printk("%sACTIVE\n", (inb(dmabase | 0x1f) & 1) ? "" : "IN");
+ }
+out:
+ return dev->irq;
+}
+
+static void __devinit pdc202ata4_fixup_irq(struct pci_dev *dev,
+ const char *name)
+{
+ if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE) {
+ u8 irq = 0, irq2 = 0;
+ pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
+ /* 0xbc */
+ pci_read_config_byte(dev, (PCI_INTERRUPT_LINE)|0x80, &irq2);
+ if (irq != irq2) {
+ pci_write_config_byte(dev,
+ (PCI_INTERRUPT_LINE)|0x80, irq); /* 0xbc */
+ printk(KERN_INFO "%s %s: PCI config space interrupt "
+ "mirror fixed\n", name, pci_name(dev));
+ }
+ }
+}
+
+#define IDE_HFLAGS_PDC202XX \
+ (IDE_HFLAG_ERROR_STOPS_FIFO | \
+ IDE_HFLAG_OFF_BOARD)
+
+static const struct ide_port_ops pdc20246_port_ops = {
+ .set_pio_mode = pdc202xx_set_pio_mode,
+ .set_dma_mode = pdc202xx_set_mode,
+ .quirkproc = pdc202xx_quirkproc,
+};
+
+static const struct ide_port_ops pdc2026x_port_ops = {
+ .set_pio_mode = pdc202xx_set_pio_mode,
+ .set_dma_mode = pdc202xx_set_mode,
+ .quirkproc = pdc202xx_quirkproc,
+ .resetproc = pdc202xx_reset,
+ .cable_detect = pdc2026x_cable_detect,
+};
+
+static const struct ide_dma_ops pdc20246_dma_ops = {
+ .dma_host_set = ide_dma_host_set,
+ .dma_setup = ide_dma_setup,
+ .dma_exec_cmd = ide_dma_exec_cmd,
+ .dma_start = ide_dma_start,
+ .dma_end = ide_dma_end,
+ .dma_test_irq = pdc202xx_dma_test_irq,
+ .dma_lost_irq = pdc202xx_dma_lost_irq,
+ .dma_timeout = pdc202xx_dma_timeout,
+};
+
+static const struct ide_dma_ops pdc2026x_dma_ops = {
+ .dma_host_set = ide_dma_host_set,
+ .dma_setup = ide_dma_setup,
+ .dma_exec_cmd = ide_dma_exec_cmd,
+ .dma_start = pdc202xx_dma_start,
+ .dma_end = pdc202xx_dma_end,
+ .dma_test_irq = pdc202xx_dma_test_irq,
+ .dma_lost_irq = pdc202xx_dma_lost_irq,
+ .dma_timeout = pdc202xx_dma_timeout,
+};
+
+#define DECLARE_PDC2026X_DEV(udma, extra_flags) \
+ { \
+ .name = DRV_NAME, \
+ .init_chipset = init_chipset_pdc202xx, \
+ .port_ops = &pdc2026x_port_ops, \
+ .dma_ops = &pdc2026x_dma_ops, \
+ .host_flags = IDE_HFLAGS_PDC202XX | extra_flags, \
+ .pio_mask = ATA_PIO4, \
+ .mwdma_mask = ATA_MWDMA2, \
+ .udma_mask = udma, \
+ }
+
+static const struct ide_port_info pdc202xx_chipsets[] __devinitdata = {
+ { /* 0: PDC20246 */
+ .name = DRV_NAME,
+ .init_chipset = init_chipset_pdc202xx,
+ .port_ops = &pdc20246_port_ops,
+ .dma_ops = &pdc20246_dma_ops,
+ .host_flags = IDE_HFLAGS_PDC202XX,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA2,
+ },
+
+ /* 1: PDC2026{2,3} */
+ DECLARE_PDC2026X_DEV(ATA_UDMA4, 0),
+ /* 2: PDC2026{5,7} */
+ DECLARE_PDC2026X_DEV(ATA_UDMA5, IDE_HFLAG_RQSIZE_256),
+};
+
+/**
+ * pdc202xx_init_one - called when a PDC202xx is found
+ * @dev: the pdc202xx device
+ * @id: the matching pci id
+ *
+ * Called when the PCI registration layer (or the IDE initialization)
+ * finds a device matching our IDE device tables.
+ */
+
+static int __devinit pdc202xx_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ const struct ide_port_info *d;
+ u8 idx = id->driver_data;
+
+ d = &pdc202xx_chipsets[idx];
+
+ if (idx < 2)
+ pdc202ata4_fixup_irq(dev, d->name);
+
+ if (dev->vendor == PCI_DEVICE_ID_PROMISE_20265) {
+ struct pci_dev *bridge = dev->bus->self;
+
+ if (bridge &&
+ bridge->vendor == PCI_VENDOR_ID_INTEL &&
+ (bridge->device == PCI_DEVICE_ID_INTEL_I960 ||
+ bridge->device == PCI_DEVICE_ID_INTEL_I960RM)) {
+ printk(KERN_INFO DRV_NAME " %s: skipping Promise "
+ "PDC20265 attached to I2O RAID controller\n",
+ pci_name(dev));
+ return -ENODEV;
+ }
+ }
+
+ return ide_pci_init_one(dev, d, NULL);
+}
+
+static const struct pci_device_id pdc202xx_pci_tbl[] = {
+ { 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 },
+ { 0, },
+};
+MODULE_DEVICE_TABLE(pci, pdc202xx_pci_tbl);
+
+static struct pci_driver pdc202xx_pci_driver = {
+ .name = "Promise_Old_IDE",
+ .id_table = pdc202xx_pci_tbl,
+ .probe = pdc202xx_init_one,
+ .remove = ide_pci_remove,
+ .suspend = ide_pci_suspend,
+ .resume = ide_pci_resume,
+};
+
+static int __init pdc202xx_ide_init(void)
+{
+ return ide_pci_register_driver(&pdc202xx_pci_driver);
+}
+
+static void __exit pdc202xx_ide_exit(void)
+{
+ pci_unregister_driver(&pdc202xx_pci_driver);
+}
+
+module_init(pdc202xx_ide_init);
+module_exit(pdc202xx_ide_exit);
+
+MODULE_AUTHOR("Andre Hedrick, Frank Tiernan");
+MODULE_DESCRIPTION("PCI driver module for older Promise IDE");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/piix.c b/drivers/ide/piix.c
new file mode 100644
index 0000000..61d2d92
--- /dev/null
+++ b/drivers/ide/piix.c
@@ -0,0 +1,480 @@
+/*
+ * Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer
+ * Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org>
+ * Copyright (C) 2003 Red Hat
+ * Copyright (C) 2006-2007 MontaVista Software, Inc. <source@mvista.com>
+ *
+ * May be copied or modified under the terms of the GNU General Public License
+ *
+ * Documentation:
+ *
+ * Publically available from Intel web site. Errata documentation
+ * is also publically available. As an aide to anyone hacking on this
+ * driver the list of errata that are relevant is below.going back to
+ * PIIX4. Older device documentation is now a bit tricky to find.
+ *
+ * Errata of note:
+ *
+ * Unfixable
+ * PIIX4 errata #9 - Only on ultra obscure hw
+ * ICH3 errata #13 - Not observed to affect real hw
+ * by Intel
+ *
+ * Things we must deal with
+ * PIIX4 errata #10 - BM IDE hang with non UDMA
+ * (must stop/start dma to recover)
+ * 440MX errata #15 - As PIIX4 errata #10
+ * PIIX4 errata #15 - Must not read control registers
+ * during a PIO transfer
+ * 440MX errata #13 - As PIIX4 errata #15
+ * ICH2 errata #21 - DMA mode 0 doesn't work right
+ * ICH0/1 errata #55 - As ICH2 errata #21
+ * ICH2 spec c #9 - Extra operations needed to handle
+ * drive hotswap [NOT YET SUPPORTED]
+ * ICH2 spec c #20 - IDE PRD must not cross a 64K boundary
+ * and must be dword aligned
+ * ICH2 spec c #24 - UDMA mode 4,5 t85/86 should be 6ns not 3.3
+ *
+ * Should have been BIOS fixed:
+ * 450NX: errata #19 - DMA hangs on old 450NX
+ * 450NX: errata #20 - DMA hangs on old 450NX
+ * 450NX: errata #25 - Corruption with DMA on old 450NX
+ * ICH3 errata #15 - IDE deadlock under high load
+ * (BIOS must set dev 31 fn 0 bit 23)
+ * ICH3 errata #18 - Don't use native mode
+ */
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#define DRV_NAME "piix"
+
+static int no_piix_dma;
+
+/**
+ * piix_set_pio_mode - set host controller for PIO mode
+ * @drive: drive
+ * @pio: PIO mode number
+ *
+ * Set the interface PIO mode based upon the settings done by AMI BIOS.
+ */
+
+static void piix_set_pio_mode(ide_drive_t *drive, const u8 pio)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+ int is_slave = drive->dn & 1;
+ int master_port = hwif->channel ? 0x42 : 0x40;
+ int slave_port = 0x44;
+ unsigned long flags;
+ u16 master_data;
+ u8 slave_data;
+ static DEFINE_SPINLOCK(tune_lock);
+ int control = 0;
+
+ /* ISP RTC */
+ static const u8 timings[][2]= {
+ { 0, 0 },
+ { 0, 0 },
+ { 1, 0 },
+ { 2, 1 },
+ { 2, 3 }, };
+
+ /*
+ * Master vs slave is synchronized above us but the slave register is
+ * shared by the two hwifs so the corner case of two slave timeouts in
+ * parallel must be locked.
+ */
+ spin_lock_irqsave(&tune_lock, flags);
+ pci_read_config_word(dev, master_port, &master_data);
+
+ if (pio > 1)
+ control |= 1; /* Programmable timing on */
+ if (drive->media == ide_disk)
+ control |= 4; /* Prefetch, post write */
+ if (pio > 2)
+ control |= 2; /* IORDY */
+ if (is_slave) {
+ master_data |= 0x4000;
+ master_data &= ~0x0070;
+ if (pio > 1) {
+ /* Set PPE, IE and TIME */
+ master_data |= control << 4;
+ }
+ pci_read_config_byte(dev, slave_port, &slave_data);
+ slave_data &= hwif->channel ? 0x0f : 0xf0;
+ slave_data |= ((timings[pio][0] << 2) | timings[pio][1]) <<
+ (hwif->channel ? 4 : 0);
+ } else {
+ master_data &= ~0x3307;
+ if (pio > 1) {
+ /* enable PPE, IE and TIME */
+ master_data |= control;
+ }
+ master_data |= (timings[pio][0] << 12) | (timings[pio][1] << 8);
+ }
+ pci_write_config_word(dev, master_port, master_data);
+ if (is_slave)
+ pci_write_config_byte(dev, slave_port, slave_data);
+ spin_unlock_irqrestore(&tune_lock, flags);
+}
+
+/**
+ * piix_set_dma_mode - set host controller for DMA mode
+ * @drive: drive
+ * @speed: DMA mode
+ *
+ * Set a PIIX host controller to the desired DMA mode. This involves
+ * programming the right timing data into the PCI configuration space.
+ */
+
+static void piix_set_dma_mode(ide_drive_t *drive, const u8 speed)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+ u8 maslave = hwif->channel ? 0x42 : 0x40;
+ int a_speed = 3 << (drive->dn * 4);
+ int u_flag = 1 << drive->dn;
+ int v_flag = 0x01 << drive->dn;
+ int w_flag = 0x10 << drive->dn;
+ int u_speed = 0;
+ int sitre;
+ u16 reg4042, reg4a;
+ u8 reg48, reg54, reg55;
+
+ pci_read_config_word(dev, maslave, &reg4042);
+ sitre = (reg4042 & 0x4000) ? 1 : 0;
+ pci_read_config_byte(dev, 0x48, &reg48);
+ pci_read_config_word(dev, 0x4a, &reg4a);
+ pci_read_config_byte(dev, 0x54, &reg54);
+ pci_read_config_byte(dev, 0x55, &reg55);
+
+ if (speed >= XFER_UDMA_0) {
+ u8 udma = speed - XFER_UDMA_0;
+
+ u_speed = min_t(u8, 2 - (udma & 1), udma) << (drive->dn * 4);
+
+ if (!(reg48 & u_flag))
+ pci_write_config_byte(dev, 0x48, reg48 | u_flag);
+ if (speed == XFER_UDMA_5) {
+ pci_write_config_byte(dev, 0x55, (u8) reg55|w_flag);
+ } else {
+ pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag);
+ }
+ if ((reg4a & a_speed) != u_speed)
+ pci_write_config_word(dev, 0x4a, (reg4a & ~a_speed) | u_speed);
+ if (speed > XFER_UDMA_2) {
+ if (!(reg54 & v_flag))
+ pci_write_config_byte(dev, 0x54, reg54 | v_flag);
+ } else
+ pci_write_config_byte(dev, 0x54, reg54 & ~v_flag);
+ } else {
+ const u8 mwdma_to_pio[] = { 0, 3, 4 };
+ u8 pio;
+
+ if (reg48 & u_flag)
+ pci_write_config_byte(dev, 0x48, reg48 & ~u_flag);
+ if (reg4a & a_speed)
+ pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
+ if (reg54 & v_flag)
+ pci_write_config_byte(dev, 0x54, reg54 & ~v_flag);
+ if (reg55 & w_flag)
+ pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag);
+
+ if (speed >= XFER_MW_DMA_0)
+ pio = mwdma_to_pio[speed - XFER_MW_DMA_0];
+ else
+ pio = 2; /* only SWDMA2 is allowed */
+
+ piix_set_pio_mode(drive, pio);
+ }
+}
+
+/**
+ * init_chipset_ich - set up the ICH chipset
+ * @dev: PCI device to set up
+ *
+ * Initialize the PCI device as required. For the ICH this turns
+ * out to be nice and simple.
+ */
+
+static unsigned int init_chipset_ich(struct pci_dev *dev)
+{
+ u32 extra = 0;
+
+ pci_read_config_dword(dev, 0x54, &extra);
+ pci_write_config_dword(dev, 0x54, extra | 0x400);
+
+ return 0;
+}
+
+/**
+ * ich_clear_irq - clear BMDMA status
+ * @drive: IDE drive
+ *
+ * ICHx contollers set DMA INTR no matter DMA or PIO.
+ * BMDMA status might need to be cleared even for
+ * PIO interrupts to prevent spurious/lost IRQ.
+ */
+static void ich_clear_irq(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ u8 dma_stat;
+
+ /*
+ * ide_dma_end() needs BMDMA status for error checking.
+ * So, skip clearing BMDMA status here and leave it
+ * to ide_dma_end() if this is DMA interrupt.
+ */
+ if (drive->waiting_for_dma || hwif->dma_base == 0)
+ return;
+
+ /* clear the INTR & ERROR bits */
+ dma_stat = inb(hwif->dma_base + ATA_DMA_STATUS);
+ /* Should we force the bit as well ? */
+ outb(dma_stat, hwif->dma_base + ATA_DMA_STATUS);
+}
+
+struct ich_laptop {
+ u16 device;
+ u16 subvendor;
+ u16 subdevice;
+};
+
+/*
+ * List of laptops that use short cables rather than 80 wire
+ */
+
+static const struct ich_laptop ich_laptop[] = {
+ /* devid, subvendor, subdev */
+ { 0x27DF, 0x1025, 0x0102 }, /* ICH7 on Acer 5602aWLMi */
+ { 0x27DF, 0x0005, 0x0280 }, /* ICH7 on Acer 5602WLMi */
+ { 0x27DF, 0x1025, 0x0110 }, /* ICH7 on Acer 3682WLMi */
+ { 0x27DF, 0x1043, 0x1267 }, /* ICH7 on Asus W5F */
+ { 0x27DF, 0x103C, 0x30A1 }, /* ICH7 on HP Compaq nc2400 */
+ { 0x27DF, 0x1071, 0xD221 }, /* ICH7 on Hercules EC-900 */
+ { 0x24CA, 0x1025, 0x0061 }, /* ICH4 on Acer Aspire 2023WLMi */
+ { 0x2653, 0x1043, 0x82D8 }, /* ICH6M on Asus Eee 701 */
+ /* end marker */
+ { 0, }
+};
+
+static u8 piix_cable_detect(ide_hwif_t *hwif)
+{
+ struct pci_dev *pdev = to_pci_dev(hwif->dev);
+ const struct ich_laptop *lap = &ich_laptop[0];
+ u8 reg54h = 0, mask = hwif->channel ? 0xc0 : 0x30;
+
+ /* check for specials */
+ while (lap->device) {
+ if (lap->device == pdev->device &&
+ lap->subvendor == pdev->subsystem_vendor &&
+ lap->subdevice == pdev->subsystem_device) {
+ return ATA_CBL_PATA40_SHORT;
+ }
+ lap++;
+ }
+
+ pci_read_config_byte(pdev, 0x54, &reg54h);
+
+ return (reg54h & mask) ? ATA_CBL_PATA80 : ATA_CBL_PATA40;
+}
+
+/**
+ * init_hwif_piix - fill in the hwif for the PIIX
+ * @hwif: IDE interface
+ *
+ * Set up the ide_hwif_t for the PIIX interface according to the
+ * capabilities of the hardware.
+ */
+
+static void __devinit init_hwif_piix(ide_hwif_t *hwif)
+{
+ if (!hwif->dma_base)
+ return;
+
+ if (no_piix_dma)
+ hwif->ultra_mask = hwif->mwdma_mask = hwif->swdma_mask = 0;
+}
+
+static const struct ide_port_ops piix_port_ops = {
+ .set_pio_mode = piix_set_pio_mode,
+ .set_dma_mode = piix_set_dma_mode,
+ .cable_detect = piix_cable_detect,
+};
+
+static const struct ide_port_ops ich_port_ops = {
+ .set_pio_mode = piix_set_pio_mode,
+ .set_dma_mode = piix_set_dma_mode,
+ .clear_irq = ich_clear_irq,
+ .cable_detect = piix_cable_detect,
+};
+
+#ifndef CONFIG_IA64
+ #define IDE_HFLAGS_PIIX IDE_HFLAG_LEGACY_IRQS
+#else
+ #define IDE_HFLAGS_PIIX 0
+#endif
+
+#define DECLARE_PIIX_DEV(udma) \
+ { \
+ .name = DRV_NAME, \
+ .init_hwif = init_hwif_piix, \
+ .enablebits = {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, \
+ .port_ops = &piix_port_ops, \
+ .host_flags = IDE_HFLAGS_PIIX, \
+ .pio_mask = ATA_PIO4, \
+ .swdma_mask = ATA_SWDMA2_ONLY, \
+ .mwdma_mask = ATA_MWDMA12_ONLY, \
+ .udma_mask = udma, \
+ }
+
+#define DECLARE_ICH_DEV(udma) \
+ { \
+ .name = DRV_NAME, \
+ .init_chipset = init_chipset_ich, \
+ .init_hwif = init_hwif_piix, \
+ .enablebits = {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, \
+ .port_ops = &ich_port_ops, \
+ .host_flags = IDE_HFLAGS_PIIX, \
+ .pio_mask = ATA_PIO4, \
+ .swdma_mask = ATA_SWDMA2_ONLY, \
+ .mwdma_mask = ATA_MWDMA12_ONLY, \
+ .udma_mask = udma, \
+ }
+
+static const struct ide_port_info piix_pci_info[] __devinitdata = {
+ /* 0: MPIIX */
+ { /*
+ * MPIIX actually has only a single IDE channel mapped to
+ * the primary or secondary ports depending on the value
+ * of the bit 14 of the IDETIM register at offset 0x6c
+ */
+ .name = DRV_NAME,
+ .enablebits = {{0x6d,0xc0,0x80}, {0x6d,0xc0,0xc0}},
+ .host_flags = IDE_HFLAG_ISA_PORTS | IDE_HFLAG_NO_DMA |
+ IDE_HFLAGS_PIIX,
+ .pio_mask = ATA_PIO4,
+ /* This is a painful system best to let it self tune for now */
+ },
+ /* 1: PIIXa/PIIXb/PIIX3 */
+ DECLARE_PIIX_DEV(0x00), /* no udma */
+ /* 2: PIIX4 */
+ DECLARE_PIIX_DEV(ATA_UDMA2),
+ /* 3: ICH0 */
+ DECLARE_ICH_DEV(ATA_UDMA2),
+ /* 4: ICH */
+ DECLARE_ICH_DEV(ATA_UDMA4),
+ /* 5: PIIX4 */
+ DECLARE_PIIX_DEV(ATA_UDMA4),
+ /* 6: ICH[2-7]/ICH[2-3]M/C-ICH/ICH5-SATA/ESB2/ICH8M */
+ DECLARE_ICH_DEV(ATA_UDMA5),
+};
+
+/**
+ * piix_init_one - called when a PIIX is found
+ * @dev: the piix device
+ * @id: the matching pci id
+ *
+ * Called when the PCI registration layer (or the IDE initialization)
+ * finds a device matching our IDE device tables.
+ */
+
+static int __devinit piix_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ return ide_pci_init_one(dev, &piix_pci_info[id->driver_data], NULL);
+}
+
+/**
+ * piix_check_450nx - Check for problem 450NX setup
+ *
+ * Check for the present of 450NX errata #19 and errata #25. If
+ * they are found, disable use of DMA IDE
+ */
+
+static void __devinit piix_check_450nx(void)
+{
+ struct pci_dev *pdev = NULL;
+ u16 cfg;
+ while((pdev=pci_get_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454NX, pdev))!=NULL)
+ {
+ /* Look for 450NX PXB. Check for problem configurations
+ A PCI quirk checks bit 6 already */
+ pci_read_config_word(pdev, 0x41, &cfg);
+ /* Only on the original revision: IDE DMA can hang */
+ if (pdev->revision == 0x00)
+ no_piix_dma = 1;
+ /* On all revisions below 5 PXB bus lock must be disabled for IDE */
+ else if (cfg & (1<<14) && pdev->revision < 5)
+ no_piix_dma = 2;
+ }
+ if(no_piix_dma)
+ printk(KERN_WARNING DRV_NAME ": 450NX errata present, disabling IDE DMA.\n");
+ if(no_piix_dma == 2)
+ printk(KERN_WARNING DRV_NAME ": A BIOS update may resolve this.\n");
+}
+
+static const struct pci_device_id piix_pci_tbl[] = {
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82371FB_0), 1 },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82371FB_1), 1 },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82371MX), 0 },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82371SB_1), 1 },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82371AB), 2 },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801AB_1), 3 },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82443MX_1), 2 },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801AA_1), 4 },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82372FB_1), 5 },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82451NX), 2 },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801BA_9), 6 },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801BA_8), 6 },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801CA_10), 6 },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801CA_11), 6 },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801DB_11), 6 },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801EB_11), 6 },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801E_11), 6 },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801DB_10), 6 },
+#ifdef CONFIG_BLK_DEV_IDE_SATA
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801EB_1), 6 },
+#endif
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ESB_2), 6 },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ICH6_19), 6 },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ICH7_21), 6 },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801DB_1), 6 },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ESB2_18), 6 },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ICH8_6), 6 },
+ { 0, },
+};
+MODULE_DEVICE_TABLE(pci, piix_pci_tbl);
+
+static struct pci_driver piix_pci_driver = {
+ .name = "PIIX_IDE",
+ .id_table = piix_pci_tbl,
+ .probe = piix_init_one,
+ .remove = ide_pci_remove,
+ .suspend = ide_pci_suspend,
+ .resume = ide_pci_resume,
+};
+
+static int __init piix_ide_init(void)
+{
+ piix_check_450nx();
+ return ide_pci_register_driver(&piix_pci_driver);
+}
+
+static void __exit piix_ide_exit(void)
+{
+ pci_unregister_driver(&piix_pci_driver);
+}
+
+module_init(piix_ide_init);
+module_exit(piix_ide_exit);
+
+MODULE_AUTHOR("Andre Hedrick, Andrzej Krzysztofowicz");
+MODULE_DESCRIPTION("PCI driver module for Intel PIIX IDE");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/pmac.c b/drivers/ide/pmac.c
new file mode 100644
index 0000000..7c481bb
--- /dev/null
+++ b/drivers/ide/pmac.c
@@ -0,0 +1,1712 @@
+/*
+ * Support for IDE interfaces on PowerMacs.
+ *
+ * These IDE interfaces are memory-mapped and have a DBDMA channel
+ * for doing DMA.
+ *
+ * Copyright (C) 1998-2003 Paul Mackerras & Ben. Herrenschmidt
+ * Copyright (C) 2007-2008 Bartlomiej Zolnierkiewicz
+ *
+ * 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.
+ *
+ * Some code taken from drivers/ide/ide-dma.c:
+ *
+ * Copyright (c) 1995-1998 Mark Lord
+ *
+ * TODO: - Use pre-calculated (kauai) timing tables all the time and
+ * get rid of the "rounded" tables used previously, so we have the
+ * same table format for all controllers and can then just have one
+ * big table
+ *
+ */
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/ide.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/pci.h>
+#include <linux/adb.h>
+#include <linux/pmu.h>
+#include <linux/scatterlist.h>
+
+#include <asm/prom.h>
+#include <asm/io.h>
+#include <asm/dbdma.h>
+#include <asm/ide.h>
+#include <asm/pci-bridge.h>
+#include <asm/machdep.h>
+#include <asm/pmac_feature.h>
+#include <asm/sections.h>
+#include <asm/irq.h>
+
+#ifndef CONFIG_PPC64
+#include <asm/mediabay.h>
+#endif
+
+#define DRV_NAME "ide-pmac"
+
+#undef IDE_PMAC_DEBUG
+
+#define DMA_WAIT_TIMEOUT 50
+
+typedef struct pmac_ide_hwif {
+ unsigned long regbase;
+ int irq;
+ int kind;
+ int aapl_bus_id;
+ unsigned mediabay : 1;
+ unsigned broken_dma : 1;
+ unsigned broken_dma_warn : 1;
+ struct device_node* node;
+ struct macio_dev *mdev;
+ u32 timings[4];
+ volatile u32 __iomem * *kauai_fcr;
+ /* Those fields are duplicating what is in hwif. We currently
+ * can't use the hwif ones because of some assumptions that are
+ * beeing done by the generic code about the kind of dma controller
+ * and format of the dma table. This will have to be fixed though.
+ */
+ volatile struct dbdma_regs __iomem * dma_regs;
+ struct dbdma_cmd* dma_table_cpu;
+} pmac_ide_hwif_t;
+
+enum {
+ controller_ohare, /* OHare based */
+ controller_heathrow, /* Heathrow/Paddington */
+ controller_kl_ata3, /* KeyLargo ATA-3 */
+ controller_kl_ata4, /* KeyLargo ATA-4 */
+ controller_un_ata6, /* UniNorth2 ATA-6 */
+ controller_k2_ata6, /* K2 ATA-6 */
+ controller_sh_ata6, /* Shasta ATA-6 */
+};
+
+static const char* model_name[] = {
+ "OHare ATA", /* OHare based */
+ "Heathrow ATA", /* Heathrow/Paddington */
+ "KeyLargo ATA-3", /* KeyLargo ATA-3 (MDMA only) */
+ "KeyLargo ATA-4", /* KeyLargo ATA-4 (UDMA/66) */
+ "UniNorth ATA-6", /* UniNorth2 ATA-6 (UDMA/100) */
+ "K2 ATA-6", /* K2 ATA-6 (UDMA/100) */
+ "Shasta ATA-6", /* Shasta ATA-6 (UDMA/133) */
+};
+
+/*
+ * Extra registers, both 32-bit little-endian
+ */
+#define IDE_TIMING_CONFIG 0x200
+#define IDE_INTERRUPT 0x300
+
+/* Kauai (U2) ATA has different register setup */
+#define IDE_KAUAI_PIO_CONFIG 0x200
+#define IDE_KAUAI_ULTRA_CONFIG 0x210
+#define IDE_KAUAI_POLL_CONFIG 0x220
+
+/*
+ * Timing configuration register definitions
+ */
+
+/* Number of IDE_SYSCLK_NS ticks, argument is in nanoseconds */
+#define SYSCLK_TICKS(t) (((t) + IDE_SYSCLK_NS - 1) / IDE_SYSCLK_NS)
+#define SYSCLK_TICKS_66(t) (((t) + IDE_SYSCLK_66_NS - 1) / IDE_SYSCLK_66_NS)
+#define IDE_SYSCLK_NS 30 /* 33Mhz cell */
+#define IDE_SYSCLK_66_NS 15 /* 66Mhz cell */
+
+/* 133Mhz cell, found in shasta.
+ * See comments about 100 Mhz Uninorth 2...
+ * Note that PIO_MASK and MDMA_MASK seem to overlap
+ */
+#define TR_133_PIOREG_PIO_MASK 0xff000fff
+#define TR_133_PIOREG_MDMA_MASK 0x00fff800
+#define TR_133_UDMAREG_UDMA_MASK 0x0003ffff
+#define TR_133_UDMAREG_UDMA_EN 0x00000001
+
+/* 100Mhz cell, found in Uninorth 2. I don't have much infos about
+ * this one yet, it appears as a pci device (106b/0033) on uninorth
+ * internal PCI bus and it's clock is controlled like gem or fw. It
+ * appears to be an evolution of keylargo ATA4 with a timing register
+ * extended to 2 32bits registers and a similar DBDMA channel. Other
+ * registers seem to exist but I can't tell much about them.
+ *
+ * So far, I'm using pre-calculated tables for this extracted from
+ * the values used by the MacOS X driver.
+ *
+ * The "PIO" register controls PIO and MDMA timings, the "ULTRA"
+ * register controls the UDMA timings. At least, it seems bit 0
+ * of this one enables UDMA vs. MDMA, and bits 4..7 are the
+ * cycle time in units of 10ns. Bits 8..15 are used by I don't
+ * know their meaning yet
+ */
+#define TR_100_PIOREG_PIO_MASK 0xff000fff
+#define TR_100_PIOREG_MDMA_MASK 0x00fff000
+#define TR_100_UDMAREG_UDMA_MASK 0x0000ffff
+#define TR_100_UDMAREG_UDMA_EN 0x00000001
+
+
+/* 66Mhz cell, found in KeyLargo. Can do ultra mode 0 to 2 on
+ * 40 connector cable and to 4 on 80 connector one.
+ * Clock unit is 15ns (66Mhz)
+ *
+ * 3 Values can be programmed:
+ * - Write data setup, which appears to match the cycle time. They
+ * also call it DIOW setup.
+ * - Ready to pause time (from spec)
+ * - Address setup. That one is weird. I don't see where exactly
+ * it fits in UDMA cycles, I got it's name from an obscure piece
+ * of commented out code in Darwin. They leave it to 0, we do as
+ * well, despite a comment that would lead to think it has a
+ * min value of 45ns.
+ * Apple also add 60ns to the write data setup (or cycle time ?) on
+ * reads.
+ */
+#define TR_66_UDMA_MASK 0xfff00000
+#define TR_66_UDMA_EN 0x00100000 /* Enable Ultra mode for DMA */
+#define TR_66_UDMA_ADDRSETUP_MASK 0xe0000000 /* Address setup */
+#define TR_66_UDMA_ADDRSETUP_SHIFT 29
+#define TR_66_UDMA_RDY2PAUS_MASK 0x1e000000 /* Ready 2 pause time */
+#define TR_66_UDMA_RDY2PAUS_SHIFT 25
+#define TR_66_UDMA_WRDATASETUP_MASK 0x01e00000 /* Write data setup time */
+#define TR_66_UDMA_WRDATASETUP_SHIFT 21
+#define TR_66_MDMA_MASK 0x000ffc00
+#define TR_66_MDMA_RECOVERY_MASK 0x000f8000
+#define TR_66_MDMA_RECOVERY_SHIFT 15
+#define TR_66_MDMA_ACCESS_MASK 0x00007c00
+#define TR_66_MDMA_ACCESS_SHIFT 10
+#define TR_66_PIO_MASK 0x000003ff
+#define TR_66_PIO_RECOVERY_MASK 0x000003e0
+#define TR_66_PIO_RECOVERY_SHIFT 5
+#define TR_66_PIO_ACCESS_MASK 0x0000001f
+#define TR_66_PIO_ACCESS_SHIFT 0
+
+/* 33Mhz cell, found in OHare, Heathrow (& Paddington) and KeyLargo
+ * Can do pio & mdma modes, clock unit is 30ns (33Mhz)
+ *
+ * The access time and recovery time can be programmed. Some older
+ * Darwin code base limit OHare to 150ns cycle time. I decided to do
+ * the same here fore safety against broken old hardware ;)
+ * The HalfTick bit, when set, adds half a clock (15ns) to the access
+ * time and removes one from recovery. It's not supported on KeyLargo
+ * implementation afaik. The E bit appears to be set for PIO mode 0 and
+ * is used to reach long timings used in this mode.
+ */
+#define TR_33_MDMA_MASK 0x003ff800
+#define TR_33_MDMA_RECOVERY_MASK 0x001f0000
+#define TR_33_MDMA_RECOVERY_SHIFT 16
+#define TR_33_MDMA_ACCESS_MASK 0x0000f800
+#define TR_33_MDMA_ACCESS_SHIFT 11
+#define TR_33_MDMA_HALFTICK 0x00200000
+#define TR_33_PIO_MASK 0x000007ff
+#define TR_33_PIO_E 0x00000400
+#define TR_33_PIO_RECOVERY_MASK 0x000003e0
+#define TR_33_PIO_RECOVERY_SHIFT 5
+#define TR_33_PIO_ACCESS_MASK 0x0000001f
+#define TR_33_PIO_ACCESS_SHIFT 0
+
+/*
+ * Interrupt register definitions
+ */
+#define IDE_INTR_DMA 0x80000000
+#define IDE_INTR_DEVICE 0x40000000
+
+/*
+ * FCR Register on Kauai. Not sure what bit 0x4 is ...
+ */
+#define KAUAI_FCR_UATA_MAGIC 0x00000004
+#define KAUAI_FCR_UATA_RESET_N 0x00000002
+#define KAUAI_FCR_UATA_ENABLE 0x00000001
+
+/* Rounded Multiword DMA timings
+ *
+ * I gave up finding a generic formula for all controller
+ * types and instead, built tables based on timing values
+ * used by Apple in Darwin's implementation.
+ */
+struct mdma_timings_t {
+ int accessTime;
+ int recoveryTime;
+ int cycleTime;
+};
+
+struct mdma_timings_t mdma_timings_33[] =
+{
+ { 240, 240, 480 },
+ { 180, 180, 360 },
+ { 135, 135, 270 },
+ { 120, 120, 240 },
+ { 105, 105, 210 },
+ { 90, 90, 180 },
+ { 75, 75, 150 },
+ { 75, 45, 120 },
+ { 0, 0, 0 }
+};
+
+struct mdma_timings_t mdma_timings_33k[] =
+{
+ { 240, 240, 480 },
+ { 180, 180, 360 },
+ { 150, 150, 300 },
+ { 120, 120, 240 },
+ { 90, 120, 210 },
+ { 90, 90, 180 },
+ { 90, 60, 150 },
+ { 90, 30, 120 },
+ { 0, 0, 0 }
+};
+
+struct mdma_timings_t mdma_timings_66[] =
+{
+ { 240, 240, 480 },
+ { 180, 180, 360 },
+ { 135, 135, 270 },
+ { 120, 120, 240 },
+ { 105, 105, 210 },
+ { 90, 90, 180 },
+ { 90, 75, 165 },
+ { 75, 45, 120 },
+ { 0, 0, 0 }
+};
+
+/* KeyLargo ATA-4 Ultra DMA timings (rounded) */
+struct {
+ int addrSetup; /* ??? */
+ int rdy2pause;
+ int wrDataSetup;
+} kl66_udma_timings[] =
+{
+ { 0, 180, 120 }, /* Mode 0 */
+ { 0, 150, 90 }, /* 1 */
+ { 0, 120, 60 }, /* 2 */
+ { 0, 90, 45 }, /* 3 */
+ { 0, 90, 30 } /* 4 */
+};
+
+/* UniNorth 2 ATA/100 timings */
+struct kauai_timing {
+ int cycle_time;
+ u32 timing_reg;
+};
+
+static struct kauai_timing kauai_pio_timings[] =
+{
+ { 930 , 0x08000fff },
+ { 600 , 0x08000a92 },
+ { 383 , 0x0800060f },
+ { 360 , 0x08000492 },
+ { 330 , 0x0800048f },
+ { 300 , 0x080003cf },
+ { 270 , 0x080003cc },
+ { 240 , 0x0800038b },
+ { 239 , 0x0800030c },
+ { 180 , 0x05000249 },
+ { 120 , 0x04000148 },
+ { 0 , 0 },
+};
+
+static struct kauai_timing kauai_mdma_timings[] =
+{
+ { 1260 , 0x00fff000 },
+ { 480 , 0x00618000 },
+ { 360 , 0x00492000 },
+ { 270 , 0x0038e000 },
+ { 240 , 0x0030c000 },
+ { 210 , 0x002cb000 },
+ { 180 , 0x00249000 },
+ { 150 , 0x00209000 },
+ { 120 , 0x00148000 },
+ { 0 , 0 },
+};
+
+static struct kauai_timing kauai_udma_timings[] =
+{
+ { 120 , 0x000070c0 },
+ { 90 , 0x00005d80 },
+ { 60 , 0x00004a60 },
+ { 45 , 0x00003a50 },
+ { 30 , 0x00002a30 },
+ { 20 , 0x00002921 },
+ { 0 , 0 },
+};
+
+static struct kauai_timing shasta_pio_timings[] =
+{
+ { 930 , 0x08000fff },
+ { 600 , 0x0A000c97 },
+ { 383 , 0x07000712 },
+ { 360 , 0x040003cd },
+ { 330 , 0x040003cd },
+ { 300 , 0x040003cd },
+ { 270 , 0x040003cd },
+ { 240 , 0x040003cd },
+ { 239 , 0x040003cd },
+ { 180 , 0x0400028b },
+ { 120 , 0x0400010a },
+ { 0 , 0 },
+};
+
+static struct kauai_timing shasta_mdma_timings[] =
+{
+ { 1260 , 0x00fff000 },
+ { 480 , 0x00820800 },
+ { 360 , 0x00820800 },
+ { 270 , 0x00820800 },
+ { 240 , 0x00820800 },
+ { 210 , 0x00820800 },
+ { 180 , 0x00820800 },
+ { 150 , 0x0028b000 },
+ { 120 , 0x001ca000 },
+ { 0 , 0 },
+};
+
+static struct kauai_timing shasta_udma133_timings[] =
+{
+ { 120 , 0x00035901, },
+ { 90 , 0x000348b1, },
+ { 60 , 0x00033881, },
+ { 45 , 0x00033861, },
+ { 30 , 0x00033841, },
+ { 20 , 0x00033031, },
+ { 15 , 0x00033021, },
+ { 0 , 0 },
+};
+
+
+static inline u32
+kauai_lookup_timing(struct kauai_timing* table, int cycle_time)
+{
+ int i;
+
+ for (i=0; table[i].cycle_time; i++)
+ if (cycle_time > table[i+1].cycle_time)
+ return table[i].timing_reg;
+ BUG();
+ return 0;
+}
+
+/* allow up to 256 DBDMA commands per xfer */
+#define MAX_DCMDS 256
+
+/*
+ * Wait 1s for disk to answer on IDE bus after a hard reset
+ * of the device (via GPIO/FCR).
+ *
+ * Some devices seem to "pollute" the bus even after dropping
+ * the BSY bit (typically some combo drives slave on the UDMA
+ * bus) after a hard reset. Since we hard reset all drives on
+ * KeyLargo ATA66, we have to keep that delay around. I may end
+ * up not hard resetting anymore on these and keep the delay only
+ * for older interfaces instead (we have to reset when coming
+ * from MacOS...) --BenH.
+ */
+#define IDE_WAKEUP_DELAY (1*HZ)
+
+static int pmac_ide_init_dma(ide_hwif_t *, const struct ide_port_info *);
+static int pmac_ide_build_dmatable(ide_drive_t *drive, struct request *rq);
+static void pmac_ide_selectproc(ide_drive_t *drive);
+static void pmac_ide_kauai_selectproc(ide_drive_t *drive);
+
+#define PMAC_IDE_REG(x) \
+ ((void __iomem *)((drive)->hwif->io_ports.data_addr + (x)))
+
+/*
+ * Apply the timings of the proper unit (master/slave) to the shared
+ * timing register when selecting that unit. This version is for
+ * ASICs with a single timing register
+ */
+static void
+pmac_ide_selectproc(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ pmac_ide_hwif_t *pmif =
+ (pmac_ide_hwif_t *)dev_get_drvdata(hwif->gendev.parent);
+
+ if (drive->dn & 1)
+ writel(pmif->timings[1], PMAC_IDE_REG(IDE_TIMING_CONFIG));
+ else
+ writel(pmif->timings[0], PMAC_IDE_REG(IDE_TIMING_CONFIG));
+ (void)readl(PMAC_IDE_REG(IDE_TIMING_CONFIG));
+}
+
+/*
+ * Apply the timings of the proper unit (master/slave) to the shared
+ * timing register when selecting that unit. This version is for
+ * ASICs with a dual timing register (Kauai)
+ */
+static void
+pmac_ide_kauai_selectproc(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ pmac_ide_hwif_t *pmif =
+ (pmac_ide_hwif_t *)dev_get_drvdata(hwif->gendev.parent);
+
+ if (drive->dn & 1) {
+ writel(pmif->timings[1], PMAC_IDE_REG(IDE_KAUAI_PIO_CONFIG));
+ writel(pmif->timings[3], PMAC_IDE_REG(IDE_KAUAI_ULTRA_CONFIG));
+ } else {
+ writel(pmif->timings[0], PMAC_IDE_REG(IDE_KAUAI_PIO_CONFIG));
+ writel(pmif->timings[2], PMAC_IDE_REG(IDE_KAUAI_ULTRA_CONFIG));
+ }
+ (void)readl(PMAC_IDE_REG(IDE_KAUAI_PIO_CONFIG));
+}
+
+/*
+ * Force an update of controller timing values for a given drive
+ */
+static void
+pmac_ide_do_update_timings(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ pmac_ide_hwif_t *pmif =
+ (pmac_ide_hwif_t *)dev_get_drvdata(hwif->gendev.parent);
+
+ if (pmif->kind == controller_sh_ata6 ||
+ pmif->kind == controller_un_ata6 ||
+ pmif->kind == controller_k2_ata6)
+ pmac_ide_kauai_selectproc(drive);
+ else
+ pmac_ide_selectproc(drive);
+}
+
+static void pmac_exec_command(ide_hwif_t *hwif, u8 cmd)
+{
+ writeb(cmd, (void __iomem *)hwif->io_ports.command_addr);
+ (void)readl((void __iomem *)(hwif->io_ports.data_addr
+ + IDE_TIMING_CONFIG));
+}
+
+static void pmac_set_irq(ide_hwif_t *hwif, int on)
+{
+ u8 ctl = ATA_DEVCTL_OBS;
+
+ if (on == 4) { /* hack for SRST */
+ ctl |= 4;
+ on &= ~4;
+ }
+
+ ctl |= on ? 0 : 2;
+
+ writeb(ctl, (void __iomem *)hwif->io_ports.ctl_addr);
+ (void)readl((void __iomem *)(hwif->io_ports.data_addr
+ + IDE_TIMING_CONFIG));
+}
+
+/*
+ * Old tuning functions (called on hdparm -p), sets up drive PIO timings
+ */
+static void
+pmac_ide_set_pio_mode(ide_drive_t *drive, const u8 pio)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ pmac_ide_hwif_t *pmif =
+ (pmac_ide_hwif_t *)dev_get_drvdata(hwif->gendev.parent);
+ struct ide_timing *tim = ide_timing_find_mode(XFER_PIO_0 + pio);
+ u32 *timings, t;
+ unsigned accessTicks, recTicks;
+ unsigned accessTime, recTime;
+ unsigned int cycle_time;
+
+ /* which drive is it ? */
+ timings = &pmif->timings[drive->dn & 1];
+ t = *timings;
+
+ cycle_time = ide_pio_cycle_time(drive, pio);
+
+ switch (pmif->kind) {
+ case controller_sh_ata6: {
+ /* 133Mhz cell */
+ u32 tr = kauai_lookup_timing(shasta_pio_timings, cycle_time);
+ t = (t & ~TR_133_PIOREG_PIO_MASK) | tr;
+ break;
+ }
+ case controller_un_ata6:
+ case controller_k2_ata6: {
+ /* 100Mhz cell */
+ u32 tr = kauai_lookup_timing(kauai_pio_timings, cycle_time);
+ t = (t & ~TR_100_PIOREG_PIO_MASK) | tr;
+ break;
+ }
+ case controller_kl_ata4:
+ /* 66Mhz cell */
+ recTime = cycle_time - tim->active - tim->setup;
+ recTime = max(recTime, 150U);
+ accessTime = tim->active;
+ accessTime = max(accessTime, 150U);
+ accessTicks = SYSCLK_TICKS_66(accessTime);
+ accessTicks = min(accessTicks, 0x1fU);
+ recTicks = SYSCLK_TICKS_66(recTime);
+ recTicks = min(recTicks, 0x1fU);
+ t = (t & ~TR_66_PIO_MASK) |
+ (accessTicks << TR_66_PIO_ACCESS_SHIFT) |
+ (recTicks << TR_66_PIO_RECOVERY_SHIFT);
+ break;
+ default: {
+ /* 33Mhz cell */
+ int ebit = 0;
+ recTime = cycle_time - tim->active - tim->setup;
+ recTime = max(recTime, 150U);
+ accessTime = tim->active;
+ accessTime = max(accessTime, 150U);
+ accessTicks = SYSCLK_TICKS(accessTime);
+ accessTicks = min(accessTicks, 0x1fU);
+ accessTicks = max(accessTicks, 4U);
+ recTicks = SYSCLK_TICKS(recTime);
+ recTicks = min(recTicks, 0x1fU);
+ recTicks = max(recTicks, 5U) - 4;
+ if (recTicks > 9) {
+ recTicks--; /* guess, but it's only for PIO0, so... */
+ ebit = 1;
+ }
+ t = (t & ~TR_33_PIO_MASK) |
+ (accessTicks << TR_33_PIO_ACCESS_SHIFT) |
+ (recTicks << TR_33_PIO_RECOVERY_SHIFT);
+ if (ebit)
+ t |= TR_33_PIO_E;
+ break;
+ }
+ }
+
+#ifdef IDE_PMAC_DEBUG
+ printk(KERN_ERR "%s: Set PIO timing for mode %d, reg: 0x%08x\n",
+ drive->name, pio, *timings);
+#endif
+
+ *timings = t;
+ pmac_ide_do_update_timings(drive);
+}
+
+/*
+ * Calculate KeyLargo ATA/66 UDMA timings
+ */
+static int
+set_timings_udma_ata4(u32 *timings, u8 speed)
+{
+ unsigned rdyToPauseTicks, wrDataSetupTicks, addrTicks;
+
+ if (speed > XFER_UDMA_4)
+ return 1;
+
+ rdyToPauseTicks = SYSCLK_TICKS_66(kl66_udma_timings[speed & 0xf].rdy2pause);
+ wrDataSetupTicks = SYSCLK_TICKS_66(kl66_udma_timings[speed & 0xf].wrDataSetup);
+ addrTicks = SYSCLK_TICKS_66(kl66_udma_timings[speed & 0xf].addrSetup);
+
+ *timings = ((*timings) & ~(TR_66_UDMA_MASK | TR_66_MDMA_MASK)) |
+ (wrDataSetupTicks << TR_66_UDMA_WRDATASETUP_SHIFT) |
+ (rdyToPauseTicks << TR_66_UDMA_RDY2PAUS_SHIFT) |
+ (addrTicks <<TR_66_UDMA_ADDRSETUP_SHIFT) |
+ TR_66_UDMA_EN;
+#ifdef IDE_PMAC_DEBUG
+ printk(KERN_ERR "ide_pmac: Set UDMA timing for mode %d, reg: 0x%08x\n",
+ speed & 0xf, *timings);
+#endif
+
+ return 0;
+}
+
+/*
+ * Calculate Kauai ATA/100 UDMA timings
+ */
+static int
+set_timings_udma_ata6(u32 *pio_timings, u32 *ultra_timings, u8 speed)
+{
+ struct ide_timing *t = ide_timing_find_mode(speed);
+ u32 tr;
+
+ if (speed > XFER_UDMA_5 || t == NULL)
+ return 1;
+ tr = kauai_lookup_timing(kauai_udma_timings, (int)t->udma);
+ *ultra_timings = ((*ultra_timings) & ~TR_100_UDMAREG_UDMA_MASK) | tr;
+ *ultra_timings = (*ultra_timings) | TR_100_UDMAREG_UDMA_EN;
+
+ return 0;
+}
+
+/*
+ * Calculate Shasta ATA/133 UDMA timings
+ */
+static int
+set_timings_udma_shasta(u32 *pio_timings, u32 *ultra_timings, u8 speed)
+{
+ struct ide_timing *t = ide_timing_find_mode(speed);
+ u32 tr;
+
+ if (speed > XFER_UDMA_6 || t == NULL)
+ return 1;
+ tr = kauai_lookup_timing(shasta_udma133_timings, (int)t->udma);
+ *ultra_timings = ((*ultra_timings) & ~TR_133_UDMAREG_UDMA_MASK) | tr;
+ *ultra_timings = (*ultra_timings) | TR_133_UDMAREG_UDMA_EN;
+
+ return 0;
+}
+
+/*
+ * Calculate MDMA timings for all cells
+ */
+static void
+set_timings_mdma(ide_drive_t *drive, int intf_type, u32 *timings, u32 *timings2,
+ u8 speed)
+{
+ u16 *id = drive->id;
+ int cycleTime, accessTime = 0, recTime = 0;
+ unsigned accessTicks, recTicks;
+ struct mdma_timings_t* tm = NULL;
+ int i;
+
+ /* Get default cycle time for mode */
+ switch(speed & 0xf) {
+ case 0: cycleTime = 480; break;
+ case 1: cycleTime = 150; break;
+ case 2: cycleTime = 120; break;
+ default:
+ BUG();
+ break;
+ }
+
+ /* Check if drive provides explicit DMA cycle time */
+ if ((id[ATA_ID_FIELD_VALID] & 2) && id[ATA_ID_EIDE_DMA_TIME])
+ cycleTime = max_t(int, id[ATA_ID_EIDE_DMA_TIME], cycleTime);
+
+ /* OHare limits according to some old Apple sources */
+ if ((intf_type == controller_ohare) && (cycleTime < 150))
+ cycleTime = 150;
+ /* Get the proper timing array for this controller */
+ switch(intf_type) {
+ case controller_sh_ata6:
+ case controller_un_ata6:
+ case controller_k2_ata6:
+ break;
+ case controller_kl_ata4:
+ tm = mdma_timings_66;
+ break;
+ case controller_kl_ata3:
+ tm = mdma_timings_33k;
+ break;
+ default:
+ tm = mdma_timings_33;
+ break;
+ }
+ if (tm != NULL) {
+ /* Lookup matching access & recovery times */
+ i = -1;
+ for (;;) {
+ if (tm[i+1].cycleTime < cycleTime)
+ break;
+ i++;
+ }
+ cycleTime = tm[i].cycleTime;
+ accessTime = tm[i].accessTime;
+ recTime = tm[i].recoveryTime;
+
+#ifdef IDE_PMAC_DEBUG
+ printk(KERN_ERR "%s: MDMA, cycleTime: %d, accessTime: %d, recTime: %d\n",
+ drive->name, cycleTime, accessTime, recTime);
+#endif
+ }
+ switch(intf_type) {
+ case controller_sh_ata6: {
+ /* 133Mhz cell */
+ u32 tr = kauai_lookup_timing(shasta_mdma_timings, cycleTime);
+ *timings = ((*timings) & ~TR_133_PIOREG_MDMA_MASK) | tr;
+ *timings2 = (*timings2) & ~TR_133_UDMAREG_UDMA_EN;
+ }
+ case controller_un_ata6:
+ case controller_k2_ata6: {
+ /* 100Mhz cell */
+ u32 tr = kauai_lookup_timing(kauai_mdma_timings, cycleTime);
+ *timings = ((*timings) & ~TR_100_PIOREG_MDMA_MASK) | tr;
+ *timings2 = (*timings2) & ~TR_100_UDMAREG_UDMA_EN;
+ }
+ break;
+ case controller_kl_ata4:
+ /* 66Mhz cell */
+ accessTicks = SYSCLK_TICKS_66(accessTime);
+ accessTicks = min(accessTicks, 0x1fU);
+ accessTicks = max(accessTicks, 0x1U);
+ recTicks = SYSCLK_TICKS_66(recTime);
+ recTicks = min(recTicks, 0x1fU);
+ recTicks = max(recTicks, 0x3U);
+ /* Clear out mdma bits and disable udma */
+ *timings = ((*timings) & ~(TR_66_MDMA_MASK | TR_66_UDMA_MASK)) |
+ (accessTicks << TR_66_MDMA_ACCESS_SHIFT) |
+ (recTicks << TR_66_MDMA_RECOVERY_SHIFT);
+ break;
+ case controller_kl_ata3:
+ /* 33Mhz cell on KeyLargo */
+ accessTicks = SYSCLK_TICKS(accessTime);
+ accessTicks = max(accessTicks, 1U);
+ accessTicks = min(accessTicks, 0x1fU);
+ accessTime = accessTicks * IDE_SYSCLK_NS;
+ recTicks = SYSCLK_TICKS(recTime);
+ recTicks = max(recTicks, 1U);
+ recTicks = min(recTicks, 0x1fU);
+ *timings = ((*timings) & ~TR_33_MDMA_MASK) |
+ (accessTicks << TR_33_MDMA_ACCESS_SHIFT) |
+ (recTicks << TR_33_MDMA_RECOVERY_SHIFT);
+ break;
+ default: {
+ /* 33Mhz cell on others */
+ int halfTick = 0;
+ int origAccessTime = accessTime;
+ int origRecTime = recTime;
+
+ accessTicks = SYSCLK_TICKS(accessTime);
+ accessTicks = max(accessTicks, 1U);
+ accessTicks = min(accessTicks, 0x1fU);
+ accessTime = accessTicks * IDE_SYSCLK_NS;
+ recTicks = SYSCLK_TICKS(recTime);
+ recTicks = max(recTicks, 2U) - 1;
+ recTicks = min(recTicks, 0x1fU);
+ recTime = (recTicks + 1) * IDE_SYSCLK_NS;
+ if ((accessTicks > 1) &&
+ ((accessTime - IDE_SYSCLK_NS/2) >= origAccessTime) &&
+ ((recTime - IDE_SYSCLK_NS/2) >= origRecTime)) {
+ halfTick = 1;
+ accessTicks--;
+ }
+ *timings = ((*timings) & ~TR_33_MDMA_MASK) |
+ (accessTicks << TR_33_MDMA_ACCESS_SHIFT) |
+ (recTicks << TR_33_MDMA_RECOVERY_SHIFT);
+ if (halfTick)
+ *timings |= TR_33_MDMA_HALFTICK;
+ }
+ }
+#ifdef IDE_PMAC_DEBUG
+ printk(KERN_ERR "%s: Set MDMA timing for mode %d, reg: 0x%08x\n",
+ drive->name, speed & 0xf, *timings);
+#endif
+}
+
+static void pmac_ide_set_dma_mode(ide_drive_t *drive, const u8 speed)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ pmac_ide_hwif_t *pmif =
+ (pmac_ide_hwif_t *)dev_get_drvdata(hwif->gendev.parent);
+ int ret = 0;
+ u32 *timings, *timings2, tl[2];
+ u8 unit = drive->dn & 1;
+
+ timings = &pmif->timings[unit];
+ timings2 = &pmif->timings[unit+2];
+
+ /* Copy timings to local image */
+ tl[0] = *timings;
+ tl[1] = *timings2;
+
+ if (speed >= XFER_UDMA_0) {
+ if (pmif->kind == controller_kl_ata4)
+ ret = set_timings_udma_ata4(&tl[0], speed);
+ else if (pmif->kind == controller_un_ata6
+ || pmif->kind == controller_k2_ata6)
+ ret = set_timings_udma_ata6(&tl[0], &tl[1], speed);
+ else if (pmif->kind == controller_sh_ata6)
+ ret = set_timings_udma_shasta(&tl[0], &tl[1], speed);
+ else
+ ret = -1;
+ } else
+ set_timings_mdma(drive, pmif->kind, &tl[0], &tl[1], speed);
+
+ if (ret)
+ return;
+
+ /* Apply timings to controller */
+ *timings = tl[0];
+ *timings2 = tl[1];
+
+ pmac_ide_do_update_timings(drive);
+}
+
+/*
+ * Blast some well known "safe" values to the timing registers at init or
+ * wakeup from sleep time, before we do real calculation
+ */
+static void
+sanitize_timings(pmac_ide_hwif_t *pmif)
+{
+ unsigned int value, value2 = 0;
+
+ switch(pmif->kind) {
+ case controller_sh_ata6:
+ value = 0x0a820c97;
+ value2 = 0x00033031;
+ break;
+ case controller_un_ata6:
+ case controller_k2_ata6:
+ value = 0x08618a92;
+ value2 = 0x00002921;
+ break;
+ case controller_kl_ata4:
+ value = 0x0008438c;
+ break;
+ case controller_kl_ata3:
+ value = 0x00084526;
+ break;
+ case controller_heathrow:
+ case controller_ohare:
+ default:
+ value = 0x00074526;
+ break;
+ }
+ pmif->timings[0] = pmif->timings[1] = value;
+ pmif->timings[2] = pmif->timings[3] = value2;
+}
+
+/* Suspend call back, should be called after the child devices
+ * have actually been suspended
+ */
+static int pmac_ide_do_suspend(pmac_ide_hwif_t *pmif)
+{
+ /* We clear the timings */
+ pmif->timings[0] = 0;
+ pmif->timings[1] = 0;
+
+ disable_irq(pmif->irq);
+
+ /* The media bay will handle itself just fine */
+ if (pmif->mediabay)
+ return 0;
+
+ /* Kauai has bus control FCRs directly here */
+ if (pmif->kauai_fcr) {
+ u32 fcr = readl(pmif->kauai_fcr);
+ fcr &= ~(KAUAI_FCR_UATA_RESET_N | KAUAI_FCR_UATA_ENABLE);
+ writel(fcr, pmif->kauai_fcr);
+ }
+
+ /* Disable the bus on older machines and the cell on kauai */
+ ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, pmif->node, pmif->aapl_bus_id,
+ 0);
+
+ return 0;
+}
+
+/* Resume call back, should be called before the child devices
+ * are resumed
+ */
+static int pmac_ide_do_resume(pmac_ide_hwif_t *pmif)
+{
+ /* Hard reset & re-enable controller (do we really need to reset ? -BenH) */
+ if (!pmif->mediabay) {
+ ppc_md.feature_call(PMAC_FTR_IDE_RESET, pmif->node, pmif->aapl_bus_id, 1);
+ ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, pmif->node, pmif->aapl_bus_id, 1);
+ msleep(10);
+ ppc_md.feature_call(PMAC_FTR_IDE_RESET, pmif->node, pmif->aapl_bus_id, 0);
+
+ /* Kauai has it different */
+ if (pmif->kauai_fcr) {
+ u32 fcr = readl(pmif->kauai_fcr);
+ fcr |= KAUAI_FCR_UATA_RESET_N | KAUAI_FCR_UATA_ENABLE;
+ writel(fcr, pmif->kauai_fcr);
+ }
+
+ msleep(jiffies_to_msecs(IDE_WAKEUP_DELAY));
+ }
+
+ /* Sanitize drive timings */
+ sanitize_timings(pmif);
+
+ enable_irq(pmif->irq);
+
+ return 0;
+}
+
+static u8 pmac_ide_cable_detect(ide_hwif_t *hwif)
+{
+ pmac_ide_hwif_t *pmif =
+ (pmac_ide_hwif_t *)dev_get_drvdata(hwif->gendev.parent);
+ struct device_node *np = pmif->node;
+ const char *cable = of_get_property(np, "cable-type", NULL);
+
+ /* Get cable type from device-tree. */
+ if (cable && !strncmp(cable, "80-", 3))
+ return ATA_CBL_PATA80;
+
+ /*
+ * G5's seem to have incorrect cable type in device-tree.
+ * Let's assume they have a 80 conductor cable, this seem
+ * to be always the case unless the user mucked around.
+ */
+ if (of_device_is_compatible(np, "K2-UATA") ||
+ of_device_is_compatible(np, "shasta-ata"))
+ return ATA_CBL_PATA80;
+
+ return ATA_CBL_PATA40;
+}
+
+static void pmac_ide_init_dev(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ pmac_ide_hwif_t *pmif =
+ (pmac_ide_hwif_t *)dev_get_drvdata(hwif->gendev.parent);
+
+ if (pmif->mediabay) {
+#ifdef CONFIG_PMAC_MEDIABAY
+ if (check_media_bay_by_base(pmif->regbase, MB_CD) == 0) {
+ drive->dev_flags &= ~IDE_DFLAG_NOPROBE;
+ return;
+ }
+#endif
+ drive->dev_flags |= IDE_DFLAG_NOPROBE;
+ }
+}
+
+static const struct ide_tp_ops pmac_tp_ops = {
+ .exec_command = pmac_exec_command,
+ .read_status = ide_read_status,
+ .read_altstatus = ide_read_altstatus,
+ .read_sff_dma_status = ide_read_sff_dma_status,
+
+ .set_irq = pmac_set_irq,
+
+ .tf_load = ide_tf_load,
+ .tf_read = ide_tf_read,
+
+ .input_data = ide_input_data,
+ .output_data = ide_output_data,
+};
+
+static const struct ide_port_ops pmac_ide_ata6_port_ops = {
+ .init_dev = pmac_ide_init_dev,
+ .set_pio_mode = pmac_ide_set_pio_mode,
+ .set_dma_mode = pmac_ide_set_dma_mode,
+ .selectproc = pmac_ide_kauai_selectproc,
+ .cable_detect = pmac_ide_cable_detect,
+};
+
+static const struct ide_port_ops pmac_ide_ata4_port_ops = {
+ .init_dev = pmac_ide_init_dev,
+ .set_pio_mode = pmac_ide_set_pio_mode,
+ .set_dma_mode = pmac_ide_set_dma_mode,
+ .selectproc = pmac_ide_selectproc,
+ .cable_detect = pmac_ide_cable_detect,
+};
+
+static const struct ide_port_ops pmac_ide_port_ops = {
+ .init_dev = pmac_ide_init_dev,
+ .set_pio_mode = pmac_ide_set_pio_mode,
+ .set_dma_mode = pmac_ide_set_dma_mode,
+ .selectproc = pmac_ide_selectproc,
+};
+
+static const struct ide_dma_ops pmac_dma_ops;
+
+static const struct ide_port_info pmac_port_info = {
+ .name = DRV_NAME,
+ .init_dma = pmac_ide_init_dma,
+ .chipset = ide_pmac,
+ .tp_ops = &pmac_tp_ops,
+ .port_ops = &pmac_ide_port_ops,
+ .dma_ops = &pmac_dma_ops,
+ .host_flags = IDE_HFLAG_SET_PIO_MODE_KEEP_DMA |
+ IDE_HFLAG_POST_SET_MODE |
+ IDE_HFLAG_MMIO |
+ IDE_HFLAG_UNMASK_IRQS,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+};
+
+/*
+ * Setup, register & probe an IDE channel driven by this driver, this is
+ * called by one of the 2 probe functions (macio or PCI).
+ */
+static int __devinit pmac_ide_setup_device(pmac_ide_hwif_t *pmif, hw_regs_t *hw)
+{
+ struct device_node *np = pmif->node;
+ const int *bidp;
+ struct ide_host *host;
+ ide_hwif_t *hwif;
+ hw_regs_t *hws[] = { hw, NULL, NULL, NULL };
+ struct ide_port_info d = pmac_port_info;
+ int rc;
+
+ pmif->broken_dma = pmif->broken_dma_warn = 0;
+ if (of_device_is_compatible(np, "shasta-ata")) {
+ pmif->kind = controller_sh_ata6;
+ d.port_ops = &pmac_ide_ata6_port_ops;
+ d.udma_mask = ATA_UDMA6;
+ } else if (of_device_is_compatible(np, "kauai-ata")) {
+ pmif->kind = controller_un_ata6;
+ d.port_ops = &pmac_ide_ata6_port_ops;
+ d.udma_mask = ATA_UDMA5;
+ } else if (of_device_is_compatible(np, "K2-UATA")) {
+ pmif->kind = controller_k2_ata6;
+ d.port_ops = &pmac_ide_ata6_port_ops;
+ d.udma_mask = ATA_UDMA5;
+ } else if (of_device_is_compatible(np, "keylargo-ata")) {
+ if (strcmp(np->name, "ata-4") == 0) {
+ pmif->kind = controller_kl_ata4;
+ d.port_ops = &pmac_ide_ata4_port_ops;
+ d.udma_mask = ATA_UDMA4;
+ } else
+ pmif->kind = controller_kl_ata3;
+ } else if (of_device_is_compatible(np, "heathrow-ata")) {
+ pmif->kind = controller_heathrow;
+ } else {
+ pmif->kind = controller_ohare;
+ pmif->broken_dma = 1;
+ }
+
+ bidp = of_get_property(np, "AAPL,bus-id", NULL);
+ pmif->aapl_bus_id = bidp ? *bidp : 0;
+
+ /* On Kauai-type controllers, we make sure the FCR is correct */
+ if (pmif->kauai_fcr)
+ writel(KAUAI_FCR_UATA_MAGIC |
+ KAUAI_FCR_UATA_RESET_N |
+ KAUAI_FCR_UATA_ENABLE, pmif->kauai_fcr);
+
+ pmif->mediabay = 0;
+
+ /* Make sure we have sane timings */
+ sanitize_timings(pmif);
+
+ host = ide_host_alloc(&d, hws);
+ if (host == NULL)
+ return -ENOMEM;
+ hwif = host->ports[0];
+
+#ifndef CONFIG_PPC64
+ /* XXX FIXME: Media bay stuff need re-organizing */
+ if (np->parent && np->parent->name
+ && strcasecmp(np->parent->name, "media-bay") == 0) {
+#ifdef CONFIG_PMAC_MEDIABAY
+ media_bay_set_ide_infos(np->parent, pmif->regbase, pmif->irq,
+ hwif);
+#endif /* CONFIG_PMAC_MEDIABAY */
+ pmif->mediabay = 1;
+ if (!bidp)
+ pmif->aapl_bus_id = 1;
+ } else if (pmif->kind == controller_ohare) {
+ /* The code below is having trouble on some ohare machines
+ * (timing related ?). Until I can put my hand on one of these
+ * units, I keep the old way
+ */
+ ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, 0, 1);
+ } else
+#endif
+ {
+ /* This is necessary to enable IDE when net-booting */
+ ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmif->aapl_bus_id, 1);
+ ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, pmif->aapl_bus_id, 1);
+ msleep(10);
+ ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmif->aapl_bus_id, 0);
+ msleep(jiffies_to_msecs(IDE_WAKEUP_DELAY));
+ }
+
+ printk(KERN_INFO DRV_NAME ": Found Apple %s controller (%s), "
+ "bus ID %d%s, irq %d\n", model_name[pmif->kind],
+ pmif->mdev ? "macio" : "PCI", pmif->aapl_bus_id,
+ pmif->mediabay ? " (mediabay)" : "", hw->irq);
+
+ rc = ide_host_register(host, &d, hws);
+ if (rc) {
+ ide_host_free(host);
+ return rc;
+ }
+
+ return 0;
+}
+
+static void __devinit pmac_ide_init_ports(hw_regs_t *hw, unsigned long base)
+{
+ int i;
+
+ for (i = 0; i < 8; ++i)
+ hw->io_ports_array[i] = base + i * 0x10;
+
+ hw->io_ports.ctl_addr = base + 0x160;
+}
+
+/*
+ * Attach to a macio probed interface
+ */
+static int __devinit
+pmac_ide_macio_attach(struct macio_dev *mdev, const struct of_device_id *match)
+{
+ void __iomem *base;
+ unsigned long regbase;
+ pmac_ide_hwif_t *pmif;
+ int irq, rc;
+ hw_regs_t hw;
+
+ pmif = kzalloc(sizeof(*pmif), GFP_KERNEL);
+ if (pmif == NULL)
+ return -ENOMEM;
+
+ if (macio_resource_count(mdev) == 0) {
+ printk(KERN_WARNING "ide-pmac: no address for %s\n",
+ mdev->ofdev.node->full_name);
+ rc = -ENXIO;
+ goto out_free_pmif;
+ }
+
+ /* Request memory resource for IO ports */
+ if (macio_request_resource(mdev, 0, "ide-pmac (ports)")) {
+ printk(KERN_ERR "ide-pmac: can't request MMIO resource for "
+ "%s!\n", mdev->ofdev.node->full_name);
+ rc = -EBUSY;
+ goto out_free_pmif;
+ }
+
+ /* XXX This is bogus. Should be fixed in the registry by checking
+ * the kind of host interrupt controller, a bit like gatwick
+ * fixes in irq.c. That works well enough for the single case
+ * where that happens though...
+ */
+ if (macio_irq_count(mdev) == 0) {
+ printk(KERN_WARNING "ide-pmac: no intrs for device %s, using "
+ "13\n", mdev->ofdev.node->full_name);
+ irq = irq_create_mapping(NULL, 13);
+ } else
+ irq = macio_irq(mdev, 0);
+
+ base = ioremap(macio_resource_start(mdev, 0), 0x400);
+ regbase = (unsigned long) base;
+
+ pmif->mdev = mdev;
+ pmif->node = mdev->ofdev.node;
+ pmif->regbase = regbase;
+ pmif->irq = irq;
+ pmif->kauai_fcr = NULL;
+
+ if (macio_resource_count(mdev) >= 2) {
+ if (macio_request_resource(mdev, 1, "ide-pmac (dma)"))
+ printk(KERN_WARNING "ide-pmac: can't request DMA "
+ "resource for %s!\n",
+ mdev->ofdev.node->full_name);
+ else
+ pmif->dma_regs = ioremap(macio_resource_start(mdev, 1), 0x1000);
+ } else
+ pmif->dma_regs = NULL;
+
+ dev_set_drvdata(&mdev->ofdev.dev, pmif);
+
+ memset(&hw, 0, sizeof(hw));
+ pmac_ide_init_ports(&hw, pmif->regbase);
+ hw.irq = irq;
+ hw.dev = &mdev->bus->pdev->dev;
+ hw.parent = &mdev->ofdev.dev;
+
+ rc = pmac_ide_setup_device(pmif, &hw);
+ if (rc != 0) {
+ /* The inteface is released to the common IDE layer */
+ dev_set_drvdata(&mdev->ofdev.dev, NULL);
+ iounmap(base);
+ if (pmif->dma_regs) {
+ iounmap(pmif->dma_regs);
+ macio_release_resource(mdev, 1);
+ }
+ macio_release_resource(mdev, 0);
+ kfree(pmif);
+ }
+
+ return rc;
+
+out_free_pmif:
+ kfree(pmif);
+ return rc;
+}
+
+static int
+pmac_ide_macio_suspend(struct macio_dev *mdev, pm_message_t mesg)
+{
+ pmac_ide_hwif_t *pmif =
+ (pmac_ide_hwif_t *)dev_get_drvdata(&mdev->ofdev.dev);
+ int rc = 0;
+
+ if (mesg.event != mdev->ofdev.dev.power.power_state.event
+ && (mesg.event & PM_EVENT_SLEEP)) {
+ rc = pmac_ide_do_suspend(pmif);
+ if (rc == 0)
+ mdev->ofdev.dev.power.power_state = mesg;
+ }
+
+ return rc;
+}
+
+static int
+pmac_ide_macio_resume(struct macio_dev *mdev)
+{
+ pmac_ide_hwif_t *pmif =
+ (pmac_ide_hwif_t *)dev_get_drvdata(&mdev->ofdev.dev);
+ int rc = 0;
+
+ if (mdev->ofdev.dev.power.power_state.event != PM_EVENT_ON) {
+ rc = pmac_ide_do_resume(pmif);
+ if (rc == 0)
+ mdev->ofdev.dev.power.power_state = PMSG_ON;
+ }
+
+ return rc;
+}
+
+/*
+ * Attach to a PCI probed interface
+ */
+static int __devinit
+pmac_ide_pci_attach(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ struct device_node *np;
+ pmac_ide_hwif_t *pmif;
+ void __iomem *base;
+ unsigned long rbase, rlen;
+ int rc;
+ hw_regs_t hw;
+
+ np = pci_device_to_OF_node(pdev);
+ if (np == NULL) {
+ printk(KERN_ERR "ide-pmac: cannot find MacIO node for Kauai ATA interface\n");
+ return -ENODEV;
+ }
+
+ pmif = kzalloc(sizeof(*pmif), GFP_KERNEL);
+ if (pmif == NULL)
+ return -ENOMEM;
+
+ if (pci_enable_device(pdev)) {
+ printk(KERN_WARNING "ide-pmac: Can't enable PCI device for "
+ "%s\n", np->full_name);
+ rc = -ENXIO;
+ goto out_free_pmif;
+ }
+ pci_set_master(pdev);
+
+ if (pci_request_regions(pdev, "Kauai ATA")) {
+ printk(KERN_ERR "ide-pmac: Cannot obtain PCI resources for "
+ "%s\n", np->full_name);
+ rc = -ENXIO;
+ goto out_free_pmif;
+ }
+
+ pmif->mdev = NULL;
+ pmif->node = np;
+
+ rbase = pci_resource_start(pdev, 0);
+ rlen = pci_resource_len(pdev, 0);
+
+ base = ioremap(rbase, rlen);
+ pmif->regbase = (unsigned long) base + 0x2000;
+ pmif->dma_regs = base + 0x1000;
+ pmif->kauai_fcr = base;
+ pmif->irq = pdev->irq;
+
+ pci_set_drvdata(pdev, pmif);
+
+ memset(&hw, 0, sizeof(hw));
+ pmac_ide_init_ports(&hw, pmif->regbase);
+ hw.irq = pdev->irq;
+ hw.dev = &pdev->dev;
+
+ rc = pmac_ide_setup_device(pmif, &hw);
+ if (rc != 0) {
+ /* The inteface is released to the common IDE layer */
+ pci_set_drvdata(pdev, NULL);
+ iounmap(base);
+ pci_release_regions(pdev);
+ kfree(pmif);
+ }
+
+ return rc;
+
+out_free_pmif:
+ kfree(pmif);
+ return rc;
+}
+
+static int
+pmac_ide_pci_suspend(struct pci_dev *pdev, pm_message_t mesg)
+{
+ pmac_ide_hwif_t *pmif = (pmac_ide_hwif_t *)pci_get_drvdata(pdev);
+ int rc = 0;
+
+ if (mesg.event != pdev->dev.power.power_state.event
+ && (mesg.event & PM_EVENT_SLEEP)) {
+ rc = pmac_ide_do_suspend(pmif);
+ if (rc == 0)
+ pdev->dev.power.power_state = mesg;
+ }
+
+ return rc;
+}
+
+static int
+pmac_ide_pci_resume(struct pci_dev *pdev)
+{
+ pmac_ide_hwif_t *pmif = (pmac_ide_hwif_t *)pci_get_drvdata(pdev);
+ int rc = 0;
+
+ if (pdev->dev.power.power_state.event != PM_EVENT_ON) {
+ rc = pmac_ide_do_resume(pmif);
+ if (rc == 0)
+ pdev->dev.power.power_state = PMSG_ON;
+ }
+
+ return rc;
+}
+
+static struct of_device_id pmac_ide_macio_match[] =
+{
+ {
+ .name = "IDE",
+ },
+ {
+ .name = "ATA",
+ },
+ {
+ .type = "ide",
+ },
+ {
+ .type = "ata",
+ },
+ {},
+};
+
+static struct macio_driver pmac_ide_macio_driver =
+{
+ .name = "ide-pmac",
+ .match_table = pmac_ide_macio_match,
+ .probe = pmac_ide_macio_attach,
+ .suspend = pmac_ide_macio_suspend,
+ .resume = pmac_ide_macio_resume,
+};
+
+static const struct pci_device_id pmac_ide_pci_match[] = {
+ { PCI_VDEVICE(APPLE, PCI_DEVICE_ID_APPLE_UNI_N_ATA), 0 },
+ { PCI_VDEVICE(APPLE, PCI_DEVICE_ID_APPLE_IPID_ATA100), 0 },
+ { PCI_VDEVICE(APPLE, PCI_DEVICE_ID_APPLE_K2_ATA100), 0 },
+ { PCI_VDEVICE(APPLE, PCI_DEVICE_ID_APPLE_SH_ATA), 0 },
+ { PCI_VDEVICE(APPLE, PCI_DEVICE_ID_APPLE_IPID2_ATA), 0 },
+ {},
+};
+
+static struct pci_driver pmac_ide_pci_driver = {
+ .name = "ide-pmac",
+ .id_table = pmac_ide_pci_match,
+ .probe = pmac_ide_pci_attach,
+ .suspend = pmac_ide_pci_suspend,
+ .resume = pmac_ide_pci_resume,
+};
+MODULE_DEVICE_TABLE(pci, pmac_ide_pci_match);
+
+int __init pmac_ide_probe(void)
+{
+ int error;
+
+ if (!machine_is(powermac))
+ return -ENODEV;
+
+#ifdef CONFIG_BLK_DEV_IDE_PMAC_ATA100FIRST
+ error = pci_register_driver(&pmac_ide_pci_driver);
+ if (error)
+ goto out;
+ error = macio_register_driver(&pmac_ide_macio_driver);
+ if (error) {
+ pci_unregister_driver(&pmac_ide_pci_driver);
+ goto out;
+ }
+#else
+ error = macio_register_driver(&pmac_ide_macio_driver);
+ if (error)
+ goto out;
+ error = pci_register_driver(&pmac_ide_pci_driver);
+ if (error) {
+ macio_unregister_driver(&pmac_ide_macio_driver);
+ goto out;
+ }
+#endif
+out:
+ return error;
+}
+
+/*
+ * pmac_ide_build_dmatable builds the DBDMA command list
+ * for a transfer and sets the DBDMA channel to point to it.
+ */
+static int
+pmac_ide_build_dmatable(ide_drive_t *drive, struct request *rq)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ pmac_ide_hwif_t *pmif =
+ (pmac_ide_hwif_t *)dev_get_drvdata(hwif->gendev.parent);
+ struct dbdma_cmd *table;
+ int i, count = 0;
+ volatile struct dbdma_regs __iomem *dma = pmif->dma_regs;
+ struct scatterlist *sg;
+ int wr = (rq_data_dir(rq) == WRITE);
+
+ /* DMA table is already aligned */
+ table = (struct dbdma_cmd *) pmif->dma_table_cpu;
+
+ /* Make sure DMA controller is stopped (necessary ?) */
+ writel((RUN|PAUSE|FLUSH|WAKE|DEAD) << 16, &dma->control);
+ while (readl(&dma->status) & RUN)
+ udelay(1);
+
+ hwif->sg_nents = i = ide_build_sglist(drive, rq);
+
+ if (!i)
+ return 0;
+
+ /* Build DBDMA commands list */
+ sg = hwif->sg_table;
+ while (i && sg_dma_len(sg)) {
+ u32 cur_addr;
+ u32 cur_len;
+
+ cur_addr = sg_dma_address(sg);
+ cur_len = sg_dma_len(sg);
+
+ if (pmif->broken_dma && cur_addr & (L1_CACHE_BYTES - 1)) {
+ if (pmif->broken_dma_warn == 0) {
+ printk(KERN_WARNING "%s: DMA on non aligned address, "
+ "switching to PIO on Ohare chipset\n", drive->name);
+ pmif->broken_dma_warn = 1;
+ }
+ goto use_pio_instead;
+ }
+ while (cur_len) {
+ unsigned int tc = (cur_len < 0xfe00)? cur_len: 0xfe00;
+
+ if (count++ >= MAX_DCMDS) {
+ printk(KERN_WARNING "%s: DMA table too small\n",
+ drive->name);
+ goto use_pio_instead;
+ }
+ st_le16(&table->command, wr? OUTPUT_MORE: INPUT_MORE);
+ st_le16(&table->req_count, tc);
+ st_le32(&table->phy_addr, cur_addr);
+ table->cmd_dep = 0;
+ table->xfer_status = 0;
+ table->res_count = 0;
+ cur_addr += tc;
+ cur_len -= tc;
+ ++table;
+ }
+ sg = sg_next(sg);
+ i--;
+ }
+
+ /* convert the last command to an input/output last command */
+ if (count) {
+ st_le16(&table[-1].command, wr? OUTPUT_LAST: INPUT_LAST);
+ /* add the stop command to the end of the list */
+ memset(table, 0, sizeof(struct dbdma_cmd));
+ st_le16(&table->command, DBDMA_STOP);
+ mb();
+ writel(hwif->dmatable_dma, &dma->cmdptr);
+ return 1;
+ }
+
+ printk(KERN_DEBUG "%s: empty DMA table?\n", drive->name);
+
+use_pio_instead:
+ ide_destroy_dmatable(drive);
+
+ return 0; /* revert to PIO for this request */
+}
+
+/*
+ * Prepare a DMA transfer. We build the DMA table, adjust the timings for
+ * a read on KeyLargo ATA/66 and mark us as waiting for DMA completion
+ */
+static int
+pmac_ide_dma_setup(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ pmac_ide_hwif_t *pmif =
+ (pmac_ide_hwif_t *)dev_get_drvdata(hwif->gendev.parent);
+ struct request *rq = HWGROUP(drive)->rq;
+ u8 unit = drive->dn & 1, ata4 = (pmif->kind == controller_kl_ata4);
+
+ if (!pmac_ide_build_dmatable(drive, rq)) {
+ ide_map_sg(drive, rq);
+ return 1;
+ }
+
+ /* Apple adds 60ns to wrDataSetup on reads */
+ if (ata4 && (pmif->timings[unit] & TR_66_UDMA_EN)) {
+ writel(pmif->timings[unit] + (!rq_data_dir(rq) ? 0x00800000UL : 0),
+ PMAC_IDE_REG(IDE_TIMING_CONFIG));
+ (void)readl(PMAC_IDE_REG(IDE_TIMING_CONFIG));
+ }
+
+ drive->waiting_for_dma = 1;
+
+ return 0;
+}
+
+static void
+pmac_ide_dma_exec_cmd(ide_drive_t *drive, u8 command)
+{
+ /* issue cmd to drive */
+ ide_execute_command(drive, command, &ide_dma_intr, 2*WAIT_CMD, NULL);
+}
+
+/*
+ * Kick the DMA controller into life after the DMA command has been issued
+ * to the drive.
+ */
+static void
+pmac_ide_dma_start(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ pmac_ide_hwif_t *pmif =
+ (pmac_ide_hwif_t *)dev_get_drvdata(hwif->gendev.parent);
+ volatile struct dbdma_regs __iomem *dma;
+
+ dma = pmif->dma_regs;
+
+ writel((RUN << 16) | RUN, &dma->control);
+ /* Make sure it gets to the controller right now */
+ (void)readl(&dma->control);
+}
+
+/*
+ * After a DMA transfer, make sure the controller is stopped
+ */
+static int
+pmac_ide_dma_end (ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ pmac_ide_hwif_t *pmif =
+ (pmac_ide_hwif_t *)dev_get_drvdata(hwif->gendev.parent);
+ volatile struct dbdma_regs __iomem *dma = pmif->dma_regs;
+ u32 dstat;
+
+ drive->waiting_for_dma = 0;
+ dstat = readl(&dma->status);
+ writel(((RUN|WAKE|DEAD) << 16), &dma->control);
+
+ ide_destroy_dmatable(drive);
+
+ /* verify good dma status. we don't check for ACTIVE beeing 0. We should...
+ * in theory, but with ATAPI decices doing buffer underruns, that would
+ * cause us to disable DMA, which isn't what we want
+ */
+ return (dstat & (RUN|DEAD)) != RUN;
+}
+
+/*
+ * Check out that the interrupt we got was for us. We can't always know this
+ * for sure with those Apple interfaces (well, we could on the recent ones but
+ * that's not implemented yet), on the other hand, we don't have shared interrupts
+ * so it's not really a problem
+ */
+static int
+pmac_ide_dma_test_irq (ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ pmac_ide_hwif_t *pmif =
+ (pmac_ide_hwif_t *)dev_get_drvdata(hwif->gendev.parent);
+ volatile struct dbdma_regs __iomem *dma = pmif->dma_regs;
+ unsigned long status, timeout;
+
+ /* We have to things to deal with here:
+ *
+ * - The dbdma won't stop if the command was started
+ * but completed with an error without transferring all
+ * datas. This happens when bad blocks are met during
+ * a multi-block transfer.
+ *
+ * - The dbdma fifo hasn't yet finished flushing to
+ * to system memory when the disk interrupt occurs.
+ *
+ */
+
+ /* If ACTIVE is cleared, the STOP command have passed and
+ * transfer is complete.
+ */
+ status = readl(&dma->status);
+ if (!(status & ACTIVE))
+ return 1;
+
+ /* If dbdma didn't execute the STOP command yet, the
+ * active bit is still set. We consider that we aren't
+ * sharing interrupts (which is hopefully the case with
+ * those controllers) and so we just try to flush the
+ * channel for pending data in the fifo
+ */
+ udelay(1);
+ writel((FLUSH << 16) | FLUSH, &dma->control);
+ timeout = 0;
+ for (;;) {
+ udelay(1);
+ status = readl(&dma->status);
+ if ((status & FLUSH) == 0)
+ break;
+ if (++timeout > 100) {
+ printk(KERN_WARNING "ide%d, ide_dma_test_irq \
+ timeout flushing channel\n", HWIF(drive)->index);
+ break;
+ }
+ }
+ return 1;
+}
+
+static void pmac_ide_dma_host_set(ide_drive_t *drive, int on)
+{
+}
+
+static void
+pmac_ide_dma_lost_irq (ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ pmac_ide_hwif_t *pmif =
+ (pmac_ide_hwif_t *)dev_get_drvdata(hwif->gendev.parent);
+ volatile struct dbdma_regs __iomem *dma = pmif->dma_regs;
+ unsigned long status = readl(&dma->status);
+
+ printk(KERN_ERR "ide-pmac lost interrupt, dma status: %lx\n", status);
+}
+
+static const struct ide_dma_ops pmac_dma_ops = {
+ .dma_host_set = pmac_ide_dma_host_set,
+ .dma_setup = pmac_ide_dma_setup,
+ .dma_exec_cmd = pmac_ide_dma_exec_cmd,
+ .dma_start = pmac_ide_dma_start,
+ .dma_end = pmac_ide_dma_end,
+ .dma_test_irq = pmac_ide_dma_test_irq,
+ .dma_timeout = ide_dma_timeout,
+ .dma_lost_irq = pmac_ide_dma_lost_irq,
+};
+
+/*
+ * Allocate the data structures needed for using DMA with an interface
+ * and fill the proper list of functions pointers
+ */
+static int __devinit pmac_ide_init_dma(ide_hwif_t *hwif,
+ const struct ide_port_info *d)
+{
+ pmac_ide_hwif_t *pmif =
+ (pmac_ide_hwif_t *)dev_get_drvdata(hwif->gendev.parent);
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+
+ /* We won't need pci_dev if we switch to generic consistent
+ * DMA routines ...
+ */
+ if (dev == NULL || pmif->dma_regs == 0)
+ return -ENODEV;
+ /*
+ * Allocate space for the DBDMA commands.
+ * The +2 is +1 for the stop command and +1 to allow for
+ * aligning the start address to a multiple of 16 bytes.
+ */
+ pmif->dma_table_cpu = (struct dbdma_cmd*)pci_alloc_consistent(
+ dev,
+ (MAX_DCMDS + 2) * sizeof(struct dbdma_cmd),
+ &hwif->dmatable_dma);
+ if (pmif->dma_table_cpu == NULL) {
+ printk(KERN_ERR "%s: unable to allocate DMA command list\n",
+ hwif->name);
+ return -ENOMEM;
+ }
+
+ hwif->sg_max_nents = MAX_DCMDS;
+
+ return 0;
+}
+
+module_init(pmac_ide_probe);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/q40ide.c b/drivers/ide/q40ide.c
new file mode 100644
index 0000000..4af4a8c
--- /dev/null
+++ b/drivers/ide/q40ide.c
@@ -0,0 +1,165 @@
+/*
+ * Q40 I/O port IDE Driver
+ *
+ * (c) Richard Zidlicky
+ *
+ * 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/types.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/ide.h>
+
+ /*
+ * Bases of the IDE interfaces
+ */
+
+#define Q40IDE_NUM_HWIFS 2
+
+#define PCIDE_BASE1 0x1f0
+#define PCIDE_BASE2 0x170
+#define PCIDE_BASE3 0x1e8
+#define PCIDE_BASE4 0x168
+#define PCIDE_BASE5 0x1e0
+#define PCIDE_BASE6 0x160
+
+static const unsigned long pcide_bases[Q40IDE_NUM_HWIFS] = {
+ PCIDE_BASE1, PCIDE_BASE2, /* PCIDE_BASE3, PCIDE_BASE4 , PCIDE_BASE5,
+ PCIDE_BASE6 */
+};
+
+static int q40ide_default_irq(unsigned long base)
+{
+ switch (base) {
+ case 0x1f0: return 14;
+ case 0x170: return 15;
+ case 0x1e8: return 11;
+ default:
+ return 0;
+ }
+}
+
+
+/*
+ * Addresses are pretranslated for Q40 ISA access.
+ */
+static void q40_ide_setup_ports(hw_regs_t *hw, unsigned long base,
+ ide_ack_intr_t *ack_intr,
+ int irq)
+{
+ memset(hw, 0, sizeof(hw_regs_t));
+ /* BIG FAT WARNING:
+ assumption: only DATA port is ever used in 16 bit mode */
+ hw->io_ports.data_addr = Q40_ISA_IO_W(base);
+ hw->io_ports.error_addr = Q40_ISA_IO_B(base + 1);
+ hw->io_ports.nsect_addr = Q40_ISA_IO_B(base + 2);
+ hw->io_ports.lbal_addr = Q40_ISA_IO_B(base + 3);
+ hw->io_ports.lbam_addr = Q40_ISA_IO_B(base + 4);
+ hw->io_ports.lbah_addr = Q40_ISA_IO_B(base + 5);
+ hw->io_ports.device_addr = Q40_ISA_IO_B(base + 6);
+ hw->io_ports.status_addr = Q40_ISA_IO_B(base + 7);
+ hw->io_ports.ctl_addr = Q40_ISA_IO_B(base + 0x206);
+
+ hw->irq = irq;
+ hw->ack_intr = ack_intr;
+
+ hw->chipset = ide_generic;
+}
+
+static void q40ide_input_data(ide_drive_t *drive, struct request *rq,
+ void *buf, unsigned int len)
+{
+ unsigned long data_addr = drive->hwif->io_ports.data_addr;
+
+ if (drive->media == ide_disk && rq && rq->cmd_type == REQ_TYPE_FS)
+ return insw(data_addr, buf, (len + 1) / 2);
+
+ insw_swapw(data_addr, buf, (len + 1) / 2);
+}
+
+static void q40ide_output_data(ide_drive_t *drive, struct request *rq,
+ void *buf, unsigned int len)
+{
+ unsigned long data_addr = drive->hwif->io_ports.data_addr;
+
+ if (drive->media == ide_disk && rq && rq->cmd_type == REQ_TYPE_FS)
+ return outsw(data_addr, buf, (len + 1) / 2);
+
+ outsw_swapw(data_addr, buf, (len + 1) / 2);
+}
+
+/* Q40 has a byte-swapped IDE interface */
+static const struct ide_tp_ops q40ide_tp_ops = {
+ .exec_command = ide_exec_command,
+ .read_status = ide_read_status,
+ .read_altstatus = ide_read_altstatus,
+ .read_sff_dma_status = ide_read_sff_dma_status,
+
+ .set_irq = ide_set_irq,
+
+ .tf_load = ide_tf_load,
+ .tf_read = ide_tf_read,
+
+ .input_data = q40ide_input_data,
+ .output_data = q40ide_output_data,
+};
+
+static const struct ide_port_info q40ide_port_info = {
+ .tp_ops = &q40ide_tp_ops,
+ .host_flags = IDE_HFLAG_NO_DMA,
+};
+
+/*
+ * the static array is needed to have the name reported in /proc/ioports,
+ * hwif->name unfortunately isn't available yet
+ */
+static const char *q40_ide_names[Q40IDE_NUM_HWIFS]={
+ "ide0", "ide1"
+};
+
+/*
+ * Probe for Q40 IDE interfaces
+ */
+
+static int __init q40ide_init(void)
+{
+ int i;
+ hw_regs_t hw[Q40IDE_NUM_HWIFS], *hws[] = { NULL, NULL, NULL, NULL };
+
+ if (!MACH_IS_Q40)
+ return -ENODEV;
+
+ printk(KERN_INFO "ide: Q40 IDE controller\n");
+
+ for (i = 0; i < Q40IDE_NUM_HWIFS; i++) {
+ const char *name = q40_ide_names[i];
+
+ if (!request_region(pcide_bases[i], 8, name)) {
+ printk("could not reserve ports %lx-%lx for %s\n",
+ pcide_bases[i],pcide_bases[i]+8,name);
+ continue;
+ }
+ if (!request_region(pcide_bases[i]+0x206, 1, name)) {
+ printk("could not reserve port %lx for %s\n",
+ pcide_bases[i]+0x206,name);
+ release_region(pcide_bases[i], 8);
+ continue;
+ }
+ q40_ide_setup_ports(&hw[i], pcide_bases[i], NULL,
+ q40ide_default_irq(pcide_bases[i]));
+
+ hws[i] = &hw[i];
+ }
+
+ return ide_host_add(&q40ide_port_info, hws, NULL);
+}
+
+module_init(q40ide_init);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/qd65xx.c b/drivers/ide/qd65xx.c
new file mode 100644
index 0000000..bc27c7a
--- /dev/null
+++ b/drivers/ide/qd65xx.c
@@ -0,0 +1,429 @@
+/*
+ * Copyright (C) 1996-2001 Linus Torvalds & author (see below)
+ */
+
+/*
+ * Version 0.03 Cleaned auto-tune, added probe
+ * Version 0.04 Added second channel tuning
+ * Version 0.05 Enhanced tuning ; added qd6500 support
+ * Version 0.06 Added dos driver's list
+ * Version 0.07 Second channel bug fix
+ *
+ * QDI QD6500/QD6580 EIDE controller fast support
+ *
+ * To activate controller support, use "ide0=qd65xx"
+ */
+
+/*
+ * Rewritten from the work of Colten Edwards <pje120@cs.usask.ca> by
+ * Samuel Thibault <samuel.thibault@fnac.net>
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+#include <asm/system.h>
+#include <asm/io.h>
+
+#define DRV_NAME "qd65xx"
+
+#include "qd65xx.h"
+
+/*
+ * I/O ports are 0x30-0x31 (and 0x32-0x33 for qd6580)
+ * or 0xb0-0xb1 (and 0xb2-0xb3 for qd6580)
+ * -- qd6500 is a single IDE interface
+ * -- qd6580 is a dual IDE interface
+ *
+ * More research on qd6580 being done by willmore@cig.mot.com (David)
+ * More Information given by Petr Soucek (petr@ryston.cz)
+ * http://www.ryston.cz/petr/vlb
+ */
+
+/*
+ * base: Timer1
+ *
+ *
+ * base+0x01: Config (R/O)
+ *
+ * bit 0: ide baseport: 1 = 0x1f0 ; 0 = 0x170 (only useful for qd6500)
+ * bit 1: qd65xx baseport: 1 = 0xb0 ; 0 = 0x30
+ * bit 2: ID3: bus speed: 1 = <=33MHz ; 0 = >33MHz
+ * bit 3: qd6500: 1 = disabled, 0 = enabled
+ * qd6580: 1
+ * upper nibble:
+ * qd6500: 1100
+ * qd6580: either 1010 or 0101
+ *
+ *
+ * base+0x02: Timer2 (qd6580 only)
+ *
+ *
+ * base+0x03: Control (qd6580 only)
+ *
+ * bits 0-3 must always be set 1
+ * bit 4 must be set 1, but is set 0 by dos driver while measuring vlb clock
+ * bit 0 : 1 = Only primary port enabled : channel 0 for hda, channel 1 for hdb
+ * 0 = Primary and Secondary ports enabled : channel 0 for hda & hdb
+ * channel 1 for hdc & hdd
+ * bit 1 : 1 = only disks on primary port
+ * 0 = disks & ATAPI devices on primary port
+ * bit 2-4 : always 0
+ * bit 5 : status, but of what ?
+ * bit 6 : always set 1 by dos driver
+ * bit 7 : set 1 for non-ATAPI devices on primary port
+ * (maybe read-ahead and post-write buffer ?)
+ */
+
+static int timings[4]={-1,-1,-1,-1}; /* stores current timing for each timer */
+
+/*
+ * qd65xx_select:
+ *
+ * This routine is invoked to prepare for access to a given drive.
+ */
+
+static void qd65xx_select(ide_drive_t *drive)
+{
+ u8 index = (( (QD_TIMREG(drive)) & 0x80 ) >> 7) |
+ (QD_TIMREG(drive) & 0x02);
+
+ if (timings[index] != QD_TIMING(drive))
+ outb(timings[index] = QD_TIMING(drive), QD_TIMREG(drive));
+}
+
+/*
+ * qd6500_compute_timing
+ *
+ * computes the timing value where
+ * lower nibble represents active time, in count of VLB clocks
+ * upper nibble represents recovery time, in count of VLB clocks
+ */
+
+static u8 qd6500_compute_timing (ide_hwif_t *hwif, int active_time, int recovery_time)
+{
+ int clk = ide_vlb_clk ? ide_vlb_clk : 50;
+ u8 act_cyc, rec_cyc;
+
+ if (clk <= 33) {
+ act_cyc = 9 - IDE_IN(active_time * clk / 1000 + 1, 2, 9);
+ rec_cyc = 15 - IDE_IN(recovery_time * clk / 1000 + 1, 0, 15);
+ } else {
+ act_cyc = 8 - IDE_IN(active_time * clk / 1000 + 1, 1, 8);
+ rec_cyc = 18 - IDE_IN(recovery_time * clk / 1000 + 1, 3, 18);
+ }
+
+ return (rec_cyc << 4) | 0x08 | act_cyc;
+}
+
+/*
+ * qd6580_compute_timing
+ *
+ * idem for qd6580
+ */
+
+static u8 qd6580_compute_timing (int active_time, int recovery_time)
+{
+ int clk = ide_vlb_clk ? ide_vlb_clk : 50;
+ u8 act_cyc, rec_cyc;
+
+ act_cyc = 17 - IDE_IN(active_time * clk / 1000 + 1, 2, 17);
+ rec_cyc = 15 - IDE_IN(recovery_time * clk / 1000 + 1, 2, 15);
+
+ return (rec_cyc << 4) | act_cyc;
+}
+
+/*
+ * qd_find_disk_type
+ *
+ * tries to find timing from dos driver's table
+ */
+
+static int qd_find_disk_type (ide_drive_t *drive,
+ int *active_time, int *recovery_time)
+{
+ struct qd65xx_timing_s *p;
+ char *m = (char *)&drive->id[ATA_ID_PROD];
+ char model[ATA_ID_PROD_LEN];
+
+ if (*m == 0)
+ return 0;
+
+ strncpy(model, m, ATA_ID_PROD_LEN);
+ ide_fixstring(model, ATA_ID_PROD_LEN, 1); /* byte-swap */
+
+ for (p = qd65xx_timing ; p->offset != -1 ; p++) {
+ if (!strncmp(p->model, model+p->offset, 4)) {
+ printk(KERN_DEBUG "%s: listed !\n", drive->name);
+ *active_time = p->active;
+ *recovery_time = p->recovery;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/*
+ * qd_set_timing:
+ *
+ * records the timing
+ */
+
+static void qd_set_timing (ide_drive_t *drive, u8 timing)
+{
+ drive->drive_data &= 0xff00;
+ drive->drive_data |= timing;
+
+ printk(KERN_DEBUG "%s: %#x\n", drive->name, timing);
+}
+
+static void qd6500_set_pio_mode(ide_drive_t *drive, const u8 pio)
+{
+ u16 *id = drive->id;
+ int active_time = 175;
+ int recovery_time = 415; /* worst case values from the dos driver */
+
+ /*
+ * FIXME: use "pio" value
+ */
+ if (!qd_find_disk_type(drive, &active_time, &recovery_time) &&
+ (id[ATA_ID_OLD_PIO_MODES] & 0xff) && (id[ATA_ID_FIELD_VALID] & 2) &&
+ id[ATA_ID_EIDE_PIO] >= 240) {
+ printk(KERN_INFO "%s: PIO mode%d\n", drive->name,
+ id[ATA_ID_OLD_PIO_MODES] & 0xff);
+ active_time = 110;
+ recovery_time = drive->id[ATA_ID_EIDE_PIO] - 120;
+ }
+
+ qd_set_timing(drive, qd6500_compute_timing(HWIF(drive), active_time, recovery_time));
+}
+
+static void qd6580_set_pio_mode(ide_drive_t *drive, const u8 pio)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ struct ide_timing *t = ide_timing_find_mode(XFER_PIO_0 + pio);
+ unsigned int cycle_time;
+ int active_time = 175;
+ int recovery_time = 415; /* worst case values from the dos driver */
+ u8 base = (hwif->config_data & 0xff00) >> 8;
+
+ if (drive->id && !qd_find_disk_type(drive, &active_time, &recovery_time)) {
+ cycle_time = ide_pio_cycle_time(drive, pio);
+
+ switch (pio) {
+ case 0: break;
+ case 3:
+ if (cycle_time >= 110) {
+ active_time = 86;
+ recovery_time = cycle_time - 102;
+ } else
+ printk(KERN_WARNING "%s: Strange recovery time !\n",drive->name);
+ break;
+ case 4:
+ if (cycle_time >= 69) {
+ active_time = 70;
+ recovery_time = cycle_time - 61;
+ } else
+ printk(KERN_WARNING "%s: Strange recovery time !\n",drive->name);
+ break;
+ default:
+ if (cycle_time >= 180) {
+ active_time = 110;
+ recovery_time = cycle_time - 120;
+ } else {
+ active_time = t->active;
+ recovery_time = cycle_time - active_time;
+ }
+ }
+ printk(KERN_INFO "%s: PIO mode%d\n", drive->name,pio);
+ }
+
+ if (!HWIF(drive)->channel && drive->media != ide_disk) {
+ outb(0x5f, QD_CONTROL_PORT);
+ printk(KERN_WARNING "%s: ATAPI: disabled read-ahead FIFO "
+ "and post-write buffer on %s.\n",
+ drive->name, HWIF(drive)->name);
+ }
+
+ qd_set_timing(drive, qd6580_compute_timing(active_time, recovery_time));
+}
+
+/*
+ * qd_testreg
+ *
+ * tests if the given port is a register
+ */
+
+static int __init qd_testreg(int port)
+{
+ unsigned long flags;
+ u8 savereg, readreg;
+
+ local_irq_save(flags);
+ savereg = inb_p(port);
+ outb_p(QD_TESTVAL, port); /* safe value */
+ readreg = inb_p(port);
+ outb(savereg, port);
+ local_irq_restore(flags);
+
+ if (savereg == QD_TESTVAL) {
+ printk(KERN_ERR "Outch ! the probe for qd65xx isn't reliable !\n");
+ printk(KERN_ERR "Please contact maintainers to tell about your hardware\n");
+ printk(KERN_ERR "Assuming qd65xx is not present.\n");
+ return 1;
+ }
+
+ return (readreg != QD_TESTVAL);
+}
+
+static void __init qd6500_init_dev(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ u8 base = (hwif->config_data & 0xff00) >> 8;
+ u8 config = QD_CONFIG(hwif);
+
+ drive->drive_data = QD6500_DEF_DATA;
+}
+
+static void __init qd6580_init_dev(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ u16 t1, t2;
+ u8 base = (hwif->config_data & 0xff00) >> 8;
+ u8 config = QD_CONFIG(hwif);
+
+ if (hwif->host_flags & IDE_HFLAG_SINGLE) {
+ t1 = QD6580_DEF_DATA;
+ t2 = QD6580_DEF_DATA2;
+ } else
+ t2 = t1 = hwif->channel ? QD6580_DEF_DATA2 : QD6580_DEF_DATA;
+
+ drive->drive_data = (drive->dn & 1) ? t2 : t1;
+}
+
+static const struct ide_port_ops qd6500_port_ops = {
+ .init_dev = qd6500_init_dev,
+ .set_pio_mode = qd6500_set_pio_mode,
+ .selectproc = qd65xx_select,
+};
+
+static const struct ide_port_ops qd6580_port_ops = {
+ .init_dev = qd6580_init_dev,
+ .set_pio_mode = qd6580_set_pio_mode,
+ .selectproc = qd65xx_select,
+};
+
+static const struct ide_port_info qd65xx_port_info __initdata = {
+ .name = DRV_NAME,
+ .chipset = ide_qd65xx,
+ .host_flags = IDE_HFLAG_IO_32BIT |
+ IDE_HFLAG_NO_DMA,
+ .pio_mask = ATA_PIO4,
+};
+
+/*
+ * qd_probe:
+ *
+ * looks at the specified baseport, and if qd found, registers & initialises it
+ * return 1 if another qd may be probed
+ */
+
+static int __init qd_probe(int base)
+{
+ int rc;
+ u8 config, unit, control;
+ struct ide_port_info d = qd65xx_port_info;
+
+ config = inb(QD_CONFIG_PORT);
+
+ if (! ((config & QD_CONFIG_BASEPORT) >> 1 == (base == 0xb0)) )
+ return -ENODEV;
+
+ unit = ! (config & QD_CONFIG_IDE_BASEPORT);
+
+ if (unit)
+ d.host_flags |= IDE_HFLAG_QD_2ND_PORT;
+
+ switch (config & 0xf0) {
+ case QD_CONFIG_QD6500:
+ if (qd_testreg(base))
+ return -ENODEV; /* bad register */
+
+ if (config & QD_CONFIG_DISABLED) {
+ printk(KERN_WARNING "qd6500 is disabled !\n");
+ return -ENODEV;
+ }
+
+ printk(KERN_NOTICE "qd6500 at %#x\n", base);
+ printk(KERN_DEBUG "qd6500: config=%#x, ID3=%u\n",
+ config, QD_ID3);
+
+ d.port_ops = &qd6500_port_ops;
+ d.host_flags |= IDE_HFLAG_SINGLE;
+ break;
+ case QD_CONFIG_QD6580_A:
+ case QD_CONFIG_QD6580_B:
+ if (qd_testreg(base) || qd_testreg(base + 0x02))
+ return -ENODEV; /* bad registers */
+
+ control = inb(QD_CONTROL_PORT);
+
+ printk(KERN_NOTICE "qd6580 at %#x\n", base);
+ printk(KERN_DEBUG "qd6580: config=%#x, control=%#x, ID3=%u\n",
+ config, control, QD_ID3);
+
+ outb(QD_DEF_CONTR, QD_CONTROL_PORT);
+
+ d.port_ops = &qd6580_port_ops;
+ if (control & QD_CONTR_SEC_DISABLED)
+ d.host_flags |= IDE_HFLAG_SINGLE;
+
+ printk(KERN_INFO "qd6580: %s IDE board\n",
+ (control & QD_CONTR_SEC_DISABLED) ? "single" : "dual");
+ break;
+ default:
+ return -ENODEV;
+ }
+
+ rc = ide_legacy_device_add(&d, (base << 8) | config);
+
+ if (d.host_flags & IDE_HFLAG_SINGLE)
+ return (rc == 0) ? 1 : rc;
+
+ return rc;
+}
+
+static int probe_qd65xx;
+
+module_param_named(probe, probe_qd65xx, bool, 0);
+MODULE_PARM_DESC(probe, "probe for QD65xx chipsets");
+
+static int __init qd65xx_init(void)
+{
+ int rc1, rc2 = -ENODEV;
+
+ if (probe_qd65xx == 0)
+ return -ENODEV;
+
+ rc1 = qd_probe(0x30);
+ if (rc1)
+ rc2 = qd_probe(0xb0);
+
+ if (rc1 < 0 && rc2 < 0)
+ return -ENODEV;
+
+ return 0;
+}
+
+module_init(qd65xx_init);
+
+MODULE_AUTHOR("Samuel Thibault");
+MODULE_DESCRIPTION("support of qd65xx vlb ide chipset");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/qd65xx.h b/drivers/ide/qd65xx.h
new file mode 100644
index 0000000..c83dea8
--- /dev/null
+++ b/drivers/ide/qd65xx.h
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2000 Linus Torvalds & authors
+ */
+
+/*
+ * Authors: Petr Soucek <petr@ryston.cz>
+ * Samuel Thibault <samuel.thibault@fnac.net>
+ */
+
+/* truncates a in [b,c] */
+#define IDE_IN(a,b,c) ( ((a)<(b)) ? (b) : ( (a)>(c) ? (c) : (a)) )
+
+#define IDE_IMPLY(a,b) ((!(a)) || (b))
+
+#define QD_TIM1_PORT (base)
+#define QD_CONFIG_PORT (base+0x01)
+#define QD_TIM2_PORT (base+0x02)
+#define QD_CONTROL_PORT (base+0x03)
+
+#define QD_CONFIG_IDE_BASEPORT 0x01
+#define QD_CONFIG_BASEPORT 0x02
+#define QD_CONFIG_ID3 0x04
+#define QD_CONFIG_DISABLED 0x08
+#define QD_CONFIG_QD6500 0xc0
+#define QD_CONFIG_QD6580_A 0xa0
+#define QD_CONFIG_QD6580_B 0x50
+
+#define QD_CONTR_SEC_DISABLED 0x01
+
+#define QD_ID3 ((config & QD_CONFIG_ID3)!=0)
+
+#define QD_CONFIG(hwif) ((hwif)->config_data & 0x00ff)
+
+#define QD_TIMING(drive) (byte)(((drive)->drive_data) & 0x00ff)
+#define QD_TIMREG(drive) (byte)((((drive)->drive_data) & 0xff00) >> 8)
+
+#define QD6500_DEF_DATA ((QD_TIM1_PORT<<8) | (QD_ID3 ? 0x0c : 0x08))
+#define QD6580_DEF_DATA ((QD_TIM1_PORT<<8) | (QD_ID3 ? 0x0a : 0x00))
+#define QD6580_DEF_DATA2 ((QD_TIM2_PORT<<8) | (QD_ID3 ? 0x0a : 0x00))
+#define QD_DEF_CONTR (0x40 | ((control & 0x02) ? 0x9f : 0x1f))
+
+#define QD_TESTVAL 0x19 /* safe value */
+
+/* Drive specific timing taken from DOS driver v3.7 */
+
+static struct qd65xx_timing_s {
+ s8 offset; /* ofset from the beginning of Model Number" */
+ char model[4]; /* 4 chars from Model number, no conversion */
+ s16 active; /* active time */
+ s16 recovery; /* recovery time */
+} qd65xx_timing [] = {
+ { 30, "2040", 110, 225 }, /* Conner CP30204 */
+ { 30, "2045", 135, 225 }, /* Conner CP30254 */
+ { 30, "1040", 155, 325 }, /* Conner CP30104 */
+ { 30, "1047", 135, 265 }, /* Conner CP30174 */
+ { 30, "5344", 135, 225 }, /* Conner CP3544 */
+ { 30, "01 4", 175, 405 }, /* Conner CP-3104 */
+ { 27, "C030", 175, 375 }, /* Conner CP3000 */
+ { 8, "PL42", 110, 295 }, /* Quantum LP240 */
+ { 8, "PL21", 110, 315 }, /* Quantum LP120 */
+ { 8, "PL25", 175, 385 }, /* Quantum LP52 */
+ { 4, "PA24", 110, 285 }, /* WD Piranha SP4200 */
+ { 6, "2200", 110, 260 }, /* WD Caviar AC2200 */
+ { 6, "3204", 110, 235 }, /* WD Caviar AC2340 */
+ { 6, "1202", 110, 265 }, /* WD Caviar AC2120 */
+ { 0, "DS3-", 135, 315 }, /* Teac SD340 */
+ { 8, "KM32", 175, 355 }, /* Toshiba MK234 */
+ { 2, "53A1", 175, 355 }, /* Seagate ST351A */
+ { 2, "4108", 175, 295 }, /* Seagate ST1480A */
+ { 2, "1344", 175, 335 }, /* Seagate ST3144A */
+ { 6, "7 12", 110, 225 }, /* Maxtor 7213A */
+ { 30, "02F4", 145, 295 }, /* Conner 3204F */
+ { 2, "1302", 175, 335 }, /* Seagate ST3120A */
+ { 2, "2334", 145, 265 }, /* Seagate ST3243A */
+ { 2, "2338", 145, 275 }, /* Seagate ST3283A */
+ { 2, "3309", 145, 275 }, /* Seagate ST3390A */
+ { 2, "5305", 145, 275 }, /* Seagate ST3550A */
+ { 2, "4100", 175, 295 }, /* Seagate ST1400A */
+ { 2, "4110", 175, 295 }, /* Seagate ST1401A */
+ { 2, "6300", 135, 265 }, /* Seagate ST3600A */
+ { 2, "5300", 135, 265 }, /* Seagate ST3500A */
+ { 6, "7 31", 135, 225 }, /* Maxtor 7131 AT */
+ { 6, "7 43", 115, 265 }, /* Maxtor 7345 AT */
+ { 6, "7 42", 110, 255 }, /* Maxtor 7245 AT */
+ { 6, "3 04", 135, 265 }, /* Maxtor 340 AT */
+ { 6, "61 0", 135, 285 }, /* WD AC160 */
+ { 6, "1107", 135, 235 }, /* WD AC1170 */
+ { 6, "2101", 110, 220 }, /* WD AC1210 */
+ { 6, "4202", 135, 245 }, /* WD AC2420 */
+ { 6, "41 0", 175, 355 }, /* WD Caviar 140 */
+ { 6, "82 0", 175, 355 }, /* WD Caviar 280 */
+ { 8, "PL01", 175, 375 }, /* Quantum LP105 */
+ { 8, "PL25", 110, 295 }, /* Quantum LP525 */
+ { 10, "4S 2", 175, 385 }, /* Quantum ELS42 */
+ { 10, "8S 5", 175, 385 }, /* Quantum ELS85 */
+ { 10, "1S72", 175, 385 }, /* Quantum ELS127 */
+ { 10, "1S07", 175, 385 }, /* Quantum ELS170 */
+ { 8, "ZE42", 135, 295 }, /* Quantum EZ240 */
+ { 8, "ZE21", 175, 385 }, /* Quantum EZ127 */
+ { 8, "ZE58", 175, 385 }, /* Quantum EZ85 */
+ { 8, "ZE24", 175, 385 }, /* Quantum EZ42 */
+ { 27, "C036", 155, 325 }, /* Conner CP30064 */
+ { 27, "C038", 155, 325 }, /* Conner CP30084 */
+ { 6, "2205", 110, 255 }, /* WDC AC2250 */
+ { 2, " CHA", 140, 415 }, /* WDC AH series; WDC AH260, WDC */
+ { 2, " CLA", 140, 415 }, /* WDC AL series: WDC AL2120, 2170, */
+ { 4, "UC41", 140, 415 }, /* WDC CU140 */
+ { 6, "1207", 130, 275 }, /* WDC AC2170 */
+ { 6, "2107", 130, 275 }, /* WDC AC1270 */
+ { 6, "5204", 130, 275 }, /* WDC AC2540 */
+ { 30, "3004", 110, 235 }, /* Conner CP30340 */
+ { 30, "0345", 135, 255 }, /* Conner CP30544 */
+ { 12, "12A3", 175, 320 }, /* MAXTOR LXT-213A */
+ { 12, "43A0", 145, 240 }, /* MAXTOR LXT-340A */
+ { 6, "7 21", 180, 290 }, /* Maxtor 7120 AT */
+ { 6, "7 71", 135, 240 }, /* Maxtor 7170 AT */
+ { 12, "45\0000", 110, 205 }, /* MAXTOR MXT-540 */
+ { 8, "PL11", 180, 290 }, /* QUANTUM LP110A */
+ { 8, "OG21", 150, 275 }, /* QUANTUM GO120 */
+ { 12, "42A5", 175, 320 }, /* MAXTOR LXT-245A */
+ { 2, "2309", 175, 295 }, /* ST3290A */
+ { 2, "3358", 180, 310 }, /* ST3385A */
+ { 2, "6355", 180, 310 }, /* ST3655A */
+ { 2, "1900", 175, 270 }, /* ST9100A */
+ { 2, "1954", 175, 270 }, /* ST9145A */
+ { 2, "1909", 175, 270 }, /* ST9190AG */
+ { 2, "2953", 175, 270 }, /* ST9235A */
+ { 2, "1359", 175, 270 }, /* ST3195A */
+ { 24, "3R11", 175, 290 }, /* ALPS ELECTRIC Co.,LTD, DR311C */
+ { 0, "2M26", 175, 215 }, /* M262XT-0Ah */
+ { 4, "2253", 175, 300 }, /* HP C2235A */
+ { 4, "-32A", 145, 245 }, /* H3133-A2 */
+ { 30, "0326", 150, 270 }, /* Samsung Electronics 120MB */
+ { 30, "3044", 110, 195 }, /* Conner CFA340A */
+ { 30, "43A0", 110, 195 }, /* Conner CFA340A */
+ { -1, " ", 175, 415 } /* unknown disk name */
+};
diff --git a/drivers/ide/rapide.c b/drivers/ide/rapide.c
new file mode 100644
index 0000000..d5003ca
--- /dev/null
+++ b/drivers/ide/rapide.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 1996-2002 Russell King.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/blkdev.h>
+#include <linux/errno.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/ecard.h>
+
+static const struct ide_port_info rapide_port_info = {
+ .host_flags = IDE_HFLAG_MMIO | IDE_HFLAG_NO_DMA,
+};
+
+static void rapide_setup_ports(hw_regs_t *hw, void __iomem *base,
+ void __iomem *ctrl, unsigned int sz, int irq)
+{
+ unsigned long port = (unsigned long)base;
+ int i;
+
+ for (i = 0; i <= 7; i++) {
+ hw->io_ports_array[i] = port;
+ port += sz;
+ }
+ hw->io_ports.ctl_addr = (unsigned long)ctrl;
+ hw->irq = irq;
+}
+
+static int __devinit
+rapide_probe(struct expansion_card *ec, const struct ecard_id *id)
+{
+ void __iomem *base;
+ struct ide_host *host;
+ int ret;
+ hw_regs_t hw, *hws[] = { &hw, NULL, NULL, NULL };
+
+ ret = ecard_request_resources(ec);
+ if (ret)
+ goto out;
+
+ base = ecardm_iomap(ec, ECARD_RES_MEMC, 0, 0);
+ if (!base) {
+ ret = -ENOMEM;
+ goto release;
+ }
+
+ memset(&hw, 0, sizeof(hw));
+ rapide_setup_ports(&hw, base, base + 0x818, 1 << 6, ec->irq);
+ hw.chipset = ide_generic;
+ hw.dev = &ec->dev;
+
+ ret = ide_host_add(&rapide_port_info, hws, &host);
+ if (ret)
+ goto release;
+
+ ecard_set_drvdata(ec, host);
+ goto out;
+
+ release:
+ ecard_release_resources(ec);
+ out:
+ return ret;
+}
+
+static void __devexit rapide_remove(struct expansion_card *ec)
+{
+ struct ide_host *host = ecard_get_drvdata(ec);
+
+ ecard_set_drvdata(ec, NULL);
+
+ ide_host_remove(host);
+
+ ecard_release_resources(ec);
+}
+
+static struct ecard_id rapide_ids[] = {
+ { MANU_YELLOWSTONE, PROD_YELLOWSTONE_RAPIDE32 },
+ { 0xffff, 0xffff }
+};
+
+static struct ecard_driver rapide_driver = {
+ .probe = rapide_probe,
+ .remove = __devexit_p(rapide_remove),
+ .id_table = rapide_ids,
+ .drv = {
+ .name = "rapide",
+ },
+};
+
+static int __init rapide_init(void)
+{
+ return ecard_register_driver(&rapide_driver);
+}
+
+static void __exit rapide_exit(void)
+{
+ ecard_remove_driver(&rapide_driver);
+}
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Yellowstone RAPIDE driver");
+
+module_init(rapide_init);
+module_exit(rapide_exit);
diff --git a/drivers/ide/rz1000.c b/drivers/ide/rz1000.c
new file mode 100644
index 0000000..7daf013
--- /dev/null
+++ b/drivers/ide/rz1000.c
@@ -0,0 +1,85 @@
+/*
+ * 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.
+ *
+ * Dunno if this fixes both ports, or only the primary port (?).
+ */
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#define DRV_NAME "rz1000"
+
+static void __devinit init_hwif_rz1000 (ide_hwif_t *hwif)
+{
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+ u16 reg;
+
+ if (!pci_read_config_word (dev, 0x40, &reg) &&
+ !pci_write_config_word(dev, 0x40, reg & 0xdfff)) {
+ printk(KERN_INFO "%s: disabled chipset read-ahead "
+ "(buggy RZ1000/RZ1001)\n", hwif->name);
+ } else {
+ if (hwif->mate)
+ hwif->mate->serialized = hwif->serialized = 1;
+ hwif->host_flags |= IDE_HFLAG_NO_UNMASK_IRQS;
+ printk(KERN_INFO "%s: serialized, disabled unmasking "
+ "(buggy RZ1000/RZ1001)\n", hwif->name);
+ }
+}
+
+static const struct ide_port_info rz1000_chipset __devinitdata = {
+ .name = DRV_NAME,
+ .init_hwif = init_hwif_rz1000,
+ .chipset = ide_rz1000,
+ .host_flags = IDE_HFLAG_NO_DMA,
+};
+
+static int __devinit rz1000_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ return ide_pci_init_one(dev, &rz1000_chipset, NULL);
+}
+
+static const struct pci_device_id rz1000_pci_tbl[] = {
+ { PCI_VDEVICE(PCTECH, PCI_DEVICE_ID_PCTECH_RZ1000), 0 },
+ { PCI_VDEVICE(PCTECH, PCI_DEVICE_ID_PCTECH_RZ1001), 0 },
+ { 0, },
+};
+MODULE_DEVICE_TABLE(pci, rz1000_pci_tbl);
+
+static struct pci_driver rz1000_pci_driver = {
+ .name = "RZ1000_IDE",
+ .id_table = rz1000_pci_tbl,
+ .probe = rz1000_init_one,
+ .remove = ide_pci_remove,
+};
+
+static int __init rz1000_ide_init(void)
+{
+ return ide_pci_register_driver(&rz1000_pci_driver);
+}
+
+static void __exit rz1000_ide_exit(void)
+{
+ pci_unregister_driver(&rz1000_pci_driver);
+}
+
+module_init(rz1000_ide_init);
+module_exit(rz1000_ide_exit);
+
+MODULE_AUTHOR("Andre Hedrick");
+MODULE_DESCRIPTION("PCI driver module for RZ1000 IDE");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/ide/sc1200.c b/drivers/ide/sc1200.c
new file mode 100644
index 0000000..ec7f766
--- /dev/null
+++ b/drivers/ide/sc1200.c
@@ -0,0 +1,358 @@
+/*
+ * Copyright (C) 2000-2002 Mark Lord <mlord@pobox.com>
+ * Copyright (C) 2007 Bartlomiej Zolnierkiewicz
+ *
+ * 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.
+ *
+ * Documentation:
+ * Available from National Semiconductor
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/ide.h>
+#include <linux/pm.h>
+
+#include <asm/io.h>
+
+#define DRV_NAME "sc1200"
+
+#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
+
+#define PCI_CLK_33 0x00
+#define PCI_CLK_48 0x01
+#define PCI_CLK_66 0x02
+#define PCI_CLK_33A 0x03
+
+static unsigned short sc1200_get_pci_clock (void)
+{
+ unsigned char chip_id, silicon_revision;
+ unsigned int pci_clock;
+ /*
+ * Check the silicon revision, as not all versions of the chip
+ * have the register with the fast PCI bus timings.
+ */
+ chip_id = inb (0x903c);
+ silicon_revision = inb (0x903d);
+
+ // Read the fast pci clock frequency
+ if (chip_id == 0x04 && silicon_revision < SC1200_REV_B1) {
+ pci_clock = PCI_CLK_33;
+ } else {
+ // check clock generator configuration (cfcc)
+ // the clock is in bits 8 and 9 of this word
+
+ pci_clock = inw (0x901e);
+ pci_clock >>= 8;
+ pci_clock &= 0x03;
+ if (pci_clock == PCI_CLK_33A)
+ pci_clock = PCI_CLK_33;
+ }
+ return pci_clock;
+}
+
+/*
+ * Here are the standard PIO mode 0-4 timings for each "format".
+ * Format-0 uses fast data reg timings, with slower command reg timings.
+ * Format-1 uses fast timings for all registers, but won't work with all drives.
+ */
+static const unsigned int sc1200_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
+
+/*
+ * After chip reset, the PIO timings are set to 0x00009172, which is not valid.
+ */
+//#define SC1200_BAD_PIO(timings) (((timings)&~0x80000000)==0x00009172)
+
+static void sc1200_tunepio(ide_drive_t *drive, u8 pio)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ struct pci_dev *pdev = to_pci_dev(hwif->dev);
+ unsigned int basereg = hwif->channel ? 0x50 : 0x40, format = 0;
+
+ pci_read_config_dword(pdev, basereg + 4, &format);
+ format = (format >> 31) & 1;
+ if (format)
+ format += sc1200_get_pci_clock();
+ pci_write_config_dword(pdev, basereg + ((drive->dn & 1) << 3),
+ sc1200_pio_timings[format][pio]);
+}
+
+/*
+ * The SC1200 specifies that two drives sharing a cable cannot mix
+ * UDMA/MDMA. It has to be one or the other, for the pair, though
+ * different timings can still be chosen for each drive. We could
+ * set the appropriate timing bits on the fly, but that might be
+ * a bit confusing. So, for now we statically handle this requirement
+ * by looking at our mate drive to see what it is capable of, before
+ * choosing a mode for our own drive.
+ */
+static u8 sc1200_udma_filter(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ ide_drive_t *mate = ide_get_pair_dev(drive);
+ u16 *mateid;
+ u8 mask = hwif->ultra_mask;
+
+ if (mate == NULL)
+ goto out;
+ mateid = mate->id;
+
+ if (ata_id_has_dma(mateid) && __ide_dma_bad_drive(mate) == 0) {
+ if ((mateid[ATA_ID_FIELD_VALID] & 4) &&
+ (mateid[ATA_ID_UDMA_MODES] & 7))
+ goto out;
+ if ((mateid[ATA_ID_FIELD_VALID] & 2) &&
+ (mateid[ATA_ID_MWDMA_MODES] & 7))
+ mask = 0;
+ }
+out:
+ return mask;
+}
+
+static void sc1200_set_dma_mode(ide_drive_t *drive, const u8 mode)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+ unsigned int reg, timings;
+ unsigned short pci_clock;
+ unsigned int basereg = hwif->channel ? 0x50 : 0x40;
+
+ 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 },
+ };
+
+ pci_clock = sc1200_get_pci_clock();
+
+ /*
+ * Note that each DMA mode has several timings associated with it.
+ * The correct timing depends on the fast PCI clock freq.
+ */
+
+ if (mode >= XFER_UDMA_0)
+ timings = udma_timing[pci_clock][mode - XFER_UDMA_0];
+ else
+ timings = mwdma_timing[pci_clock][mode - XFER_MW_DMA_0];
+
+ if ((drive->dn & 1) == 0) {
+ pci_read_config_dword(dev, basereg + 4, &reg);
+ timings |= reg & 0x80000000; /* preserve PIO format bit */
+ pci_write_config_dword(dev, basereg + 4, timings);
+ } else
+ pci_write_config_dword(dev, basereg + 12, timings);
+}
+
+/* Replacement for the standard ide_dma_end action in
+ * dma_proc.
+ *
+ * returns 1 on error, 0 otherwise
+ */
+static int sc1200_dma_end(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ unsigned long dma_base = hwif->dma_base;
+ byte dma_stat;
+
+ dma_stat = inb(dma_base+2); /* get DMA status */
+
+ if (!(dma_stat & 4))
+ printk(" ide_dma_end dma_stat=%0x err=%x newerr=%x\n",
+ dma_stat, ((dma_stat&7)!=4), ((dma_stat&2)==2));
+
+ outb(dma_stat|0x1b, dma_base+2); /* clear the INTR & ERROR bits */
+ outb(inb(dma_base)&~1, dma_base); /* !! DO THIS HERE !! stop DMA */
+
+ drive->waiting_for_dma = 0;
+ ide_destroy_dmatable(drive); /* purge DMA mappings */
+
+ return (dma_stat & 7) != 4; /* verify good DMA status */
+}
+
+/*
+ * sc1200_set_pio_mode() handles setting of PIO modes
+ * for both the chipset and drive.
+ *
+ * All existing BIOSs for this chipset guarantee that all drives
+ * will have valid default PIO timings set up before we get here.
+ */
+
+static void sc1200_set_pio_mode(ide_drive_t *drive, const u8 pio)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ int mode = -1;
+
+ /*
+ * bad abuse of ->set_pio_mode interface
+ */
+ switch (pio) {
+ case 200: mode = XFER_UDMA_0; break;
+ case 201: mode = XFER_UDMA_1; break;
+ case 202: mode = XFER_UDMA_2; break;
+ case 100: mode = XFER_MW_DMA_0; break;
+ case 101: mode = XFER_MW_DMA_1; break;
+ case 102: mode = XFER_MW_DMA_2; break;
+ }
+ if (mode != -1) {
+ printk("SC1200: %s: changing (U)DMA mode\n", drive->name);
+ ide_dma_off_quietly(drive);
+ if (ide_set_dma_mode(drive, mode) == 0 &&
+ (drive->dev_flags & IDE_DFLAG_USING_DMA))
+ hwif->dma_ops->dma_host_set(drive, 1);
+ return;
+ }
+
+ sc1200_tunepio(drive, pio);
+}
+
+#ifdef CONFIG_PM
+struct sc1200_saved_state {
+ u32 regs[8];
+};
+
+static int sc1200_suspend (struct pci_dev *dev, pm_message_t state)
+{
+ printk("SC1200: suspend(%u)\n", state.event);
+
+ /*
+ * we only save state when going from full power to less
+ */
+ if (state.event == PM_EVENT_ON) {
+ struct ide_host *host = pci_get_drvdata(dev);
+ struct sc1200_saved_state *ss = host->host_priv;
+ unsigned int r;
+
+ /*
+ * save timing registers
+ * (this may be unnecessary if BIOS also does it)
+ */
+ for (r = 0; r < 8; r++)
+ pci_read_config_dword(dev, 0x40 + r * 4, &ss->regs[r]);
+ }
+
+ pci_disable_device(dev);
+ pci_set_power_state(dev, pci_choose_state(dev, state));
+ return 0;
+}
+
+static int sc1200_resume (struct pci_dev *dev)
+{
+ struct ide_host *host = pci_get_drvdata(dev);
+ struct sc1200_saved_state *ss = host->host_priv;
+ unsigned int r;
+ int i;
+
+ i = pci_enable_device(dev);
+ if (i)
+ return i;
+
+ /*
+ * restore timing registers
+ * (this may be unnecessary if BIOS also does it)
+ */
+ for (r = 0; r < 8; r++)
+ pci_write_config_dword(dev, 0x40 + r * 4, ss->regs[r]);
+
+ return 0;
+}
+#endif
+
+static const struct ide_port_ops sc1200_port_ops = {
+ .set_pio_mode = sc1200_set_pio_mode,
+ .set_dma_mode = sc1200_set_dma_mode,
+ .udma_filter = sc1200_udma_filter,
+};
+
+static const struct ide_dma_ops sc1200_dma_ops = {
+ .dma_host_set = ide_dma_host_set,
+ .dma_setup = ide_dma_setup,
+ .dma_exec_cmd = ide_dma_exec_cmd,
+ .dma_start = ide_dma_start,
+ .dma_end = sc1200_dma_end,
+ .dma_test_irq = ide_dma_test_irq,
+ .dma_lost_irq = ide_dma_lost_irq,
+ .dma_timeout = ide_dma_timeout,
+};
+
+static const struct ide_port_info sc1200_chipset __devinitdata = {
+ .name = DRV_NAME,
+ .port_ops = &sc1200_port_ops,
+ .dma_ops = &sc1200_dma_ops,
+ .host_flags = IDE_HFLAG_SERIALIZE |
+ IDE_HFLAG_POST_SET_MODE |
+ IDE_HFLAG_ABUSE_DMA_MODES,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA2,
+};
+
+static int __devinit sc1200_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ struct sc1200_saved_state *ss = NULL;
+ int rc;
+
+#ifdef CONFIG_PM
+ ss = kmalloc(sizeof(*ss), GFP_KERNEL);
+ if (ss == NULL)
+ return -ENOMEM;
+#endif
+ rc = ide_pci_init_one(dev, &sc1200_chipset, ss);
+ if (rc)
+ kfree(ss);
+
+ return rc;
+}
+
+static const struct pci_device_id sc1200_pci_tbl[] = {
+ { PCI_VDEVICE(NS, PCI_DEVICE_ID_NS_SCx200_IDE), 0},
+ { 0, },
+};
+MODULE_DEVICE_TABLE(pci, sc1200_pci_tbl);
+
+static struct pci_driver sc1200_pci_driver = {
+ .name = "SC1200_IDE",
+ .id_table = sc1200_pci_tbl,
+ .probe = sc1200_init_one,
+ .remove = ide_pci_remove,
+#ifdef CONFIG_PM
+ .suspend = sc1200_suspend,
+ .resume = sc1200_resume,
+#endif
+};
+
+static int __init sc1200_ide_init(void)
+{
+ return ide_pci_register_driver(&sc1200_pci_driver);
+}
+
+static void __exit sc1200_ide_exit(void)
+{
+ pci_unregister_driver(&sc1200_pci_driver);
+}
+
+module_init(sc1200_ide_init);
+module_exit(sc1200_ide_exit);
+
+MODULE_AUTHOR("Mark Lord");
+MODULE_DESCRIPTION("PCI driver module for NS SC1200 IDE");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/scc_pata.c b/drivers/ide/scc_pata.c
new file mode 100644
index 0000000..0f48f9d
--- /dev/null
+++ b/drivers/ide/scc_pata.c
@@ -0,0 +1,964 @@
+/*
+ * Support for IDE interfaces on Celleb platform
+ *
+ * (C) Copyright 2006 TOSHIBA CORPORATION
+ *
+ * This code is based on drivers/ide/pci/siimage.c:
+ * Copyright (C) 2001-2002 Andre Hedrick <andre@linux-ide.org>
+ * Copyright (C) 2003 Red Hat
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#define PCI_DEVICE_ID_TOSHIBA_SCC_ATA 0x01b4
+
+#define SCC_PATA_NAME "scc IDE"
+
+#define TDVHSEL_MASTER 0x00000001
+#define TDVHSEL_SLAVE 0x00000004
+
+#define MODE_JCUSFEN 0x00000080
+
+#define CCKCTRL_ATARESET 0x00040000
+#define CCKCTRL_BUFCNT 0x00020000
+#define CCKCTRL_CRST 0x00010000
+#define CCKCTRL_OCLKEN 0x00000100
+#define CCKCTRL_ATACLKOEN 0x00000002
+#define CCKCTRL_LCLKEN 0x00000001
+
+#define QCHCD_IOS_SS 0x00000001
+
+#define QCHSD_STPDIAG 0x00020000
+
+#define INTMASK_MSK 0xD1000012
+#define INTSTS_SERROR 0x80000000
+#define INTSTS_PRERR 0x40000000
+#define INTSTS_RERR 0x10000000
+#define INTSTS_ICERR 0x01000000
+#define INTSTS_BMSINT 0x00000010
+#define INTSTS_BMHE 0x00000008
+#define INTSTS_IOIRQS 0x00000004
+#define INTSTS_INTRQ 0x00000002
+#define INTSTS_ACTEINT 0x00000001
+
+#define ECMODE_VALUE 0x01
+
+static struct scc_ports {
+ unsigned long ctl, dma;
+ struct ide_host *host; /* for removing port from system */
+} scc_ports[MAX_HWIFS];
+
+/* PIO transfer mode table */
+/* JCHST */
+static unsigned long JCHSTtbl[2][7] = {
+ {0x0E, 0x05, 0x02, 0x03, 0x02, 0x00, 0x00}, /* 100MHz */
+ {0x13, 0x07, 0x04, 0x04, 0x03, 0x00, 0x00} /* 133MHz */
+};
+
+/* JCHHT */
+static unsigned long JCHHTtbl[2][7] = {
+ {0x0E, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00}, /* 100MHz */
+ {0x13, 0x03, 0x03, 0x03, 0x03, 0x00, 0x00} /* 133MHz */
+};
+
+/* JCHCT */
+static unsigned long JCHCTtbl[2][7] = {
+ {0x1D, 0x1D, 0x1C, 0x0B, 0x06, 0x00, 0x00}, /* 100MHz */
+ {0x27, 0x26, 0x26, 0x0E, 0x09, 0x00, 0x00} /* 133MHz */
+};
+
+
+/* DMA transfer mode table */
+/* JCHDCTM/JCHDCTS */
+static unsigned long JCHDCTxtbl[2][7] = {
+ {0x0A, 0x06, 0x04, 0x03, 0x01, 0x00, 0x00}, /* 100MHz */
+ {0x0E, 0x09, 0x06, 0x04, 0x02, 0x01, 0x00} /* 133MHz */
+};
+
+/* JCSTWTM/JCSTWTS */
+static unsigned long JCSTWTxtbl[2][7] = {
+ {0x06, 0x04, 0x03, 0x02, 0x02, 0x02, 0x00}, /* 100MHz */
+ {0x09, 0x06, 0x04, 0x02, 0x02, 0x02, 0x02} /* 133MHz */
+};
+
+/* JCTSS */
+static unsigned long JCTSStbl[2][7] = {
+ {0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x00}, /* 100MHz */
+ {0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05} /* 133MHz */
+};
+
+/* JCENVT */
+static unsigned long JCENVTtbl[2][7] = {
+ {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00}, /* 100MHz */
+ {0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02} /* 133MHz */
+};
+
+/* JCACTSELS/JCACTSELM */
+static unsigned long JCACTSELtbl[2][7] = {
+ {0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00}, /* 100MHz */
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01} /* 133MHz */
+};
+
+
+static u8 scc_ide_inb(unsigned long port)
+{
+ u32 data = in_be32((void*)port);
+ return (u8)data;
+}
+
+static void scc_exec_command(ide_hwif_t *hwif, u8 cmd)
+{
+ out_be32((void *)hwif->io_ports.command_addr, cmd);
+ eieio();
+ in_be32((void *)(hwif->dma_base + 0x01c));
+ eieio();
+}
+
+static u8 scc_read_status(ide_hwif_t *hwif)
+{
+ return (u8)in_be32((void *)hwif->io_ports.status_addr);
+}
+
+static u8 scc_read_altstatus(ide_hwif_t *hwif)
+{
+ return (u8)in_be32((void *)hwif->io_ports.ctl_addr);
+}
+
+static u8 scc_read_sff_dma_status(ide_hwif_t *hwif)
+{
+ return (u8)in_be32((void *)(hwif->dma_base + 4));
+}
+
+static void scc_set_irq(ide_hwif_t *hwif, int on)
+{
+ u8 ctl = ATA_DEVCTL_OBS;
+
+ if (on == 4) { /* hack for SRST */
+ ctl |= 4;
+ on &= ~4;
+ }
+
+ ctl |= on ? 0 : 2;
+
+ out_be32((void *)hwif->io_ports.ctl_addr, ctl);
+ eieio();
+ in_be32((void *)(hwif->dma_base + 0x01c));
+ eieio();
+}
+
+static void scc_ide_insw(unsigned long port, void *addr, u32 count)
+{
+ u16 *ptr = (u16 *)addr;
+ while (count--) {
+ *ptr++ = le16_to_cpu(in_be32((void*)port));
+ }
+}
+
+static void scc_ide_insl(unsigned long port, void *addr, u32 count)
+{
+ u16 *ptr = (u16 *)addr;
+ while (count--) {
+ *ptr++ = le16_to_cpu(in_be32((void*)port));
+ *ptr++ = le16_to_cpu(in_be32((void*)port));
+ }
+}
+
+static void scc_ide_outb(u8 addr, unsigned long port)
+{
+ out_be32((void*)port, addr);
+}
+
+static void
+scc_ide_outsw(unsigned long port, void *addr, u32 count)
+{
+ u16 *ptr = (u16 *)addr;
+ while (count--) {
+ out_be32((void*)port, cpu_to_le16(*ptr++));
+ }
+}
+
+static void
+scc_ide_outsl(unsigned long port, void *addr, u32 count)
+{
+ u16 *ptr = (u16 *)addr;
+ while (count--) {
+ out_be32((void*)port, cpu_to_le16(*ptr++));
+ out_be32((void*)port, cpu_to_le16(*ptr++));
+ }
+}
+
+/**
+ * scc_set_pio_mode - set host controller for PIO mode
+ * @drive: drive
+ * @pio: PIO mode number
+ *
+ * Load the timing settings for this device mode into the
+ * controller.
+ */
+
+static void scc_set_pio_mode(ide_drive_t *drive, const u8 pio)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct scc_ports *ports = ide_get_hwifdata(hwif);
+ unsigned long ctl_base = ports->ctl;
+ unsigned long cckctrl_port = ctl_base + 0xff0;
+ unsigned long piosht_port = ctl_base + 0x000;
+ unsigned long pioct_port = ctl_base + 0x004;
+ unsigned long reg;
+ int offset;
+
+ reg = in_be32((void __iomem *)cckctrl_port);
+ if (reg & CCKCTRL_ATACLKOEN) {
+ offset = 1; /* 133MHz */
+ } else {
+ offset = 0; /* 100MHz */
+ }
+ reg = JCHSTtbl[offset][pio] << 16 | JCHHTtbl[offset][pio];
+ out_be32((void __iomem *)piosht_port, reg);
+ reg = JCHCTtbl[offset][pio];
+ out_be32((void __iomem *)pioct_port, reg);
+}
+
+/**
+ * scc_set_dma_mode - set host controller for DMA mode
+ * @drive: drive
+ * @speed: DMA mode
+ *
+ * Load the timing settings for this device mode into the
+ * controller.
+ */
+
+static void scc_set_dma_mode(ide_drive_t *drive, const u8 speed)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct scc_ports *ports = ide_get_hwifdata(hwif);
+ unsigned long ctl_base = ports->ctl;
+ unsigned long cckctrl_port = ctl_base + 0xff0;
+ unsigned long mdmact_port = ctl_base + 0x008;
+ unsigned long mcrcst_port = ctl_base + 0x00c;
+ unsigned long sdmact_port = ctl_base + 0x010;
+ unsigned long scrcst_port = ctl_base + 0x014;
+ unsigned long udenvt_port = ctl_base + 0x018;
+ unsigned long tdvhsel_port = ctl_base + 0x020;
+ int is_slave = (&hwif->drives[1] == drive);
+ int offset, idx;
+ unsigned long reg;
+ unsigned long jcactsel;
+
+ reg = in_be32((void __iomem *)cckctrl_port);
+ if (reg & CCKCTRL_ATACLKOEN) {
+ offset = 1; /* 133MHz */
+ } else {
+ offset = 0; /* 100MHz */
+ }
+
+ idx = speed - XFER_UDMA_0;
+
+ jcactsel = JCACTSELtbl[offset][idx];
+ if (is_slave) {
+ out_be32((void __iomem *)sdmact_port, JCHDCTxtbl[offset][idx]);
+ out_be32((void __iomem *)scrcst_port, JCSTWTxtbl[offset][idx]);
+ jcactsel = jcactsel << 2;
+ out_be32((void __iomem *)tdvhsel_port, (in_be32((void __iomem *)tdvhsel_port) & ~TDVHSEL_SLAVE) | jcactsel);
+ } else {
+ out_be32((void __iomem *)mdmact_port, JCHDCTxtbl[offset][idx]);
+ out_be32((void __iomem *)mcrcst_port, JCSTWTxtbl[offset][idx]);
+ out_be32((void __iomem *)tdvhsel_port, (in_be32((void __iomem *)tdvhsel_port) & ~TDVHSEL_MASTER) | jcactsel);
+ }
+ reg = JCTSStbl[offset][idx] << 16 | JCENVTtbl[offset][idx];
+ out_be32((void __iomem *)udenvt_port, reg);
+}
+
+static void scc_dma_host_set(ide_drive_t *drive, int on)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ u8 unit = drive->dn & 1;
+ u8 dma_stat = scc_ide_inb(hwif->dma_base + 4);
+
+ if (on)
+ dma_stat |= (1 << (5 + unit));
+ else
+ dma_stat &= ~(1 << (5 + unit));
+
+ scc_ide_outb(dma_stat, hwif->dma_base + 4);
+}
+
+/**
+ * scc_ide_dma_setup - begin a DMA phase
+ * @drive: target device
+ *
+ * Build an IDE DMA PRD (IDE speak for scatter gather table)
+ * and then set up the DMA transfer registers.
+ *
+ * Returns 0 on success. If a PIO fallback is required then 1
+ * is returned.
+ */
+
+static int scc_dma_setup(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ struct request *rq = HWGROUP(drive)->rq;
+ unsigned int reading;
+ u8 dma_stat;
+
+ if (rq_data_dir(rq))
+ reading = 0;
+ else
+ reading = 1 << 3;
+
+ /* fall back to pio! */
+ if (!ide_build_dmatable(drive, rq)) {
+ ide_map_sg(drive, rq);
+ return 1;
+ }
+
+ /* PRD table */
+ out_be32((void __iomem *)(hwif->dma_base + 8), hwif->dmatable_dma);
+
+ /* specify r/w */
+ out_be32((void __iomem *)hwif->dma_base, reading);
+
+ /* read DMA status for INTR & ERROR flags */
+ dma_stat = in_be32((void __iomem *)(hwif->dma_base + 4));
+
+ /* clear INTR & ERROR flags */
+ out_be32((void __iomem *)(hwif->dma_base + 4), dma_stat | 6);
+ drive->waiting_for_dma = 1;
+ return 0;
+}
+
+static void scc_dma_start(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ u8 dma_cmd = scc_ide_inb(hwif->dma_base);
+
+ /* start DMA */
+ scc_ide_outb(dma_cmd | 1, hwif->dma_base);
+ wmb();
+}
+
+static int __scc_dma_end(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ u8 dma_stat, dma_cmd;
+
+ drive->waiting_for_dma = 0;
+ /* get DMA command mode */
+ dma_cmd = scc_ide_inb(hwif->dma_base);
+ /* stop DMA */
+ scc_ide_outb(dma_cmd & ~1, hwif->dma_base);
+ /* get DMA status */
+ dma_stat = scc_ide_inb(hwif->dma_base + 4);
+ /* clear the INTR & ERROR bits */
+ scc_ide_outb(dma_stat | 6, hwif->dma_base + 4);
+ /* purge DMA mappings */
+ ide_destroy_dmatable(drive);
+ /* verify good DMA status */
+ wmb();
+ return (dma_stat & 7) != 4 ? (0x10 | dma_stat) : 0;
+}
+
+/**
+ * scc_dma_end - Stop DMA
+ * @drive: IDE drive
+ *
+ * Check and clear INT Status register.
+ * Then call __scc_dma_end().
+ */
+
+static int scc_dma_end(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ void __iomem *dma_base = (void __iomem *)hwif->dma_base;
+ unsigned long intsts_port = hwif->dma_base + 0x014;
+ u32 reg;
+ int dma_stat, data_loss = 0;
+ static int retry = 0;
+
+ /* errata A308 workaround: Step5 (check data loss) */
+ /* We don't check non ide_disk because it is limited to UDMA4 */
+ if (!(in_be32((void __iomem *)hwif->io_ports.ctl_addr)
+ & ATA_ERR) &&
+ drive->media == ide_disk && drive->current_speed > XFER_UDMA_4) {
+ reg = in_be32((void __iomem *)intsts_port);
+ if (!(reg & INTSTS_ACTEINT)) {
+ printk(KERN_WARNING "%s: operation failed (transfer data loss)\n",
+ drive->name);
+ data_loss = 1;
+ if (retry++) {
+ struct request *rq = HWGROUP(drive)->rq;
+ int unit;
+ /* ERROR_RESET and drive->crc_count are needed
+ * to reduce DMA transfer mode in retry process.
+ */
+ if (rq)
+ rq->errors |= ERROR_RESET;
+ for (unit = 0; unit < MAX_DRIVES; unit++) {
+ ide_drive_t *drive = &hwif->drives[unit];
+ drive->crc_count++;
+ }
+ }
+ }
+ }
+
+ while (1) {
+ reg = in_be32((void __iomem *)intsts_port);
+
+ if (reg & INTSTS_SERROR) {
+ printk(KERN_WARNING "%s: SERROR\n", SCC_PATA_NAME);
+ out_be32((void __iomem *)intsts_port, INTSTS_SERROR|INTSTS_BMSINT);
+
+ out_be32(dma_base, in_be32(dma_base) & ~QCHCD_IOS_SS);
+ continue;
+ }
+
+ if (reg & INTSTS_PRERR) {
+ u32 maea0, maec0;
+ unsigned long ctl_base = hwif->config_data;
+
+ maea0 = in_be32((void __iomem *)(ctl_base + 0xF50));
+ maec0 = in_be32((void __iomem *)(ctl_base + 0xF54));
+
+ printk(KERN_WARNING "%s: PRERR [addr:%x cmd:%x]\n", SCC_PATA_NAME, maea0, maec0);
+
+ out_be32((void __iomem *)intsts_port, INTSTS_PRERR|INTSTS_BMSINT);
+
+ out_be32(dma_base, in_be32(dma_base) & ~QCHCD_IOS_SS);
+ continue;
+ }
+
+ if (reg & INTSTS_RERR) {
+ printk(KERN_WARNING "%s: Response Error\n", SCC_PATA_NAME);
+ out_be32((void __iomem *)intsts_port, INTSTS_RERR|INTSTS_BMSINT);
+
+ out_be32(dma_base, in_be32(dma_base) & ~QCHCD_IOS_SS);
+ continue;
+ }
+
+ if (reg & INTSTS_ICERR) {
+ out_be32(dma_base, in_be32(dma_base) & ~QCHCD_IOS_SS);
+
+ printk(KERN_WARNING "%s: Illegal Configuration\n", SCC_PATA_NAME);
+ out_be32((void __iomem *)intsts_port, INTSTS_ICERR|INTSTS_BMSINT);
+ continue;
+ }
+
+ if (reg & INTSTS_BMSINT) {
+ printk(KERN_WARNING "%s: Internal Bus Error\n", SCC_PATA_NAME);
+ out_be32((void __iomem *)intsts_port, INTSTS_BMSINT);
+
+ ide_do_reset(drive);
+ continue;
+ }
+
+ if (reg & INTSTS_BMHE) {
+ out_be32((void __iomem *)intsts_port, INTSTS_BMHE);
+ continue;
+ }
+
+ if (reg & INTSTS_ACTEINT) {
+ out_be32((void __iomem *)intsts_port, INTSTS_ACTEINT);
+ continue;
+ }
+
+ if (reg & INTSTS_IOIRQS) {
+ out_be32((void __iomem *)intsts_port, INTSTS_IOIRQS);
+ continue;
+ }
+ break;
+ }
+
+ dma_stat = __scc_dma_end(drive);
+ if (data_loss)
+ dma_stat |= 2; /* emulate DMA error (to retry command) */
+ return dma_stat;
+}
+
+/* returns 1 if dma irq issued, 0 otherwise */
+static int scc_dma_test_irq(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ u32 int_stat = in_be32((void __iomem *)hwif->dma_base + 0x014);
+
+ /* SCC errata A252,A308 workaround: Step4 */
+ if ((in_be32((void __iomem *)hwif->io_ports.ctl_addr)
+ & ATA_ERR) &&
+ (int_stat & INTSTS_INTRQ))
+ return 1;
+
+ /* SCC errata A308 workaround: Step5 (polling IOIRQS) */
+ if (int_stat & INTSTS_IOIRQS)
+ return 1;
+
+ return 0;
+}
+
+static u8 scc_udma_filter(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ u8 mask = hwif->ultra_mask;
+
+ /* errata A308 workaround: limit non ide_disk drive to UDMA4 */
+ if ((drive->media != ide_disk) && (mask & 0xE0)) {
+ printk(KERN_INFO "%s: limit %s to UDMA4\n",
+ SCC_PATA_NAME, drive->name);
+ mask = ATA_UDMA4;
+ }
+
+ return mask;
+}
+
+/**
+ * setup_mmio_scc - map CTRL/BMID region
+ * @dev: PCI device we are configuring
+ * @name: device name
+ *
+ */
+
+static int setup_mmio_scc (struct pci_dev *dev, const char *name)
+{
+ void __iomem *ctl_addr;
+ void __iomem *dma_addr;
+ int i, ret;
+
+ for (i = 0; i < MAX_HWIFS; i++) {
+ if (scc_ports[i].ctl == 0)
+ break;
+ }
+ if (i >= MAX_HWIFS)
+ return -ENOMEM;
+
+ ret = pci_request_selected_regions(dev, (1 << 2) - 1, name);
+ if (ret < 0) {
+ printk(KERN_ERR "%s: can't reserve resources\n", name);
+ return ret;
+ }
+
+ ctl_addr = pci_ioremap_bar(dev, 0);
+ if (!ctl_addr)
+ goto fail_0;
+
+ dma_addr = pci_ioremap_bar(dev, 1);
+ if (!dma_addr)
+ goto fail_1;
+
+ pci_set_master(dev);
+ scc_ports[i].ctl = (unsigned long)ctl_addr;
+ scc_ports[i].dma = (unsigned long)dma_addr;
+ pci_set_drvdata(dev, (void *) &scc_ports[i]);
+
+ return 1;
+
+ fail_1:
+ iounmap(ctl_addr);
+ fail_0:
+ return -ENOMEM;
+}
+
+static int scc_ide_setup_pci_device(struct pci_dev *dev,
+ const struct ide_port_info *d)
+{
+ struct scc_ports *ports = pci_get_drvdata(dev);
+ struct ide_host *host;
+ hw_regs_t hw, *hws[] = { &hw, NULL, NULL, NULL };
+ int i, rc;
+
+ memset(&hw, 0, sizeof(hw));
+ for (i = 0; i <= 8; i++)
+ hw.io_ports_array[i] = ports->dma + 0x20 + i * 4;
+ hw.irq = dev->irq;
+ hw.dev = &dev->dev;
+ hw.chipset = ide_pci;
+
+ rc = ide_host_add(d, hws, &host);
+ if (rc)
+ return rc;
+
+ ports->host = host;
+
+ return 0;
+}
+
+/**
+ * init_setup_scc - set up an SCC PATA Controller
+ * @dev: PCI device
+ * @d: IDE port info
+ *
+ * Perform the initial set up for this device.
+ */
+
+static int __devinit init_setup_scc(struct pci_dev *dev,
+ const struct ide_port_info *d)
+{
+ unsigned long ctl_base;
+ unsigned long dma_base;
+ unsigned long cckctrl_port;
+ unsigned long intmask_port;
+ unsigned long mode_port;
+ unsigned long ecmode_port;
+ u32 reg = 0;
+ struct scc_ports *ports;
+ int rc;
+
+ rc = pci_enable_device(dev);
+ if (rc)
+ goto end;
+
+ rc = setup_mmio_scc(dev, d->name);
+ if (rc < 0)
+ goto end;
+
+ ports = pci_get_drvdata(dev);
+ ctl_base = ports->ctl;
+ dma_base = ports->dma;
+ cckctrl_port = ctl_base + 0xff0;
+ intmask_port = dma_base + 0x010;
+ mode_port = ctl_base + 0x024;
+ ecmode_port = ctl_base + 0xf00;
+
+ /* controller initialization */
+ reg = 0;
+ out_be32((void*)cckctrl_port, reg);
+ reg |= CCKCTRL_ATACLKOEN;
+ out_be32((void*)cckctrl_port, reg);
+ reg |= CCKCTRL_LCLKEN | CCKCTRL_OCLKEN;
+ out_be32((void*)cckctrl_port, reg);
+ reg |= CCKCTRL_CRST;
+ out_be32((void*)cckctrl_port, reg);
+
+ for (;;) {
+ reg = in_be32((void*)cckctrl_port);
+ if (reg & CCKCTRL_CRST)
+ break;
+ udelay(5000);
+ }
+
+ reg |= CCKCTRL_ATARESET;
+ out_be32((void*)cckctrl_port, reg);
+
+ out_be32((void*)ecmode_port, ECMODE_VALUE);
+ out_be32((void*)mode_port, MODE_JCUSFEN);
+ out_be32((void*)intmask_port, INTMASK_MSK);
+
+ rc = scc_ide_setup_pci_device(dev, d);
+
+ end:
+ return rc;
+}
+
+static void scc_tf_load(ide_drive_t *drive, ide_task_t *task)
+{
+ struct ide_io_ports *io_ports = &drive->hwif->io_ports;
+ struct ide_taskfile *tf = &task->tf;
+ u8 HIHI = (task->tf_flags & IDE_TFLAG_LBA48) ? 0xE0 : 0xEF;
+
+ if (task->tf_flags & IDE_TFLAG_FLAGGED)
+ HIHI = 0xFF;
+
+ if (task->tf_flags & IDE_TFLAG_OUT_DATA)
+ out_be32((void *)io_ports->data_addr,
+ (tf->hob_data << 8) | tf->data);
+
+ if (task->tf_flags & IDE_TFLAG_OUT_HOB_FEATURE)
+ scc_ide_outb(tf->hob_feature, io_ports->feature_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_HOB_NSECT)
+ scc_ide_outb(tf->hob_nsect, io_ports->nsect_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAL)
+ scc_ide_outb(tf->hob_lbal, io_ports->lbal_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAM)
+ scc_ide_outb(tf->hob_lbam, io_ports->lbam_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAH)
+ scc_ide_outb(tf->hob_lbah, io_ports->lbah_addr);
+
+ if (task->tf_flags & IDE_TFLAG_OUT_FEATURE)
+ scc_ide_outb(tf->feature, io_ports->feature_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_NSECT)
+ scc_ide_outb(tf->nsect, io_ports->nsect_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_LBAL)
+ scc_ide_outb(tf->lbal, io_ports->lbal_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_LBAM)
+ scc_ide_outb(tf->lbam, io_ports->lbam_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_LBAH)
+ scc_ide_outb(tf->lbah, io_ports->lbah_addr);
+
+ if (task->tf_flags & IDE_TFLAG_OUT_DEVICE)
+ scc_ide_outb((tf->device & HIHI) | drive->select,
+ io_ports->device_addr);
+}
+
+static void scc_tf_read(ide_drive_t *drive, ide_task_t *task)
+{
+ struct ide_io_ports *io_ports = &drive->hwif->io_ports;
+ struct ide_taskfile *tf = &task->tf;
+
+ if (task->tf_flags & IDE_TFLAG_IN_DATA) {
+ u16 data = (u16)in_be32((void *)io_ports->data_addr);
+
+ tf->data = data & 0xff;
+ tf->hob_data = (data >> 8) & 0xff;
+ }
+
+ /* be sure we're looking at the low order bits */
+ scc_ide_outb(ATA_DEVCTL_OBS & ~0x80, io_ports->ctl_addr);
+
+ if (task->tf_flags & IDE_TFLAG_IN_FEATURE)
+ tf->feature = scc_ide_inb(io_ports->feature_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_NSECT)
+ tf->nsect = scc_ide_inb(io_ports->nsect_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_LBAL)
+ tf->lbal = scc_ide_inb(io_ports->lbal_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_LBAM)
+ tf->lbam = scc_ide_inb(io_ports->lbam_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_LBAH)
+ tf->lbah = scc_ide_inb(io_ports->lbah_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_DEVICE)
+ tf->device = scc_ide_inb(io_ports->device_addr);
+
+ if (task->tf_flags & IDE_TFLAG_LBA48) {
+ scc_ide_outb(ATA_DEVCTL_OBS | 0x80, io_ports->ctl_addr);
+
+ if (task->tf_flags & IDE_TFLAG_IN_HOB_FEATURE)
+ tf->hob_feature = scc_ide_inb(io_ports->feature_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_HOB_NSECT)
+ tf->hob_nsect = scc_ide_inb(io_ports->nsect_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAL)
+ tf->hob_lbal = scc_ide_inb(io_ports->lbal_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAM)
+ tf->hob_lbam = scc_ide_inb(io_ports->lbam_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAH)
+ tf->hob_lbah = scc_ide_inb(io_ports->lbah_addr);
+ }
+}
+
+static void scc_input_data(ide_drive_t *drive, struct request *rq,
+ void *buf, unsigned int len)
+{
+ unsigned long data_addr = drive->hwif->io_ports.data_addr;
+
+ len++;
+
+ if (drive->io_32bit) {
+ scc_ide_insl(data_addr, buf, len / 4);
+
+ if ((len & 3) >= 2)
+ scc_ide_insw(data_addr, (u8 *)buf + (len & ~3), 1);
+ } else
+ scc_ide_insw(data_addr, buf, len / 2);
+}
+
+static void scc_output_data(ide_drive_t *drive, struct request *rq,
+ void *buf, unsigned int len)
+{
+ unsigned long data_addr = drive->hwif->io_ports.data_addr;
+
+ len++;
+
+ if (drive->io_32bit) {
+ scc_ide_outsl(data_addr, buf, len / 4);
+
+ if ((len & 3) >= 2)
+ scc_ide_outsw(data_addr, (u8 *)buf + (len & ~3), 1);
+ } else
+ scc_ide_outsw(data_addr, buf, len / 2);
+}
+
+/**
+ * init_mmio_iops_scc - set up the iops for MMIO
+ * @hwif: interface to set up
+ *
+ */
+
+static void __devinit init_mmio_iops_scc(ide_hwif_t *hwif)
+{
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+ struct scc_ports *ports = pci_get_drvdata(dev);
+ unsigned long dma_base = ports->dma;
+
+ ide_set_hwifdata(hwif, ports);
+
+ hwif->dma_base = dma_base;
+ hwif->config_data = ports->ctl;
+}
+
+/**
+ * init_iops_scc - set up iops
+ * @hwif: interface to set up
+ *
+ * Do the basic setup for the SCC hardware interface
+ * and then do the MMIO setup.
+ */
+
+static void __devinit init_iops_scc(ide_hwif_t *hwif)
+{
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+
+ hwif->hwif_data = NULL;
+ if (pci_get_drvdata(dev) == NULL)
+ return;
+ init_mmio_iops_scc(hwif);
+}
+
+static int __devinit scc_init_dma(ide_hwif_t *hwif,
+ const struct ide_port_info *d)
+{
+ return ide_allocate_dma_engine(hwif);
+}
+
+static u8 scc_cable_detect(ide_hwif_t *hwif)
+{
+ return ATA_CBL_PATA80;
+}
+
+/**
+ * init_hwif_scc - set up hwif
+ * @hwif: interface to set up
+ *
+ * We do the basic set up of the interface structure. The SCC
+ * requires several custom handlers so we override the default
+ * ide DMA handlers appropriately.
+ */
+
+static void __devinit init_hwif_scc(ide_hwif_t *hwif)
+{
+ /* PTERADD */
+ out_be32((void __iomem *)(hwif->dma_base + 0x018), hwif->dmatable_dma);
+
+ if (in_be32((void __iomem *)(hwif->config_data + 0xff0)) & CCKCTRL_ATACLKOEN)
+ hwif->ultra_mask = ATA_UDMA6; /* 133MHz */
+ else
+ hwif->ultra_mask = ATA_UDMA5; /* 100MHz */
+}
+
+static const struct ide_tp_ops scc_tp_ops = {
+ .exec_command = scc_exec_command,
+ .read_status = scc_read_status,
+ .read_altstatus = scc_read_altstatus,
+ .read_sff_dma_status = scc_read_sff_dma_status,
+
+ .set_irq = scc_set_irq,
+
+ .tf_load = scc_tf_load,
+ .tf_read = scc_tf_read,
+
+ .input_data = scc_input_data,
+ .output_data = scc_output_data,
+};
+
+static const struct ide_port_ops scc_port_ops = {
+ .set_pio_mode = scc_set_pio_mode,
+ .set_dma_mode = scc_set_dma_mode,
+ .udma_filter = scc_udma_filter,
+ .cable_detect = scc_cable_detect,
+};
+
+static const struct ide_dma_ops scc_dma_ops = {
+ .dma_host_set = scc_dma_host_set,
+ .dma_setup = scc_dma_setup,
+ .dma_exec_cmd = ide_dma_exec_cmd,
+ .dma_start = scc_dma_start,
+ .dma_end = scc_dma_end,
+ .dma_test_irq = scc_dma_test_irq,
+ .dma_lost_irq = ide_dma_lost_irq,
+ .dma_timeout = ide_dma_timeout,
+};
+
+#define DECLARE_SCC_DEV(name_str) \
+ { \
+ .name = name_str, \
+ .init_iops = init_iops_scc, \
+ .init_dma = scc_init_dma, \
+ .init_hwif = init_hwif_scc, \
+ .tp_ops = &scc_tp_ops, \
+ .port_ops = &scc_port_ops, \
+ .dma_ops = &scc_dma_ops, \
+ .host_flags = IDE_HFLAG_SINGLE, \
+ .pio_mask = ATA_PIO4, \
+ }
+
+static const struct ide_port_info scc_chipsets[] __devinitdata = {
+ /* 0 */ DECLARE_SCC_DEV("sccIDE"),
+};
+
+/**
+ * scc_init_one - pci layer discovery entry
+ * @dev: PCI device
+ * @id: ident table entry
+ *
+ * Called by the PCI code when it finds an SCC PATA controller.
+ * We then use the IDE PCI generic helper to do most of the work.
+ */
+
+static int __devinit scc_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ return init_setup_scc(dev, &scc_chipsets[id->driver_data]);
+}
+
+/**
+ * scc_remove - pci layer remove entry
+ * @dev: PCI device
+ *
+ * Called by the PCI code when it removes an SCC PATA controller.
+ */
+
+static void __devexit scc_remove(struct pci_dev *dev)
+{
+ struct scc_ports *ports = pci_get_drvdata(dev);
+ struct ide_host *host = ports->host;
+
+ ide_host_remove(host);
+
+ iounmap((void*)ports->dma);
+ iounmap((void*)ports->ctl);
+ pci_release_selected_regions(dev, (1 << 2) - 1);
+ memset(ports, 0, sizeof(*ports));
+}
+
+static const struct pci_device_id scc_pci_tbl[] = {
+ { PCI_VDEVICE(TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_SCC_ATA), 0 },
+ { 0, },
+};
+MODULE_DEVICE_TABLE(pci, scc_pci_tbl);
+
+static struct pci_driver scc_pci_driver = {
+ .name = "SCC IDE",
+ .id_table = scc_pci_tbl,
+ .probe = scc_init_one,
+ .remove = __devexit_p(scc_remove),
+};
+
+static int scc_ide_init(void)
+{
+ return ide_pci_register_driver(&scc_pci_driver);
+}
+
+module_init(scc_ide_init);
+/* -- No exit code?
+static void scc_ide_exit(void)
+{
+ ide_pci_unregister_driver(&scc_pci_driver);
+}
+module_exit(scc_ide_exit);
+ */
+
+
+MODULE_DESCRIPTION("PCI driver module for Toshiba SCC IDE");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/serverworks.c b/drivers/ide/serverworks.c
new file mode 100644
index 0000000..437bc91
--- /dev/null
+++ b/drivers/ide/serverworks.c
@@ -0,0 +1,470 @@
+/*
+ * Copyright (C) 1998-2000 Michel Aubry
+ * Copyright (C) 1998-2000 Andrzej Krzysztofowicz
+ * Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org>
+ * Copyright (C) 2007 Bartlomiej Zolnierkiewicz
+ * 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)
+ *
+ * HT1000: AKA BCM5785 - Hypertransport Southbridge for Opteron systems. IDE
+ * controller same as the CSB6. Single channel ATA100 only.
+ *
+ * Documentation:
+ * Available under NDA only. Errata info very hard to get.
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#define DRV_NAME "serverworks"
+
+#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 *svwks_bad_ata100[] = {
+ "ST320011A",
+ "ST340016A",
+ "ST360021A",
+ "ST380021A",
+ NULL
+};
+
+static struct pci_dev *isa_dev;
+
+static int check_in_drive_lists (ide_drive_t *drive, const char **list)
+{
+ char *m = (char *)&drive->id[ATA_ID_PROD];
+
+ while (*list)
+ if (!strcmp(*list++, m))
+ return 1;
+ return 0;
+}
+
+static u8 svwks_udma_filter(ide_drive_t *drive)
+{
+ struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
+ u8 mask = 0;
+
+ if (dev->device == PCI_DEVICE_ID_SERVERWORKS_HT1000IDE)
+ return 0x1f;
+ if (dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) {
+ u32 reg = 0;
+ if (isa_dev)
+ pci_read_config_dword(isa_dev, 0x64, &reg);
+
+ /*
+ * Don't enable UDMA on disk devices for the moment
+ */
+ if(drive->media == ide_disk)
+ return 0;
+ /* Check the OSB4 DMA33 enable bit */
+ return ((reg & 0x00004000) == 0x00004000) ? 0x07 : 0;
+ } else if (dev->revision < SVWKS_CSB5_REVISION_NEW) {
+ return 0x07;
+ } else if (dev->revision >= SVWKS_CSB5_REVISION_NEW) {
+ u8 btr = 0, mode;
+ pci_read_config_byte(dev, 0x5A, &btr);
+ mode = btr & 0x3;
+
+ /* If someone decides to do UDMA133 on CSB5 the same
+ issue will bite so be inclusive */
+ if (mode > 2 && check_in_drive_lists(drive, svwks_bad_ata100))
+ mode = 2;
+
+ switch(mode) {
+ case 3: mask = 0x3f; break;
+ case 2: mask = 0x1f; break;
+ case 1: mask = 0x07; break;
+ default: mask = 0x00; break;
+ }
+ }
+ if (((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) ||
+ (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2)) &&
+ (!(PCI_FUNC(dev->devfn) & 1)))
+ mask = 0x1f;
+
+ return mask;
+}
+
+static u8 svwks_csb_check (struct pci_dev *dev)
+{
+ switch (dev->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;
+}
+
+static void svwks_set_pio_mode(ide_drive_t *drive, const u8 pio)
+{
+ static const u8 pio_modes[] = { 0x5d, 0x47, 0x34, 0x22, 0x20 };
+ static const u8 drive_pci[] = { 0x41, 0x40, 0x43, 0x42 };
+
+ struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
+
+ pci_write_config_byte(dev, drive_pci[drive->dn], pio_modes[pio]);
+
+ if (svwks_csb_check(dev)) {
+ u16 csb_pio = 0;
+
+ pci_read_config_word(dev, 0x4a, &csb_pio);
+
+ csb_pio &= ~(0x0f << (4 * drive->dn));
+ csb_pio |= (pio << (4 * drive->dn));
+
+ pci_write_config_word(dev, 0x4a, csb_pio);
+ }
+}
+
+static void svwks_set_dma_mode(ide_drive_t *drive, const u8 speed)
+{
+ static const u8 udma_modes[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 };
+ static const u8 dma_modes[] = { 0x77, 0x21, 0x20 };
+ static const u8 drive_pci2[] = { 0x45, 0x44, 0x47, 0x46 };
+
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+ u8 unit = drive->dn & 1;
+
+ u8 ultra_enable = 0, ultra_timing = 0, dma_timing = 0;
+
+ pci_read_config_byte(dev, (0x56|hwif->channel), &ultra_timing);
+ pci_read_config_byte(dev, 0x54, &ultra_enable);
+
+ ultra_timing &= ~(0x0F << (4*unit));
+ ultra_enable &= ~(0x01 << drive->dn);
+
+ if (speed >= XFER_UDMA_0) {
+ dma_timing |= dma_modes[2];
+ ultra_timing |= (udma_modes[speed - XFER_UDMA_0] << (4 * unit));
+ ultra_enable |= (0x01 << drive->dn);
+ } else if (speed >= XFER_MW_DMA_0)
+ dma_timing |= dma_modes[speed - XFER_MW_DMA_0];
+
+ pci_write_config_byte(dev, drive_pci2[drive->dn], dma_timing);
+ pci_write_config_byte(dev, (0x56|hwif->channel), ultra_timing);
+ pci_write_config_byte(dev, 0x54, ultra_enable);
+}
+
+static unsigned int init_chipset_svwks(struct pci_dev *dev)
+{
+ unsigned int reg;
+ u8 btr;
+
+ /* force Master Latency Timer value to 64 PCICLKs */
+ pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x40);
+
+ /* OSB4 : South Bridge and IDE */
+ if (dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) {
+ isa_dev = pci_get_device(PCI_VENDOR_ID_SERVERWORKS,
+ PCI_DEVICE_ID_SERVERWORKS_OSB4, NULL);
+ if (isa_dev) {
+ pci_read_config_dword(isa_dev, 0x64, &reg);
+ reg &= ~0x00002000; /* disable 600ns interrupt mask */
+ if(!(reg & 0x00004000))
+ printk(KERN_DEBUG DRV_NAME " %s: UDMA not BIOS "
+ "enabled.\n", pci_name(dev));
+ reg |= 0x00004000; /* enable UDMA/33 support */
+ pci_write_config_dword(isa_dev, 0x64, reg);
+ }
+ }
+
+ /* setup CSB5/CSB6 : South Bridge and IDE option RAID */
+ else if ((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) ||
+ (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) ||
+ (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2)) {
+
+ /* Third Channel Test */
+ if (!(PCI_FUNC(dev->devfn) & 1)) {
+ struct pci_dev * findev = NULL;
+ u32 reg4c = 0;
+ findev = pci_get_device(PCI_VENDOR_ID_SERVERWORKS,
+ PCI_DEVICE_ID_SERVERWORKS_CSB5, NULL);
+ if (findev) {
+ pci_read_config_dword(findev, 0x4C, &reg4c);
+ reg4c &= ~0x000007FF;
+ reg4c |= 0x00000040;
+ reg4c |= 0x00000020;
+ pci_write_config_dword(findev, 0x4C, reg4c);
+ pci_dev_put(findev);
+ }
+ outb_p(0x06, 0x0c00);
+ dev->irq = inb_p(0x0c01);
+ } else {
+ struct pci_dev * findev = NULL;
+ u8 reg41 = 0;
+
+ findev = pci_get_device(PCI_VENDOR_ID_SERVERWORKS,
+ PCI_DEVICE_ID_SERVERWORKS_CSB6, NULL);
+ if (findev) {
+ pci_read_config_byte(findev, 0x41, &reg41);
+ reg41 &= ~0x40;
+ pci_write_config_byte(findev, 0x41, reg41);
+ pci_dev_put(findev);
+ }
+ /*
+ * This is a device pin issue on CSB6.
+ * Since there will be a future raid mode,
+ * early versions of the chipset require the
+ * interrupt pin to be set, and it is a compatibility
+ * mode issue.
+ */
+ if ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE)
+ dev->irq = 0;
+ }
+// pci_read_config_dword(dev, 0x40, &pioreg)
+// pci_write_config_dword(dev, 0x40, 0x99999999);
+// pci_read_config_dword(dev, 0x44, &dmareg);
+// pci_write_config_dword(dev, 0x44, 0xFFFFFFFF);
+ /* 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(dev, 0x5A, &btr);
+ btr &= ~0x40;
+ if (!(PCI_FUNC(dev->devfn) & 1))
+ btr |= 0x2;
+ else
+ btr |= (dev->revision >= SVWKS_CSB5_REVISION_NEW) ? 0x3 : 0x2;
+ pci_write_config_byte(dev, 0x5A, btr);
+ }
+ /* Setup HT1000 SouthBridge Controller - Single Channel Only */
+ else if (dev->device == PCI_DEVICE_ID_SERVERWORKS_HT1000IDE) {
+ pci_read_config_byte(dev, 0x5A, &btr);
+ btr &= ~0x40;
+ btr |= 0x3;
+ pci_write_config_byte(dev, 0x5A, btr);
+ }
+
+ return dev->irq;
+}
+
+static u8 ata66_svwks_svwks(ide_hwif_t *hwif)
+{
+ return ATA_CBL_PATA80;
+}
+
+/* On Dell PowerEdge servers with a CSB5/CSB6, the top two bits
+ * of the subsystem device ID indicate presence of an 80-pin cable.
+ * Bit 15 clear = secondary IDE channel does not have 80-pin cable.
+ * Bit 15 set = secondary IDE channel has 80-pin cable.
+ * Bit 14 clear = primary IDE channel does not have 80-pin cable.
+ * Bit 14 set = primary IDE channel has 80-pin cable.
+ */
+static u8 ata66_svwks_dell(ide_hwif_t *hwif)
+{
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+
+ if (dev->subsystem_vendor == PCI_VENDOR_ID_DELL &&
+ dev->vendor == PCI_VENDOR_ID_SERVERWORKS &&
+ (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE ||
+ dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE))
+ return ((1 << (hwif->channel + 14)) &
+ dev->subsystem_device) ? ATA_CBL_PATA80 : ATA_CBL_PATA40;
+ return ATA_CBL_PATA40;
+}
+
+/* Sun Cobalt Alpine hardware avoids the 80-pin cable
+ * detect issue by attaching the drives directly to the board.
+ * This check follows the Dell precedent (how scary is that?!)
+ *
+ * WARNING: this only works on Alpine hardware!
+ */
+static u8 ata66_svwks_cobalt(ide_hwif_t *hwif)
+{
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+
+ if (dev->subsystem_vendor == PCI_VENDOR_ID_SUN &&
+ dev->vendor == PCI_VENDOR_ID_SERVERWORKS &&
+ dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE)
+ return ((1 << (hwif->channel + 14)) &
+ dev->subsystem_device) ? ATA_CBL_PATA80 : ATA_CBL_PATA40;
+ return ATA_CBL_PATA40;
+}
+
+static u8 svwks_cable_detect(ide_hwif_t *hwif)
+{
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+
+ /* Server Works */
+ if (dev->subsystem_vendor == PCI_VENDOR_ID_SERVERWORKS)
+ return ata66_svwks_svwks (hwif);
+
+ /* Dell PowerEdge */
+ if (dev->subsystem_vendor == PCI_VENDOR_ID_DELL)
+ return ata66_svwks_dell (hwif);
+
+ /* Cobalt Alpine */
+ if (dev->subsystem_vendor == PCI_VENDOR_ID_SUN)
+ return ata66_svwks_cobalt (hwif);
+
+ /* Per Specified Design by OEM, and ASIC Architect */
+ if ((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) ||
+ (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2))
+ return ATA_CBL_PATA80;
+
+ return ATA_CBL_PATA40;
+}
+
+static const struct ide_port_ops osb4_port_ops = {
+ .set_pio_mode = svwks_set_pio_mode,
+ .set_dma_mode = svwks_set_dma_mode,
+ .udma_filter = svwks_udma_filter,
+};
+
+static const struct ide_port_ops svwks_port_ops = {
+ .set_pio_mode = svwks_set_pio_mode,
+ .set_dma_mode = svwks_set_dma_mode,
+ .udma_filter = svwks_udma_filter,
+ .cable_detect = svwks_cable_detect,
+};
+
+#define IDE_HFLAGS_SVWKS IDE_HFLAG_LEGACY_IRQS
+
+static const struct ide_port_info serverworks_chipsets[] __devinitdata = {
+ { /* 0: OSB4 */
+ .name = DRV_NAME,
+ .init_chipset = init_chipset_svwks,
+ .port_ops = &osb4_port_ops,
+ .host_flags = IDE_HFLAGS_SVWKS,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = 0x00, /* UDMA is problematic on OSB4 */
+ },
+ { /* 1: CSB5 */
+ .name = DRV_NAME,
+ .init_chipset = init_chipset_svwks,
+ .port_ops = &svwks_port_ops,
+ .host_flags = IDE_HFLAGS_SVWKS,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA5,
+ },
+ { /* 2: CSB6 */
+ .name = DRV_NAME,
+ .init_chipset = init_chipset_svwks,
+ .port_ops = &svwks_port_ops,
+ .host_flags = IDE_HFLAGS_SVWKS,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA5,
+ },
+ { /* 3: CSB6-2 */
+ .name = DRV_NAME,
+ .init_chipset = init_chipset_svwks,
+ .port_ops = &svwks_port_ops,
+ .host_flags = IDE_HFLAGS_SVWKS | IDE_HFLAG_SINGLE,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA5,
+ },
+ { /* 4: HT1000 */
+ .name = DRV_NAME,
+ .init_chipset = init_chipset_svwks,
+ .port_ops = &svwks_port_ops,
+ .host_flags = IDE_HFLAGS_SVWKS | IDE_HFLAG_SINGLE,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA5,
+ }
+};
+
+/**
+ * svwks_init_one - called when a OSB/CSB is found
+ * @dev: the svwks device
+ * @id: the matching pci id
+ *
+ * Called when the PCI registration layer (or the IDE initialization)
+ * finds a device matching our IDE device tables.
+ */
+
+static int __devinit svwks_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ struct ide_port_info d;
+ u8 idx = id->driver_data;
+
+ d = serverworks_chipsets[idx];
+
+ if (idx == 1)
+ d.host_flags |= IDE_HFLAG_CLEAR_SIMPLEX;
+ else if (idx == 2 || idx == 3) {
+ if ((PCI_FUNC(dev->devfn) & 1) == 0) {
+ if (pci_resource_start(dev, 0) != 0x01f1)
+ d.host_flags |= IDE_HFLAG_NON_BOOTABLE;
+ d.host_flags |= IDE_HFLAG_SINGLE;
+ } else
+ d.host_flags &= ~IDE_HFLAG_SINGLE;
+ }
+
+ return ide_pci_init_one(dev, &d, NULL);
+}
+
+static const struct pci_device_id svwks_pci_tbl[] = {
+ { PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4IDE), 0 },
+ { PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5IDE), 1 },
+ { PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6IDE), 2 },
+ { PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2), 3 },
+ { PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_HT1000IDE), 4 },
+ { 0, },
+};
+MODULE_DEVICE_TABLE(pci, svwks_pci_tbl);
+
+static struct pci_driver svwks_pci_driver = {
+ .name = "Serverworks_IDE",
+ .id_table = svwks_pci_tbl,
+ .probe = svwks_init_one,
+ .remove = ide_pci_remove,
+ .suspend = ide_pci_suspend,
+ .resume = ide_pci_resume,
+};
+
+static int __init svwks_ide_init(void)
+{
+ return ide_pci_register_driver(&svwks_pci_driver);
+}
+
+static void __exit svwks_ide_exit(void)
+{
+ pci_unregister_driver(&svwks_pci_driver);
+}
+
+module_init(svwks_ide_init);
+module_exit(svwks_ide_exit);
+
+MODULE_AUTHOR("Michael Aubry. Andrzej Krzysztofowicz, Andre Hedrick");
+MODULE_DESCRIPTION("PCI driver module for Serverworks OSB4/CSB5/CSB6 IDE");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/setup-pci.c b/drivers/ide/setup-pci.c
new file mode 100644
index 0000000..9f1f916
--- /dev/null
+++ b/drivers/ide/setup-pci.c
@@ -0,0 +1,694 @@
+/*
+ * Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org>
+ * Copyright (C) 1995-1998 Mark Lord
+ * Copyright (C) 2007 Bartlomiej Zolnierkiewicz
+ *
+ * May be copied or modified under the terms of the GNU General Public License
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/ide.h>
+#include <linux/dma-mapping.h>
+
+#include <asm/io.h>
+
+/**
+ * ide_setup_pci_baseregs - place a PCI IDE controller native
+ * @dev: PCI device of interface to switch native
+ * @name: Name of interface
+ *
+ * We attempt to place the PCI interface into PCI native mode. If
+ * we succeed the BARs are ok and the controller is in PCI mode.
+ * Returns 0 on success or an errno code.
+ *
+ * FIXME: if we program the interface and then fail to set the BARS
+ * we don't switch it back to legacy mode. Do we actually care ??
+ */
+
+static int ide_setup_pci_baseregs(struct pci_dev *dev, const char *name)
+{
+ u8 progif = 0;
+
+ /*
+ * Place both IDE interfaces into PCI "native" mode:
+ */
+ if (pci_read_config_byte(dev, PCI_CLASS_PROG, &progif) ||
+ (progif & 5) != 5) {
+ if ((progif & 0xa) != 0xa) {
+ printk(KERN_INFO "%s %s: device not capable of full "
+ "native PCI mode\n", name, pci_name(dev));
+ return -EOPNOTSUPP;
+ }
+ printk(KERN_INFO "%s %s: placing both ports into native PCI "
+ "mode\n", name, pci_name(dev));
+ (void) pci_write_config_byte(dev, PCI_CLASS_PROG, progif|5);
+ if (pci_read_config_byte(dev, PCI_CLASS_PROG, &progif) ||
+ (progif & 5) != 5) {
+ printk(KERN_ERR "%s %s: rewrite of PROGIF failed, "
+ "wanted 0x%04x, got 0x%04x\n",
+ name, pci_name(dev), progif | 5, progif);
+ return -EOPNOTSUPP;
+ }
+ }
+ return 0;
+}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA_PCI
+static int ide_pci_clear_simplex(unsigned long dma_base, const char *name)
+{
+ u8 dma_stat = inb(dma_base + 2);
+
+ outb(dma_stat & 0x60, dma_base + 2);
+ dma_stat = inb(dma_base + 2);
+
+ return (dma_stat & 0x80) ? 1 : 0;
+}
+
+/**
+ * ide_pci_dma_base - setup BMIBA
+ * @hwif: IDE interface
+ * @d: IDE port info
+ *
+ * Fetch the DMA Bus-Master-I/O-Base-Address (BMIBA) from PCI space.
+ */
+
+unsigned long ide_pci_dma_base(ide_hwif_t *hwif, const struct ide_port_info *d)
+{
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+ unsigned long dma_base = 0;
+
+ if (hwif->host_flags & IDE_HFLAG_MMIO)
+ return hwif->dma_base;
+
+ if (hwif->mate && hwif->mate->dma_base) {
+ dma_base = hwif->mate->dma_base - (hwif->channel ? 0 : 8);
+ } else {
+ u8 baridx = (d->host_flags & IDE_HFLAG_CS5520) ? 2 : 4;
+
+ dma_base = pci_resource_start(dev, baridx);
+
+ if (dma_base == 0) {
+ printk(KERN_ERR "%s %s: DMA base is invalid\n",
+ d->name, pci_name(dev));
+ return 0;
+ }
+ }
+
+ if (hwif->channel)
+ dma_base += 8;
+
+ return dma_base;
+}
+EXPORT_SYMBOL_GPL(ide_pci_dma_base);
+
+int ide_pci_check_simplex(ide_hwif_t *hwif, const struct ide_port_info *d)
+{
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+ u8 dma_stat;
+
+ if (d->host_flags & (IDE_HFLAG_MMIO | IDE_HFLAG_CS5520))
+ goto out;
+
+ if (d->host_flags & IDE_HFLAG_CLEAR_SIMPLEX) {
+ if (ide_pci_clear_simplex(hwif->dma_base, d->name))
+ printk(KERN_INFO "%s %s: simplex device: DMA forced\n",
+ d->name, pci_name(dev));
+ goto out;
+ }
+
+ /*
+ * If the device claims "simplex" DMA, this means that only one of
+ * the two interfaces can be trusted with DMA at any point in time
+ * (so we should enable DMA only on one of the two interfaces).
+ *
+ * FIXME: At this point we haven't probed the drives so we can't make
+ * the appropriate decision. Really we should defer this problem until
+ * we tune the drive then try to grab DMA ownership if we want to be
+ * the DMA end. This has to be become dynamic to handle hot-plug.
+ */
+ dma_stat = hwif->tp_ops->read_sff_dma_status(hwif);
+ if ((dma_stat & 0x80) && hwif->mate && hwif->mate->dma_base) {
+ printk(KERN_INFO "%s %s: simplex device: DMA disabled\n",
+ d->name, pci_name(dev));
+ return -1;
+ }
+out:
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ide_pci_check_simplex);
+
+/*
+ * Set up BM-DMA capability (PnP BIOS should have done this)
+ */
+int ide_pci_set_master(struct pci_dev *dev, const char *name)
+{
+ u16 pcicmd;
+
+ pci_read_config_word(dev, PCI_COMMAND, &pcicmd);
+
+ if ((pcicmd & PCI_COMMAND_MASTER) == 0) {
+ pci_set_master(dev);
+
+ if (pci_read_config_word(dev, PCI_COMMAND, &pcicmd) ||
+ (pcicmd & PCI_COMMAND_MASTER) == 0) {
+ printk(KERN_ERR "%s %s: error updating PCICMD\n",
+ name, pci_name(dev));
+ return -EIO;
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ide_pci_set_master);
+#endif /* CONFIG_BLK_DEV_IDEDMA_PCI */
+
+void ide_setup_pci_noise(struct pci_dev *dev, const struct ide_port_info *d)
+{
+ printk(KERN_INFO "%s %s: IDE controller (0x%04x:0x%04x rev 0x%02x)\n",
+ d->name, pci_name(dev),
+ dev->vendor, dev->device, dev->revision);
+}
+EXPORT_SYMBOL_GPL(ide_setup_pci_noise);
+
+
+/**
+ * ide_pci_enable - do PCI enables
+ * @dev: PCI device
+ * @d: IDE port info
+ *
+ * Enable the IDE PCI device. We attempt to enable the device in full
+ * but if that fails then we only need IO space. The PCI code should
+ * have setup the proper resources for us already for controllers in
+ * legacy mode.
+ *
+ * Returns zero on success or an error code
+ */
+
+static int ide_pci_enable(struct pci_dev *dev, const struct ide_port_info *d)
+{
+ int ret, bars;
+
+ if (pci_enable_device(dev)) {
+ ret = pci_enable_device_io(dev);
+ if (ret < 0) {
+ printk(KERN_WARNING "%s %s: couldn't enable device\n",
+ d->name, pci_name(dev));
+ goto out;
+ }
+ printk(KERN_WARNING "%s %s: BIOS configuration fixed\n",
+ d->name, pci_name(dev));
+ }
+
+ /*
+ * assume all devices can do 32-bit DMA for now, we can add
+ * a DMA mask field to the struct ide_port_info if we need it
+ * (or let lower level driver set the DMA mask)
+ */
+ ret = pci_set_dma_mask(dev, DMA_32BIT_MASK);
+ if (ret < 0) {
+ printk(KERN_ERR "%s %s: can't set DMA mask\n",
+ d->name, pci_name(dev));
+ goto out;
+ }
+
+ if (d->host_flags & IDE_HFLAG_SINGLE)
+ bars = (1 << 2) - 1;
+ else
+ bars = (1 << 4) - 1;
+
+ if ((d->host_flags & IDE_HFLAG_NO_DMA) == 0) {
+ if (d->host_flags & IDE_HFLAG_CS5520)
+ bars |= (1 << 2);
+ else
+ bars |= (1 << 4);
+ }
+
+ ret = pci_request_selected_regions(dev, bars, d->name);
+ if (ret < 0)
+ printk(KERN_ERR "%s %s: can't reserve resources\n",
+ d->name, pci_name(dev));
+out:
+ return ret;
+}
+
+/**
+ * ide_pci_configure - configure an unconfigured device
+ * @dev: PCI device
+ * @d: IDE port info
+ *
+ * Enable and configure the PCI device we have been passed.
+ * Returns zero on success or an error code.
+ */
+
+static int ide_pci_configure(struct pci_dev *dev, const struct ide_port_info *d)
+{
+ u16 pcicmd = 0;
+ /*
+ * PnP BIOS was *supposed* to have setup this device, but we
+ * can do it ourselves, so long as the BIOS has assigned an IRQ
+ * (or possibly the device is using a "legacy header" for IRQs).
+ * Maybe the user deliberately *disabled* the device,
+ * but we'll eventually ignore it again if no drives respond.
+ */
+ if (ide_setup_pci_baseregs(dev, d->name) ||
+ pci_write_config_word(dev, PCI_COMMAND, pcicmd | PCI_COMMAND_IO)) {
+ printk(KERN_INFO "%s %s: device disabled (BIOS)\n",
+ d->name, pci_name(dev));
+ return -ENODEV;
+ }
+ if (pci_read_config_word(dev, PCI_COMMAND, &pcicmd)) {
+ printk(KERN_ERR "%s %s: error accessing PCI regs\n",
+ d->name, pci_name(dev));
+ return -EIO;
+ }
+ if (!(pcicmd & PCI_COMMAND_IO)) {
+ printk(KERN_ERR "%s %s: unable to enable IDE controller\n",
+ d->name, pci_name(dev));
+ return -ENXIO;
+ }
+ return 0;
+}
+
+/**
+ * ide_pci_check_iomem - check a register is I/O
+ * @dev: PCI device
+ * @d: IDE port info
+ * @bar: BAR number
+ *
+ * Checks if a BAR is configured and points to MMIO space. If so,
+ * return an error code. Otherwise return 0
+ */
+
+static int ide_pci_check_iomem(struct pci_dev *dev, const struct ide_port_info *d,
+ int bar)
+{
+ ulong flags = pci_resource_flags(dev, bar);
+
+ /* Unconfigured ? */
+ if (!flags || pci_resource_len(dev, bar) == 0)
+ return 0;
+
+ /* I/O space */
+ if (flags & IORESOURCE_IO)
+ return 0;
+
+ /* Bad */
+ return -EINVAL;
+}
+
+/**
+ * ide_hw_configure - configure a hw_regs_t instance
+ * @dev: PCI device holding interface
+ * @d: IDE port info
+ * @port: port number
+ * @irq: PCI IRQ
+ * @hw: hw_regs_t instance corresponding to this port
+ *
+ * Perform the initial set up for the hardware interface structure. This
+ * is done per interface port rather than per PCI device. There may be
+ * more than one port per device.
+ *
+ * Returns zero on success or an error code.
+ */
+
+static int ide_hw_configure(struct pci_dev *dev, const struct ide_port_info *d,
+ unsigned int port, int irq, hw_regs_t *hw)
+{
+ unsigned long ctl = 0, base = 0;
+
+ if ((d->host_flags & IDE_HFLAG_ISA_PORTS) == 0) {
+ if (ide_pci_check_iomem(dev, d, 2 * port) ||
+ ide_pci_check_iomem(dev, d, 2 * port + 1)) {
+ printk(KERN_ERR "%s %s: I/O baseregs (BIOS) are "
+ "reported as MEM for port %d!\n",
+ d->name, pci_name(dev), port);
+ return -EINVAL;
+ }
+
+ ctl = pci_resource_start(dev, 2*port+1);
+ base = pci_resource_start(dev, 2*port);
+ } else {
+ /* Use default values */
+ ctl = port ? 0x374 : 0x3f4;
+ base = port ? 0x170 : 0x1f0;
+ }
+
+ if (!base || !ctl) {
+ printk(KERN_ERR "%s %s: bad PCI BARs for port %d, skipping\n",
+ d->name, pci_name(dev), port);
+ return -EINVAL;
+ }
+
+ memset(hw, 0, sizeof(*hw));
+ hw->irq = irq;
+ hw->dev = &dev->dev;
+ hw->chipset = d->chipset ? d->chipset : ide_pci;
+ ide_std_init_ports(hw, base, ctl | 2);
+
+ return 0;
+}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA_PCI
+/**
+ * ide_hwif_setup_dma - configure DMA interface
+ * @hwif: IDE interface
+ * @d: IDE port info
+ *
+ * Set up the DMA base for the interface. Enable the master bits as
+ * necessary and attempt to bring the device DMA into a ready to use
+ * state
+ */
+
+int ide_hwif_setup_dma(ide_hwif_t *hwif, const struct ide_port_info *d)
+{
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+
+ if ((d->host_flags & IDE_HFLAG_NO_AUTODMA) == 0 ||
+ ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE &&
+ (dev->class & 0x80))) {
+ unsigned long base = ide_pci_dma_base(hwif, d);
+
+ if (base == 0)
+ return -1;
+
+ hwif->dma_base = base;
+
+ if (ide_pci_check_simplex(hwif, d) < 0)
+ return -1;
+
+ if (ide_pci_set_master(dev, d->name) < 0)
+ return -1;
+
+ if (hwif->host_flags & IDE_HFLAG_MMIO)
+ printk(KERN_INFO " %s: MMIO-DMA\n", hwif->name);
+ else
+ printk(KERN_INFO " %s: BM-DMA at 0x%04lx-0x%04lx\n",
+ hwif->name, base, base + 7);
+
+ hwif->extra_base = base + (hwif->channel ? 8 : 16);
+
+ if (ide_allocate_dma_engine(hwif))
+ return -1;
+
+ hwif->dma_ops = &sff_dma_ops;
+ }
+
+ return 0;
+}
+#endif /* CONFIG_BLK_DEV_IDEDMA_PCI */
+
+/**
+ * ide_setup_pci_controller - set up IDE PCI
+ * @dev: PCI device
+ * @d: IDE port info
+ * @noisy: verbose flag
+ *
+ * Set up the PCI and controller side of the IDE interface. This brings
+ * up the PCI side of the device, checks that the device is enabled
+ * and enables it if need be
+ */
+
+static int ide_setup_pci_controller(struct pci_dev *dev,
+ const struct ide_port_info *d, int noisy)
+{
+ int ret;
+ u16 pcicmd;
+
+ if (noisy)
+ ide_setup_pci_noise(dev, d);
+
+ ret = ide_pci_enable(dev, d);
+ if (ret < 0)
+ goto out;
+
+ ret = pci_read_config_word(dev, PCI_COMMAND, &pcicmd);
+ if (ret < 0) {
+ printk(KERN_ERR "%s %s: error accessing PCI regs\n",
+ d->name, pci_name(dev));
+ goto out;
+ }
+ if (!(pcicmd & PCI_COMMAND_IO)) { /* is device disabled? */
+ ret = ide_pci_configure(dev, d);
+ if (ret < 0)
+ goto out;
+ printk(KERN_INFO "%s %s: device enabled (Linux)\n",
+ d->name, pci_name(dev));
+ }
+
+out:
+ return ret;
+}
+
+/**
+ * ide_pci_setup_ports - configure ports/devices on PCI IDE
+ * @dev: PCI device
+ * @d: IDE port info
+ * @pciirq: IRQ line
+ * @hw: hw_regs_t instances corresponding to this PCI IDE device
+ * @hws: hw_regs_t pointers table to update
+ *
+ * Scan the interfaces attached to this device and do any
+ * necessary per port setup. Attach the devices and ask the
+ * generic DMA layer to do its work for us.
+ *
+ * Normally called automaticall from do_ide_pci_setup_device,
+ * but is also used directly as a helper function by some controllers
+ * where the chipset setup is not the default PCI IDE one.
+ */
+
+void ide_pci_setup_ports(struct pci_dev *dev, const struct ide_port_info *d,
+ int pciirq, hw_regs_t *hw, hw_regs_t **hws)
+{
+ int channels = (d->host_flags & IDE_HFLAG_SINGLE) ? 1 : 2, port;
+ u8 tmp;
+
+ /*
+ * Set up the IDE ports
+ */
+
+ for (port = 0; port < channels; ++port) {
+ const ide_pci_enablebit_t *e = &(d->enablebits[port]);
+
+ if (e->reg && (pci_read_config_byte(dev, e->reg, &tmp) ||
+ (tmp & e->mask) != e->val)) {
+ printk(KERN_INFO "%s %s: IDE port disabled\n",
+ d->name, pci_name(dev));
+ continue; /* port not enabled */
+ }
+
+ if (ide_hw_configure(dev, d, port, pciirq, hw + port))
+ continue;
+
+ *(hws + port) = hw + port;
+ }
+}
+EXPORT_SYMBOL_GPL(ide_pci_setup_ports);
+
+/*
+ * ide_setup_pci_device() looks at the primary/secondary interfaces
+ * on a PCI IDE device and, if they are enabled, prepares the IDE driver
+ * for use with them. This generic code works for most PCI chipsets.
+ *
+ * One thing that is not standardized is the location of the
+ * primary/secondary interface "enable/disable" bits. For chipsets that
+ * we "know" about, this information is in the struct ide_port_info;
+ * for all other chipsets, we just assume both interfaces are enabled.
+ */
+static int do_ide_setup_pci_device(struct pci_dev *dev,
+ const struct ide_port_info *d,
+ u8 noisy)
+{
+ int pciirq, ret;
+
+ /*
+ * Can we trust the reported IRQ?
+ */
+ pciirq = dev->irq;
+
+ /*
+ * This allows offboard ide-pci cards the enable a BIOS,
+ * verify interrupt settings of split-mirror pci-config
+ * space, place chipset into init-mode, and/or preserve
+ * an interrupt if the card is not native ide support.
+ */
+ ret = d->init_chipset ? d->init_chipset(dev) : 0;
+ if (ret < 0)
+ goto out;
+
+ /* Is it an "IDE storage" device in non-PCI mode? */
+ if ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE && (dev->class & 5) != 5) {
+ if (noisy)
+ printk(KERN_INFO "%s %s: not 100%% native mode: will "
+ "probe irqs later\n", d->name, pci_name(dev));
+ pciirq = ret;
+ } else if (!pciirq && noisy) {
+ printk(KERN_WARNING "%s %s: bad irq (%d): will probe later\n",
+ d->name, pci_name(dev), pciirq);
+ } else if (noisy) {
+ printk(KERN_INFO "%s %s: 100%% native mode on irq %d\n",
+ d->name, pci_name(dev), pciirq);
+ }
+
+ ret = pciirq;
+out:
+ return ret;
+}
+
+int ide_pci_init_one(struct pci_dev *dev, const struct ide_port_info *d,
+ void *priv)
+{
+ struct ide_host *host;
+ hw_regs_t hw[4], *hws[] = { NULL, NULL, NULL, NULL };
+ int ret;
+
+ ret = ide_setup_pci_controller(dev, d, 1);
+ if (ret < 0)
+ goto out;
+
+ ide_pci_setup_ports(dev, d, 0, &hw[0], &hws[0]);
+
+ host = ide_host_alloc(d, hws);
+ if (host == NULL) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ host->dev[0] = &dev->dev;
+
+ host->host_priv = priv;
+
+ pci_set_drvdata(dev, host);
+
+ ret = do_ide_setup_pci_device(dev, d, 1);
+ if (ret < 0)
+ goto out;
+
+ /* fixup IRQ */
+ hw[1].irq = hw[0].irq = ret;
+
+ ret = ide_host_register(host, d, hws);
+ if (ret)
+ ide_host_free(host);
+out:
+ return ret;
+}
+EXPORT_SYMBOL_GPL(ide_pci_init_one);
+
+int ide_pci_init_two(struct pci_dev *dev1, struct pci_dev *dev2,
+ const struct ide_port_info *d, void *priv)
+{
+ struct pci_dev *pdev[] = { dev1, dev2 };
+ struct ide_host *host;
+ int ret, i;
+ hw_regs_t hw[4], *hws[] = { NULL, NULL, NULL, NULL };
+
+ for (i = 0; i < 2; i++) {
+ ret = ide_setup_pci_controller(pdev[i], d, !i);
+ if (ret < 0)
+ goto out;
+
+ ide_pci_setup_ports(pdev[i], d, 0, &hw[i*2], &hws[i*2]);
+ }
+
+ host = ide_host_alloc(d, hws);
+ if (host == NULL) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ host->dev[0] = &dev1->dev;
+ host->dev[1] = &dev2->dev;
+
+ host->host_priv = priv;
+
+ pci_set_drvdata(pdev[0], host);
+ pci_set_drvdata(pdev[1], host);
+
+ for (i = 0; i < 2; i++) {
+ ret = do_ide_setup_pci_device(pdev[i], d, !i);
+
+ /*
+ * FIXME: Mom, mom, they stole me the helper function to undo
+ * do_ide_setup_pci_device() on the first device!
+ */
+ if (ret < 0)
+ goto out;
+
+ /* fixup IRQ */
+ hw[i*2 + 1].irq = hw[i*2].irq = ret;
+ }
+
+ ret = ide_host_register(host, d, hws);
+ if (ret)
+ ide_host_free(host);
+out:
+ return ret;
+}
+EXPORT_SYMBOL_GPL(ide_pci_init_two);
+
+void ide_pci_remove(struct pci_dev *dev)
+{
+ struct ide_host *host = pci_get_drvdata(dev);
+ struct pci_dev *dev2 = host->dev[1] ? to_pci_dev(host->dev[1]) : NULL;
+ int bars;
+
+ if (host->host_flags & IDE_HFLAG_SINGLE)
+ bars = (1 << 2) - 1;
+ else
+ bars = (1 << 4) - 1;
+
+ if ((host->host_flags & IDE_HFLAG_NO_DMA) == 0) {
+ if (host->host_flags & IDE_HFLAG_CS5520)
+ bars |= (1 << 2);
+ else
+ bars |= (1 << 4);
+ }
+
+ ide_host_remove(host);
+
+ if (dev2)
+ pci_release_selected_regions(dev2, bars);
+ pci_release_selected_regions(dev, bars);
+
+ if (dev2)
+ pci_disable_device(dev2);
+ pci_disable_device(dev);
+}
+EXPORT_SYMBOL_GPL(ide_pci_remove);
+
+#ifdef CONFIG_PM
+int ide_pci_suspend(struct pci_dev *dev, pm_message_t state)
+{
+ pci_save_state(dev);
+ pci_disable_device(dev);
+ pci_set_power_state(dev, pci_choose_state(dev, state));
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ide_pci_suspend);
+
+int ide_pci_resume(struct pci_dev *dev)
+{
+ struct ide_host *host = pci_get_drvdata(dev);
+ int rc;
+
+ pci_set_power_state(dev, PCI_D0);
+
+ rc = pci_enable_device(dev);
+ if (rc)
+ return rc;
+
+ pci_restore_state(dev);
+ pci_set_master(dev);
+
+ if (host->init_chipset)
+ host->init_chipset(dev);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ide_pci_resume);
+#endif
diff --git a/drivers/ide/sgiioc4.c b/drivers/ide/sgiioc4.c
new file mode 100644
index 0000000..a687a7d
--- /dev/null
+++ b/drivers/ide/sgiioc4.c
@@ -0,0 +1,664 @@
+/*
+ * Copyright (c) 2003-2006 Silicon Graphics, Inc. All Rights Reserved.
+ * Copyright (C) 2008 MontaVista Software, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/NoticeExplan
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/scatterlist.h>
+#include <linux/ioc4.h>
+#include <asm/io.h>
+
+#include <linux/ide.h>
+
+#define DRV_NAME "SGIIOC4"
+
+/* IOC4 Specific Definitions */
+#define IOC4_CMD_OFFSET 0x100
+#define IOC4_CTRL_OFFSET 0x120
+#define IOC4_DMA_OFFSET 0x140
+#define IOC4_INTR_OFFSET 0x0
+
+#define IOC4_TIMING 0x00
+#define IOC4_DMA_PTR_L 0x01
+#define IOC4_DMA_PTR_H 0x02
+#define IOC4_DMA_ADDR_L 0x03
+#define IOC4_DMA_ADDR_H 0x04
+#define IOC4_BC_DEV 0x05
+#define IOC4_BC_MEM 0x06
+#define IOC4_DMA_CTRL 0x07
+#define IOC4_DMA_END_ADDR 0x08
+
+/* Bits in the IOC4 Control/Status Register */
+#define IOC4_S_DMA_START 0x01
+#define IOC4_S_DMA_STOP 0x02
+#define IOC4_S_DMA_DIR 0x04
+#define IOC4_S_DMA_ACTIVE 0x08
+#define IOC4_S_DMA_ERROR 0x10
+#define IOC4_ATA_MEMERR 0x02
+
+/* Read/Write Directions */
+#define IOC4_DMA_WRITE 0x04
+#define IOC4_DMA_READ 0x00
+
+/* Interrupt Register Offsets */
+#define IOC4_INTR_REG 0x03
+#define IOC4_INTR_SET 0x05
+#define IOC4_INTR_CLEAR 0x07
+
+#define IOC4_IDE_CACHELINE_SIZE 128
+#define IOC4_CMD_CTL_BLK_SIZE 0x20
+#define IOC4_SUPPORTED_FIRMWARE_REV 46
+
+typedef struct {
+ u32 timing_reg0;
+ u32 timing_reg1;
+ u32 low_mem_ptr;
+ u32 high_mem_ptr;
+ u32 low_mem_addr;
+ u32 high_mem_addr;
+ u32 dev_byte_count;
+ u32 mem_byte_count;
+ u32 status;
+} ioc4_dma_regs_t;
+
+/* Each Physical Region Descriptor Entry size is 16 bytes (2 * 64 bits) */
+/* IOC4 has only 1 IDE channel */
+#define IOC4_PRD_BYTES 16
+#define IOC4_PRD_ENTRIES (PAGE_SIZE /(4*IOC4_PRD_BYTES))
+
+
+static void
+sgiioc4_init_hwif_ports(hw_regs_t * hw, unsigned long data_port,
+ unsigned long ctrl_port, unsigned long irq_port)
+{
+ unsigned long reg = data_port;
+ int i;
+
+ /* Registers are word (32 bit) aligned */
+ for (i = 0; i <= 7; i++)
+ hw->io_ports_array[i] = reg + i * 4;
+
+ hw->io_ports.ctl_addr = ctrl_port;
+ hw->io_ports.irq_addr = irq_port;
+}
+
+static int
+sgiioc4_checkirq(ide_hwif_t * hwif)
+{
+ unsigned long intr_addr =
+ hwif->io_ports.irq_addr + IOC4_INTR_REG * 4;
+
+ if ((u8)readl((void __iomem *)intr_addr) & 0x03)
+ return 1;
+
+ return 0;
+}
+
+static u8 sgiioc4_read_status(ide_hwif_t *);
+
+static int
+sgiioc4_clearirq(ide_drive_t * drive)
+{
+ u32 intr_reg;
+ ide_hwif_t *hwif = HWIF(drive);
+ struct ide_io_ports *io_ports = &hwif->io_ports;
+ unsigned long other_ir = io_ports->irq_addr + (IOC4_INTR_REG << 2);
+
+ /* Code to check for PCI error conditions */
+ intr_reg = readl((void __iomem *)other_ir);
+ if (intr_reg & 0x03) { /* Valid IOC4-IDE interrupt */
+ /*
+ * Using sgiioc4_read_status to read the Status register has a
+ * side effect of clearing the interrupt. The first read should
+ * clear it if it is set. The second read should return
+ * a "clear" status if it got cleared. If not, then spin
+ * for a bit trying to clear it.
+ */
+ u8 stat = sgiioc4_read_status(hwif);
+ int count = 0;
+
+ stat = sgiioc4_read_status(hwif);
+ while ((stat & ATA_BUSY) && (count++ < 100)) {
+ udelay(1);
+ stat = sgiioc4_read_status(hwif);
+ }
+
+ if (intr_reg & 0x02) {
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+ /* Error when transferring DMA data on PCI bus */
+ u32 pci_err_addr_low, pci_err_addr_high,
+ pci_stat_cmd_reg;
+
+ pci_err_addr_low =
+ readl((void __iomem *)io_ports->irq_addr);
+ pci_err_addr_high =
+ readl((void __iomem *)(io_ports->irq_addr + 4));
+ pci_read_config_dword(dev, PCI_COMMAND,
+ &pci_stat_cmd_reg);
+ printk(KERN_ERR
+ "%s(%s) : PCI Bus Error when doing DMA:"
+ " status-cmd reg is 0x%x\n",
+ __func__, drive->name, pci_stat_cmd_reg);
+ printk(KERN_ERR
+ "%s(%s) : PCI Error Address is 0x%x%x\n",
+ __func__, drive->name,
+ pci_err_addr_high, pci_err_addr_low);
+ /* Clear the PCI Error indicator */
+ pci_write_config_dword(dev, PCI_COMMAND, 0x00000146);
+ }
+
+ /* Clear the Interrupt, Error bits on the IOC4 */
+ writel(0x03, (void __iomem *)other_ir);
+
+ intr_reg = readl((void __iomem *)other_ir);
+ }
+
+ return intr_reg & 3;
+}
+
+static void sgiioc4_dma_start(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ unsigned long ioc4_dma_addr = hwif->dma_base + IOC4_DMA_CTRL * 4;
+ unsigned int reg = readl((void __iomem *)ioc4_dma_addr);
+ unsigned int temp_reg = reg | IOC4_S_DMA_START;
+
+ writel(temp_reg, (void __iomem *)ioc4_dma_addr);
+}
+
+static u32
+sgiioc4_ide_dma_stop(ide_hwif_t *hwif, u64 dma_base)
+{
+ unsigned long ioc4_dma_addr = dma_base + IOC4_DMA_CTRL * 4;
+ u32 ioc4_dma;
+ int count;
+
+ count = 0;
+ ioc4_dma = readl((void __iomem *)ioc4_dma_addr);
+ while ((ioc4_dma & IOC4_S_DMA_STOP) && (count++ < 200)) {
+ udelay(1);
+ ioc4_dma = readl((void __iomem *)ioc4_dma_addr);
+ }
+ return ioc4_dma;
+}
+
+/* Stops the IOC4 DMA Engine */
+static int sgiioc4_dma_end(ide_drive_t *drive)
+{
+ u32 ioc4_dma, bc_dev, bc_mem, num, valid = 0, cnt = 0;
+ ide_hwif_t *hwif = HWIF(drive);
+ unsigned long dma_base = hwif->dma_base;
+ int dma_stat = 0;
+ unsigned long *ending_dma = ide_get_hwifdata(hwif);
+
+ writel(IOC4_S_DMA_STOP, (void __iomem *)(dma_base + IOC4_DMA_CTRL * 4));
+
+ ioc4_dma = sgiioc4_ide_dma_stop(hwif, dma_base);
+
+ if (ioc4_dma & IOC4_S_DMA_STOP) {
+ printk(KERN_ERR
+ "%s(%s): IOC4 DMA STOP bit is still 1 :"
+ "ioc4_dma_reg 0x%x\n",
+ __func__, drive->name, ioc4_dma);
+ dma_stat = 1;
+ }
+
+ /*
+ * The IOC4 will DMA 1's to the ending dma area to indicate that
+ * previous data DMA is complete. This is necessary because of relaxed
+ * ordering between register reads and DMA writes on the Altix.
+ */
+ while ((cnt++ < 200) && (!valid)) {
+ for (num = 0; num < 16; num++) {
+ if (ending_dma[num]) {
+ valid = 1;
+ break;
+ }
+ }
+ udelay(1);
+ }
+ if (!valid) {
+ printk(KERN_ERR "%s(%s) : DMA incomplete\n", __func__,
+ drive->name);
+ dma_stat = 1;
+ }
+
+ bc_dev = readl((void __iomem *)(dma_base + IOC4_BC_DEV * 4));
+ bc_mem = readl((void __iomem *)(dma_base + IOC4_BC_MEM * 4));
+
+ if ((bc_dev & 0x01FF) || (bc_mem & 0x1FF)) {
+ if (bc_dev > bc_mem + 8) {
+ printk(KERN_ERR
+ "%s(%s): WARNING!! byte_count_dev %d "
+ "!= byte_count_mem %d\n",
+ __func__, drive->name, bc_dev, bc_mem);
+ }
+ }
+
+ drive->waiting_for_dma = 0;
+ ide_destroy_dmatable(drive);
+
+ return dma_stat;
+}
+
+static void sgiioc4_set_dma_mode(ide_drive_t *drive, const u8 speed)
+{
+}
+
+/* returns 1 if dma irq issued, 0 otherwise */
+static int sgiioc4_dma_test_irq(ide_drive_t *drive)
+{
+ return sgiioc4_checkirq(HWIF(drive));
+}
+
+static void sgiioc4_dma_host_set(ide_drive_t *drive, int on)
+{
+ if (!on)
+ sgiioc4_clearirq(drive);
+}
+
+static void
+sgiioc4_resetproc(ide_drive_t * drive)
+{
+ sgiioc4_dma_end(drive);
+ sgiioc4_clearirq(drive);
+}
+
+static void
+sgiioc4_dma_lost_irq(ide_drive_t * drive)
+{
+ sgiioc4_resetproc(drive);
+
+ ide_dma_lost_irq(drive);
+}
+
+static u8 sgiioc4_read_status(ide_hwif_t *hwif)
+{
+ unsigned long port = hwif->io_ports.status_addr;
+ u8 reg = (u8) readb((void __iomem *) port);
+
+ if (!(reg & ATA_BUSY)) { /* Not busy... check for interrupt */
+ unsigned long other_ir = port - 0x110;
+ unsigned int intr_reg = (u32) readl((void __iomem *) other_ir);
+
+ /* Clear the Interrupt, Error bits on the IOC4 */
+ if (intr_reg & 0x03) {
+ writel(0x03, (void __iomem *) other_ir);
+ intr_reg = (u32) readl((void __iomem *) other_ir);
+ }
+ }
+
+ return reg;
+}
+
+/* Creates a dma map for the scatter-gather list entries */
+static int __devinit
+ide_dma_sgiioc4(ide_hwif_t *hwif, const struct ide_port_info *d)
+{
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+ unsigned long dma_base = pci_resource_start(dev, 0) + IOC4_DMA_OFFSET;
+ int num_ports = sizeof (ioc4_dma_regs_t);
+ void *pad;
+
+ printk(KERN_INFO " %s: MMIO-DMA\n", hwif->name);
+
+ if (request_mem_region(dma_base, num_ports, hwif->name) == NULL) {
+ printk(KERN_ERR "%s(%s) -- ERROR: addresses 0x%08lx to 0x%08lx "
+ "already in use\n", __func__, hwif->name,
+ dma_base, dma_base + num_ports - 1);
+ return -1;
+ }
+
+ hwif->dma_base = (unsigned long)hwif->io_ports.irq_addr +
+ IOC4_DMA_OFFSET;
+
+ hwif->sg_max_nents = IOC4_PRD_ENTRIES;
+
+ hwif->prd_max_nents = IOC4_PRD_ENTRIES;
+ hwif->prd_ent_size = IOC4_PRD_BYTES;
+
+ if (ide_allocate_dma_engine(hwif))
+ goto dma_pci_alloc_failure;
+
+ pad = pci_alloc_consistent(dev, IOC4_IDE_CACHELINE_SIZE,
+ (dma_addr_t *)&hwif->extra_base);
+ if (pad) {
+ ide_set_hwifdata(hwif, pad);
+ return 0;
+ }
+
+ ide_release_dma_engine(hwif);
+
+ printk(KERN_ERR "%s(%s) -- ERROR: Unable to allocate DMA maps\n",
+ __func__, hwif->name);
+ printk(KERN_INFO "%s: changing from DMA to PIO mode", hwif->name);
+
+dma_pci_alloc_failure:
+ release_mem_region(dma_base, num_ports);
+
+ return -1;
+}
+
+/* Initializes the IOC4 DMA Engine */
+static void
+sgiioc4_configure_for_dma(int dma_direction, ide_drive_t * drive)
+{
+ u32 ioc4_dma;
+ ide_hwif_t *hwif = HWIF(drive);
+ unsigned long dma_base = hwif->dma_base;
+ unsigned long ioc4_dma_addr = dma_base + IOC4_DMA_CTRL * 4;
+ u32 dma_addr, ending_dma_addr;
+
+ ioc4_dma = readl((void __iomem *)ioc4_dma_addr);
+
+ if (ioc4_dma & IOC4_S_DMA_ACTIVE) {
+ printk(KERN_WARNING
+ "%s(%s):Warning!! DMA from previous transfer was still active\n",
+ __func__, drive->name);
+ writel(IOC4_S_DMA_STOP, (void __iomem *)ioc4_dma_addr);
+ ioc4_dma = sgiioc4_ide_dma_stop(hwif, dma_base);
+
+ if (ioc4_dma & IOC4_S_DMA_STOP)
+ printk(KERN_ERR
+ "%s(%s) : IOC4 Dma STOP bit is still 1\n",
+ __func__, drive->name);
+ }
+
+ ioc4_dma = readl((void __iomem *)ioc4_dma_addr);
+ if (ioc4_dma & IOC4_S_DMA_ERROR) {
+ printk(KERN_WARNING
+ "%s(%s) : Warning!! - DMA Error during Previous"
+ " transfer | status 0x%x\n",
+ __func__, drive->name, ioc4_dma);
+ writel(IOC4_S_DMA_STOP, (void __iomem *)ioc4_dma_addr);
+ ioc4_dma = sgiioc4_ide_dma_stop(hwif, dma_base);
+
+ if (ioc4_dma & IOC4_S_DMA_STOP)
+ printk(KERN_ERR
+ "%s(%s) : IOC4 DMA STOP bit is still 1\n",
+ __func__, drive->name);
+ }
+
+ /* Address of the Scatter Gather List */
+ dma_addr = cpu_to_le32(hwif->dmatable_dma);
+ writel(dma_addr, (void __iomem *)(dma_base + IOC4_DMA_PTR_L * 4));
+
+ /* Address of the Ending DMA */
+ memset(ide_get_hwifdata(hwif), 0, IOC4_IDE_CACHELINE_SIZE);
+ ending_dma_addr = cpu_to_le32(hwif->extra_base);
+ writel(ending_dma_addr, (void __iomem *)(dma_base + IOC4_DMA_END_ADDR * 4));
+
+ writel(dma_direction, (void __iomem *)ioc4_dma_addr);
+ drive->waiting_for_dma = 1;
+}
+
+/* IOC4 Scatter Gather list Format */
+/* 128 Bit entries to support 64 bit addresses in the future */
+/* The Scatter Gather list Entry should be in the BIG-ENDIAN Format */
+/* --------------------------------------------------------------------- */
+/* | Upper 32 bits - Zero | Lower 32 bits- address | */
+/* --------------------------------------------------------------------- */
+/* | Upper 32 bits - Zero |EOL| 15 unused | 16 Bit Length| */
+/* --------------------------------------------------------------------- */
+/* Creates the scatter gather list, DMA Table */
+static unsigned int
+sgiioc4_build_dma_table(ide_drive_t * drive, struct request *rq, int ddir)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ unsigned int *table = hwif->dmatable_cpu;
+ unsigned int count = 0, i = 1;
+ struct scatterlist *sg;
+
+ hwif->sg_nents = i = ide_build_sglist(drive, rq);
+
+ if (!i)
+ return 0; /* sglist of length Zero */
+
+ sg = hwif->sg_table;
+ while (i && sg_dma_len(sg)) {
+ dma_addr_t cur_addr;
+ int cur_len;
+ cur_addr = sg_dma_address(sg);
+ cur_len = sg_dma_len(sg);
+
+ while (cur_len) {
+ if (count++ >= IOC4_PRD_ENTRIES) {
+ printk(KERN_WARNING
+ "%s: DMA table too small\n",
+ drive->name);
+ goto use_pio_instead;
+ } else {
+ u32 bcount =
+ 0x10000 - (cur_addr & 0xffff);
+
+ if (bcount > cur_len)
+ bcount = cur_len;
+
+ /* put the addr, length in
+ * the IOC4 dma-table format */
+ *table = 0x0;
+ table++;
+ *table = cpu_to_be32(cur_addr);
+ table++;
+ *table = 0x0;
+ table++;
+
+ *table = cpu_to_be32(bcount);
+ table++;
+
+ cur_addr += bcount;
+ cur_len -= bcount;
+ }
+ }
+
+ sg = sg_next(sg);
+ i--;
+ }
+
+ if (count) {
+ table--;
+ *table |= cpu_to_be32(0x80000000);
+ return count;
+ }
+
+use_pio_instead:
+ ide_destroy_dmatable(drive);
+
+ return 0; /* revert to PIO for this request */
+}
+
+static int sgiioc4_dma_setup(ide_drive_t *drive)
+{
+ struct request *rq = HWGROUP(drive)->rq;
+ unsigned int count = 0;
+ int ddir;
+
+ if (rq_data_dir(rq))
+ ddir = PCI_DMA_TODEVICE;
+ else
+ ddir = PCI_DMA_FROMDEVICE;
+
+ if (!(count = sgiioc4_build_dma_table(drive, rq, ddir))) {
+ /* try PIO instead of DMA */
+ ide_map_sg(drive, rq);
+ return 1;
+ }
+
+ if (rq_data_dir(rq))
+ /* Writes TO the IOC4 FROM Main Memory */
+ ddir = IOC4_DMA_READ;
+ else
+ /* Writes FROM the IOC4 TO Main Memory */
+ ddir = IOC4_DMA_WRITE;
+
+ sgiioc4_configure_for_dma(ddir, drive);
+
+ return 0;
+}
+
+static const struct ide_tp_ops sgiioc4_tp_ops = {
+ .exec_command = ide_exec_command,
+ .read_status = sgiioc4_read_status,
+ .read_altstatus = ide_read_altstatus,
+ .read_sff_dma_status = ide_read_sff_dma_status,
+
+ .set_irq = ide_set_irq,
+
+ .tf_load = ide_tf_load,
+ .tf_read = ide_tf_read,
+
+ .input_data = ide_input_data,
+ .output_data = ide_output_data,
+};
+
+static const struct ide_port_ops sgiioc4_port_ops = {
+ .set_dma_mode = sgiioc4_set_dma_mode,
+ /* reset DMA engine, clear IRQs */
+ .resetproc = sgiioc4_resetproc,
+};
+
+static const struct ide_dma_ops sgiioc4_dma_ops = {
+ .dma_host_set = sgiioc4_dma_host_set,
+ .dma_setup = sgiioc4_dma_setup,
+ .dma_start = sgiioc4_dma_start,
+ .dma_end = sgiioc4_dma_end,
+ .dma_test_irq = sgiioc4_dma_test_irq,
+ .dma_lost_irq = sgiioc4_dma_lost_irq,
+ .dma_timeout = ide_dma_timeout,
+};
+
+static const struct ide_port_info sgiioc4_port_info __devinitconst = {
+ .name = DRV_NAME,
+ .chipset = ide_pci,
+ .init_dma = ide_dma_sgiioc4,
+ .tp_ops = &sgiioc4_tp_ops,
+ .port_ops = &sgiioc4_port_ops,
+ .dma_ops = &sgiioc4_dma_ops,
+ .host_flags = IDE_HFLAG_MMIO,
+ .mwdma_mask = ATA_MWDMA2_ONLY,
+};
+
+static int __devinit
+sgiioc4_ide_setup_pci_device(struct pci_dev *dev)
+{
+ unsigned long cmd_base, irqport;
+ unsigned long bar0, cmd_phys_base, ctl;
+ void __iomem *virt_base;
+ hw_regs_t hw, *hws[] = { &hw, NULL, NULL, NULL };
+ int rc;
+
+ /* Get the CmdBlk and CtrlBlk Base Registers */
+ bar0 = pci_resource_start(dev, 0);
+ virt_base = pci_ioremap_bar(dev, 0);
+ if (virt_base == NULL) {
+ printk(KERN_ERR "%s: Unable to remap BAR 0 address: 0x%lx\n",
+ DRV_NAME, bar0);
+ return -ENOMEM;
+ }
+ cmd_base = (unsigned long) virt_base + IOC4_CMD_OFFSET;
+ ctl = (unsigned long) virt_base + IOC4_CTRL_OFFSET;
+ irqport = (unsigned long) virt_base + IOC4_INTR_OFFSET;
+
+ cmd_phys_base = bar0 + IOC4_CMD_OFFSET;
+ if (request_mem_region(cmd_phys_base, IOC4_CMD_CTL_BLK_SIZE,
+ DRV_NAME) == NULL) {
+ printk(KERN_ERR "%s %s -- ERROR: addresses 0x%08lx to 0x%08lx "
+ "already in use\n", DRV_NAME, pci_name(dev),
+ cmd_phys_base, cmd_phys_base + IOC4_CMD_CTL_BLK_SIZE);
+ rc = -EBUSY;
+ goto req_mem_rgn_err;
+ }
+
+ /* Initialize the IO registers */
+ memset(&hw, 0, sizeof(hw));
+ sgiioc4_init_hwif_ports(&hw, cmd_base, ctl, irqport);
+ hw.irq = dev->irq;
+ hw.chipset = ide_pci;
+ hw.dev = &dev->dev;
+
+ /* Initializing chipset IRQ Registers */
+ writel(0x03, (void __iomem *)(irqport + IOC4_INTR_SET * 4));
+
+ rc = ide_host_add(&sgiioc4_port_info, hws, NULL);
+ if (!rc)
+ return 0;
+
+ release_mem_region(cmd_phys_base, IOC4_CMD_CTL_BLK_SIZE);
+req_mem_rgn_err:
+ iounmap(virt_base);
+ return rc;
+}
+
+static unsigned int __devinit
+pci_init_sgiioc4(struct pci_dev *dev)
+{
+ int ret;
+
+ printk(KERN_INFO "%s: IDE controller at PCI slot %s, revision %d\n",
+ DRV_NAME, pci_name(dev), dev->revision);
+
+ if (dev->revision < IOC4_SUPPORTED_FIRMWARE_REV) {
+ printk(KERN_ERR "Skipping %s IDE controller in slot %s: "
+ "firmware is obsolete - please upgrade to "
+ "revision46 or higher\n",
+ DRV_NAME, pci_name(dev));
+ ret = -EAGAIN;
+ goto out;
+ }
+ ret = sgiioc4_ide_setup_pci_device(dev);
+out:
+ return ret;
+}
+
+int __devinit
+ioc4_ide_attach_one(struct ioc4_driver_data *idd)
+{
+ /* PCI-RT does not bring out IDE connection.
+ * Do not attach to this particular IOC4.
+ */
+ if (idd->idd_variant == IOC4_VARIANT_PCI_RT)
+ return 0;
+
+ return pci_init_sgiioc4(idd->idd_pdev);
+}
+
+static struct ioc4_submodule __devinitdata ioc4_ide_submodule = {
+ .is_name = "IOC4_ide",
+ .is_owner = THIS_MODULE,
+ .is_probe = ioc4_ide_attach_one,
+/* .is_remove = ioc4_ide_remove_one, */
+};
+
+static int __init ioc4_ide_init(void)
+{
+ return ioc4_register_submodule(&ioc4_ide_submodule);
+}
+
+late_initcall(ioc4_ide_init); /* Call only after IDE init is done */
+
+MODULE_AUTHOR("Aniket Malatpure/Jeremy Higdon");
+MODULE_DESCRIPTION("IDE PCI driver module for SGI IOC4 Base-IO Card");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/siimage.c b/drivers/ide/siimage.c
new file mode 100644
index 0000000..7d622d2
--- /dev/null
+++ b/drivers/ide/siimage.c
@@ -0,0 +1,857 @@
+/*
+ * Copyright (C) 2001-2002 Andre Hedrick <andre@linux-ide.org>
+ * Copyright (C) 2003 Red Hat
+ * Copyright (C) 2007-2008 MontaVista Software, Inc.
+ * Copyright (C) 2007-2008 Bartlomiej Zolnierkiewicz
+ *
+ * May be copied or modified under the terms of the GNU General Public License
+ *
+ * Documentation for CMD680:
+ * http://gkernel.sourceforge.net/specs/sii/sii-0680a-v1.31.pdf.bz2
+ *
+ * Documentation for SiI 3112:
+ * http://gkernel.sourceforge.net/specs/sii/3112A_SiI-DS-0095-B2.pdf.bz2
+ *
+ * Errata and other documentation only available under NDA.
+ *
+ *
+ * FAQ Items:
+ * If you are using Marvell SATA-IDE adapters with Maxtor drives
+ * ensure the system is set up for ATA100/UDMA5, not UDMA6.
+ *
+ * If you are using WD drives with SATA bridges you must set the
+ * drive to "Single". "Master" will hang.
+ *
+ * If you have strange problems with nVidia chipset systems please
+ * see the SI support documentation and update your system BIOS
+ * if necessary
+ *
+ * The Dell DRAC4 has some interesting features including effectively hot
+ * unplugging/replugging the virtual CD interface when the DRAC is reset.
+ * This often causes drivers/ide/siimage to panic but is ok with the rather
+ * smarter code in libata.
+ *
+ * TODO:
+ * - IORDY fixes
+ * - VDMA support
+ */
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+#include <linux/io.h>
+
+#define DRV_NAME "siimage"
+
+/**
+ * pdev_is_sata - check if device is SATA
+ * @pdev: PCI device to check
+ *
+ * Returns true if this is a SATA controller
+ */
+
+static int pdev_is_sata(struct pci_dev *pdev)
+{
+#ifdef CONFIG_BLK_DEV_IDE_SATA
+ switch (pdev->device) {
+ case PCI_DEVICE_ID_SII_3112:
+ case PCI_DEVICE_ID_SII_1210SA:
+ return 1;
+ case PCI_DEVICE_ID_SII_680:
+ return 0;
+ }
+ BUG();
+#endif
+ return 0;
+}
+
+/**
+ * is_sata - check if hwif is SATA
+ * @hwif: interface to check
+ *
+ * Returns true if this is a SATA controller
+ */
+
+static inline int is_sata(ide_hwif_t *hwif)
+{
+ return pdev_is_sata(to_pci_dev(hwif->dev));
+}
+
+/**
+ * siimage_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 isn't performance
+ * critical.
+ */
+
+static unsigned long siimage_selreg(ide_hwif_t *hwif, int r)
+{
+ unsigned long base = (unsigned long)hwif->hwif_data;
+
+ base += 0xA0 + r;
+ if (hwif->host_flags & IDE_HFLAG_MMIO)
+ base += hwif->channel << 6;
+ else
+ base += hwif->channel << 4;
+ return base;
+}
+
+/**
+ * siimage_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 inline unsigned long siimage_seldev(ide_drive_t *drive, int r)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ unsigned long base = (unsigned long)hwif->hwif_data;
+ u8 unit = drive->dn & 1;
+
+ base += 0xA0 + r;
+ if (hwif->host_flags & IDE_HFLAG_MMIO)
+ base += hwif->channel << 6;
+ else
+ base += hwif->channel << 4;
+ base |= unit << unit;
+ return base;
+}
+
+static u8 sil_ioread8(struct pci_dev *dev, unsigned long addr)
+{
+ struct ide_host *host = pci_get_drvdata(dev);
+ u8 tmp = 0;
+
+ if (host->host_priv)
+ tmp = readb((void __iomem *)addr);
+ else
+ pci_read_config_byte(dev, addr, &tmp);
+
+ return tmp;
+}
+
+static u16 sil_ioread16(struct pci_dev *dev, unsigned long addr)
+{
+ struct ide_host *host = pci_get_drvdata(dev);
+ u16 tmp = 0;
+
+ if (host->host_priv)
+ tmp = readw((void __iomem *)addr);
+ else
+ pci_read_config_word(dev, addr, &tmp);
+
+ return tmp;
+}
+
+static void sil_iowrite8(struct pci_dev *dev, u8 val, unsigned long addr)
+{
+ struct ide_host *host = pci_get_drvdata(dev);
+
+ if (host->host_priv)
+ writeb(val, (void __iomem *)addr);
+ else
+ pci_write_config_byte(dev, addr, val);
+}
+
+static void sil_iowrite16(struct pci_dev *dev, u16 val, unsigned long addr)
+{
+ struct ide_host *host = pci_get_drvdata(dev);
+
+ if (host->host_priv)
+ writew(val, (void __iomem *)addr);
+ else
+ pci_write_config_word(dev, addr, val);
+}
+
+static void sil_iowrite32(struct pci_dev *dev, u32 val, unsigned long addr)
+{
+ struct ide_host *host = pci_get_drvdata(dev);
+
+ if (host->host_priv)
+ writel(val, (void __iomem *)addr);
+ else
+ pci_write_config_dword(dev, addr, val);
+}
+
+/**
+ * sil_udma_filter - compute UDMA mask
+ * @drive: IDE device
+ *
+ * Compute the available UDMA speeds for the device on the interface.
+ *
+ * For the CMD680 this depends on the clocking mode (scsc), for the
+ * SI3112 SATA controller life is a bit simpler.
+ */
+
+static u8 sil_pata_udma_filter(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+ unsigned long base = (unsigned long)hwif->hwif_data;
+ u8 scsc, mask = 0;
+
+ base += (hwif->host_flags & IDE_HFLAG_MMIO) ? 0x4A : 0x8A;
+
+ scsc = sil_ioread8(dev, base);
+
+ switch (scsc & 0x30) {
+ case 0x10: /* 133 */
+ mask = ATA_UDMA6;
+ break;
+ case 0x20: /* 2xPCI */
+ mask = ATA_UDMA6;
+ break;
+ case 0x00: /* 100 */
+ mask = ATA_UDMA5;
+ break;
+ default: /* Disabled ? */
+ BUG();
+ }
+
+ return mask;
+}
+
+static u8 sil_sata_udma_filter(ide_drive_t *drive)
+{
+ char *m = (char *)&drive->id[ATA_ID_PROD];
+
+ return strstr(m, "Maxtor") ? ATA_UDMA5 : ATA_UDMA6;
+}
+
+/**
+ * sil_set_pio_mode - set host controller for PIO mode
+ * @drive: drive
+ * @pio: PIO mode number
+ *
+ * Load the timing settings for this device mode into the
+ * controller. If we are in PIO mode 3 or 4 turn on IORDY
+ * monitoring (bit 9). The TF timing is bits 31:16
+ */
+
+static void sil_set_pio_mode(ide_drive_t *drive, u8 pio)
+{
+ static const u16 tf_speed[] = { 0x328a, 0x2283, 0x1281, 0x10c3, 0x10c1 };
+ static const u16 data_speed[] = { 0x328a, 0x2283, 0x1104, 0x10c3, 0x10c1 };
+
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+ ide_drive_t *pair = ide_get_pair_dev(drive);
+ u32 speedt = 0;
+ u16 speedp = 0;
+ unsigned long addr = siimage_seldev(drive, 0x04);
+ unsigned long tfaddr = siimage_selreg(hwif, 0x02);
+ unsigned long base = (unsigned long)hwif->hwif_data;
+ u8 tf_pio = pio;
+ u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0;
+ u8 addr_mask = hwif->channel ? (mmio ? 0xF4 : 0x84)
+ : (mmio ? 0xB4 : 0x80);
+ u8 mode = 0;
+ u8 unit = drive->dn & 1;
+
+ /* trim *taskfile* PIO to the slowest of the master/slave */
+ if (pair) {
+ u8 pair_pio = ide_get_best_pio_mode(pair, 255, 4);
+
+ if (pair_pio < tf_pio)
+ tf_pio = pair_pio;
+ }
+
+ /* cheat for now and use the docs */
+ speedp = data_speed[pio];
+ speedt = tf_speed[tf_pio];
+
+ sil_iowrite16(dev, speedp, addr);
+ sil_iowrite16(dev, speedt, tfaddr);
+
+ /* now set up IORDY */
+ speedp = sil_ioread16(dev, tfaddr - 2);
+ speedp &= ~0x200;
+ if (pio > 2)
+ speedp |= 0x200;
+ sil_iowrite16(dev, speedp, tfaddr - 2);
+
+ mode = sil_ioread8(dev, base + addr_mask);
+ mode &= ~(unit ? 0x30 : 0x03);
+ mode |= unit ? 0x10 : 0x01;
+ sil_iowrite8(dev, mode, base + addr_mask);
+}
+
+/**
+ * sil_set_dma_mode - set host controller for DMA mode
+ * @drive: drive
+ * @speed: DMA mode
+ *
+ * Tune the SiI chipset for the desired DMA mode.
+ */
+
+static void sil_set_dma_mode(ide_drive_t *drive, const u8 speed)
+{
+ static const u8 ultra6[] = { 0x0F, 0x0B, 0x07, 0x05, 0x03, 0x02, 0x01 };
+ static const u8 ultra5[] = { 0x0C, 0x07, 0x05, 0x04, 0x02, 0x01 };
+ static const u16 dma[] = { 0x2208, 0x10C2, 0x10C1 };
+
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+ unsigned long base = (unsigned long)hwif->hwif_data;
+ u16 ultra = 0, multi = 0;
+ u8 mode = 0, unit = drive->dn & 1;
+ u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0;
+ u8 scsc = 0, addr_mask = hwif->channel ? (mmio ? 0xF4 : 0x84)
+ : (mmio ? 0xB4 : 0x80);
+ unsigned long ma = siimage_seldev(drive, 0x08);
+ unsigned long ua = siimage_seldev(drive, 0x0C);
+
+ scsc = sil_ioread8 (dev, base + (mmio ? 0x4A : 0x8A));
+ mode = sil_ioread8 (dev, base + addr_mask);
+ multi = sil_ioread16(dev, ma);
+ ultra = sil_ioread16(dev, ua);
+
+ mode &= ~(unit ? 0x30 : 0x03);
+ ultra &= ~0x3F;
+ scsc = ((scsc & 0x30) == 0x00) ? 0 : 1;
+
+ scsc = is_sata(hwif) ? 1 : scsc;
+
+ if (speed >= XFER_UDMA_0) {
+ multi = dma[2];
+ ultra |= scsc ? ultra6[speed - XFER_UDMA_0] :
+ ultra5[speed - XFER_UDMA_0];
+ mode |= unit ? 0x30 : 0x03;
+ } else {
+ multi = dma[speed - XFER_MW_DMA_0];
+ mode |= unit ? 0x20 : 0x02;
+ }
+
+ sil_iowrite8 (dev, mode, base + addr_mask);
+ sil_iowrite16(dev, multi, ma);
+ sil_iowrite16(dev, ultra, ua);
+}
+
+/* returns 1 if dma irq issued, 0 otherwise */
+static int siimage_io_dma_test_irq(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+ u8 dma_altstat = 0;
+ unsigned long addr = siimage_selreg(hwif, 1);
+
+ /* return 1 if INTR asserted */
+ if (inb(hwif->dma_base + ATA_DMA_STATUS) & 4)
+ return 1;
+
+ /* return 1 if Device INTR asserted */
+ pci_read_config_byte(dev, addr, &dma_altstat);
+ if (dma_altstat & 8)
+ return 0; /* return 1; */
+
+ return 0;
+}
+
+/**
+ * siimage_mmio_dma_test_irq - check we caused an IRQ
+ * @drive: drive we are testing
+ *
+ * Check if we caused an IDE DMA interrupt. We may also have caused
+ * SATA status interrupts, if so we clean them up and continue.
+ */
+
+static int siimage_mmio_dma_test_irq(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ unsigned long addr = siimage_selreg(hwif, 0x1);
+ void __iomem *sata_error_addr
+ = (void __iomem *)hwif->sata_scr[SATA_ERROR_OFFSET];
+
+ if (sata_error_addr) {
+ unsigned long base = (unsigned long)hwif->hwif_data;
+ u32 ext_stat = readl((void __iomem *)(base + 0x10));
+ u8 watchdog = 0;
+
+ if (ext_stat & ((hwif->channel) ? 0x40 : 0x10)) {
+ u32 sata_error = readl(sata_error_addr);
+
+ writel(sata_error, sata_error_addr);
+ watchdog = (sata_error & 0x00680000) ? 1 : 0;
+ printk(KERN_WARNING "%s: sata_error = 0x%08x, "
+ "watchdog = %d, %s\n",
+ drive->name, sata_error, watchdog, __func__);
+ } else
+ watchdog = (ext_stat & 0x8000) ? 1 : 0;
+
+ ext_stat >>= 16;
+ if (!(ext_stat & 0x0404) && !watchdog)
+ return 0;
+ }
+
+ /* return 1 if INTR asserted */
+ if (readb((void __iomem *)(hwif->dma_base + ATA_DMA_STATUS)) & 4)
+ return 1;
+
+ /* return 1 if Device INTR asserted */
+ if (readb((void __iomem *)addr) & 8)
+ return 0; /* return 1; */
+
+ return 0;
+}
+
+static int siimage_dma_test_irq(ide_drive_t *drive)
+{
+ if (drive->hwif->host_flags & IDE_HFLAG_MMIO)
+ return siimage_mmio_dma_test_irq(drive);
+ else
+ return siimage_io_dma_test_irq(drive);
+}
+
+/**
+ * sil_sata_reset_poll - wait for SATA reset
+ * @drive: drive we are resetting
+ *
+ * Poll the SATA phy and see whether it has come back from the dead
+ * yet.
+ */
+
+static int sil_sata_reset_poll(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ void __iomem *sata_status_addr
+ = (void __iomem *)hwif->sata_scr[SATA_STATUS_OFFSET];
+
+ if (sata_status_addr) {
+ /* SATA Status is available only when in MMIO mode */
+ u32 sata_stat = readl(sata_status_addr);
+
+ if ((sata_stat & 0x03) != 0x03) {
+ printk(KERN_WARNING "%s: reset phy dead, status=0x%08x\n",
+ hwif->name, sata_stat);
+ return -ENXIO;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * sil_sata_pre_reset - reset hook
+ * @drive: IDE device being reset
+ *
+ * For the SATA devices we need to handle recalibration/geometry
+ * differently
+ */
+
+static void sil_sata_pre_reset(ide_drive_t *drive)
+{
+ if (drive->media == ide_disk) {
+ drive->special.b.set_geometry = 0;
+ drive->special.b.recalibrate = 0;
+ }
+}
+
+/**
+ * init_chipset_siimage - set up an SI device
+ * @dev: PCI device
+ *
+ * Perform the initial PCI set up for this device. Attempt to switch
+ * to 133 MHz clocking if the system isn't already set up to do it.
+ */
+
+static unsigned int init_chipset_siimage(struct pci_dev *dev)
+{
+ struct ide_host *host = pci_get_drvdata(dev);
+ void __iomem *ioaddr = host->host_priv;
+ unsigned long base, scsc_addr;
+ u8 rev = dev->revision, tmp;
+
+ pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, rev ? 1 : 255);
+
+ if (ioaddr)
+ pci_set_master(dev);
+
+ base = (unsigned long)ioaddr;
+
+ if (ioaddr && pdev_is_sata(dev)) {
+ u32 tmp32, irq_mask;
+
+ /* make sure IDE0/1 interrupts are not masked */
+ irq_mask = (1 << 22) | (1 << 23);
+ tmp32 = readl(ioaddr + 0x48);
+ if (tmp32 & irq_mask) {
+ tmp32 &= ~irq_mask;
+ writel(tmp32, ioaddr + 0x48);
+ readl(ioaddr + 0x48); /* flush */
+ }
+ writel(0, ioaddr + 0x148);
+ writel(0, ioaddr + 0x1C8);
+ }
+
+ sil_iowrite8(dev, 0, base ? (base + 0xB4) : 0x80);
+ sil_iowrite8(dev, 0, base ? (base + 0xF4) : 0x84);
+
+ scsc_addr = base ? (base + 0x4A) : 0x8A;
+ tmp = sil_ioread8(dev, scsc_addr);
+
+ switch (tmp & 0x30) {
+ case 0x00:
+ /* On 100 MHz clocking, try and switch to 133 MHz */
+ sil_iowrite8(dev, tmp | 0x10, scsc_addr);
+ break;
+ case 0x30:
+ /* Clocking is disabled, attempt to force 133MHz clocking. */
+ sil_iowrite8(dev, tmp & ~0x20, scsc_addr);
+ case 0x10:
+ /* On 133Mhz clocking. */
+ break;
+ case 0x20:
+ /* On PCIx2 clocking. */
+ break;
+ }
+
+ tmp = sil_ioread8(dev, scsc_addr);
+
+ sil_iowrite8 (dev, 0x72, base + 0xA1);
+ sil_iowrite16(dev, 0x328A, base + 0xA2);
+ sil_iowrite32(dev, 0x62DD62DD, base + 0xA4);
+ sil_iowrite32(dev, 0x43924392, base + 0xA8);
+ sil_iowrite32(dev, 0x40094009, base + 0xAC);
+ sil_iowrite8 (dev, 0x72, base ? (base + 0xE1) : 0xB1);
+ sil_iowrite16(dev, 0x328A, base ? (base + 0xE2) : 0xB2);
+ sil_iowrite32(dev, 0x62DD62DD, base ? (base + 0xE4) : 0xB4);
+ sil_iowrite32(dev, 0x43924392, base ? (base + 0xE8) : 0xB8);
+ sil_iowrite32(dev, 0x40094009, base ? (base + 0xEC) : 0xBC);
+
+ if (base && pdev_is_sata(dev)) {
+ writel(0xFFFF0000, ioaddr + 0x108);
+ writel(0xFFFF0000, ioaddr + 0x188);
+ writel(0x00680000, ioaddr + 0x148);
+ writel(0x00680000, ioaddr + 0x1C8);
+ }
+
+ /* report the clocking mode of the controller */
+ if (!pdev_is_sata(dev)) {
+ static const char *clk_str[] =
+ { "== 100", "== 133", "== 2X PCI", "DISABLED!" };
+
+ tmp >>= 4;
+ printk(KERN_INFO DRV_NAME " %s: BASE CLOCK %s\n",
+ pci_name(dev), clk_str[tmp & 3]);
+ }
+
+ return 0;
+}
+
+/**
+ * init_mmio_iops_siimage - set up the iops for MMIO
+ * @hwif: interface to set up
+ *
+ * The basic setup here is fairly simple, we can use standard MMIO
+ * operations. However we do have to set the taskfile register offsets
+ * by hand as there isn't a standard defined layout for them this time.
+ *
+ * The hardware supports buffered taskfiles and also some rather nice
+ * extended PRD tables. For better SI3112 support use the libata driver
+ */
+
+static void __devinit init_mmio_iops_siimage(ide_hwif_t *hwif)
+{
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+ struct ide_host *host = pci_get_drvdata(dev);
+ void *addr = host->host_priv;
+ u8 ch = hwif->channel;
+ struct ide_io_ports *io_ports = &hwif->io_ports;
+ unsigned long base;
+
+ /*
+ * Fill in the basic hwif bits
+ */
+ hwif->host_flags |= IDE_HFLAG_MMIO;
+
+ hwif->hwif_data = addr;
+
+ /*
+ * Now set up the hw. We have to do this ourselves as the
+ * MMIO layout isn't the same as the standard port based I/O.
+ */
+ memset(io_ports, 0, sizeof(*io_ports));
+
+ base = (unsigned long)addr;
+ if (ch)
+ base += 0xC0;
+ else
+ base += 0x80;
+
+ /*
+ * The buffered task file doesn't have status/control, so we
+ * can't currently use it sanely since we want to use LBA48 mode.
+ */
+ io_ports->data_addr = base;
+ io_ports->error_addr = base + 1;
+ io_ports->nsect_addr = base + 2;
+ io_ports->lbal_addr = base + 3;
+ io_ports->lbam_addr = base + 4;
+ io_ports->lbah_addr = base + 5;
+ io_ports->device_addr = base + 6;
+ io_ports->status_addr = base + 7;
+ io_ports->ctl_addr = base + 10;
+
+ if (pdev_is_sata(dev)) {
+ base = (unsigned long)addr;
+ if (ch)
+ base += 0x80;
+ hwif->sata_scr[SATA_STATUS_OFFSET] = base + 0x104;
+ hwif->sata_scr[SATA_ERROR_OFFSET] = base + 0x108;
+ hwif->sata_scr[SATA_CONTROL_OFFSET] = base + 0x100;
+ }
+
+ hwif->irq = dev->irq;
+
+ hwif->dma_base = (unsigned long)addr + (ch ? 0x08 : 0x00);
+}
+
+static int is_dev_seagate_sata(ide_drive_t *drive)
+{
+ const char *s = (const char *)&drive->id[ATA_ID_PROD];
+ unsigned len = strnlen(s, ATA_ID_PROD_LEN);
+
+ if ((len > 4) && (!memcmp(s, "ST", 2)))
+ if ((!memcmp(s + len - 2, "AS", 2)) ||
+ (!memcmp(s + len - 3, "ASL", 3))) {
+ printk(KERN_INFO "%s: applying pessimistic Seagate "
+ "errata fix\n", drive->name);
+ return 1;
+ }
+
+ return 0;
+}
+
+/**
+ * sil_quirkproc - post probe fixups
+ * @drive: drive
+ *
+ * Called after drive probe we use this to decide whether the
+ * Seagate fixup must be applied. This used to be in init_iops but
+ * that can occur before we know what drives are present.
+ */
+
+static void sil_quirkproc(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = drive->hwif;
+
+ /* Try and rise the rqsize */
+ if (!is_sata(hwif) || !is_dev_seagate_sata(drive))
+ hwif->rqsize = 128;
+}
+
+/**
+ * init_iops_siimage - set up iops
+ * @hwif: interface to set up
+ *
+ * Do the basic setup for the SIIMAGE hardware interface
+ * and then do the MMIO setup if we can. This is the first
+ * look in we get for setting up the hwif so that we
+ * can get the iops right before using them.
+ */
+
+static void __devinit init_iops_siimage(ide_hwif_t *hwif)
+{
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+ struct ide_host *host = pci_get_drvdata(dev);
+
+ hwif->hwif_data = NULL;
+
+ /* Pessimal until we finish probing */
+ hwif->rqsize = 15;
+
+ if (host->host_priv)
+ init_mmio_iops_siimage(hwif);
+}
+
+/**
+ * sil_cable_detect - cable detection
+ * @hwif: interface to check
+ *
+ * Check for the presence of an ATA66 capable cable on the interface.
+ */
+
+static u8 sil_cable_detect(ide_hwif_t *hwif)
+{
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+ unsigned long addr = siimage_selreg(hwif, 0);
+ u8 ata66 = sil_ioread8(dev, addr);
+
+ return (ata66 & 0x01) ? ATA_CBL_PATA80 : ATA_CBL_PATA40;
+}
+
+static const struct ide_port_ops sil_pata_port_ops = {
+ .set_pio_mode = sil_set_pio_mode,
+ .set_dma_mode = sil_set_dma_mode,
+ .quirkproc = sil_quirkproc,
+ .udma_filter = sil_pata_udma_filter,
+ .cable_detect = sil_cable_detect,
+};
+
+static const struct ide_port_ops sil_sata_port_ops = {
+ .set_pio_mode = sil_set_pio_mode,
+ .set_dma_mode = sil_set_dma_mode,
+ .reset_poll = sil_sata_reset_poll,
+ .pre_reset = sil_sata_pre_reset,
+ .quirkproc = sil_quirkproc,
+ .udma_filter = sil_sata_udma_filter,
+ .cable_detect = sil_cable_detect,
+};
+
+static const struct ide_dma_ops sil_dma_ops = {
+ .dma_host_set = ide_dma_host_set,
+ .dma_setup = ide_dma_setup,
+ .dma_exec_cmd = ide_dma_exec_cmd,
+ .dma_start = ide_dma_start,
+ .dma_end = ide_dma_end,
+ .dma_test_irq = siimage_dma_test_irq,
+ .dma_timeout = ide_dma_timeout,
+ .dma_lost_irq = ide_dma_lost_irq,
+};
+
+#define DECLARE_SII_DEV(p_ops) \
+ { \
+ .name = DRV_NAME, \
+ .init_chipset = init_chipset_siimage, \
+ .init_iops = init_iops_siimage, \
+ .port_ops = p_ops, \
+ .dma_ops = &sil_dma_ops, \
+ .pio_mask = ATA_PIO4, \
+ .mwdma_mask = ATA_MWDMA2, \
+ .udma_mask = ATA_UDMA6, \
+ }
+
+static const struct ide_port_info siimage_chipsets[] __devinitdata = {
+ /* 0: SiI680 */ DECLARE_SII_DEV(&sil_pata_port_ops),
+ /* 1: SiI3112 */ DECLARE_SII_DEV(&sil_sata_port_ops)
+};
+
+/**
+ * siimage_init_one - PCI layer discovery entry
+ * @dev: PCI device
+ * @id: ident table entry
+ *
+ * Called by the PCI code when it finds an SiI680 or SiI3112 controller.
+ * We then use the IDE PCI generic helper to do most of the work.
+ */
+
+static int __devinit siimage_init_one(struct pci_dev *dev,
+ const struct pci_device_id *id)
+{
+ void __iomem *ioaddr = NULL;
+ resource_size_t bar5 = pci_resource_start(dev, 5);
+ unsigned long barsize = pci_resource_len(dev, 5);
+ int rc;
+ struct ide_port_info d;
+ u8 idx = id->driver_data;
+ u8 BA5_EN;
+
+ d = siimage_chipsets[idx];
+
+ if (idx) {
+ static int first = 1;
+
+ if (first) {
+ printk(KERN_INFO DRV_NAME ": For full SATA support you "
+ "should use the libata sata_sil module.\n");
+ first = 0;
+ }
+
+ d.host_flags |= IDE_HFLAG_NO_ATAPI_DMA;
+ }
+
+ rc = pci_enable_device(dev);
+ if (rc)
+ return rc;
+
+ pci_read_config_byte(dev, 0x8A, &BA5_EN);
+ if ((BA5_EN & 0x01) || bar5) {
+ /*
+ * Drop back to PIO if we can't map the MMIO. Some systems
+ * seem to get terminally confused in the PCI spaces.
+ */
+ if (!request_mem_region(bar5, barsize, d.name)) {
+ printk(KERN_WARNING DRV_NAME " %s: MMIO ports not "
+ "available\n", pci_name(dev));
+ } else {
+ ioaddr = pci_ioremap_bar(dev, 5);
+ if (ioaddr == NULL)
+ release_mem_region(bar5, barsize);
+ }
+ }
+
+ rc = ide_pci_init_one(dev, &d, ioaddr);
+ if (rc) {
+ if (ioaddr) {
+ iounmap(ioaddr);
+ release_mem_region(bar5, barsize);
+ }
+ pci_disable_device(dev);
+ }
+
+ return rc;
+}
+
+static void __devexit siimage_remove(struct pci_dev *dev)
+{
+ struct ide_host *host = pci_get_drvdata(dev);
+ void __iomem *ioaddr = host->host_priv;
+
+ ide_pci_remove(dev);
+
+ if (ioaddr) {
+ resource_size_t bar5 = pci_resource_start(dev, 5);
+ unsigned long barsize = pci_resource_len(dev, 5);
+
+ iounmap(ioaddr);
+ release_mem_region(bar5, barsize);
+ }
+
+ pci_disable_device(dev);
+}
+
+static const struct pci_device_id siimage_pci_tbl[] = {
+ { PCI_VDEVICE(CMD, PCI_DEVICE_ID_SII_680), 0 },
+#ifdef CONFIG_BLK_DEV_IDE_SATA
+ { PCI_VDEVICE(CMD, PCI_DEVICE_ID_SII_3112), 1 },
+ { PCI_VDEVICE(CMD, PCI_DEVICE_ID_SII_1210SA), 1 },
+#endif
+ { 0, },
+};
+MODULE_DEVICE_TABLE(pci, siimage_pci_tbl);
+
+static struct pci_driver siimage_pci_driver = {
+ .name = "SiI_IDE",
+ .id_table = siimage_pci_tbl,
+ .probe = siimage_init_one,
+ .remove = __devexit_p(siimage_remove),
+ .suspend = ide_pci_suspend,
+ .resume = ide_pci_resume,
+};
+
+static int __init siimage_ide_init(void)
+{
+ return ide_pci_register_driver(&siimage_pci_driver);
+}
+
+static void __exit siimage_ide_exit(void)
+{
+ pci_unregister_driver(&siimage_pci_driver);
+}
+
+module_init(siimage_ide_init);
+module_exit(siimage_ide_exit);
+
+MODULE_AUTHOR("Andre Hedrick, Alan Cox");
+MODULE_DESCRIPTION("PCI driver module for SiI IDE");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/sis5513.c b/drivers/ide/sis5513.c
new file mode 100644
index 0000000..ad32e18
--- /dev/null
+++ b/drivers/ide/sis5513.c
@@ -0,0 +1,641 @@
+/*
+ * Copyright (C) 1999-2000 Andre Hedrick <andre@linux-ide.org>
+ * Copyright (C) 2002 Lionel Bouton <Lionel.Bouton@inet6.fr>, Maintainer
+ * Copyright (C) 2003 Vojtech Pavlik <vojtech@suse.cz>
+ * Copyright (C) 2007 Bartlomiej Zolnierkiewicz
+ *
+ * May be copied or modified under the terms of the GNU General Public License
+ *
+ *
+ * Thanks :
+ *
+ * SiS Taiwan : for direct support and hardware.
+ * Daniela Engert : for initial ATA100 advices and numerous others.
+ * John Fremlin, Manfred Spraul, Dave Morgan, Peter Kjellerstedt :
+ * for checking code correctness, providing patches.
+ *
+ *
+ * Original tests and design on the SiS620 chipset.
+ * ATA100 tests and design on the SiS735 chipset.
+ * ATA16/33 support from specs
+ * ATA133 support for SiS961/962 by L.C. Chang <lcchang@sis.com.tw>
+ * ATA133 961/962/963 fixes by Vojtech Pavlik <vojtech@suse.cz>
+ *
+ * Documentation:
+ * SiS chipset documentation available under NDA to companies only
+ * (not to individuals).
+ */
+
+/*
+ * The original SiS5513 comes from a SiS5511/55112/5513 chipset. The original
+ * SiS5513 was also used in the SiS5596/5513 chipset. Thus if we see a SiS5511
+ * or SiS5596, we can assume we see the first MWDMA-16 capable SiS5513 chip.
+ *
+ * Later SiS chipsets integrated the 5513 functionality into the NorthBridge,
+ * starting with SiS5571 and up to SiS745. The PCI ID didn't change, though. We
+ * can figure out that we have a more modern and more capable 5513 by looking
+ * for the respective NorthBridge IDs.
+ *
+ * Even later (96x family) SiS chipsets use the MuTIOL link and place the 5513
+ * into the SouthBrige. Here we cannot rely on looking up the NorthBridge PCI
+ * ID, while the now ATA-133 capable 5513 still has the same PCI ID.
+ * Fortunately the 5513 can be 'unmasked' by fiddling with some config space
+ * bits, changing its device id to the true one - 5517 for 961 and 5518 for
+ * 962/963.
+ */
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/ide.h>
+
+#define DRV_NAME "sis5513"
+
+/* registers layout and init values are chipset family dependant */
+
+#define ATA_16 0x01
+#define ATA_33 0x02
+#define ATA_66 0x03
+#define ATA_100a 0x04 /* SiS730/SiS550 is ATA100 with ATA66 layout */
+#define ATA_100 0x05
+#define ATA_133a 0x06 /* SiS961b with 133 support */
+#define ATA_133 0x07 /* SiS962/963 */
+
+static u8 chipset_family;
+
+/*
+ * Devices supported
+ */
+static const struct {
+ const char *name;
+ u16 host_id;
+ u8 chipset_family;
+ u8 flags;
+} SiSHostChipInfo[] = {
+ { "SiS968", PCI_DEVICE_ID_SI_968, ATA_133 },
+ { "SiS966", PCI_DEVICE_ID_SI_966, ATA_133 },
+ { "SiS965", PCI_DEVICE_ID_SI_965, ATA_133 },
+ { "SiS745", PCI_DEVICE_ID_SI_745, ATA_100 },
+ { "SiS735", PCI_DEVICE_ID_SI_735, ATA_100 },
+ { "SiS733", PCI_DEVICE_ID_SI_733, ATA_100 },
+ { "SiS635", PCI_DEVICE_ID_SI_635, ATA_100 },
+ { "SiS633", PCI_DEVICE_ID_SI_633, ATA_100 },
+
+ { "SiS730", PCI_DEVICE_ID_SI_730, ATA_100a },
+ { "SiS550", PCI_DEVICE_ID_SI_550, ATA_100a },
+
+ { "SiS640", PCI_DEVICE_ID_SI_640, ATA_66 },
+ { "SiS630", PCI_DEVICE_ID_SI_630, ATA_66 },
+ { "SiS620", PCI_DEVICE_ID_SI_620, ATA_66 },
+ { "SiS540", PCI_DEVICE_ID_SI_540, ATA_66 },
+ { "SiS530", PCI_DEVICE_ID_SI_530, ATA_66 },
+
+ { "SiS5600", PCI_DEVICE_ID_SI_5600, ATA_33 },
+ { "SiS5598", PCI_DEVICE_ID_SI_5598, ATA_33 },
+ { "SiS5597", PCI_DEVICE_ID_SI_5597, ATA_33 },
+ { "SiS5591/2", PCI_DEVICE_ID_SI_5591, ATA_33 },
+ { "SiS5582", PCI_DEVICE_ID_SI_5582, ATA_33 },
+ { "SiS5581", PCI_DEVICE_ID_SI_5581, ATA_33 },
+
+ { "SiS5596", PCI_DEVICE_ID_SI_5596, ATA_16 },
+ { "SiS5571", PCI_DEVICE_ID_SI_5571, ATA_16 },
+ { "SiS5517", PCI_DEVICE_ID_SI_5517, ATA_16 },
+ { "SiS551x", PCI_DEVICE_ID_SI_5511, ATA_16 },
+};
+
+/* Cycle time bits and values vary across chip dma capabilities
+ These three arrays hold the register layout and the values to set.
+ Indexed by chipset_family and (dma_mode - XFER_UDMA_0) */
+
+/* {0, ATA_16, ATA_33, ATA_66, ATA_100a, ATA_100, ATA_133} */
+static u8 cycle_time_offset[] = { 0, 0, 5, 4, 4, 0, 0 };
+static u8 cycle_time_range[] = { 0, 0, 2, 3, 3, 4, 4 };
+static u8 cycle_time_value[][XFER_UDMA_6 - XFER_UDMA_0 + 1] = {
+ { 0, 0, 0, 0, 0, 0, 0 }, /* no UDMA */
+ { 0, 0, 0, 0, 0, 0, 0 }, /* no UDMA */
+ { 3, 2, 1, 0, 0, 0, 0 }, /* ATA_33 */
+ { 7, 5, 3, 2, 1, 0, 0 }, /* ATA_66 */
+ { 7, 5, 3, 2, 1, 0, 0 }, /* ATA_100a (730 specific),
+ different cycle_time range and offset */
+ { 11, 7, 5, 4, 2, 1, 0 }, /* ATA_100 */
+ { 15, 10, 7, 5, 3, 2, 1 }, /* ATA_133a (earliest 691 southbridges) */
+ { 15, 10, 7, 5, 3, 2, 1 }, /* ATA_133 */
+};
+/* CRC Valid Setup Time vary across IDE clock setting 33/66/100/133
+ See SiS962 data sheet for more detail */
+static u8 cvs_time_value[][XFER_UDMA_6 - XFER_UDMA_0 + 1] = {
+ { 0, 0, 0, 0, 0, 0, 0 }, /* no UDMA */
+ { 0, 0, 0, 0, 0, 0, 0 }, /* no UDMA */
+ { 2, 1, 1, 0, 0, 0, 0 },
+ { 4, 3, 2, 1, 0, 0, 0 },
+ { 4, 3, 2, 1, 0, 0, 0 },
+ { 6, 4, 3, 1, 1, 1, 0 },
+ { 9, 6, 4, 2, 2, 2, 2 },
+ { 9, 6, 4, 2, 2, 2, 2 },
+};
+/* Initialize time, Active time, Recovery time vary across
+ IDE clock settings. These 3 arrays hold the register value
+ for PIO0/1/2/3/4 and DMA0/1/2 mode in order */
+static u8 ini_time_value[][8] = {
+ { 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 2, 1, 0, 0, 0, 1, 0, 0 },
+ { 4, 3, 1, 1, 1, 3, 1, 1 },
+ { 4, 3, 1, 1, 1, 3, 1, 1 },
+ { 6, 4, 2, 2, 2, 4, 2, 2 },
+ { 9, 6, 3, 3, 3, 6, 3, 3 },
+ { 9, 6, 3, 3, 3, 6, 3, 3 },
+};
+static u8 act_time_value[][8] = {
+ { 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 9, 9, 9, 2, 2, 7, 2, 2 },
+ { 19, 19, 19, 5, 4, 14, 5, 4 },
+ { 19, 19, 19, 5, 4, 14, 5, 4 },
+ { 28, 28, 28, 7, 6, 21, 7, 6 },
+ { 38, 38, 38, 10, 9, 28, 10, 9 },
+ { 38, 38, 38, 10, 9, 28, 10, 9 },
+};
+static u8 rco_time_value[][8] = {
+ { 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 9, 2, 0, 2, 0, 7, 1, 1 },
+ { 19, 5, 1, 5, 2, 16, 3, 2 },
+ { 19, 5, 1, 5, 2, 16, 3, 2 },
+ { 30, 9, 3, 9, 4, 25, 6, 4 },
+ { 40, 12, 4, 12, 5, 34, 12, 5 },
+ { 40, 12, 4, 12, 5, 34, 12, 5 },
+};
+
+/*
+ * Printing configuration
+ */
+/* Used for chipset type printing at boot time */
+static char *chipset_capability[] = {
+ "ATA", "ATA 16",
+ "ATA 33", "ATA 66",
+ "ATA 100 (1st gen)", "ATA 100 (2nd gen)",
+ "ATA 133 (1st gen)", "ATA 133 (2nd gen)"
+};
+
+/*
+ * Configuration functions
+ */
+
+static u8 sis_ata133_get_base(ide_drive_t *drive)
+{
+ struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
+ u32 reg54 = 0;
+
+ pci_read_config_dword(dev, 0x54, &reg54);
+
+ return ((reg54 & 0x40000000) ? 0x70 : 0x40) + drive->dn * 4;
+}
+
+static void sis_ata16_program_timings(ide_drive_t *drive, const u8 mode)
+{
+ struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
+ u16 t1 = 0;
+ u8 drive_pci = 0x40 + drive->dn * 2;
+
+ const u16 pio_timings[] = { 0x000, 0x607, 0x404, 0x303, 0x301 };
+ const u16 mwdma_timings[] = { 0x008, 0x302, 0x301 };
+
+ pci_read_config_word(dev, drive_pci, &t1);
+
+ /* clear active/recovery timings */
+ t1 &= ~0x070f;
+ if (mode >= XFER_MW_DMA_0) {
+ if (chipset_family > ATA_16)
+ t1 &= ~0x8000; /* disable UDMA */
+ t1 |= mwdma_timings[mode - XFER_MW_DMA_0];
+ } else
+ t1 |= pio_timings[mode - XFER_PIO_0];
+
+ pci_write_config_word(dev, drive_pci, t1);
+}
+
+static void sis_ata100_program_timings(ide_drive_t *drive, const u8 mode)
+{
+ struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
+ u8 t1, drive_pci = 0x40 + drive->dn * 2;
+
+ /* timing bits: 7:4 active 3:0 recovery */
+ const u8 pio_timings[] = { 0x00, 0x67, 0x44, 0x33, 0x31 };
+ const u8 mwdma_timings[] = { 0x08, 0x32, 0x31 };
+
+ if (mode >= XFER_MW_DMA_0) {
+ u8 t2 = 0;
+
+ pci_read_config_byte(dev, drive_pci, &t2);
+ t2 &= ~0x80; /* disable UDMA */
+ pci_write_config_byte(dev, drive_pci, t2);
+
+ t1 = mwdma_timings[mode - XFER_MW_DMA_0];
+ } else
+ t1 = pio_timings[mode - XFER_PIO_0];
+
+ pci_write_config_byte(dev, drive_pci + 1, t1);
+}
+
+static void sis_ata133_program_timings(ide_drive_t *drive, const u8 mode)
+{
+ struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
+ u32 t1 = 0;
+ u8 drive_pci = sis_ata133_get_base(drive), clk, idx;
+
+ pci_read_config_dword(dev, drive_pci, &t1);
+
+ t1 &= 0xc0c00fff;
+ clk = (t1 & 0x08) ? ATA_133 : ATA_100;
+ if (mode >= XFER_MW_DMA_0) {
+ t1 &= ~0x04; /* disable UDMA */
+ idx = mode - XFER_MW_DMA_0 + 5;
+ } else
+ idx = mode - XFER_PIO_0;
+ t1 |= ini_time_value[clk][idx] << 12;
+ t1 |= act_time_value[clk][idx] << 16;
+ t1 |= rco_time_value[clk][idx] << 24;
+
+ pci_write_config_dword(dev, drive_pci, t1);
+}
+
+static void sis_program_timings(ide_drive_t *drive, const u8 mode)
+{
+ if (chipset_family < ATA_100) /* ATA_16/33/66/100a */
+ sis_ata16_program_timings(drive, mode);
+ else if (chipset_family < ATA_133) /* ATA_100/133a */
+ sis_ata100_program_timings(drive, mode);
+ else /* ATA_133 */
+ sis_ata133_program_timings(drive, mode);
+}
+
+static void config_drive_art_rwp(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+ u8 reg4bh = 0;
+ u8 rw_prefetch = 0;
+
+ pci_read_config_byte(dev, 0x4b, &reg4bh);
+
+ if (drive->media == ide_disk)
+ rw_prefetch = 0x11 << drive->dn;
+
+ if ((reg4bh & (0x11 << drive->dn)) != rw_prefetch)
+ pci_write_config_byte(dev, 0x4b, reg4bh|rw_prefetch);
+}
+
+static void sis_set_pio_mode(ide_drive_t *drive, const u8 pio)
+{
+ config_drive_art_rwp(drive);
+ sis_program_timings(drive, XFER_PIO_0 + pio);
+}
+
+static void sis_ata133_program_udma_timings(ide_drive_t *drive, const u8 mode)
+{
+ struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
+ u32 regdw = 0;
+ u8 drive_pci = sis_ata133_get_base(drive), clk, idx;
+
+ pci_read_config_dword(dev, drive_pci, &regdw);
+
+ regdw |= 0x04;
+ regdw &= 0xfffff00f;
+ /* check if ATA133 enable */
+ clk = (regdw & 0x08) ? ATA_133 : ATA_100;
+ idx = mode - XFER_UDMA_0;
+ regdw |= cycle_time_value[clk][idx] << 4;
+ regdw |= cvs_time_value[clk][idx] << 8;
+
+ pci_write_config_dword(dev, drive_pci, regdw);
+}
+
+static void sis_ata33_program_udma_timings(ide_drive_t *drive, const u8 mode)
+{
+ struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
+ u8 drive_pci = 0x40 + drive->dn * 2, reg = 0, i = chipset_family;
+
+ pci_read_config_byte(dev, drive_pci + 1, &reg);
+
+ /* force the UDMA bit on if we want to use UDMA */
+ reg |= 0x80;
+ /* clean reg cycle time bits */
+ reg &= ~((0xff >> (8 - cycle_time_range[i])) << cycle_time_offset[i]);
+ /* set reg cycle time bits */
+ reg |= cycle_time_value[i][mode - XFER_UDMA_0] << cycle_time_offset[i];
+
+ pci_write_config_byte(dev, drive_pci + 1, reg);
+}
+
+static void sis_program_udma_timings(ide_drive_t *drive, const u8 mode)
+{
+ if (chipset_family >= ATA_133) /* ATA_133 */
+ sis_ata133_program_udma_timings(drive, mode);
+ else /* ATA_33/66/100a/100/133a */
+ sis_ata33_program_udma_timings(drive, mode);
+}
+
+static void sis_set_dma_mode(ide_drive_t *drive, const u8 speed)
+{
+ if (speed >= XFER_UDMA_0)
+ sis_program_udma_timings(drive, speed);
+ else
+ sis_program_timings(drive, speed);
+}
+
+static u8 sis_ata133_udma_filter(ide_drive_t *drive)
+{
+ struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
+ u32 regdw = 0;
+ u8 drive_pci = sis_ata133_get_base(drive);
+
+ pci_read_config_dword(dev, drive_pci, &regdw);
+
+ /* if ATA133 disable, we should not set speed above UDMA5 */
+ return (regdw & 0x08) ? ATA_UDMA6 : ATA_UDMA5;
+}
+
+static int __devinit sis_find_family(struct pci_dev *dev)
+{
+ struct pci_dev *host;
+ int i = 0;
+
+ chipset_family = 0;
+
+ for (i = 0; i < ARRAY_SIZE(SiSHostChipInfo) && !chipset_family; i++) {
+
+ host = pci_get_device(PCI_VENDOR_ID_SI, SiSHostChipInfo[i].host_id, NULL);
+
+ if (!host)
+ continue;
+
+ chipset_family = SiSHostChipInfo[i].chipset_family;
+
+ /* Special case for SiS630 : 630S/ET is ATA_100a */
+ if (SiSHostChipInfo[i].host_id == PCI_DEVICE_ID_SI_630) {
+ if (host->revision >= 0x30)
+ chipset_family = ATA_100a;
+ }
+ pci_dev_put(host);
+
+ printk(KERN_INFO DRV_NAME " %s: %s %s controller\n",
+ pci_name(dev), SiSHostChipInfo[i].name,
+ chipset_capability[chipset_family]);
+ }
+
+ if (!chipset_family) { /* Belongs to pci-quirks */
+
+ u32 idemisc;
+ u16 trueid;
+
+ /* Disable ID masking and register remapping */
+ pci_read_config_dword(dev, 0x54, &idemisc);
+ pci_write_config_dword(dev, 0x54, (idemisc & 0x7fffffff));
+ pci_read_config_word(dev, PCI_DEVICE_ID, &trueid);
+ pci_write_config_dword(dev, 0x54, idemisc);
+
+ if (trueid == 0x5518) {
+ printk(KERN_INFO DRV_NAME " %s: SiS 962/963 MuTIOL IDE UDMA133 controller\n",
+ pci_name(dev));
+ chipset_family = ATA_133;
+
+ /* Check for 5513 compability mapping
+ * We must use this, else the port enabled code will fail,
+ * as it expects the enablebits at 0x4a.
+ */
+ if ((idemisc & 0x40000000) == 0) {
+ pci_write_config_dword(dev, 0x54, idemisc | 0x40000000);
+ printk(KERN_INFO DRV_NAME " %s: Switching to 5513 register mapping\n",
+ pci_name(dev));
+ }
+ }
+ }
+
+ if (!chipset_family) { /* Belongs to pci-quirks */
+
+ struct pci_dev *lpc_bridge;
+ u16 trueid;
+ u8 prefctl;
+ u8 idecfg;
+
+ pci_read_config_byte(dev, 0x4a, &idecfg);
+ pci_write_config_byte(dev, 0x4a, idecfg | 0x10);
+ pci_read_config_word(dev, PCI_DEVICE_ID, &trueid);
+ pci_write_config_byte(dev, 0x4a, idecfg);
+
+ if (trueid == 0x5517) { /* SiS 961/961B */
+
+ lpc_bridge = pci_get_slot(dev->bus, 0x10); /* Bus 0, Dev 2, Fn 0 */
+ pci_read_config_byte(dev, 0x49, &prefctl);
+ pci_dev_put(lpc_bridge);
+
+ if (lpc_bridge->revision == 0x10 && (prefctl & 0x80)) {
+ printk(KERN_INFO DRV_NAME " %s: SiS 961B MuTIOL IDE UDMA133 controller\n",
+ pci_name(dev));
+ chipset_family = ATA_133a;
+ } else {
+ printk(KERN_INFO DRV_NAME " %s: SiS 961 MuTIOL IDE UDMA100 controller\n",
+ pci_name(dev));
+ chipset_family = ATA_100;
+ }
+ }
+ }
+
+ return chipset_family;
+}
+
+static unsigned int init_chipset_sis5513(struct pci_dev *dev)
+{
+ /* Make general config ops here
+ 1/ tell IDE channels to operate in Compatibility mode only
+ 2/ tell old chips to allow per drive IDE timings */
+
+ u8 reg;
+ u16 regw;
+
+ switch (chipset_family) {
+ case ATA_133:
+ /* SiS962 operation mode */
+ pci_read_config_word(dev, 0x50, &regw);
+ if (regw & 0x08)
+ pci_write_config_word(dev, 0x50, regw&0xfff7);
+ pci_read_config_word(dev, 0x52, &regw);
+ if (regw & 0x08)
+ pci_write_config_word(dev, 0x52, regw&0xfff7);
+ break;
+ case ATA_133a:
+ case ATA_100:
+ /* Fixup latency */
+ pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x80);
+ /* Set compatibility bit */
+ pci_read_config_byte(dev, 0x49, &reg);
+ if (!(reg & 0x01))
+ pci_write_config_byte(dev, 0x49, reg|0x01);
+ break;
+ case ATA_100a:
+ case ATA_66:
+ /* Fixup latency */
+ pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x10);
+
+ /* On ATA_66 chips the bit was elsewhere */
+ pci_read_config_byte(dev, 0x52, &reg);
+ if (!(reg & 0x04))
+ pci_write_config_byte(dev, 0x52, reg|0x04);
+ break;
+ case ATA_33:
+ /* On ATA_33 we didn't have a single bit to set */
+ pci_read_config_byte(dev, 0x09, &reg);
+ if ((reg & 0x0f) != 0x00)
+ pci_write_config_byte(dev, 0x09, reg&0xf0);
+ case ATA_16:
+ /* force per drive recovery and active timings
+ needed on ATA_33 and below chips */
+ pci_read_config_byte(dev, 0x52, &reg);
+ if (!(reg & 0x08))
+ pci_write_config_byte(dev, 0x52, reg|0x08);
+ break;
+ }
+
+ return 0;
+}
+
+struct sis_laptop {
+ u16 device;
+ u16 subvendor;
+ u16 subdevice;
+};
+
+static const struct sis_laptop sis_laptop[] = {
+ /* devid, subvendor, subdev */
+ { 0x5513, 0x1043, 0x1107 }, /* ASUS A6K */
+ { 0x5513, 0x1734, 0x105f }, /* FSC Amilo A1630 */
+ { 0x5513, 0x1071, 0x8640 }, /* EasyNote K5305 */
+ /* end marker */
+ { 0, }
+};
+
+static u8 sis_cable_detect(ide_hwif_t *hwif)
+{
+ struct pci_dev *pdev = to_pci_dev(hwif->dev);
+ const struct sis_laptop *lap = &sis_laptop[0];
+ u8 ata66 = 0;
+
+ while (lap->device) {
+ if (lap->device == pdev->device &&
+ lap->subvendor == pdev->subsystem_vendor &&
+ lap->subdevice == pdev->subsystem_device)
+ return ATA_CBL_PATA40_SHORT;
+ lap++;
+ }
+
+ if (chipset_family >= ATA_133) {
+ u16 regw = 0;
+ u16 reg_addr = hwif->channel ? 0x52: 0x50;
+ pci_read_config_word(pdev, reg_addr, &regw);
+ ata66 = (regw & 0x8000) ? 0 : 1;
+ } else if (chipset_family >= ATA_66) {
+ u8 reg48h = 0;
+ u8 mask = hwif->channel ? 0x20 : 0x10;
+ pci_read_config_byte(pdev, 0x48, &reg48h);
+ ata66 = (reg48h & mask) ? 0 : 1;
+ }
+
+ return ata66 ? ATA_CBL_PATA80 : ATA_CBL_PATA40;
+}
+
+static const struct ide_port_ops sis_port_ops = {
+ .set_pio_mode = sis_set_pio_mode,
+ .set_dma_mode = sis_set_dma_mode,
+ .cable_detect = sis_cable_detect,
+};
+
+static const struct ide_port_ops sis_ata133_port_ops = {
+ .set_pio_mode = sis_set_pio_mode,
+ .set_dma_mode = sis_set_dma_mode,
+ .udma_filter = sis_ata133_udma_filter,
+ .cable_detect = sis_cable_detect,
+};
+
+static const struct ide_port_info sis5513_chipset __devinitdata = {
+ .name = DRV_NAME,
+ .init_chipset = init_chipset_sis5513,
+ .enablebits = { {0x4a, 0x02, 0x02}, {0x4a, 0x04, 0x04} },
+ .host_flags = IDE_HFLAG_LEGACY_IRQS | IDE_HFLAG_NO_AUTODMA,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+};
+
+static int __devinit sis5513_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ struct ide_port_info d = sis5513_chipset;
+ u8 udma_rates[] = { 0x00, 0x00, 0x07, 0x1f, 0x3f, 0x3f, 0x7f, 0x7f };
+ int rc;
+
+ rc = pci_enable_device(dev);
+ if (rc)
+ return rc;
+
+ if (sis_find_family(dev) == 0)
+ return -ENOTSUPP;
+
+ if (chipset_family >= ATA_133)
+ d.port_ops = &sis_ata133_port_ops;
+ else
+ d.port_ops = &sis_port_ops;
+
+ d.udma_mask = udma_rates[chipset_family];
+
+ return ide_pci_init_one(dev, &d, NULL);
+}
+
+static void __devexit sis5513_remove(struct pci_dev *dev)
+{
+ ide_pci_remove(dev);
+ pci_disable_device(dev);
+}
+
+static const struct pci_device_id sis5513_pci_tbl[] = {
+ { PCI_VDEVICE(SI, PCI_DEVICE_ID_SI_5513), 0 },
+ { PCI_VDEVICE(SI, PCI_DEVICE_ID_SI_5518), 0 },
+ { PCI_VDEVICE(SI, PCI_DEVICE_ID_SI_1180), 0 },
+ { 0, },
+};
+MODULE_DEVICE_TABLE(pci, sis5513_pci_tbl);
+
+static struct pci_driver sis5513_pci_driver = {
+ .name = "SIS_IDE",
+ .id_table = sis5513_pci_tbl,
+ .probe = sis5513_init_one,
+ .remove = __devexit_p(sis5513_remove),
+ .suspend = ide_pci_suspend,
+ .resume = ide_pci_resume,
+};
+
+static int __init sis5513_ide_init(void)
+{
+ return ide_pci_register_driver(&sis5513_pci_driver);
+}
+
+static void __exit sis5513_ide_exit(void)
+{
+ pci_unregister_driver(&sis5513_pci_driver);
+}
+
+module_init(sis5513_ide_init);
+module_exit(sis5513_ide_exit);
+
+MODULE_AUTHOR("Lionel Bouton, L C Chang, Andre Hedrick, Vojtech Pavlik");
+MODULE_DESCRIPTION("PCI driver module for SIS IDE");
+MODULE_LICENSE("GPL");
+
+/*
+ * TODO:
+ * - CLEANUP
+ * - More checks in the config registers (force values instead of
+ * relying on the BIOS setting them correctly).
+ * - Further optimisations ?
+ * . for example ATA66+ regs 0x48 & 0x4A
+ */
diff --git a/drivers/ide/sl82c105.c b/drivers/ide/sl82c105.c
new file mode 100644
index 0000000..84dc336
--- /dev/null
+++ b/drivers/ide/sl82c105.c
@@ -0,0 +1,371 @@
+/*
+ * SL82C105/Winbond 553 IDE driver
+ *
+ * Maintainer unknown.
+ *
+ * Drive tuning added from Rebel.com's kernel sources
+ * -- Russell King (15/11/98) linux@arm.linux.org.uk
+ *
+ * Merge in Russell's HW workarounds, fix various problems
+ * with the timing registers setup.
+ * -- Benjamin Herrenschmidt (01/11/03) benh@kernel.crashing.org
+ *
+ * Copyright (C) 2006-2007 MontaVista Software, Inc. <source@mvista.com>
+ * Copyright (C) 2007 Bartlomiej Zolnierkiewicz
+ */
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+
+#define DRV_NAME "sl82c105"
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(arg) printk arg
+#else
+#define DBG(fmt,...)
+#endif
+/*
+ * SL82C105 PCI config register 0x40 bits.
+ */
+#define CTRL_IDE_IRQB (1 << 30)
+#define CTRL_IDE_IRQA (1 << 28)
+#define CTRL_LEGIRQ (1 << 11)
+#define CTRL_P1F16 (1 << 5)
+#define CTRL_P1EN (1 << 4)
+#define CTRL_P0F16 (1 << 1)
+#define CTRL_P0EN (1 << 0)
+
+/*
+ * Convert a PIO mode and cycle time to the required on/off times
+ * for the interface. This has protection against runaway timings.
+ */
+static unsigned int get_pio_timings(ide_drive_t *drive, u8 pio)
+{
+ struct ide_timing *t = ide_timing_find_mode(XFER_PIO_0 + pio);
+ unsigned int cmd_on, cmd_off;
+ u8 iordy = 0;
+
+ cmd_on = (t->active + 29) / 30;
+ cmd_off = (ide_pio_cycle_time(drive, pio) - 30 * cmd_on + 29) / 30;
+
+ if (cmd_on == 0)
+ cmd_on = 1;
+
+ if (cmd_off == 0)
+ cmd_off = 1;
+
+ if (pio > 2 || ata_id_has_iordy(drive->id))
+ iordy = 0x40;
+
+ return (cmd_on - 1) << 8 | (cmd_off - 1) | iordy;
+}
+
+/*
+ * Configure the chipset for PIO mode.
+ */
+static void sl82c105_set_pio_mode(ide_drive_t *drive, const u8 pio)
+{
+ struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
+ int reg = 0x44 + drive->dn * 4;
+ u16 drv_ctrl;
+
+ drv_ctrl = get_pio_timings(drive, pio);
+
+ /*
+ * Store the PIO timings so that we can restore them
+ * in case DMA will be turned off...
+ */
+ drive->drive_data &= 0xffff0000;
+ drive->drive_data |= drv_ctrl;
+
+ pci_write_config_word(dev, reg, drv_ctrl);
+ pci_read_config_word (dev, reg, &drv_ctrl);
+
+ printk(KERN_DEBUG "%s: selected %s (%dns) (%04X)\n", drive->name,
+ ide_xfer_verbose(pio + XFER_PIO_0),
+ ide_pio_cycle_time(drive, pio), drv_ctrl);
+}
+
+/*
+ * Configure the chipset for DMA mode.
+ */
+static void sl82c105_set_dma_mode(ide_drive_t *drive, const u8 speed)
+{
+ static u16 mwdma_timings[] = {0x0707, 0x0201, 0x0200};
+ u16 drv_ctrl;
+
+ DBG(("sl82c105_tune_chipset(drive:%s, speed:%s)\n",
+ drive->name, ide_xfer_verbose(speed)));
+
+ drv_ctrl = mwdma_timings[speed - XFER_MW_DMA_0];
+
+ /*
+ * Store the DMA timings so that we can actually program
+ * them when DMA will be turned on...
+ */
+ drive->drive_data &= 0x0000ffff;
+ drive->drive_data |= (unsigned long)drv_ctrl << 16;
+}
+
+/*
+ * The SL82C105 holds off all IDE interrupts while in DMA mode until
+ * all DMA activity is completed. Sometimes this causes problems (eg,
+ * when the drive wants to report an error condition).
+ *
+ * 0x7e is a "chip testing" register. Bit 2 resets the DMA controller
+ * state machine. We need to kick this to work around various bugs.
+ */
+static inline void sl82c105_reset_host(struct pci_dev *dev)
+{
+ u16 val;
+
+ pci_read_config_word(dev, 0x7e, &val);
+ pci_write_config_word(dev, 0x7e, val | (1 << 2));
+ pci_write_config_word(dev, 0x7e, val & ~(1 << 2));
+}
+
+/*
+ * If we get an IRQ timeout, it might be that the DMA state machine
+ * got confused. Fix from Todd Inglett. Details from Winbond.
+ *
+ * This function is called when the IDE timer expires, the drive
+ * indicates that it is READY, and we were waiting for DMA to complete.
+ */
+static void sl82c105_dma_lost_irq(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+ u32 val, mask = hwif->channel ? CTRL_IDE_IRQB : CTRL_IDE_IRQA;
+ u8 dma_cmd;
+
+ printk("sl82c105: lost IRQ, resetting host\n");
+
+ /*
+ * Check the raw interrupt from the drive.
+ */
+ pci_read_config_dword(dev, 0x40, &val);
+ if (val & mask)
+ printk("sl82c105: drive was requesting IRQ, but host lost it\n");
+
+ /*
+ * Was DMA enabled? If so, disable it - we're resetting the
+ * host. The IDE layer will be handling the drive for us.
+ */
+ dma_cmd = inb(hwif->dma_base + ATA_DMA_CMD);
+ if (dma_cmd & 1) {
+ outb(dma_cmd & ~1, hwif->dma_base + ATA_DMA_CMD);
+ printk("sl82c105: DMA was enabled\n");
+ }
+
+ sl82c105_reset_host(dev);
+}
+
+/*
+ * ATAPI devices can cause the SL82C105 DMA state machine to go gaga.
+ * Winbond recommend that the DMA state machine is reset prior to
+ * setting the bus master DMA enable bit.
+ *
+ * The generic IDE core will have disabled the BMEN bit before this
+ * function is called.
+ */
+static void sl82c105_dma_start(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+ int reg = 0x44 + drive->dn * 4;
+
+ DBG(("%s(drive:%s)\n", __func__, drive->name));
+
+ pci_write_config_word(dev, reg, drive->drive_data >> 16);
+
+ sl82c105_reset_host(dev);
+ ide_dma_start(drive);
+}
+
+static void sl82c105_dma_timeout(ide_drive_t *drive)
+{
+ struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
+
+ DBG(("sl82c105_dma_timeout(drive:%s)\n", drive->name));
+
+ sl82c105_reset_host(dev);
+ ide_dma_timeout(drive);
+}
+
+static int sl82c105_dma_end(ide_drive_t *drive)
+{
+ struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
+ int reg = 0x44 + drive->dn * 4;
+ int ret;
+
+ DBG(("%s(drive:%s)\n", __func__, drive->name));
+
+ ret = ide_dma_end(drive);
+
+ pci_write_config_word(dev, reg, drive->drive_data);
+
+ return ret;
+}
+
+/*
+ * ATA reset will clear the 16 bits mode in the control
+ * register, we need to reprogram it
+ */
+static void sl82c105_resetproc(ide_drive_t *drive)
+{
+ struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
+ u32 val;
+
+ DBG(("sl82c105_resetproc(drive:%s)\n", drive->name));
+
+ pci_read_config_dword(dev, 0x40, &val);
+ val |= (CTRL_P1F16 | CTRL_P0F16);
+ pci_write_config_dword(dev, 0x40, val);
+}
+
+/*
+ * Return the revision of the Winbond bridge
+ * which this function is part of.
+ */
+static u8 sl82c105_bridge_revision(struct pci_dev *dev)
+{
+ struct pci_dev *bridge;
+
+ /*
+ * The bridge should be part of the same device, but function 0.
+ */
+ bridge = pci_get_bus_and_slot(dev->bus->number,
+ PCI_DEVFN(PCI_SLOT(dev->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_dev_put(bridge);
+
+ return bridge->revision;
+}
+
+/*
+ * Enable the PCI device
+ *
+ * --BenH: It's arch fixup code that should enable channels that
+ * have not been enabled by firmware. I decided we can still enable
+ * channel 0 here at least, but channel 1 has to be enabled by
+ * firmware or arch code. We still set both to 16 bits mode.
+ */
+static unsigned int init_chipset_sl82c105(struct pci_dev *dev)
+{
+ u32 val;
+
+ DBG(("init_chipset_sl82c105()\n"));
+
+ pci_read_config_dword(dev, 0x40, &val);
+ val |= CTRL_P0EN | CTRL_P0F16 | CTRL_P1F16;
+ pci_write_config_dword(dev, 0x40, val);
+
+ return dev->irq;
+}
+
+static const struct ide_port_ops sl82c105_port_ops = {
+ .set_pio_mode = sl82c105_set_pio_mode,
+ .set_dma_mode = sl82c105_set_dma_mode,
+ .resetproc = sl82c105_resetproc,
+};
+
+static const struct ide_dma_ops sl82c105_dma_ops = {
+ .dma_host_set = ide_dma_host_set,
+ .dma_setup = ide_dma_setup,
+ .dma_exec_cmd = ide_dma_exec_cmd,
+ .dma_start = sl82c105_dma_start,
+ .dma_end = sl82c105_dma_end,
+ .dma_test_irq = ide_dma_test_irq,
+ .dma_lost_irq = sl82c105_dma_lost_irq,
+ .dma_timeout = sl82c105_dma_timeout,
+};
+
+static const struct ide_port_info sl82c105_chipset __devinitdata = {
+ .name = DRV_NAME,
+ .init_chipset = init_chipset_sl82c105,
+ .enablebits = {{0x40,0x01,0x01}, {0x40,0x10,0x10}},
+ .port_ops = &sl82c105_port_ops,
+ .dma_ops = &sl82c105_dma_ops,
+ .host_flags = IDE_HFLAG_IO_32BIT |
+ IDE_HFLAG_UNMASK_IRQS |
+/* FIXME: check for Compatibility mode in generic IDE PCI code */
+#if defined(CONFIG_LOPEC) || defined(CONFIG_SANDPOINT)
+ IDE_HFLAG_FORCE_LEGACY_IRQS |
+#endif
+ IDE_HFLAG_SERIALIZE_DMA |
+ IDE_HFLAG_NO_AUTODMA,
+ .pio_mask = ATA_PIO5,
+ .mwdma_mask = ATA_MWDMA2,
+};
+
+static int __devinit sl82c105_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ struct ide_port_info d = sl82c105_chipset;
+ u8 rev = sl82c105_bridge_revision(dev);
+
+ if (rev <= 5) {
+ /*
+ * Never ever EVER under any circumstances enable
+ * DMA when the bridge is this old.
+ */
+ printk(KERN_INFO DRV_NAME ": Winbond W83C553 bridge "
+ "revision %d, BM-DMA disabled\n", rev);
+ d.dma_ops = NULL;
+ d.mwdma_mask = 0;
+ d.host_flags &= ~IDE_HFLAG_SERIALIZE_DMA;
+ }
+
+ return ide_pci_init_one(dev, &d, NULL);
+}
+
+static const struct pci_device_id sl82c105_pci_tbl[] = {
+ { PCI_VDEVICE(WINBOND, PCI_DEVICE_ID_WINBOND_82C105), 0 },
+ { 0, },
+};
+MODULE_DEVICE_TABLE(pci, sl82c105_pci_tbl);
+
+static struct pci_driver sl82c105_pci_driver = {
+ .name = "W82C105_IDE",
+ .id_table = sl82c105_pci_tbl,
+ .probe = sl82c105_init_one,
+ .remove = ide_pci_remove,
+ .suspend = ide_pci_suspend,
+ .resume = ide_pci_resume,
+};
+
+static int __init sl82c105_ide_init(void)
+{
+ return ide_pci_register_driver(&sl82c105_pci_driver);
+}
+
+static void __exit sl82c105_ide_exit(void)
+{
+ pci_unregister_driver(&sl82c105_pci_driver);
+}
+
+module_init(sl82c105_ide_init);
+module_exit(sl82c105_ide_exit);
+
+MODULE_DESCRIPTION("PCI driver module for W82C105 IDE");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/slc90e66.c b/drivers/ide/slc90e66.c
new file mode 100644
index 0000000..0f759e4
--- /dev/null
+++ b/drivers/ide/slc90e66.c
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2000-2002 Andre Hedrick <andre@linux-ide.org>
+ * Copyright (C) 2006-2007 MontaVista Software, Inc. <source@mvista.com>
+ *
+ * This is a look-alike variation of the ICH0 PIIX4 Ultra-66,
+ * but this keeps the ISA-Bridge and slots alive.
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#define DRV_NAME "slc90e66"
+
+static DEFINE_SPINLOCK(slc90e66_lock);
+
+static void slc90e66_set_pio_mode(ide_drive_t *drive, const u8 pio)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+ int is_slave = drive->dn & 1;
+ int master_port = hwif->channel ? 0x42 : 0x40;
+ int slave_port = 0x44;
+ unsigned long flags;
+ u16 master_data;
+ u8 slave_data;
+ int control = 0;
+ /* ISP RTC */
+ static const u8 timings[][2] = {
+ { 0, 0 },
+ { 0, 0 },
+ { 1, 0 },
+ { 2, 1 },
+ { 2, 3 }, };
+
+ spin_lock_irqsave(&slc90e66_lock, flags);
+ pci_read_config_word(dev, master_port, &master_data);
+
+ if (pio > 1)
+ control |= 1; /* Programmable timing on */
+ if (drive->media == ide_disk)
+ control |= 4; /* Prefetch, post write */
+ if (pio > 2)
+ control |= 2; /* IORDY */
+ if (is_slave) {
+ master_data |= 0x4000;
+ master_data &= ~0x0070;
+ if (pio > 1) {
+ /* Set PPE, IE and TIME */
+ master_data |= control << 4;
+ }
+ pci_read_config_byte(dev, slave_port, &slave_data);
+ slave_data &= hwif->channel ? 0x0f : 0xf0;
+ slave_data |= ((timings[pio][0] << 2) | timings[pio][1]) <<
+ (hwif->channel ? 4 : 0);
+ } else {
+ master_data &= ~0x3307;
+ if (pio > 1) {
+ /* enable PPE, IE and TIME */
+ master_data |= control;
+ }
+ master_data |= (timings[pio][0] << 12) | (timings[pio][1] << 8);
+ }
+ pci_write_config_word(dev, master_port, master_data);
+ if (is_slave)
+ pci_write_config_byte(dev, slave_port, slave_data);
+ spin_unlock_irqrestore(&slc90e66_lock, flags);
+}
+
+static void slc90e66_set_dma_mode(ide_drive_t *drive, const u8 speed)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+ u8 maslave = hwif->channel ? 0x42 : 0x40;
+ int sitre = 0, a_speed = 7 << (drive->dn * 4);
+ int u_speed = 0, u_flag = 1 << drive->dn;
+ u16 reg4042, reg44, reg48, reg4a;
+
+ pci_read_config_word(dev, maslave, &reg4042);
+ sitre = (reg4042 & 0x4000) ? 1 : 0;
+ pci_read_config_word(dev, 0x44, &reg44);
+ pci_read_config_word(dev, 0x48, &reg48);
+ pci_read_config_word(dev, 0x4a, &reg4a);
+
+ if (speed >= XFER_UDMA_0) {
+ u_speed = (speed - XFER_UDMA_0) << (drive->dn * 4);
+
+ if (!(reg48 & u_flag))
+ pci_write_config_word(dev, 0x48, reg48|u_flag);
+ /* FIXME: (reg4a & a_speed) ? */
+ if ((reg4a & u_speed) != u_speed) {
+ pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
+ pci_read_config_word(dev, 0x4a, &reg4a);
+ pci_write_config_word(dev, 0x4a, reg4a|u_speed);
+ }
+ } else {
+ const u8 mwdma_to_pio[] = { 0, 3, 4 };
+ u8 pio;
+
+ if (reg48 & u_flag)
+ pci_write_config_word(dev, 0x48, reg48 & ~u_flag);
+ if (reg4a & a_speed)
+ pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
+
+ if (speed >= XFER_MW_DMA_0)
+ pio = mwdma_to_pio[speed - XFER_MW_DMA_0];
+ else
+ pio = 2; /* only SWDMA2 is allowed */
+
+ slc90e66_set_pio_mode(drive, pio);
+ }
+}
+
+static u8 slc90e66_cable_detect(ide_hwif_t *hwif)
+{
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+ u8 reg47 = 0, mask = hwif->channel ? 0x01 : 0x02;
+
+ pci_read_config_byte(dev, 0x47, &reg47);
+
+ /* bit[0(1)]: 0:80, 1:40 */
+ return (reg47 & mask) ? ATA_CBL_PATA40 : ATA_CBL_PATA80;
+}
+
+static const struct ide_port_ops slc90e66_port_ops = {
+ .set_pio_mode = slc90e66_set_pio_mode,
+ .set_dma_mode = slc90e66_set_dma_mode,
+ .cable_detect = slc90e66_cable_detect,
+};
+
+static const struct ide_port_info slc90e66_chipset __devinitdata = {
+ .name = DRV_NAME,
+ .enablebits = { {0x41, 0x80, 0x80}, {0x43, 0x80, 0x80} },
+ .port_ops = &slc90e66_port_ops,
+ .host_flags = IDE_HFLAG_LEGACY_IRQS,
+ .pio_mask = ATA_PIO4,
+ .swdma_mask = ATA_SWDMA2_ONLY,
+ .mwdma_mask = ATA_MWDMA12_ONLY,
+ .udma_mask = ATA_UDMA4,
+};
+
+static int __devinit slc90e66_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ return ide_pci_init_one(dev, &slc90e66_chipset, NULL);
+}
+
+static const struct pci_device_id slc90e66_pci_tbl[] = {
+ { PCI_VDEVICE(EFAR, PCI_DEVICE_ID_EFAR_SLC90E66_1), 0 },
+ { 0, },
+};
+MODULE_DEVICE_TABLE(pci, slc90e66_pci_tbl);
+
+static struct pci_driver slc90e66_pci_driver = {
+ .name = "SLC90e66_IDE",
+ .id_table = slc90e66_pci_tbl,
+ .probe = slc90e66_init_one,
+ .remove = ide_pci_remove,
+ .suspend = ide_pci_suspend,
+ .resume = ide_pci_resume,
+};
+
+static int __init slc90e66_ide_init(void)
+{
+ return ide_pci_register_driver(&slc90e66_pci_driver);
+}
+
+static void __exit slc90e66_ide_exit(void)
+{
+ pci_unregister_driver(&slc90e66_pci_driver);
+}
+
+module_init(slc90e66_ide_init);
+module_exit(slc90e66_ide_exit);
+
+MODULE_AUTHOR("Andre Hedrick");
+MODULE_DESCRIPTION("PCI driver module for SLC90E66 IDE");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/tc86c001.c b/drivers/ide/tc86c001.c
new file mode 100644
index 0000000..93e2cce
--- /dev/null
+++ b/drivers/ide/tc86c001.c
@@ -0,0 +1,270 @@
+/*
+ * Copyright (C) 2002 Toshiba Corporation
+ * Copyright (C) 2005-2006 MontaVista Software, Inc. <source@mvista.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#define DRV_NAME "tc86c001"
+
+static void tc86c001_set_mode(ide_drive_t *drive, const u8 speed)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ unsigned long scr_port = hwif->config_data + (drive->dn ? 0x02 : 0x00);
+ u16 mode, scr = inw(scr_port);
+
+ switch (speed) {
+ case XFER_UDMA_4: mode = 0x00c0; break;
+ case XFER_UDMA_3: mode = 0x00b0; break;
+ case XFER_UDMA_2: mode = 0x00a0; break;
+ case XFER_UDMA_1: mode = 0x0090; break;
+ case XFER_UDMA_0: mode = 0x0080; break;
+ case XFER_MW_DMA_2: mode = 0x0070; break;
+ case XFER_MW_DMA_1: mode = 0x0060; break;
+ case XFER_MW_DMA_0: mode = 0x0050; break;
+ case XFER_PIO_4: mode = 0x0400; break;
+ case XFER_PIO_3: mode = 0x0300; break;
+ case XFER_PIO_2: mode = 0x0200; break;
+ case XFER_PIO_1: mode = 0x0100; break;
+ case XFER_PIO_0:
+ default: mode = 0x0000; break;
+ }
+
+ scr &= (speed < XFER_MW_DMA_0) ? 0xf8ff : 0xff0f;
+ scr |= mode;
+ outw(scr, scr_port);
+}
+
+static void tc86c001_set_pio_mode(ide_drive_t *drive, const u8 pio)
+{
+ tc86c001_set_mode(drive, XFER_PIO_0 + pio);
+}
+
+/*
+ * HACKITY HACK
+ *
+ * This is a workaround for the limitation 5 of the TC86C001 IDE controller:
+ * if a DMA transfer terminates prematurely, the controller leaves the device's
+ * interrupt request (INTRQ) pending and does not generate a PCI interrupt (or
+ * set the interrupt bit in the DMA status register), thus no PCI interrupt
+ * will occur until a DMA transfer has been successfully completed.
+ *
+ * We work around this by initiating dummy, zero-length DMA transfer on
+ * a DMA timeout expiration. I found no better way to do this with the current
+ * IDE core than to temporarily replace a higher level driver's timer expiry
+ * handler with our own backing up to that handler in case our recovery fails.
+ */
+static int tc86c001_timer_expiry(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ ide_expiry_t *expiry = ide_get_hwifdata(hwif);
+ ide_hwgroup_t *hwgroup = HWGROUP(drive);
+ u8 dma_stat = inb(hwif->dma_base + ATA_DMA_STATUS);
+
+ /* Restore a higher level driver's expiry handler first. */
+ hwgroup->expiry = expiry;
+
+ if ((dma_stat & 5) == 1) { /* DMA active and no interrupt */
+ unsigned long sc_base = hwif->config_data;
+ unsigned long twcr_port = sc_base + (drive->dn ? 0x06 : 0x04);
+ u8 dma_cmd = inb(hwif->dma_base + ATA_DMA_CMD);
+
+ printk(KERN_WARNING "%s: DMA interrupt possibly stuck, "
+ "attempting recovery...\n", drive->name);
+
+ /* Stop DMA */
+ outb(dma_cmd & ~0x01, hwif->dma_base + ATA_DMA_CMD);
+
+ /* Setup the dummy DMA transfer */
+ outw(0, sc_base + 0x0a); /* Sector Count */
+ outw(0, twcr_port); /* Transfer Word Count 1 or 2 */
+
+ /* Start the dummy DMA transfer */
+
+ /* clear R_OR_WCTR for write */
+ outb(0x00, hwif->dma_base + ATA_DMA_CMD);
+ /* set START_STOPBM */
+ outb(0x01, hwif->dma_base + ATA_DMA_CMD);
+
+ /*
+ * If an interrupt was pending, it should come thru shortly.
+ * If not, a higher level driver's expiry handler should
+ * eventually cause some kind of recovery from the DMA stall.
+ */
+ return WAIT_MIN_SLEEP;
+ }
+
+ /* Chain to the restored expiry handler if DMA wasn't active. */
+ if (likely(expiry != NULL))
+ return expiry(drive);
+
+ /* If there was no handler, "emulate" that for ide_timer_expiry()... */
+ return -1;
+}
+
+static void tc86c001_dma_start(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ ide_hwgroup_t *hwgroup = HWGROUP(drive);
+ unsigned long sc_base = hwif->config_data;
+ unsigned long twcr_port = sc_base + (drive->dn ? 0x06 : 0x04);
+ unsigned long nsectors = hwgroup->rq->nr_sectors;
+
+ /*
+ * We have to manually load the sector count and size into
+ * the appropriate system control registers for DMA to work
+ * with LBA48 and ATAPI devices...
+ */
+ outw(nsectors, sc_base + 0x0a); /* Sector Count */
+ outw(SECTOR_SIZE / 2, twcr_port); /* Transfer Word Count 1/2 */
+
+ /* Install our timeout expiry hook, saving the current handler... */
+ ide_set_hwifdata(hwif, hwgroup->expiry);
+ hwgroup->expiry = &tc86c001_timer_expiry;
+
+ ide_dma_start(drive);
+}
+
+static u8 tc86c001_cable_detect(ide_hwif_t *hwif)
+{
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+ unsigned long sc_base = pci_resource_start(dev, 5);
+ u16 scr1 = inw(sc_base + 0x00);
+
+ /*
+ * System Control 1 Register bit 13 (PDIAGN):
+ * 0=80-pin cable, 1=40-pin cable
+ */
+ return (scr1 & 0x2000) ? ATA_CBL_PATA40 : ATA_CBL_PATA80;
+}
+
+static void __devinit init_hwif_tc86c001(ide_hwif_t *hwif)
+{
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+ unsigned long sc_base = pci_resource_start(dev, 5);
+ u16 scr1 = inw(sc_base + 0x00);
+
+ /* System Control 1 Register bit 15 (Soft Reset) set */
+ outw(scr1 | 0x8000, sc_base + 0x00);
+
+ /* System Control 1 Register bit 14 (FIFO Reset) set */
+ outw(scr1 | 0x4000, sc_base + 0x00);
+
+ /* System Control 1 Register: reset clear */
+ outw(scr1 & ~0xc000, sc_base + 0x00);
+
+ /* Store the system control register base for convenience... */
+ hwif->config_data = sc_base;
+
+ if (!hwif->dma_base)
+ return;
+
+ /*
+ * Sector Count Control Register bits 0 and 1 set:
+ * software sets Sector Count Register for master and slave device
+ */
+ outw(0x0003, sc_base + 0x0c);
+
+ /* Sector Count Register limit */
+ hwif->rqsize = 0xffff;
+}
+
+static const struct ide_port_ops tc86c001_port_ops = {
+ .set_pio_mode = tc86c001_set_pio_mode,
+ .set_dma_mode = tc86c001_set_mode,
+ .cable_detect = tc86c001_cable_detect,
+};
+
+static const struct ide_dma_ops tc86c001_dma_ops = {
+ .dma_host_set = ide_dma_host_set,
+ .dma_setup = ide_dma_setup,
+ .dma_exec_cmd = ide_dma_exec_cmd,
+ .dma_start = tc86c001_dma_start,
+ .dma_end = ide_dma_end,
+ .dma_test_irq = ide_dma_test_irq,
+ .dma_lost_irq = ide_dma_lost_irq,
+ .dma_timeout = ide_dma_timeout,
+};
+
+static const struct ide_port_info tc86c001_chipset __devinitdata = {
+ .name = DRV_NAME,
+ .init_hwif = init_hwif_tc86c001,
+ .port_ops = &tc86c001_port_ops,
+ .dma_ops = &tc86c001_dma_ops,
+ .host_flags = IDE_HFLAG_SINGLE | IDE_HFLAG_OFF_BOARD,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA4,
+};
+
+static int __devinit tc86c001_init_one(struct pci_dev *dev,
+ const struct pci_device_id *id)
+{
+ int rc;
+
+ rc = pci_enable_device(dev);
+ if (rc)
+ goto out;
+
+ rc = pci_request_region(dev, 5, DRV_NAME);
+ if (rc) {
+ printk(KERN_ERR DRV_NAME ": system control regs already in use");
+ goto out_disable;
+ }
+
+ rc = ide_pci_init_one(dev, &tc86c001_chipset, NULL);
+ if (rc)
+ goto out_release;
+
+ goto out;
+
+out_release:
+ pci_release_region(dev, 5);
+out_disable:
+ pci_disable_device(dev);
+out:
+ return rc;
+}
+
+static void __devexit tc86c001_remove(struct pci_dev *dev)
+{
+ ide_pci_remove(dev);
+ pci_release_region(dev, 5);
+ pci_disable_device(dev);
+}
+
+static const struct pci_device_id tc86c001_pci_tbl[] = {
+ { PCI_VDEVICE(TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC86C001_IDE), 0 },
+ { 0, }
+};
+MODULE_DEVICE_TABLE(pci, tc86c001_pci_tbl);
+
+static struct pci_driver tc86c001_pci_driver = {
+ .name = "TC86C001",
+ .id_table = tc86c001_pci_tbl,
+ .probe = tc86c001_init_one,
+ .remove = __devexit_p(tc86c001_remove),
+};
+
+static int __init tc86c001_ide_init(void)
+{
+ return ide_pci_register_driver(&tc86c001_pci_driver);
+}
+
+static void __exit tc86c001_ide_exit(void)
+{
+ pci_unregister_driver(&tc86c001_pci_driver);
+}
+
+module_init(tc86c001_ide_init);
+module_exit(tc86c001_ide_exit);
+
+MODULE_AUTHOR("MontaVista Software, Inc. <source@mvista.com>");
+MODULE_DESCRIPTION("PCI driver module for TC86C001 IDE");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/triflex.c b/drivers/ide/triflex.c
new file mode 100644
index 0000000..b6ff403
--- /dev/null
+++ b/drivers/ide/triflex.c
@@ -0,0 +1,142 @@
+/*
+ * 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/types.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#define DRV_NAME "triflex"
+
+static void triflex_set_mode(ide_drive_t *drive, const u8 speed)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+ u32 triflex_timings = 0;
+ u16 timing = 0;
+ u8 channel_offset = hwif->channel ? 0x74 : 0x70, unit = drive->dn & 1;
+
+ pci_read_config_dword(dev, channel_offset, &triflex_timings);
+
+ 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;
+ }
+
+ triflex_timings &= ~(0xFFFF << (16 * unit));
+ triflex_timings |= (timing << (16 * unit));
+
+ pci_write_config_dword(dev, channel_offset, triflex_timings);
+}
+
+static void triflex_set_pio_mode(ide_drive_t *drive, const u8 pio)
+{
+ triflex_set_mode(drive, XFER_PIO_0 + pio);
+}
+
+static const struct ide_port_ops triflex_port_ops = {
+ .set_pio_mode = triflex_set_pio_mode,
+ .set_dma_mode = triflex_set_mode,
+};
+
+static const struct ide_port_info triflex_device __devinitdata = {
+ .name = DRV_NAME,
+ .enablebits = {{0x80, 0x01, 0x01}, {0x80, 0x02, 0x02}},
+ .port_ops = &triflex_port_ops,
+ .pio_mask = ATA_PIO4,
+ .swdma_mask = ATA_SWDMA2,
+ .mwdma_mask = ATA_MWDMA2,
+};
+
+static int __devinit triflex_init_one(struct pci_dev *dev,
+ const struct pci_device_id *id)
+{
+ return ide_pci_init_one(dev, &triflex_device, NULL);
+}
+
+static const struct pci_device_id triflex_pci_tbl[] = {
+ { PCI_VDEVICE(COMPAQ, PCI_DEVICE_ID_COMPAQ_TRIFLEX_IDE), 0 },
+ { 0, },
+};
+MODULE_DEVICE_TABLE(pci, triflex_pci_tbl);
+
+static struct pci_driver triflex_pci_driver = {
+ .name = "TRIFLEX_IDE",
+ .id_table = triflex_pci_tbl,
+ .probe = triflex_init_one,
+ .remove = ide_pci_remove,
+ .suspend = ide_pci_suspend,
+ .resume = ide_pci_resume,
+};
+
+static int __init triflex_ide_init(void)
+{
+ return ide_pci_register_driver(&triflex_pci_driver);
+}
+
+static void __exit triflex_ide_exit(void)
+{
+ pci_unregister_driver(&triflex_pci_driver);
+}
+
+module_init(triflex_ide_init);
+module_exit(triflex_ide_exit);
+
+MODULE_AUTHOR("Torben Mathiasen");
+MODULE_DESCRIPTION("PCI driver module for Compaq Triflex IDE");
+MODULE_LICENSE("GPL");
+
+
diff --git a/drivers/ide/trm290.c b/drivers/ide/trm290.c
new file mode 100644
index 0000000..75ea615
--- /dev/null
+++ b/drivers/ide/trm290.c
@@ -0,0 +1,375 @@
+/*
+ * Copyright (c) 1997-1998 Mark Lord
+ * Copyright (c) 2007 MontaVista Software, Inc. <source@mvista.com>
+ *
+ * May be copied or modified under the terms of the GNU General Public License
+ *
+ * June 22, 2004 - get rid of check_region
+ * - Jesper Juhl
+ *
+ */
+
+/*
+ * This module provides support for the bus-master IDE DMA function
+ * of the Tekram TRM290 chip, used on a variety of PCI IDE add-on boards,
+ * including a "Precision Instruments" board. The TRM290 pre-dates
+ * the sff-8038 standard (ide-dma.c) by a few months, and differs
+ * significantly enough to warrant separate routines for some functions,
+ * while re-using others from ide-dma.c.
+ *
+ * EXPERIMENTAL! It works for me (a sample of one).
+ *
+ * Works reliably for me in DMA mode (READs only),
+ * DMA WRITEs are disabled by default (see #define below);
+ *
+ * DMA is not enabled automatically for this chipset,
+ * but can be turned on manually (with "hdparm -d1") at run time.
+ *
+ * I need volunteers with "spare" drives for further testing
+ * and development, and maybe to help figure out the peculiarities.
+ * Even knowing the registers (below), some things behave strangely.
+ */
+
+#define TRM290_NO_DMA_WRITES /* DMA writes seem unreliable sometimes */
+
+/*
+ * TRM-290 PCI-IDE2 Bus Master Chip
+ * ================================
+ * The configuration registers are addressed in normal I/O port space
+ * and are used as follows:
+ *
+ * trm290_base depends on jumper settings, and is probed for by ide-dma.c
+ *
+ * trm290_base+2 when WRITTEN: chiptest register (byte, write-only)
+ * bit7 must always be written as "1"
+ * bits6-2 undefined
+ * bit1 1=legacy_compatible_mode, 0=native_pci_mode
+ * bit0 1=test_mode, 0=normal(default)
+ *
+ * trm290_base+2 when READ: status register (byte, read-only)
+ * bits7-2 undefined
+ * bit1 channel0 busmaster interrupt status 0=none, 1=asserted
+ * bit0 channel0 interrupt status 0=none, 1=asserted
+ *
+ * trm290_base+3 Interrupt mask register
+ * bits7-5 undefined
+ * bit4 legacy_header: 1=present, 0=absent
+ * bit3 channel1 busmaster interrupt status 0=none, 1=asserted (read only)
+ * bit2 channel1 interrupt status 0=none, 1=asserted (read only)
+ * bit1 channel1 interrupt mask: 1=masked, 0=unmasked(default)
+ * bit0 channel0 interrupt mask: 1=masked, 0=unmasked(default)
+ *
+ * trm290_base+1 "CPR" Config Pointer Register (byte)
+ * bit7 1=autoincrement CPR bits 2-0 after each access of CDR
+ * bit6 1=min. 1 wait-state posted write cycle (default), 0=0 wait-state
+ * bit5 0=enabled master burst access (default), 1=disable (write only)
+ * bit4 PCI DEVSEL# timing select: 1=medium(default), 0=fast
+ * bit3 0=primary IDE channel, 1=secondary IDE channel
+ * bits2-0 register index for accesses through CDR port
+ *
+ * trm290_base+0 "CDR" Config Data Register (word)
+ * two sets of seven config registers,
+ * selected by CPR bit 3 (channel) and CPR bits 2-0 (index 0 to 6),
+ * each index defined below:
+ *
+ * Index-0 Base address register for command block (word)
+ * defaults: 0x1f0 for primary, 0x170 for secondary
+ *
+ * Index-1 general config register (byte)
+ * bit7 1=DMA enable, 0=DMA disable
+ * bit6 1=activate IDE_RESET, 0=no action (default)
+ * bit5 1=enable IORDY, 0=disable IORDY (default)
+ * bit4 0=16-bit data port(default), 1=8-bit (XT) data port
+ * bit3 interrupt polarity: 1=active_low, 0=active_high(default)
+ * bit2 power-saving-mode(?): 1=enable, 0=disable(default) (write only)
+ * bit1 bus_master_mode(?): 1=enable, 0=disable(default)
+ * bit0 enable_io_ports: 1=enable(default), 0=disable
+ *
+ * Index-2 read-ahead counter preload bits 0-7 (byte, write only)
+ * bits7-0 bits7-0 of readahead count
+ *
+ * Index-3 read-ahead config register (byte, write only)
+ * bit7 1=enable_readahead, 0=disable_readahead(default)
+ * bit6 1=clear_FIFO, 0=no_action
+ * bit5 undefined
+ * bit4 mode4 timing control: 1=enable, 0=disable(default)
+ * bit3 undefined
+ * bit2 undefined
+ * bits1-0 bits9-8 of read-ahead count
+ *
+ * Index-4 base address register for control block (word)
+ * defaults: 0x3f6 for primary, 0x376 for secondary
+ *
+ * Index-5 data port timings (shared by both drives) (byte)
+ * standard PCI "clk" (clock) counts, default value = 0xf5
+ *
+ * bits7-6 setup time: 00=1clk, 01=2clk, 10=3clk, 11=4clk
+ * bits5-3 hold time: 000=1clk, 001=2clk, 010=3clk,
+ * 011=4clk, 100=5clk, 101=6clk,
+ * 110=8clk, 111=12clk
+ * bits2-0 active time: 000=2clk, 001=3clk, 010=4clk,
+ * 011=5clk, 100=6clk, 101=8clk,
+ * 110=12clk, 111=16clk
+ *
+ * Index-6 command/control port timings (shared by both drives) (byte)
+ * same layout as Index-5, default value = 0xde
+ *
+ * Suggested CDR programming for PIO mode0 (600ns):
+ * 0x01f0,0x21,0xff,0x80,0x03f6,0xf5,0xde ; primary
+ * 0x0170,0x21,0xff,0x80,0x0376,0xf5,0xde ; secondary
+ *
+ * Suggested CDR programming for PIO mode3 (180ns):
+ * 0x01f0,0x21,0xff,0x80,0x03f6,0x09,0xde ; primary
+ * 0x0170,0x21,0xff,0x80,0x0376,0x09,0xde ; secondary
+ *
+ * Suggested CDR programming for PIO mode4 (120ns):
+ * 0x01f0,0x21,0xff,0x80,0x03f6,0x00,0xde ; primary
+ * 0x0170,0x21,0xff,0x80,0x0376,0x00,0xde ; secondary
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+
+#define DRV_NAME "trm290"
+
+static void trm290_prepare_drive (ide_drive_t *drive, unsigned int use_dma)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ u16 reg = 0;
+ unsigned long flags;
+
+ /* select PIO or DMA */
+ reg = use_dma ? (0x21 | 0x82) : (0x21 & ~0x82);
+
+ local_irq_save(flags);
+
+ if (reg != hwif->select_data) {
+ hwif->select_data = reg;
+ /* set PIO/DMA */
+ outb(0x51 | (hwif->channel << 3), hwif->config_data + 1);
+ outw(reg & 0xff, hwif->config_data);
+ }
+
+ /* enable IRQ if not probing */
+ if (drive->dev_flags & IDE_DFLAG_PRESENT) {
+ reg = inw(hwif->config_data + 3);
+ reg &= 0x13;
+ reg &= ~(1 << hwif->channel);
+ outw(reg, hwif->config_data + 3);
+ }
+
+ local_irq_restore(flags);
+}
+
+static void trm290_selectproc (ide_drive_t *drive)
+{
+ trm290_prepare_drive(drive, !!(drive->dev_flags & IDE_DFLAG_USING_DMA));
+}
+
+static void trm290_dma_exec_cmd(ide_drive_t *drive, u8 command)
+{
+ ide_execute_command(drive, command, &ide_dma_intr, WAIT_CMD, NULL);
+}
+
+static int trm290_dma_setup(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ struct request *rq = hwif->hwgroup->rq;
+ unsigned int count, rw;
+
+ if (rq_data_dir(rq)) {
+#ifdef TRM290_NO_DMA_WRITES
+ /* always use PIO for writes */
+ trm290_prepare_drive(drive, 0); /* select PIO xfer */
+ return 1;
+#endif
+ rw = 1;
+ } else
+ rw = 2;
+
+ if (!(count = ide_build_dmatable(drive, rq))) {
+ /* try PIO instead of DMA */
+ trm290_prepare_drive(drive, 0); /* select PIO xfer */
+ return 1;
+ }
+ /* select DMA xfer */
+ trm290_prepare_drive(drive, 1);
+ outl(hwif->dmatable_dma | rw, hwif->dma_base);
+ drive->waiting_for_dma = 1;
+ /* start DMA */
+ outw(count * 2 - 1, hwif->dma_base + 2);
+ return 0;
+}
+
+static void trm290_dma_start(ide_drive_t *drive)
+{
+}
+
+static int trm290_dma_end(ide_drive_t *drive)
+{
+ u16 status;
+
+ drive->waiting_for_dma = 0;
+ /* purge DMA mappings */
+ ide_destroy_dmatable(drive);
+ status = inw(HWIF(drive)->dma_base + 2);
+ return status != 0x00ff;
+}
+
+static int trm290_dma_test_irq(ide_drive_t *drive)
+{
+ u16 status;
+
+ status = inw(HWIF(drive)->dma_base + 2);
+ return status == 0x00ff;
+}
+
+static void trm290_dma_host_set(ide_drive_t *drive, int on)
+{
+}
+
+static void __devinit init_hwif_trm290(ide_hwif_t *hwif)
+{
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+ unsigned int cfg_base = pci_resource_start(dev, 4);
+ unsigned long flags;
+ u8 reg = 0;
+
+ if ((dev->class & 5) && cfg_base)
+ printk(KERN_INFO DRV_NAME " %s: chip", pci_name(dev));
+ else {
+ cfg_base = 0x3df0;
+ printk(KERN_INFO DRV_NAME " %s: using default", pci_name(dev));
+ }
+ printk(KERN_CONT " config base at 0x%04x\n", cfg_base);
+ hwif->config_data = cfg_base;
+ hwif->dma_base = (cfg_base + 4) ^ (hwif->channel ? 0x80 : 0);
+
+ printk(KERN_INFO " %s: BM-DMA at 0x%04lx-0x%04lx\n",
+ hwif->name, hwif->dma_base, hwif->dma_base + 3);
+
+ if (ide_allocate_dma_engine(hwif))
+ return;
+
+ local_irq_save(flags);
+ /* put config reg into first byte of hwif->select_data */
+ outb(0x51 | (hwif->channel << 3), hwif->config_data + 1);
+ /* select PIO as default */
+ hwif->select_data = 0x21;
+ outb(hwif->select_data, hwif->config_data);
+ /* get IRQ info */
+ reg = inb(hwif->config_data + 3);
+ /* mask IRQs for both ports */
+ reg = (reg & 0x10) | 0x03;
+ outb(reg, hwif->config_data + 3);
+ local_irq_restore(flags);
+
+ if (reg & 0x10)
+ /* legacy mode */
+ hwif->irq = hwif->channel ? 15 : 14;
+ else if (!hwif->irq && hwif->mate && hwif->mate->irq)
+ /* sharing IRQ with mate */
+ hwif->irq = hwif->mate->irq;
+
+#if 1
+ {
+ /*
+ * My trm290-based card doesn't seem to work with all possible values
+ * for the control basereg, so this kludge ensures that we use only
+ * values that are known to work. Ugh. -ml
+ */
+ u16 new, old, compat = hwif->channel ? 0x374 : 0x3f4;
+ static u16 next_offset = 0;
+ u8 old_mask;
+
+ outb(0x54 | (hwif->channel << 3), hwif->config_data + 1);
+ old = inw(hwif->config_data);
+ old &= ~1;
+ old_mask = inb(old + 2);
+ if (old != compat && old_mask == 0xff) {
+ /* leave lower 10 bits untouched */
+ compat += (next_offset += 0x400);
+ hwif->io_ports.ctl_addr = compat + 2;
+ outw(compat | 1, hwif->config_data);
+ new = inw(hwif->config_data);
+ printk(KERN_INFO "%s: control basereg workaround: "
+ "old=0x%04x, new=0x%04x\n",
+ hwif->name, old, new & ~1);
+ }
+ }
+#endif
+}
+
+static const struct ide_port_ops trm290_port_ops = {
+ .selectproc = trm290_selectproc,
+};
+
+static struct ide_dma_ops trm290_dma_ops = {
+ .dma_host_set = trm290_dma_host_set,
+ .dma_setup = trm290_dma_setup,
+ .dma_exec_cmd = trm290_dma_exec_cmd,
+ .dma_start = trm290_dma_start,
+ .dma_end = trm290_dma_end,
+ .dma_test_irq = trm290_dma_test_irq,
+ .dma_lost_irq = ide_dma_lost_irq,
+ .dma_timeout = ide_dma_timeout,
+};
+
+static const struct ide_port_info trm290_chipset __devinitdata = {
+ .name = DRV_NAME,
+ .init_hwif = init_hwif_trm290,
+ .chipset = ide_trm290,
+ .port_ops = &trm290_port_ops,
+ .dma_ops = &trm290_dma_ops,
+ .host_flags = IDE_HFLAG_NO_ATAPI_DMA |
+#if 0 /* play it safe for now */
+ IDE_HFLAG_TRUST_BIOS_FOR_DMA |
+#endif
+ IDE_HFLAG_NO_AUTODMA |
+ IDE_HFLAG_NO_LBA48,
+};
+
+static int __devinit trm290_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ return ide_pci_init_one(dev, &trm290_chipset, NULL);
+}
+
+static const struct pci_device_id trm290_pci_tbl[] = {
+ { PCI_VDEVICE(TEKRAM, PCI_DEVICE_ID_TEKRAM_DC290), 0 },
+ { 0, },
+};
+MODULE_DEVICE_TABLE(pci, trm290_pci_tbl);
+
+static struct pci_driver trm290_pci_driver = {
+ .name = "TRM290_IDE",
+ .id_table = trm290_pci_tbl,
+ .probe = trm290_init_one,
+ .remove = ide_pci_remove,
+};
+
+static int __init trm290_ide_init(void)
+{
+ return ide_pci_register_driver(&trm290_pci_driver);
+}
+
+static void __exit trm290_ide_exit(void)
+{
+ pci_unregister_driver(&trm290_pci_driver);
+}
+
+module_init(trm290_ide_init);
+module_exit(trm290_ide_exit);
+
+MODULE_AUTHOR("Mark Lord");
+MODULE_DESCRIPTION("PCI driver module for Tekram TRM290 IDE");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/tx4938ide.c b/drivers/ide/tx4938ide.c
new file mode 100644
index 0000000..13b63e7
--- /dev/null
+++ b/drivers/ide/tx4938ide.c
@@ -0,0 +1,323 @@
+/*
+ * TX4938 internal IDE driver
+ * Based on tx4939ide.c.
+ *
+ * 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.
+ *
+ * (C) Copyright TOSHIBA CORPORATION 2005-2007
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <asm/txx9/tx4938.h>
+
+static void tx4938ide_tune_ebusc(unsigned int ebus_ch,
+ unsigned int gbus_clock,
+ u8 pio)
+{
+ struct ide_timing *t = ide_timing_find_mode(XFER_PIO_0 + pio);
+ u64 cr = __raw_readq(&tx4938_ebuscptr->cr[ebus_ch]);
+ unsigned int sp = (cr >> 4) & 3;
+ unsigned int clock = gbus_clock / (4 - sp);
+ unsigned int cycle = 1000000000 / clock;
+ unsigned int shwt;
+ int wt;
+
+ /* Minimum DIOx- active time */
+ wt = DIV_ROUND_UP(t->act8b, cycle) - 2;
+ /* IORDY setup time: 35ns */
+ wt = max_t(int, wt, DIV_ROUND_UP(35, cycle));
+ /* actual wait-cycle is max(wt & ~1, 1) */
+ if (wt > 2 && (wt & 1))
+ wt++;
+ wt &= ~1;
+ /* Address-valid to DIOR/DIOW setup */
+ shwt = DIV_ROUND_UP(t->setup, cycle);
+
+ /* -DIOx recovery time (SHWT * 4) and cycle time requirement */
+ while ((shwt * 4 + wt + (wt ? 2 : 3)) * cycle < t->cycle)
+ shwt++;
+ if (shwt > 7) {
+ pr_warning("tx4938ide: SHWT violation (%d)\n", shwt);
+ shwt = 7;
+ }
+ pr_debug("tx4938ide: ebus %d, bus cycle %dns, WT %d, SHWT %d\n",
+ ebus_ch, cycle, wt, shwt);
+
+ __raw_writeq((cr & ~0x3f007ull) | (wt << 12) | shwt,
+ &tx4938_ebuscptr->cr[ebus_ch]);
+}
+
+static void tx4938ide_set_pio_mode(ide_drive_t *drive, const u8 pio)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ struct tx4938ide_platform_info *pdata = hwif->dev->platform_data;
+ u8 safe = pio;
+ ide_drive_t *pair;
+
+ pair = ide_get_pair_dev(drive);
+ if (pair)
+ safe = min(safe, ide_get_best_pio_mode(pair, 255, 5));
+ tx4938ide_tune_ebusc(pdata->ebus_ch, pdata->gbus_clock, safe);
+}
+
+#ifdef __BIG_ENDIAN
+
+/* custom iops (independent from SWAP_IO_SPACE) */
+static u8 tx4938ide_inb(unsigned long port)
+{
+ return __raw_readb((void __iomem *)port);
+}
+
+static void tx4938ide_outb(u8 value, unsigned long port)
+{
+ __raw_writeb(value, (void __iomem *)port);
+}
+
+static void tx4938ide_tf_load(ide_drive_t *drive, ide_task_t *task)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ struct ide_io_ports *io_ports = &hwif->io_ports;
+ struct ide_taskfile *tf = &task->tf;
+ u8 HIHI = task->tf_flags & IDE_TFLAG_LBA48 ? 0xE0 : 0xEF;
+
+ if (task->tf_flags & IDE_TFLAG_FLAGGED)
+ HIHI = 0xFF;
+
+ if (task->tf_flags & IDE_TFLAG_OUT_DATA) {
+ u16 data = (tf->hob_data << 8) | tf->data;
+
+ /* no endian swap */
+ __raw_writew(data, (void __iomem *)io_ports->data_addr);
+ }
+
+ if (task->tf_flags & IDE_TFLAG_OUT_HOB_FEATURE)
+ tx4938ide_outb(tf->hob_feature, io_ports->feature_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_HOB_NSECT)
+ tx4938ide_outb(tf->hob_nsect, io_ports->nsect_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAL)
+ tx4938ide_outb(tf->hob_lbal, io_ports->lbal_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAM)
+ tx4938ide_outb(tf->hob_lbam, io_ports->lbam_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAH)
+ tx4938ide_outb(tf->hob_lbah, io_ports->lbah_addr);
+
+ if (task->tf_flags & IDE_TFLAG_OUT_FEATURE)
+ tx4938ide_outb(tf->feature, io_ports->feature_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_NSECT)
+ tx4938ide_outb(tf->nsect, io_ports->nsect_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_LBAL)
+ tx4938ide_outb(tf->lbal, io_ports->lbal_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_LBAM)
+ tx4938ide_outb(tf->lbam, io_ports->lbam_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_LBAH)
+ tx4938ide_outb(tf->lbah, io_ports->lbah_addr);
+
+ if (task->tf_flags & IDE_TFLAG_OUT_DEVICE)
+ tx4938ide_outb((tf->device & HIHI) | drive->select,
+ io_ports->device_addr);
+}
+
+static void tx4938ide_tf_read(ide_drive_t *drive, ide_task_t *task)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ struct ide_io_ports *io_ports = &hwif->io_ports;
+ struct ide_taskfile *tf = &task->tf;
+
+ if (task->tf_flags & IDE_TFLAG_IN_DATA) {
+ u16 data;
+
+ /* no endian swap */
+ data = __raw_readw((void __iomem *)io_ports->data_addr);
+ tf->data = data & 0xff;
+ tf->hob_data = (data >> 8) & 0xff;
+ }
+
+ /* be sure we're looking at the low order bits */
+ tx4938ide_outb(ATA_DEVCTL_OBS & ~0x80, io_ports->ctl_addr);
+
+ if (task->tf_flags & IDE_TFLAG_IN_FEATURE)
+ tf->feature = tx4938ide_inb(io_ports->feature_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_NSECT)
+ tf->nsect = tx4938ide_inb(io_ports->nsect_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_LBAL)
+ tf->lbal = tx4938ide_inb(io_ports->lbal_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_LBAM)
+ tf->lbam = tx4938ide_inb(io_ports->lbam_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_LBAH)
+ tf->lbah = tx4938ide_inb(io_ports->lbah_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_DEVICE)
+ tf->device = tx4938ide_inb(io_ports->device_addr);
+
+ if (task->tf_flags & IDE_TFLAG_LBA48) {
+ tx4938ide_outb(ATA_DEVCTL_OBS | 0x80, io_ports->ctl_addr);
+
+ if (task->tf_flags & IDE_TFLAG_IN_HOB_FEATURE)
+ tf->hob_feature =
+ tx4938ide_inb(io_ports->feature_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_HOB_NSECT)
+ tf->hob_nsect = tx4938ide_inb(io_ports->nsect_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAL)
+ tf->hob_lbal = tx4938ide_inb(io_ports->lbal_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAM)
+ tf->hob_lbam = tx4938ide_inb(io_ports->lbam_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAH)
+ tf->hob_lbah = tx4938ide_inb(io_ports->lbah_addr);
+ }
+}
+
+static void tx4938ide_input_data_swap(ide_drive_t *drive, struct request *rq,
+ void *buf, unsigned int len)
+{
+ unsigned long port = drive->hwif->io_ports.data_addr;
+ unsigned short *ptr = buf;
+ unsigned int count = (len + 1) / 2;
+
+ while (count--)
+ *ptr++ = cpu_to_le16(__raw_readw((void __iomem *)port));
+ __ide_flush_dcache_range((unsigned long)buf, roundup(len, 2));
+}
+
+static void tx4938ide_output_data_swap(ide_drive_t *drive, struct request *rq,
+ void *buf, unsigned int len)
+{
+ unsigned long port = drive->hwif->io_ports.data_addr;
+ unsigned short *ptr = buf;
+ unsigned int count = (len + 1) / 2;
+
+ while (count--) {
+ __raw_writew(le16_to_cpu(*ptr), (void __iomem *)port);
+ ptr++;
+ }
+ __ide_flush_dcache_range((unsigned long)buf, roundup(len, 2));
+}
+
+static const struct ide_tp_ops tx4938ide_tp_ops = {
+ .exec_command = ide_exec_command,
+ .read_status = ide_read_status,
+ .read_altstatus = ide_read_altstatus,
+ .read_sff_dma_status = ide_read_sff_dma_status,
+
+ .set_irq = ide_set_irq,
+
+ .tf_load = tx4938ide_tf_load,
+ .tf_read = tx4938ide_tf_read,
+
+ .input_data = tx4938ide_input_data_swap,
+ .output_data = tx4938ide_output_data_swap,
+};
+
+#endif /* __BIG_ENDIAN */
+
+static const struct ide_port_ops tx4938ide_port_ops = {
+ .set_pio_mode = tx4938ide_set_pio_mode,
+};
+
+static const struct ide_port_info tx4938ide_port_info __initdata = {
+ .port_ops = &tx4938ide_port_ops,
+#ifdef __BIG_ENDIAN
+ .tp_ops = &tx4938ide_tp_ops,
+#endif
+ .host_flags = IDE_HFLAG_MMIO | IDE_HFLAG_NO_DMA,
+ .pio_mask = ATA_PIO5,
+};
+
+static int __init tx4938ide_probe(struct platform_device *pdev)
+{
+ hw_regs_t hw;
+ hw_regs_t *hws[] = { &hw, NULL, NULL, NULL };
+ struct ide_host *host;
+ struct resource *res;
+ struct tx4938ide_platform_info *pdata = pdev->dev.platform_data;
+ int irq, ret, i;
+ unsigned long mapbase, mapctl;
+ struct ide_port_info d = tx4938ide_port_info;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return -ENODEV;
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+
+ if (!devm_request_mem_region(&pdev->dev, res->start,
+ res->end - res->start + 1, "tx4938ide"))
+ return -EBUSY;
+ mapbase = (unsigned long)devm_ioremap(&pdev->dev, res->start,
+ 8 << pdata->ioport_shift);
+ mapctl = (unsigned long)devm_ioremap(&pdev->dev,
+ res->start + 0x10000 +
+ (6 << pdata->ioport_shift),
+ 1 << pdata->ioport_shift);
+ if (!mapbase || !mapctl)
+ return -EBUSY;
+
+ memset(&hw, 0, sizeof(hw));
+ if (pdata->ioport_shift) {
+ unsigned long port = mapbase;
+ unsigned long ctl = mapctl;
+
+ hw.io_ports_array[0] = port;
+#ifdef __BIG_ENDIAN
+ port++;
+ ctl++;
+#endif
+ for (i = 1; i <= 7; i++)
+ hw.io_ports_array[i] =
+ port + (i << pdata->ioport_shift);
+ hw.io_ports.ctl_addr = ctl;
+ } else
+ ide_std_init_ports(&hw, mapbase, mapctl);
+ hw.irq = irq;
+ hw.dev = &pdev->dev;
+
+ pr_info("TX4938 IDE interface (base %#lx, ctl %#lx, irq %d)\n",
+ mapbase, mapctl, hw.irq);
+ if (pdata->gbus_clock)
+ tx4938ide_tune_ebusc(pdata->ebus_ch, pdata->gbus_clock, 0);
+ else
+ d.port_ops = NULL;
+ ret = ide_host_add(&d, hws, &host);
+ if (!ret)
+ platform_set_drvdata(pdev, host);
+ return ret;
+}
+
+static int __exit tx4938ide_remove(struct platform_device *pdev)
+{
+ struct ide_host *host = platform_get_drvdata(pdev);
+
+ ide_host_remove(host);
+ return 0;
+}
+
+static struct platform_driver tx4938ide_driver = {
+ .driver = {
+ .name = "tx4938ide",
+ .owner = THIS_MODULE,
+ },
+ .remove = __exit_p(tx4938ide_remove),
+};
+
+static int __init tx4938ide_init(void)
+{
+ return platform_driver_probe(&tx4938ide_driver, tx4938ide_probe);
+}
+
+static void __exit tx4938ide_exit(void)
+{
+ platform_driver_unregister(&tx4938ide_driver);
+}
+
+module_init(tx4938ide_init);
+module_exit(tx4938ide_exit);
+
+MODULE_DESCRIPTION("TX4938 internal IDE driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:tx4938ide");
diff --git a/drivers/ide/tx4939ide.c b/drivers/ide/tx4939ide.c
new file mode 100644
index 0000000..97cd9e0
--- /dev/null
+++ b/drivers/ide/tx4939ide.c
@@ -0,0 +1,760 @@
+/*
+ * TX4939 internal IDE driver
+ * Based on RBTX49xx patch from CELF patch archive.
+ *
+ * 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.
+ *
+ * (C) Copyright TOSHIBA CORPORATION 2005-2007
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/scatterlist.h>
+
+#define MODNAME "tx4939ide"
+
+/* ATA Shadow Registers (8-bit except for Data which is 16-bit) */
+#define TX4939IDE_Data 0x000
+#define TX4939IDE_Error_Feature 0x001
+#define TX4939IDE_Sec 0x002
+#define TX4939IDE_LBA0 0x003
+#define TX4939IDE_LBA1 0x004
+#define TX4939IDE_LBA2 0x005
+#define TX4939IDE_DevHead 0x006
+#define TX4939IDE_Stat_Cmd 0x007
+#define TX4939IDE_AltStat_DevCtl 0x402
+/* H/W DMA Registers */
+#define TX4939IDE_DMA_Cmd 0x800 /* 8-bit */
+#define TX4939IDE_DMA_Stat 0x802 /* 8-bit */
+#define TX4939IDE_PRD_Ptr 0x804 /* 32-bit */
+/* ATA100 CORE Registers (16-bit) */
+#define TX4939IDE_Sys_Ctl 0xc00
+#define TX4939IDE_Xfer_Cnt_1 0xc08
+#define TX4939IDE_Xfer_Cnt_2 0xc0a
+#define TX4939IDE_Sec_Cnt 0xc10
+#define TX4939IDE_Start_Lo_Addr 0xc18
+#define TX4939IDE_Start_Up_Addr 0xc20
+#define TX4939IDE_Add_Ctl 0xc28
+#define TX4939IDE_Lo_Burst_Cnt 0xc30
+#define TX4939IDE_Up_Burst_Cnt 0xc38
+#define TX4939IDE_PIO_Addr 0xc88
+#define TX4939IDE_H_Rst_Tim 0xc90
+#define TX4939IDE_Int_Ctl 0xc98
+#define TX4939IDE_Pkt_Cmd 0xcb8
+#define TX4939IDE_Bxfer_Cnt_Hi 0xcc0
+#define TX4939IDE_Bxfer_Cnt_Lo 0xcc8
+#define TX4939IDE_Dev_TErr 0xcd0
+#define TX4939IDE_Pkt_Xfer_Ctl 0xcd8
+#define TX4939IDE_Start_TAddr 0xce0
+
+/* bits for Int_Ctl */
+#define TX4939IDE_INT_ADDRERR 0x80
+#define TX4939IDE_INT_REACHMUL 0x40
+#define TX4939IDE_INT_DEVTIMING 0x20
+#define TX4939IDE_INT_UDMATERM 0x10
+#define TX4939IDE_INT_TIMER 0x08
+#define TX4939IDE_INT_BUSERR 0x04
+#define TX4939IDE_INT_XFEREND 0x02
+#define TX4939IDE_INT_HOST 0x01
+
+#define TX4939IDE_IGNORE_INTS \
+ (TX4939IDE_INT_ADDRERR | TX4939IDE_INT_REACHMUL | \
+ TX4939IDE_INT_DEVTIMING | TX4939IDE_INT_UDMATERM | \
+ TX4939IDE_INT_TIMER | TX4939IDE_INT_XFEREND)
+
+#ifdef __BIG_ENDIAN
+#define tx4939ide_swizzlel(a) ((a) ^ 4)
+#define tx4939ide_swizzlew(a) ((a) ^ 6)
+#define tx4939ide_swizzleb(a) ((a) ^ 7)
+#else
+#define tx4939ide_swizzlel(a) (a)
+#define tx4939ide_swizzlew(a) (a)
+#define tx4939ide_swizzleb(a) (a)
+#endif
+
+static u16 tx4939ide_readw(void __iomem *base, u32 reg)
+{
+ return __raw_readw(base + tx4939ide_swizzlew(reg));
+}
+static u8 tx4939ide_readb(void __iomem *base, u32 reg)
+{
+ return __raw_readb(base + tx4939ide_swizzleb(reg));
+}
+static void tx4939ide_writel(u32 val, void __iomem *base, u32 reg)
+{
+ __raw_writel(val, base + tx4939ide_swizzlel(reg));
+}
+static void tx4939ide_writew(u16 val, void __iomem *base, u32 reg)
+{
+ __raw_writew(val, base + tx4939ide_swizzlew(reg));
+}
+static void tx4939ide_writeb(u8 val, void __iomem *base, u32 reg)
+{
+ __raw_writeb(val, base + tx4939ide_swizzleb(reg));
+}
+
+#define TX4939IDE_BASE(hwif) ((void __iomem *)(hwif)->extra_base)
+
+static void tx4939ide_set_pio_mode(ide_drive_t *drive, const u8 pio)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ int is_slave = drive->dn;
+ u32 mask, val;
+ u8 safe = pio;
+ ide_drive_t *pair;
+
+ pair = ide_get_pair_dev(drive);
+ if (pair)
+ safe = min(safe, ide_get_best_pio_mode(pair, 255, 4));
+ /*
+ * Update Command Transfer Mode for master/slave and Data
+ * Transfer Mode for this drive.
+ */
+ mask = is_slave ? 0x07f00000 : 0x000007f0;
+ val = ((safe << 8) | (pio << 4)) << (is_slave ? 16 : 0);
+ hwif->select_data = (hwif->select_data & ~mask) | val;
+ /* tx4939ide_tf_load_fixup() will set the Sys_Ctl register */
+}
+
+static void tx4939ide_set_dma_mode(ide_drive_t *drive, const u8 mode)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ u32 mask, val;
+
+ /* Update Data Transfer Mode for this drive. */
+ if (mode >= XFER_UDMA_0)
+ val = mode - XFER_UDMA_0 + 8;
+ else
+ val = mode - XFER_MW_DMA_0 + 5;
+ if (drive->dn) {
+ mask = 0x00f00000;
+ val <<= 20;
+ } else {
+ mask = 0x000000f0;
+ val <<= 4;
+ }
+ hwif->select_data = (hwif->select_data & ~mask) | val;
+ /* tx4939ide_tf_load_fixup() will set the Sys_Ctl register */
+}
+
+static u16 tx4939ide_check_error_ints(ide_hwif_t *hwif)
+{
+ void __iomem *base = TX4939IDE_BASE(hwif);
+ u16 ctl = tx4939ide_readw(base, TX4939IDE_Int_Ctl);
+
+ if (ctl & TX4939IDE_INT_BUSERR) {
+ /* reset FIFO */
+ u16 sysctl = tx4939ide_readw(base, TX4939IDE_Sys_Ctl);
+
+ tx4939ide_writew(sysctl | 0x4000, base, TX4939IDE_Sys_Ctl);
+ mmiowb();
+ /* wait 12GBUSCLK (typ. 60ns @ GBUS200MHz, max 270ns) */
+ ndelay(270);
+ tx4939ide_writew(sysctl, base, TX4939IDE_Sys_Ctl);
+ }
+ if (ctl & (TX4939IDE_INT_ADDRERR |
+ TX4939IDE_INT_DEVTIMING | TX4939IDE_INT_BUSERR))
+ pr_err("%s: Error interrupt %#x (%s%s%s )\n",
+ hwif->name, ctl,
+ ctl & TX4939IDE_INT_ADDRERR ? " Address-Error" : "",
+ ctl & TX4939IDE_INT_DEVTIMING ? " DEV-Timing" : "",
+ ctl & TX4939IDE_INT_BUSERR ? " Bus-Error" : "");
+ return ctl;
+}
+
+static void tx4939ide_clear_irq(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif;
+ void __iomem *base;
+ u16 ctl;
+
+ /*
+ * tx4939ide_dma_test_irq() and tx4939ide_dma_end() do all job
+ * for DMA case.
+ */
+ if (drive->waiting_for_dma)
+ return;
+ hwif = drive->hwif;
+ base = TX4939IDE_BASE(hwif);
+ ctl = tx4939ide_check_error_ints(hwif);
+ tx4939ide_writew(ctl, base, TX4939IDE_Int_Ctl);
+}
+
+static u8 tx4939ide_cable_detect(ide_hwif_t *hwif)
+{
+ void __iomem *base = TX4939IDE_BASE(hwif);
+
+ return tx4939ide_readw(base, TX4939IDE_Sys_Ctl) & 0x2000 ?
+ ATA_CBL_PATA40 : ATA_CBL_PATA80;
+}
+
+#ifdef __BIG_ENDIAN
+static void tx4939ide_dma_host_set(ide_drive_t *drive, int on)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ u8 unit = drive->dn;
+ void __iomem *base = TX4939IDE_BASE(hwif);
+ u8 dma_stat = tx4939ide_readb(base, TX4939IDE_DMA_Stat);
+
+ if (on)
+ dma_stat |= (1 << (5 + unit));
+ else
+ dma_stat &= ~(1 << (5 + unit));
+
+ tx4939ide_writeb(dma_stat, base, TX4939IDE_DMA_Stat);
+}
+#else
+#define tx4939ide_dma_host_set ide_dma_host_set
+#endif
+
+static u8 tx4939ide_clear_dma_status(void __iomem *base)
+{
+ u8 dma_stat;
+
+ /* read DMA status for INTR & ERROR flags */
+ dma_stat = tx4939ide_readb(base, TX4939IDE_DMA_Stat);
+ /* clear INTR & ERROR flags */
+ tx4939ide_writeb(dma_stat | ATA_DMA_INTR | ATA_DMA_ERR, base,
+ TX4939IDE_DMA_Stat);
+ /* recover intmask cleared by writing to bit2 of DMA_Stat */
+ tx4939ide_writew(TX4939IDE_IGNORE_INTS << 8, base, TX4939IDE_Int_Ctl);
+ return dma_stat;
+}
+
+#ifdef __BIG_ENDIAN
+/* custom ide_build_dmatable to handle swapped layout */
+static int tx4939ide_build_dmatable(ide_drive_t *drive, struct request *rq)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ u32 *table = (u32 *)hwif->dmatable_cpu;
+ unsigned int count = 0;
+ int i;
+ struct scatterlist *sg;
+
+ hwif->sg_nents = ide_build_sglist(drive, rq);
+ if (hwif->sg_nents == 0)
+ return 0;
+
+ for_each_sg(hwif->sg_table, sg, hwif->sg_nents, i) {
+ u32 cur_addr, cur_len, bcount;
+
+ cur_addr = sg_dma_address(sg);
+ cur_len = sg_dma_len(sg);
+
+ /*
+ * Fill in the DMA table, without crossing any 64kB boundaries.
+ */
+
+ while (cur_len) {
+ if (count++ >= PRD_ENTRIES)
+ goto use_pio_instead;
+
+ bcount = 0x10000 - (cur_addr & 0xffff);
+ if (bcount > cur_len)
+ bcount = cur_len;
+ /*
+ * This workaround for zero count seems required.
+ * (standard ide_build_dmatable do it too)
+ */
+ if ((bcount & 0xffff) == 0x0000)
+ bcount = 0x8000;
+ *table++ = bcount & 0xffff;
+ *table++ = cur_addr;
+ cur_addr += bcount;
+ cur_len -= bcount;
+ }
+ }
+
+ if (count) {
+ *(table - 2) |= 0x80000000;
+ return count;
+ }
+
+use_pio_instead:
+ printk(KERN_ERR "%s: %s\n", drive->name,
+ count ? "DMA table too small" : "empty DMA table?");
+
+ ide_destroy_dmatable(drive);
+
+ return 0; /* revert to PIO for this request */
+}
+#else
+#define tx4939ide_build_dmatable ide_build_dmatable
+#endif
+
+static int tx4939ide_dma_setup(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ void __iomem *base = TX4939IDE_BASE(hwif);
+ struct request *rq = hwif->hwgroup->rq;
+ u8 reading;
+ int nent;
+
+ if (rq_data_dir(rq))
+ reading = 0;
+ else
+ reading = ATA_DMA_WR;
+
+ /* fall back to PIO! */
+ nent = tx4939ide_build_dmatable(drive, rq);
+ if (!nent) {
+ ide_map_sg(drive, rq);
+ return 1;
+ }
+
+ /* PRD table */
+ tx4939ide_writel(hwif->dmatable_dma, base, TX4939IDE_PRD_Ptr);
+
+ /* specify r/w */
+ tx4939ide_writeb(reading, base, TX4939IDE_DMA_Cmd);
+
+ /* clear INTR & ERROR flags */
+ tx4939ide_clear_dma_status(base);
+
+ drive->waiting_for_dma = 1;
+
+ tx4939ide_writew(SECTOR_SIZE / 2, base, drive->dn ?
+ TX4939IDE_Xfer_Cnt_2 : TX4939IDE_Xfer_Cnt_1);
+ tx4939ide_writew(rq->nr_sectors, base, TX4939IDE_Sec_Cnt);
+ return 0;
+}
+
+static int tx4939ide_dma_end(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ u8 dma_stat, dma_cmd;
+ void __iomem *base = TX4939IDE_BASE(hwif);
+ u16 ctl = tx4939ide_readw(base, TX4939IDE_Int_Ctl);
+
+ drive->waiting_for_dma = 0;
+
+ /* get DMA command mode */
+ dma_cmd = tx4939ide_readb(base, TX4939IDE_DMA_Cmd);
+ /* stop DMA */
+ tx4939ide_writeb(dma_cmd & ~ATA_DMA_START, base, TX4939IDE_DMA_Cmd);
+
+ /* read and clear the INTR & ERROR bits */
+ dma_stat = tx4939ide_clear_dma_status(base);
+
+ /* purge DMA mappings */
+ ide_destroy_dmatable(drive);
+ /* verify good DMA status */
+ wmb();
+
+ if ((dma_stat & (ATA_DMA_INTR | ATA_DMA_ERR | ATA_DMA_ACTIVE)) == 0 &&
+ (ctl & (TX4939IDE_INT_XFEREND | TX4939IDE_INT_HOST)) ==
+ (TX4939IDE_INT_XFEREND | TX4939IDE_INT_HOST))
+ /* INT_IDE lost... bug? */
+ return 0;
+ return ((dma_stat & (ATA_DMA_INTR | ATA_DMA_ERR | ATA_DMA_ACTIVE)) !=
+ ATA_DMA_INTR) ? 0x10 | dma_stat : 0;
+}
+
+/* returns 1 if DMA IRQ issued, 0 otherwise */
+static int tx4939ide_dma_test_irq(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ void __iomem *base = TX4939IDE_BASE(hwif);
+ u16 ctl, ide_int;
+ u8 dma_stat, stat;
+ int found = 0;
+
+ ctl = tx4939ide_check_error_ints(hwif);
+ ide_int = ctl & (TX4939IDE_INT_XFEREND | TX4939IDE_INT_HOST);
+ switch (ide_int) {
+ case TX4939IDE_INT_HOST:
+ /* On error, XFEREND might not be asserted. */
+ stat = tx4939ide_readb(base, TX4939IDE_AltStat_DevCtl);
+ if ((stat & (ATA_BUSY | ATA_DRQ | ATA_ERR)) == ATA_ERR)
+ found = 1;
+ else
+ /* Wait for XFEREND (Mask HOST and unmask XFEREND) */
+ ctl &= ~TX4939IDE_INT_XFEREND << 8;
+ ctl |= ide_int << 8;
+ break;
+ case TX4939IDE_INT_HOST | TX4939IDE_INT_XFEREND:
+ dma_stat = tx4939ide_readb(base, TX4939IDE_DMA_Stat);
+ if (!(dma_stat & ATA_DMA_INTR))
+ pr_warning("%s: weird interrupt status. "
+ "DMA_Stat %#02x int_ctl %#04x\n",
+ hwif->name, dma_stat, ctl);
+ found = 1;
+ break;
+ }
+ /*
+ * Do not clear XFEREND, HOST now. They will be cleared by
+ * clearing bit2 of DMA_Stat.
+ */
+ ctl &= ~ide_int;
+ tx4939ide_writew(ctl, base, TX4939IDE_Int_Ctl);
+ return found;
+}
+
+static void tx4939ide_init_hwif(ide_hwif_t *hwif)
+{
+ void __iomem *base = TX4939IDE_BASE(hwif);
+
+ /* Soft Reset */
+ tx4939ide_writew(0x8000, base, TX4939IDE_Sys_Ctl);
+ mmiowb();
+ /* at least 20 GBUSCLK (typ. 100ns @ GBUS200MHz, max 450ns) */
+ ndelay(450);
+ tx4939ide_writew(0x0000, base, TX4939IDE_Sys_Ctl);
+ /* mask some interrupts and clear all interrupts */
+ tx4939ide_writew((TX4939IDE_IGNORE_INTS << 8) | 0xff, base,
+ TX4939IDE_Int_Ctl);
+
+ tx4939ide_writew(0x0008, base, TX4939IDE_Lo_Burst_Cnt);
+ tx4939ide_writew(0, base, TX4939IDE_Up_Burst_Cnt);
+}
+
+static int tx4939ide_init_dma(ide_hwif_t *hwif, const struct ide_port_info *d)
+{
+ hwif->dma_base =
+ hwif->extra_base + tx4939ide_swizzleb(TX4939IDE_DMA_Cmd);
+ /*
+ * Note that we cannot use ATA_DMA_TABLE_OFS, ATA_DMA_STATUS
+ * for big endian.
+ */
+ return ide_allocate_dma_engine(hwif);
+}
+
+static void tx4939ide_tf_load_fixup(ide_drive_t *drive, ide_task_t *task)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ void __iomem *base = TX4939IDE_BASE(hwif);
+ u16 sysctl = hwif->select_data >> (drive->dn ? 16 : 0);
+
+ /*
+ * Fix ATA100 CORE System Control Register. (The write to the
+ * Device/Head register may write wrong data to the System
+ * Control Register)
+ * While Sys_Ctl is written here, selectproc is not needed.
+ */
+ tx4939ide_writew(sysctl, base, TX4939IDE_Sys_Ctl);
+}
+
+#ifdef __BIG_ENDIAN
+
+static u8 tx4939ide_read_sff_dma_status(ide_hwif_t *hwif)
+{
+ void __iomem *base = TX4939IDE_BASE(hwif);
+
+ return tx4939ide_readb(base, TX4939IDE_DMA_Stat);
+}
+
+/* custom iops (independent from SWAP_IO_SPACE) */
+static u8 tx4939ide_inb(unsigned long port)
+{
+ return __raw_readb((void __iomem *)port);
+}
+
+static void tx4939ide_outb(u8 value, unsigned long port)
+{
+ __raw_writeb(value, (void __iomem *)port);
+}
+
+static void tx4939ide_tf_load(ide_drive_t *drive, ide_task_t *task)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ struct ide_io_ports *io_ports = &hwif->io_ports;
+ struct ide_taskfile *tf = &task->tf;
+ u8 HIHI = task->tf_flags & IDE_TFLAG_LBA48 ? 0xE0 : 0xEF;
+
+ if (task->tf_flags & IDE_TFLAG_FLAGGED)
+ HIHI = 0xFF;
+
+ if (task->tf_flags & IDE_TFLAG_OUT_DATA) {
+ u16 data = (tf->hob_data << 8) | tf->data;
+
+ /* no endian swap */
+ __raw_writew(data, (void __iomem *)io_ports->data_addr);
+ }
+
+ if (task->tf_flags & IDE_TFLAG_OUT_HOB_FEATURE)
+ tx4939ide_outb(tf->hob_feature, io_ports->feature_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_HOB_NSECT)
+ tx4939ide_outb(tf->hob_nsect, io_ports->nsect_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAL)
+ tx4939ide_outb(tf->hob_lbal, io_ports->lbal_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAM)
+ tx4939ide_outb(tf->hob_lbam, io_ports->lbam_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAH)
+ tx4939ide_outb(tf->hob_lbah, io_ports->lbah_addr);
+
+ if (task->tf_flags & IDE_TFLAG_OUT_FEATURE)
+ tx4939ide_outb(tf->feature, io_ports->feature_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_NSECT)
+ tx4939ide_outb(tf->nsect, io_ports->nsect_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_LBAL)
+ tx4939ide_outb(tf->lbal, io_ports->lbal_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_LBAM)
+ tx4939ide_outb(tf->lbam, io_ports->lbam_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_LBAH)
+ tx4939ide_outb(tf->lbah, io_ports->lbah_addr);
+
+ if (task->tf_flags & IDE_TFLAG_OUT_DEVICE) {
+ tx4939ide_outb((tf->device & HIHI) | drive->select,
+ io_ports->device_addr);
+ tx4939ide_tf_load_fixup(drive, task);
+ }
+}
+
+static void tx4939ide_tf_read(ide_drive_t *drive, ide_task_t *task)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ struct ide_io_ports *io_ports = &hwif->io_ports;
+ struct ide_taskfile *tf = &task->tf;
+
+ if (task->tf_flags & IDE_TFLAG_IN_DATA) {
+ u16 data;
+
+ /* no endian swap */
+ data = __raw_readw((void __iomem *)io_ports->data_addr);
+ tf->data = data & 0xff;
+ tf->hob_data = (data >> 8) & 0xff;
+ }
+
+ /* be sure we're looking at the low order bits */
+ tx4939ide_outb(ATA_DEVCTL_OBS & ~0x80, io_ports->ctl_addr);
+
+ if (task->tf_flags & IDE_TFLAG_IN_FEATURE)
+ tf->feature = tx4939ide_inb(io_ports->feature_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_NSECT)
+ tf->nsect = tx4939ide_inb(io_ports->nsect_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_LBAL)
+ tf->lbal = tx4939ide_inb(io_ports->lbal_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_LBAM)
+ tf->lbam = tx4939ide_inb(io_ports->lbam_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_LBAH)
+ tf->lbah = tx4939ide_inb(io_ports->lbah_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_DEVICE)
+ tf->device = tx4939ide_inb(io_ports->device_addr);
+
+ if (task->tf_flags & IDE_TFLAG_LBA48) {
+ tx4939ide_outb(ATA_DEVCTL_OBS | 0x80, io_ports->ctl_addr);
+
+ if (task->tf_flags & IDE_TFLAG_IN_HOB_FEATURE)
+ tf->hob_feature =
+ tx4939ide_inb(io_ports->feature_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_HOB_NSECT)
+ tf->hob_nsect = tx4939ide_inb(io_ports->nsect_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAL)
+ tf->hob_lbal = tx4939ide_inb(io_ports->lbal_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAM)
+ tf->hob_lbam = tx4939ide_inb(io_ports->lbam_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAH)
+ tf->hob_lbah = tx4939ide_inb(io_ports->lbah_addr);
+ }
+}
+
+static void tx4939ide_input_data_swap(ide_drive_t *drive, struct request *rq,
+ void *buf, unsigned int len)
+{
+ unsigned long port = drive->hwif->io_ports.data_addr;
+ unsigned short *ptr = buf;
+ unsigned int count = (len + 1) / 2;
+
+ while (count--)
+ *ptr++ = cpu_to_le16(__raw_readw((void __iomem *)port));
+ __ide_flush_dcache_range((unsigned long)buf, roundup(len, 2));
+}
+
+static void tx4939ide_output_data_swap(ide_drive_t *drive, struct request *rq,
+ void *buf, unsigned int len)
+{
+ unsigned long port = drive->hwif->io_ports.data_addr;
+ unsigned short *ptr = buf;
+ unsigned int count = (len + 1) / 2;
+
+ while (count--) {
+ __raw_writew(le16_to_cpu(*ptr), (void __iomem *)port);
+ ptr++;
+ }
+ __ide_flush_dcache_range((unsigned long)buf, roundup(len, 2));
+}
+
+static const struct ide_tp_ops tx4939ide_tp_ops = {
+ .exec_command = ide_exec_command,
+ .read_status = ide_read_status,
+ .read_altstatus = ide_read_altstatus,
+ .read_sff_dma_status = tx4939ide_read_sff_dma_status,
+
+ .set_irq = ide_set_irq,
+
+ .tf_load = tx4939ide_tf_load,
+ .tf_read = tx4939ide_tf_read,
+
+ .input_data = tx4939ide_input_data_swap,
+ .output_data = tx4939ide_output_data_swap,
+};
+
+#else /* __LITTLE_ENDIAN */
+
+static void tx4939ide_tf_load(ide_drive_t *drive, ide_task_t *task)
+{
+ ide_tf_load(drive, task);
+ if (task->tf_flags & IDE_TFLAG_OUT_DEVICE)
+ tx4939ide_tf_load_fixup(drive, task);
+}
+
+static const struct ide_tp_ops tx4939ide_tp_ops = {
+ .exec_command = ide_exec_command,
+ .read_status = ide_read_status,
+ .read_altstatus = ide_read_altstatus,
+ .read_sff_dma_status = ide_read_sff_dma_status,
+
+ .set_irq = ide_set_irq,
+
+ .tf_load = tx4939ide_tf_load,
+ .tf_read = ide_tf_read,
+
+ .input_data = ide_input_data,
+ .output_data = ide_output_data,
+};
+
+#endif /* __LITTLE_ENDIAN */
+
+static const struct ide_port_ops tx4939ide_port_ops = {
+ .set_pio_mode = tx4939ide_set_pio_mode,
+ .set_dma_mode = tx4939ide_set_dma_mode,
+ .clear_irq = tx4939ide_clear_irq,
+ .cable_detect = tx4939ide_cable_detect,
+};
+
+static const struct ide_dma_ops tx4939ide_dma_ops = {
+ .dma_host_set = tx4939ide_dma_host_set,
+ .dma_setup = tx4939ide_dma_setup,
+ .dma_exec_cmd = ide_dma_exec_cmd,
+ .dma_start = ide_dma_start,
+ .dma_end = tx4939ide_dma_end,
+ .dma_test_irq = tx4939ide_dma_test_irq,
+ .dma_lost_irq = ide_dma_lost_irq,
+ .dma_timeout = ide_dma_timeout,
+};
+
+static const struct ide_port_info tx4939ide_port_info __initdata = {
+ .init_hwif = tx4939ide_init_hwif,
+ .init_dma = tx4939ide_init_dma,
+ .port_ops = &tx4939ide_port_ops,
+ .dma_ops = &tx4939ide_dma_ops,
+ .tp_ops = &tx4939ide_tp_ops,
+ .host_flags = IDE_HFLAG_MMIO,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA5,
+};
+
+static int __init tx4939ide_probe(struct platform_device *pdev)
+{
+ hw_regs_t hw;
+ hw_regs_t *hws[] = { &hw, NULL, NULL, NULL };
+ struct ide_host *host;
+ struct resource *res;
+ int irq, ret;
+ unsigned long mapbase;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return -ENODEV;
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+
+ if (!devm_request_mem_region(&pdev->dev, res->start,
+ res->end - res->start + 1, "tx4938ide"))
+ return -EBUSY;
+ mapbase = (unsigned long)devm_ioremap(&pdev->dev, res->start,
+ res->end - res->start + 1);
+ if (!mapbase)
+ return -EBUSY;
+ memset(&hw, 0, sizeof(hw));
+ hw.io_ports.data_addr =
+ mapbase + tx4939ide_swizzlew(TX4939IDE_Data);
+ hw.io_ports.error_addr =
+ mapbase + tx4939ide_swizzleb(TX4939IDE_Error_Feature);
+ hw.io_ports.nsect_addr =
+ mapbase + tx4939ide_swizzleb(TX4939IDE_Sec);
+ hw.io_ports.lbal_addr =
+ mapbase + tx4939ide_swizzleb(TX4939IDE_LBA0);
+ hw.io_ports.lbam_addr =
+ mapbase + tx4939ide_swizzleb(TX4939IDE_LBA1);
+ hw.io_ports.lbah_addr =
+ mapbase + tx4939ide_swizzleb(TX4939IDE_LBA2);
+ hw.io_ports.device_addr =
+ mapbase + tx4939ide_swizzleb(TX4939IDE_DevHead);
+ hw.io_ports.command_addr =
+ mapbase + tx4939ide_swizzleb(TX4939IDE_Stat_Cmd);
+ hw.io_ports.ctl_addr =
+ mapbase + tx4939ide_swizzleb(TX4939IDE_AltStat_DevCtl);
+ hw.irq = irq;
+ hw.dev = &pdev->dev;
+
+ pr_info("TX4939 IDE interface (base %#lx, irq %d)\n", mapbase, irq);
+ host = ide_host_alloc(&tx4939ide_port_info, hws);
+ if (!host)
+ return -ENOMEM;
+ /* use extra_base for base address of the all registers */
+ host->ports[0]->extra_base = mapbase;
+ ret = ide_host_register(host, &tx4939ide_port_info, hws);
+ if (ret) {
+ ide_host_free(host);
+ return ret;
+ }
+ platform_set_drvdata(pdev, host);
+ return 0;
+}
+
+static int __exit tx4939ide_remove(struct platform_device *pdev)
+{
+ struct ide_host *host = platform_get_drvdata(pdev);
+
+ ide_host_remove(host);
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int tx4939ide_resume(struct platform_device *dev)
+{
+ struct ide_host *host = platform_get_drvdata(dev);
+ ide_hwif_t *hwif = host->ports[0];
+
+ tx4939ide_init_hwif(hwif);
+ return 0;
+}
+#else
+#define tx4939ide_resume NULL
+#endif
+
+static struct platform_driver tx4939ide_driver = {
+ .driver = {
+ .name = MODNAME,
+ .owner = THIS_MODULE,
+ },
+ .remove = __exit_p(tx4939ide_remove),
+ .resume = tx4939ide_resume,
+};
+
+static int __init tx4939ide_init(void)
+{
+ return platform_driver_probe(&tx4939ide_driver, tx4939ide_probe);
+}
+
+static void __exit tx4939ide_exit(void)
+{
+ platform_driver_unregister(&tx4939ide_driver);
+}
+
+module_init(tx4939ide_init);
+module_exit(tx4939ide_exit);
+
+MODULE_DESCRIPTION("TX4939 internal IDE driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:tx4939ide");
diff --git a/drivers/ide/umc8672.c b/drivers/ide/umc8672.c
new file mode 100644
index 0000000..1da076e
--- /dev/null
+++ b/drivers/ide/umc8672.c
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 1995-1996 Linus Torvalds & author (see below)
+ */
+
+/*
+ * Principal Author/Maintainer: PODIEN@hml2.atlas.de (Wolfram Podien)
+ *
+ * This file provides support for the advanced features
+ * of the UMC 8672 IDE interface.
+ *
+ * Version 0.01 Initial version, hacked out of ide.c,
+ * and #include'd rather than compiled separately.
+ * This will get cleaned up in a subsequent release.
+ *
+ * Version 0.02 now configs/compiles separate from ide.c -ml
+ * Version 0.03 enhanced auto-tune, fix display bug
+ * Version 0.05 replace sti() with restore_flags() -ml
+ * add detection of possible race condition -ml
+ */
+
+/*
+ * VLB Controller Support from
+ * Wolfram Podien
+ * Rohoefe 3
+ * D28832 Achim
+ * Germany
+ *
+ * To enable UMC8672 support there must a lilo line like
+ * append="ide0=umc8672"...
+ * To set the speed according to the abilities of the hardware there must be a
+ * line like
+ * #define UMC_DRIVE0 11
+ * in the beginning of the driver, which sets the speed of drive 0 to 11 (there
+ * are some lines present). 0 - 11 are allowed speed values. These values are
+ * the results from the DOS speed test program supplied from UMC. 11 is the
+ * highest speed (about PIO mode 3)
+ */
+#define REALLY_SLOW_IO /* some systems can safely undef this */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#define DRV_NAME "umc8672"
+
+/*
+ * Default speeds. These can be changed with "auto-tune" and/or hdparm.
+ */
+#define UMC_DRIVE0 1 /* DOS measured drive speeds */
+#define UMC_DRIVE1 1 /* 0 to 11 allowed */
+#define UMC_DRIVE2 1 /* 11 = Fastest Speed */
+#define UMC_DRIVE3 1 /* In case of crash reduce speed */
+
+static u8 current_speeds[4] = {UMC_DRIVE0, UMC_DRIVE1, UMC_DRIVE2, UMC_DRIVE3};
+static const u8 pio_to_umc [5] = {0, 3, 7, 10, 11}; /* rough guesses */
+
+/* 0 1 2 3 4 5 6 7 8 9 10 11 */
+static const u8 speedtab [3][12] = {
+ {0x0f, 0x0b, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x1},
+ {0x03, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x1},
+ {0xff, 0xcb, 0xc0, 0x58, 0x36, 0x33, 0x23, 0x22, 0x21, 0x11, 0x10, 0x0}
+};
+
+static void out_umc(char port, char wert)
+{
+ outb_p(port, 0x108);
+ outb_p(wert, 0x109);
+}
+
+static inline u8 in_umc(char port)
+{
+ outb_p(port, 0x108);
+ return inb_p(0x109);
+}
+
+static void umc_set_speeds(u8 speeds[])
+{
+ int i, tmp;
+
+ outb_p(0x5A, 0x108); /* enable umc */
+
+ out_umc(0xd7, (speedtab[0][speeds[2]] | (speedtab[0][speeds[3]]<<4)));
+ out_umc(0xd6, (speedtab[0][speeds[0]] | (speedtab[0][speeds[1]]<<4)));
+ tmp = 0;
+ for (i = 3; i >= 0; i--)
+ tmp = (tmp << 2) | speedtab[1][speeds[i]];
+ out_umc(0xdc, tmp);
+ for (i = 0; i < 4; i++) {
+ out_umc(0xd0 + i, speedtab[2][speeds[i]]);
+ out_umc(0xd8 + i, speedtab[2][speeds[i]]);
+ }
+ outb_p(0xa5, 0x108); /* disable umc */
+
+ printk("umc8672: drive speeds [0 to 11]: %d %d %d %d\n",
+ speeds[0], speeds[1], speeds[2], speeds[3]);
+}
+
+static void umc_set_pio_mode(ide_drive_t *drive, const u8 pio)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ unsigned long flags;
+
+ printk("%s: setting umc8672 to PIO mode%d (speed %d)\n",
+ drive->name, pio, pio_to_umc[pio]);
+ spin_lock_irqsave(&ide_lock, flags);
+ if (hwif->mate && hwif->mate->hwgroup->handler) {
+ printk(KERN_ERR "umc8672: other interface is busy: exiting tune_umc()\n");
+ } else {
+ current_speeds[drive->name[2] - 'a'] = pio_to_umc[pio];
+ umc_set_speeds(current_speeds);
+ }
+ spin_unlock_irqrestore(&ide_lock, flags);
+}
+
+static const struct ide_port_ops umc8672_port_ops = {
+ .set_pio_mode = umc_set_pio_mode,
+};
+
+static const struct ide_port_info umc8672_port_info __initdata = {
+ .name = DRV_NAME,
+ .chipset = ide_umc8672,
+ .port_ops = &umc8672_port_ops,
+ .host_flags = IDE_HFLAG_NO_DMA,
+ .pio_mask = ATA_PIO4,
+};
+
+static int __init umc8672_probe(void)
+{
+ unsigned long flags;
+
+ if (!request_region(0x108, 2, "umc8672")) {
+ printk(KERN_ERR "umc8672: ports 0x108-0x109 already in use.\n");
+ return 1;
+ }
+ local_irq_save(flags);
+ outb_p(0x5A, 0x108); /* enable umc */
+ if (in_umc (0xd5) != 0xa0) {
+ local_irq_restore(flags);
+ printk(KERN_ERR "umc8672: not found\n");
+ release_region(0x108, 2);
+ return 1;
+ }
+ outb_p(0xa5, 0x108); /* disable umc */
+
+ umc_set_speeds(current_speeds);
+ local_irq_restore(flags);
+
+ return ide_legacy_device_add(&umc8672_port_info, 0);
+}
+
+static int probe_umc8672;
+
+module_param_named(probe, probe_umc8672, bool, 0);
+MODULE_PARM_DESC(probe, "probe for UMC8672 chipset");
+
+static int __init umc8672_init(void)
+{
+ if (probe_umc8672 == 0)
+ goto out;
+
+ if (umc8672_probe() == 0)
+ return 0;;
+out:
+ return -ENODEV;;
+}
+
+module_init(umc8672_init);
+
+MODULE_AUTHOR("Wolfram Podien");
+MODULE_DESCRIPTION("Support for UMC 8672 IDE chipset");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/via82cxxx.c b/drivers/ide/via82cxxx.c
new file mode 100644
index 0000000..2a812d3
--- /dev/null
+++ b/drivers/ide/via82cxxx.c
@@ -0,0 +1,514 @@
+/*
+ * VIA IDE driver for Linux. Supported southbridges:
+ *
+ * vt82c576, vt82c586, vt82c586a, vt82c586b, vt82c596a, vt82c596b,
+ * vt82c686, vt82c686a, vt82c686b, vt8231, vt8233, vt8233c, vt8233a,
+ * vt8235, vt8237, vt8237a
+ *
+ * Copyright (c) 2000-2002 Vojtech Pavlik
+ * Copyright (c) 2007 Bartlomiej Zolnierkiewicz
+ *
+ * Based on the work of:
+ * Michel Aubry
+ * Jeff Garzik
+ * Andre Hedrick
+ *
+ * Documentation:
+ * Obsolete device documentation publically available from via.com.tw
+ * Current device documentation available under NDA only
+ */
+
+/*
+ * 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/module.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/ide.h>
+#include <linux/dmi.h>
+
+#ifdef CONFIG_PPC_CHRP
+#include <asm/processor.h>
+#endif
+
+#define DRV_NAME "via82cxxx"
+
+#define VIA_IDE_ENABLE 0x40
+#define VIA_IDE_CONFIG 0x41
+#define VIA_FIFO_CONFIG 0x43
+#define VIA_MISC_1 0x44
+#define VIA_MISC_2 0x45
+#define VIA_MISC_3 0x46
+#define VIA_DRIVE_TIMING 0x48
+#define VIA_8BIT_TIMING 0x4e
+#define VIA_ADDRESS_SETUP 0x4c
+#define VIA_UDMA_TIMING 0x50
+
+#define VIA_BAD_PREQ 0x01 /* Crashes if PREQ# till DDACK# set */
+#define VIA_BAD_CLK66 0x02 /* 66 MHz clock doesn't work correctly */
+#define VIA_SET_FIFO 0x04 /* Needs to have FIFO split set */
+#define VIA_NO_UNMASK 0x08 /* Doesn't work with IRQ unmasking on */
+#define VIA_BAD_ID 0x10 /* Has wrong vendor ID (0x1107) */
+#define VIA_BAD_AST 0x20 /* Don't touch Address Setup Timing */
+
+/*
+ * VIA SouthBridge chips.
+ */
+
+static struct via_isa_bridge {
+ char *name;
+ u16 id;
+ u8 rev_min;
+ u8 rev_max;
+ u8 udma_mask;
+ u8 flags;
+} via_isa_bridges[] = {
+ { "vx800", PCI_DEVICE_ID_VIA_VX800, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST },
+ { "cx700", PCI_DEVICE_ID_VIA_CX700, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST },
+ { "vt8237s", PCI_DEVICE_ID_VIA_8237S, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST },
+ { "vt6410", PCI_DEVICE_ID_VIA_6410, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST },
+ { "vt8251", PCI_DEVICE_ID_VIA_8251, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST },
+ { "vt8237", PCI_DEVICE_ID_VIA_8237, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST },
+ { "vt8237a", PCI_DEVICE_ID_VIA_8237A, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST },
+ { "vt8235", PCI_DEVICE_ID_VIA_8235, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST },
+ { "vt8233a", PCI_DEVICE_ID_VIA_8233A, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST },
+ { "vt8233c", PCI_DEVICE_ID_VIA_8233C_0, 0x00, 0x2f, ATA_UDMA5, },
+ { "vt8233", PCI_DEVICE_ID_VIA_8233_0, 0x00, 0x2f, ATA_UDMA5, },
+ { "vt8231", PCI_DEVICE_ID_VIA_8231, 0x00, 0x2f, ATA_UDMA5, },
+ { "vt82c686b", PCI_DEVICE_ID_VIA_82C686, 0x40, 0x4f, ATA_UDMA5, },
+ { "vt82c686a", PCI_DEVICE_ID_VIA_82C686, 0x10, 0x2f, ATA_UDMA4, },
+ { "vt82c686", PCI_DEVICE_ID_VIA_82C686, 0x00, 0x0f, ATA_UDMA2, VIA_BAD_CLK66 },
+ { "vt82c596b", PCI_DEVICE_ID_VIA_82C596, 0x10, 0x2f, ATA_UDMA4, },
+ { "vt82c596a", PCI_DEVICE_ID_VIA_82C596, 0x00, 0x0f, ATA_UDMA2, VIA_BAD_CLK66 },
+ { "vt82c586b", PCI_DEVICE_ID_VIA_82C586_0, 0x47, 0x4f, ATA_UDMA2, VIA_SET_FIFO },
+ { "vt82c586b", PCI_DEVICE_ID_VIA_82C586_0, 0x40, 0x46, ATA_UDMA2, VIA_SET_FIFO | VIA_BAD_PREQ },
+ { "vt82c586b", PCI_DEVICE_ID_VIA_82C586_0, 0x30, 0x3f, ATA_UDMA2, VIA_SET_FIFO },
+ { "vt82c586a", PCI_DEVICE_ID_VIA_82C586_0, 0x20, 0x2f, ATA_UDMA2, VIA_SET_FIFO },
+ { "vt82c586", PCI_DEVICE_ID_VIA_82C586_0, 0x00, 0x0f, 0x00, VIA_SET_FIFO },
+ { "vt82c576", PCI_DEVICE_ID_VIA_82C576, 0x00, 0x2f, 0x00, VIA_SET_FIFO | VIA_NO_UNMASK },
+ { "vt82c576", PCI_DEVICE_ID_VIA_82C576, 0x00, 0x2f, 0x00, VIA_SET_FIFO | VIA_NO_UNMASK | VIA_BAD_ID },
+ { NULL }
+};
+
+static unsigned int via_clock;
+static char *via_dma[] = { "16", "25", "33", "44", "66", "100", "133" };
+
+struct via82cxxx_dev
+{
+ struct via_isa_bridge *via_config;
+ unsigned int via_80w;
+};
+
+/**
+ * via_set_speed - write timing registers
+ * @dev: PCI device
+ * @dn: device
+ * @timing: IDE timing data to use
+ *
+ * via_set_speed writes timing values to the chipset registers
+ */
+
+static void via_set_speed(ide_hwif_t *hwif, u8 dn, struct ide_timing *timing)
+{
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+ struct ide_host *host = pci_get_drvdata(dev);
+ struct via82cxxx_dev *vdev = host->host_priv;
+ u8 t;
+
+ if (~vdev->via_config->flags & VIA_BAD_AST) {
+ pci_read_config_byte(dev, VIA_ADDRESS_SETUP, &t);
+ t = (t & ~(3 << ((3 - dn) << 1))) | ((clamp_val(timing->setup, 1, 4) - 1) << ((3 - dn) << 1));
+ pci_write_config_byte(dev, VIA_ADDRESS_SETUP, t);
+ }
+
+ pci_write_config_byte(dev, VIA_8BIT_TIMING + (1 - (dn >> 1)),
+ ((clamp_val(timing->act8b, 1, 16) - 1) << 4) | (clamp_val(timing->rec8b, 1, 16) - 1));
+
+ pci_write_config_byte(dev, VIA_DRIVE_TIMING + (3 - dn),
+ ((clamp_val(timing->active, 1, 16) - 1) << 4) | (clamp_val(timing->recover, 1, 16) - 1));
+
+ switch (vdev->via_config->udma_mask) {
+ case ATA_UDMA2: t = timing->udma ? (0xe0 | (clamp_val(timing->udma, 2, 5) - 2)) : 0x03; break;
+ case ATA_UDMA4: t = timing->udma ? (0xe8 | (clamp_val(timing->udma, 2, 9) - 2)) : 0x0f; break;
+ case ATA_UDMA5: t = timing->udma ? (0xe0 | (clamp_val(timing->udma, 2, 9) - 2)) : 0x07; break;
+ case ATA_UDMA6: t = timing->udma ? (0xe0 | (clamp_val(timing->udma, 2, 9) - 2)) : 0x07; break;
+ default: return;
+ }
+
+ pci_write_config_byte(dev, VIA_UDMA_TIMING + (3 - dn), t);
+}
+
+/**
+ * via_set_drive - configure transfer mode
+ * @drive: Drive to set up
+ * @speed: desired speed
+ *
+ * via_set_drive() computes timing values configures the chipset to
+ * a desired transfer mode. It also can be called by upper layers.
+ */
+
+static void via_set_drive(ide_drive_t *drive, const u8 speed)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ ide_drive_t *peer = ide_get_pair_dev(drive);
+ struct pci_dev *dev = to_pci_dev(hwif->dev);
+ struct ide_host *host = pci_get_drvdata(dev);
+ struct via82cxxx_dev *vdev = host->host_priv;
+ struct ide_timing t, p;
+ unsigned int T, UT;
+
+ T = 1000000000 / via_clock;
+
+ switch (vdev->via_config->udma_mask) {
+ case ATA_UDMA2: UT = T; break;
+ case ATA_UDMA4: UT = T/2; break;
+ case ATA_UDMA5: UT = T/3; break;
+ case ATA_UDMA6: UT = T/4; break;
+ default: UT = T;
+ }
+
+ ide_timing_compute(drive, speed, &t, T, UT);
+
+ if (peer) {
+ ide_timing_compute(peer, peer->current_speed, &p, T, UT);
+ ide_timing_merge(&p, &t, &t, IDE_TIMING_8BIT);
+ }
+
+ via_set_speed(HWIF(drive), drive->dn, &t);
+}
+
+/**
+ * via_set_pio_mode - set host controller for PIO mode
+ * @drive: drive
+ * @pio: PIO mode number
+ *
+ * A callback from the upper layers for PIO-only tuning.
+ */
+
+static void via_set_pio_mode(ide_drive_t *drive, const u8 pio)
+{
+ via_set_drive(drive, XFER_PIO_0 + pio);
+}
+
+static struct via_isa_bridge *via_config_find(struct pci_dev **isa)
+{
+ struct via_isa_bridge *via_config;
+
+ for (via_config = via_isa_bridges; via_config->id; via_config++)
+ if ((*isa = pci_get_device(PCI_VENDOR_ID_VIA +
+ !!(via_config->flags & VIA_BAD_ID),
+ via_config->id, NULL))) {
+
+ if ((*isa)->revision >= via_config->rev_min &&
+ (*isa)->revision <= via_config->rev_max)
+ break;
+ pci_dev_put(*isa);
+ }
+
+ return via_config;
+}
+
+/*
+ * Check and handle 80-wire cable presence
+ */
+static void via_cable_detect(struct via82cxxx_dev *vdev, u32 u)
+{
+ int i;
+
+ switch (vdev->via_config->udma_mask) {
+ case ATA_UDMA4:
+ for (i = 24; i >= 0; i -= 8)
+ if (((u >> (i & 16)) & 8) &&
+ ((u >> i) & 0x20) &&
+ (((u >> i) & 7) < 2)) {
+ /*
+ * 2x PCI clock and
+ * UDMA w/ < 3T/cycle
+ */
+ vdev->via_80w |= (1 << (1 - (i >> 4)));
+ }
+ break;
+
+ case ATA_UDMA5:
+ for (i = 24; i >= 0; i -= 8)
+ if (((u >> i) & 0x10) ||
+ (((u >> i) & 0x20) &&
+ (((u >> i) & 7) < 4))) {
+ /* BIOS 80-wire bit or
+ * UDMA w/ < 60ns/cycle
+ */
+ vdev->via_80w |= (1 << (1 - (i >> 4)));
+ }
+ break;
+
+ case ATA_UDMA6:
+ for (i = 24; i >= 0; i -= 8)
+ if (((u >> i) & 0x10) ||
+ (((u >> i) & 0x20) &&
+ (((u >> i) & 7) < 6))) {
+ /* BIOS 80-wire bit or
+ * UDMA w/ < 60ns/cycle
+ */
+ vdev->via_80w |= (1 << (1 - (i >> 4)));
+ }
+ break;
+ }
+}
+
+/**
+ * init_chipset_via82cxxx - initialization handler
+ * @dev: PCI device
+ *
+ * The initialization callback. Here we determine the IDE chip type
+ * and initialize its drive independent registers.
+ */
+
+static unsigned int init_chipset_via82cxxx(struct pci_dev *dev)
+{
+ struct ide_host *host = pci_get_drvdata(dev);
+ struct via82cxxx_dev *vdev = host->host_priv;
+ struct via_isa_bridge *via_config = vdev->via_config;
+ u8 t, v;
+ u32 u;
+
+ /*
+ * Detect cable and configure Clk66
+ */
+ pci_read_config_dword(dev, VIA_UDMA_TIMING, &u);
+
+ via_cable_detect(vdev, u);
+
+ if (via_config->udma_mask == ATA_UDMA4) {
+ /* Enable Clk66 */
+ pci_write_config_dword(dev, VIA_UDMA_TIMING, u|0x80008);
+ } else if (via_config->flags & VIA_BAD_CLK66) {
+ /* Would cause trouble on 596a and 686 */
+ pci_write_config_dword(dev, VIA_UDMA_TIMING, u & ~0x80008);
+ }
+
+ /*
+ * Check whether interfaces are enabled.
+ */
+
+ pci_read_config_byte(dev, VIA_IDE_ENABLE, &v);
+
+ /*
+ * Set up FIFO sizes and thresholds.
+ */
+
+ pci_read_config_byte(dev, VIA_FIFO_CONFIG, &t);
+
+ /* Disable PREQ# till DDACK# */
+ if (via_config->flags & VIA_BAD_PREQ) {
+ /* Would crash on 586b rev 41 */
+ t &= 0x7f;
+ }
+
+ /* Fix FIFO split between channels */
+ if (via_config->flags & VIA_SET_FIFO) {
+ t &= (t & 0x9f);
+ switch (v & 3) {
+ case 2: t |= 0x00; break; /* 16 on primary */
+ case 1: t |= 0x60; break; /* 16 on secondary */
+ case 3: t |= 0x20; break; /* 8 pri 8 sec */
+ }
+ }
+
+ pci_write_config_byte(dev, VIA_FIFO_CONFIG, t);
+
+ return 0;
+}
+
+/*
+ * Cable special cases
+ */
+
+static const struct dmi_system_id cable_dmi_table[] = {
+ {
+ .ident = "Acer Ferrari 3400",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "Acer,Inc."),
+ DMI_MATCH(DMI_BOARD_NAME, "Ferrari 3400"),
+ },
+ },
+ { }
+};
+
+static int via_cable_override(struct pci_dev *pdev)
+{
+ /* Systems by DMI */
+ if (dmi_check_system(cable_dmi_table))
+ return 1;
+
+ /* Arima W730-K8/Targa Visionary 811/... */
+ if (pdev->subsystem_vendor == 0x161F &&
+ pdev->subsystem_device == 0x2032)
+ return 1;
+
+ return 0;
+}
+
+static u8 via82cxxx_cable_detect(ide_hwif_t *hwif)
+{
+ struct pci_dev *pdev = to_pci_dev(hwif->dev);
+ struct ide_host *host = pci_get_drvdata(pdev);
+ struct via82cxxx_dev *vdev = host->host_priv;
+
+ if (via_cable_override(pdev))
+ return ATA_CBL_PATA40_SHORT;
+
+ if ((vdev->via_80w >> hwif->channel) & 1)
+ return ATA_CBL_PATA80;
+ else
+ return ATA_CBL_PATA40;
+}
+
+static const struct ide_port_ops via_port_ops = {
+ .set_pio_mode = via_set_pio_mode,
+ .set_dma_mode = via_set_drive,
+ .cable_detect = via82cxxx_cable_detect,
+};
+
+static const struct ide_port_info via82cxxx_chipset __devinitdata = {
+ .name = DRV_NAME,
+ .init_chipset = init_chipset_via82cxxx,
+ .enablebits = { { 0x40, 0x02, 0x02 }, { 0x40, 0x01, 0x01 } },
+ .port_ops = &via_port_ops,
+ .host_flags = IDE_HFLAG_PIO_NO_BLACKLIST |
+ IDE_HFLAG_POST_SET_MODE |
+ IDE_HFLAG_IO_32BIT,
+ .pio_mask = ATA_PIO5,
+ .swdma_mask = ATA_SWDMA2,
+ .mwdma_mask = ATA_MWDMA2,
+};
+
+static int __devinit via_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ struct pci_dev *isa = NULL;
+ struct via_isa_bridge *via_config;
+ struct via82cxxx_dev *vdev;
+ int rc;
+ u8 idx = id->driver_data;
+ struct ide_port_info d;
+
+ d = via82cxxx_chipset;
+
+ /*
+ * Find the ISA bridge and check we know what it is.
+ */
+ via_config = via_config_find(&isa);
+ if (!via_config->id) {
+ printk(KERN_WARNING DRV_NAME " %s: unknown chipset, skipping\n",
+ pci_name(dev));
+ return -ENODEV;
+ }
+
+ /*
+ * Print the boot message.
+ */
+ printk(KERN_INFO DRV_NAME " %s: VIA %s (rev %02x) IDE %sDMA%s\n",
+ pci_name(dev), via_config->name, isa->revision,
+ via_config->udma_mask ? "U" : "MW",
+ via_dma[via_config->udma_mask ?
+ (fls(via_config->udma_mask) - 1) : 0]);
+
+ pci_dev_put(isa);
+
+ /*
+ * Determine system bus clock.
+ */
+ via_clock = (ide_pci_clk ? ide_pci_clk : 33) * 1000;
+
+ switch (via_clock) {
+ case 33000: via_clock = 33333; break;
+ case 37000: via_clock = 37500; break;
+ case 41000: via_clock = 41666; break;
+ }
+
+ if (via_clock < 20000 || via_clock > 50000) {
+ printk(KERN_WARNING DRV_NAME ": User given PCI clock speed "
+ "impossible (%d), using 33 MHz instead.\n", via_clock);
+ printk(KERN_WARNING DRV_NAME ": Use ide0=ata66 if you want "
+ "to assume 80-wire cable.\n");
+ via_clock = 33333;
+ }
+
+ if (idx == 0)
+ d.host_flags |= IDE_HFLAG_NO_AUTODMA;
+ else
+ d.enablebits[1].reg = d.enablebits[0].reg = 0;
+
+ if ((via_config->flags & VIA_NO_UNMASK) == 0)
+ d.host_flags |= IDE_HFLAG_UNMASK_IRQS;
+
+#ifdef CONFIG_PPC_CHRP
+ if (machine_is(chrp) && _chrp_type == _CHRP_Pegasos)
+ d.host_flags |= IDE_HFLAG_FORCE_LEGACY_IRQS;
+#endif
+
+ d.udma_mask = via_config->udma_mask;
+
+ vdev = kzalloc(sizeof(*vdev), GFP_KERNEL);
+ if (!vdev) {
+ printk(KERN_ERR DRV_NAME " %s: out of memory :(\n",
+ pci_name(dev));
+ return -ENOMEM;
+ }
+
+ vdev->via_config = via_config;
+
+ rc = ide_pci_init_one(dev, &d, vdev);
+ if (rc)
+ kfree(vdev);
+
+ return rc;
+}
+
+static void __devexit via_remove(struct pci_dev *dev)
+{
+ struct ide_host *host = pci_get_drvdata(dev);
+ struct via82cxxx_dev *vdev = host->host_priv;
+
+ ide_pci_remove(dev);
+ kfree(vdev);
+}
+
+static const struct pci_device_id via_pci_tbl[] = {
+ { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_82C576_1), 0 },
+ { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_82C586_1), 0 },
+ { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_CX700_IDE), 0 },
+ { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_6410), 1 },
+ { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_SATA_EIDE), 1 },
+ { 0, },
+};
+MODULE_DEVICE_TABLE(pci, via_pci_tbl);
+
+static struct pci_driver via_pci_driver = {
+ .name = "VIA_IDE",
+ .id_table = via_pci_tbl,
+ .probe = via_init_one,
+ .remove = __devexit_p(via_remove),
+ .suspend = ide_pci_suspend,
+ .resume = ide_pci_resume,
+};
+
+static int __init via_ide_init(void)
+{
+ return ide_pci_register_driver(&via_pci_driver);
+}
+
+static void __exit via_ide_exit(void)
+{
+ pci_unregister_driver(&via_pci_driver);
+}
+
+module_init(via_ide_init);
+module_exit(via_ide_exit);
+
+MODULE_AUTHOR("Vojtech Pavlik, Michel Aubry, Jeff Garzik, Andre Hedrick");
+MODULE_DESCRIPTION("PCI driver module for VIA IDE");
+MODULE_LICENSE("GPL");
OpenPOWER on IntegriCloud