aboutsummaryrefslogtreecommitdiff
path: root/drivers/ide
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/ide')
-rw-r--r--drivers/ide/Kconfig1056
-rw-r--r--drivers/ide/Makefile54
-rw-r--r--drivers/ide/arm/Makefile6
-rw-r--r--drivers/ide/arm/bast-ide.c71
-rw-r--r--drivers/ide/arm/icside.c870
-rw-r--r--drivers/ide/arm/ide_arm.c43
-rw-r--r--drivers/ide/arm/rapide.c125
-rw-r--r--drivers/ide/cris/Makefile3
-rw-r--r--drivers/ide/cris/ide-v10.c842
-rw-r--r--drivers/ide/h8300/ide-h8300.c119
-rw-r--r--drivers/ide/ide-cd.c3524
-rw-r--r--drivers/ide/ide-cd.h746
-rw-r--r--drivers/ide/ide-disk.c1280
-rw-r--r--drivers/ide/ide-dma.c959
-rw-r--r--drivers/ide/ide-floppy.c2211
-rw-r--r--drivers/ide/ide-generic.c32
-rw-r--r--drivers/ide/ide-io.c1681
-rw-r--r--drivers/ide/ide-iops.c1285
-rw-r--r--drivers/ide/ide-lib.c622
-rw-r--r--drivers/ide/ide-pnp.c75
-rw-r--r--drivers/ide/ide-probe.c1421
-rw-r--r--drivers/ide/ide-proc.c521
-rw-r--r--drivers/ide/ide-tape.c4937
-rw-r--r--drivers/ide/ide-taskfile.c884
-rw-r--r--drivers/ide/ide-timing.h281
-rw-r--r--drivers/ide/ide.c2269
-rw-r--r--drivers/ide/legacy/Makefile13
-rw-r--r--drivers/ide/legacy/ali14xx.c253
-rw-r--r--drivers/ide/legacy/buddha.c235
-rw-r--r--drivers/ide/legacy/dtc2278.c165
-rw-r--r--drivers/ide/legacy/falconide.c78
-rw-r--r--drivers/ide/legacy/gayle.c186
-rw-r--r--drivers/ide/legacy/hd.c864
-rw-r--r--drivers/ide/legacy/ht6560b.c370
-rw-r--r--drivers/ide/legacy/ide-cs.c481
-rw-r--r--drivers/ide/legacy/macide.c155
-rw-r--r--drivers/ide/legacy/q40ide.c150
-rw-r--r--drivers/ide/legacy/qd65xx.c511
-rw-r--r--drivers/ide/legacy/qd65xx.h140
-rw-r--r--drivers/ide/legacy/umc8672.c183
-rw-r--r--drivers/ide/pci/Makefile34
-rw-r--r--drivers/ide/pci/aec62xx.c485
-rw-r--r--drivers/ide/pci/alim15x3.c913
-rw-r--r--drivers/ide/pci/amd74xx.c543
-rw-r--r--drivers/ide/pci/atiixp.c370
-rw-r--r--drivers/ide/pci/cmd640.c879
-rw-r--r--drivers/ide/pci/cmd64x.c821
-rw-r--r--drivers/ide/pci/cs5520.c274
-rw-r--r--drivers/ide/pci/cs5530.c384
-rw-r--r--drivers/ide/pci/cy82c693.c531
-rw-r--r--drivers/ide/pci/generic.c232
-rw-r--r--drivers/ide/pci/hpt34x.c278
-rw-r--r--drivers/ide/pci/hpt366.c1745
-rw-r--r--drivers/ide/pci/it8172.c308
-rw-r--r--drivers/ide/pci/ns87415.c315
-rw-r--r--drivers/ide/pci/opti621.c394
-rw-r--r--drivers/ide/pci/pdc202xx_new.c508
-rw-r--r--drivers/ide/pci/pdc202xx_old.c892
-rw-r--r--drivers/ide/pci/piix.c670
-rw-r--r--drivers/ide/pci/rz1000.c91
-rw-r--r--drivers/ide/pci/sc1200.c518
-rw-r--r--drivers/ide/pci/serverworks.c675
-rw-r--r--drivers/ide/pci/sgiioc4.c728
-rw-r--r--drivers/ide/pci/siimage.c1133
-rw-r--r--drivers/ide/pci/sis5513.c984
-rw-r--r--drivers/ide/pci/sl82c105.c516
-rw-r--r--drivers/ide/pci/slc90e66.c273
-rw-r--r--drivers/ide/pci/triflex.c188
-rw-r--r--drivers/ide/pci/trm290.c369
-rw-r--r--drivers/ide/pci/via82cxxx.c656
-rw-r--r--drivers/ide/ppc/mpc8xx.c855
-rw-r--r--drivers/ide/ppc/pmac.c2208
-rw-r--r--drivers/ide/setup-pci.c901
73 files changed, 50372 insertions, 0 deletions
diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig
new file mode 100644
index 000000000000..3ac0a535b4aa
--- /dev/null
+++ b/drivers/ide/Kconfig
@@ -0,0 +1,1056 @@
+#
+# IDE ATA ATAPI Block device driver configuration
+#
+# Andre Hedrick <andre@linux-ide.org>
+#
+
+menu "ATA/ATAPI/MFM/RLL support"
+
+config IDE
+ tristate "ATA/ATAPI/MFM/RLL support"
+ ---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.txt>.
+
+ If unsure, say Y.
+
+if IDE
+
+config IDE_MAX_HWIFS
+ int "Max IDE interfaces"
+ depends on ALPHA || SUPERH
+ default 4
+ help
+ This is the maximum number of IDE hardware interfaces that will
+ be supported by the driver. Make sure it is at least as high as
+ the number of IDE interfaces in your system.
+
+config BLK_DEV_IDE
+ tristate "Enhanced IDE/MFM/RLL disk/cdrom/tape/floppy support"
+ ---help---
+ If you say Y here, you will use the full-featured IDE driver to
+ control up to ten ATA/IDE interfaces, each being able to serve a
+ "master" and a "slave" device, for a total of up to twenty ATA/IDE
+ disk/cdrom/tape/floppy drives.
+
+ Useful information about large (>540 MB) IDE disks, multiple
+ interfaces, what to do if ATA/IDE devices are not automatically
+ detected, sound card ATA/IDE ports, module support, and other
+ topics, is contained in <file:Documentation/ide.txt>. For detailed
+ information about hard drives, consult the Disk-HOWTO and the
+ Multi-Disk-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ To fine-tune ATA/IDE drive/interface parameters for improved
+ performance, look for the hdparm package at
+ <ftp://ibiblio.org/pub/Linux/system/hardware/>.
+
+ To compile this driver as a module, choose M here and read
+ <file:Documentation/ide.txt>. The module will be called ide-mod.
+ Do not compile this driver as a module if your root file system (the
+ one containing the directory /) is located on an IDE device.
+
+ If you have one or more IDE drives, say Y or M here. If your system
+ has no IDE drives, or if memory requirements are really tight, you
+ could say N here, and select the "Old hard disk driver" below
+ instead to save about 13 KB of memory in the kernel.
+
+if BLK_DEV_IDE
+
+comment "Please see Documentation/ide.txt for help/info on IDE drives"
+
+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", exists inside the SCSI subsystem
+ and supports most modern SATA controllers.
+
+ 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 BLK_DEV_HD_IDE
+ bool "Use old disk-only driver on primary interface"
+ depends on (X86 || SH_MPC1211)
+ ---help---
+ There are two drivers for MFM/RLL/IDE disks. Most people use just
+ the new enhanced driver by itself. This option however installs the
+ old hard disk driver to control the primary IDE/disk interface in
+ the system, leaving the new enhanced IDE driver to take care of only
+ the 2nd/3rd/4th IDE interfaces. Doing this will prevent you from
+ having an IDE/ATAPI CD-ROM or tape drive connected to the primary
+ IDE interface. Choosing this option may be useful for older systems
+ which have MFM/RLL/ESDI controller+drives at the primary port
+ address (0x1f0), along with IDE drives at the secondary/3rd/4th port
+ addresses.
+
+ Normally, just say N here; you will then use the new driver for all
+ 4 interfaces.
+
+config BLK_DEV_IDEDISK
+ tristate "Include IDE/ATA-2 DISK support"
+ ---help---
+ This will include enhanced support for MFM/RLL/IDE hard disks. If
+ you have a MFM/RLL/IDE disk, and there is no special reason to use
+ the old hard disk driver instead, say Y. If you have an SCSI-only
+ system, you can say N here.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ide-disk.
+ Do not compile this driver as a module if your root file system
+ (the one containing the directory /) is located on the IDE disk.
+
+ If unsure, say Y.
+
+config IDEDISK_MULTI_MODE
+ bool "Use multi-mode by default"
+ help
+ If you get this error, try to say Y here:
+
+ hda: set_multmode: status=0x51 { DriveReady SeekComplete Error }
+ hda: set_multmode: error=0x04 { DriveStatusError }
+
+ If in doubt, say N.
+
+config BLK_DEV_IDECS
+ tristate "PCMCIA IDE support"
+ depends on PCMCIA
+ help
+ Support for outboard IDE disks, tape drives, and CD-ROM drives
+ connected through a PCMCIA card.
+
+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".
+
+ Note that older versions of LILO (LInux LOader) cannot properly deal
+ with IDE/ATAPI CD-ROMs, so install LILO 16 or higher, available from
+ <http://lilo.go.dyndns.org/>.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ide-cd.
+
+config BLK_DEV_IDETAPE
+ tristate "Include IDE/ATAPI TAPE support (EXPERIMENTAL)"
+ depends on EXPERIMENTAL
+ 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.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_IDEFLOPPY
+ tristate "Include IDE/ATAPI FLOPPY support"
+ ---help---
+ If you have an IDE floppy drive which uses the ATAPI protocol,
+ answer Y. ATAPI is a newer protocol used by IDE CD-ROM/tape/floppy
+ drives, similar to the SCSI protocol.
+
+ The LS-120 and the IDE/ATAPI Iomega ZIP drive are also supported by
+ this driver. 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>.
+ (ATAPI PD-CD/CDR drives are not supported by this driver; support
+ for PD-CD/CDR drives is available if you answer Y to
+ "SCSI emulation support", below).
+
+ If you say Y here, the FLOPPY drive will be identified along with
+ other IDE devices, as "hdb" or "hdc", or something similar (check
+ the boot messages with dmesg).
+
+ To compile this driver as a module, choose M here: the
+ module will be called ide-floppy.
+
+config BLK_DEV_IDESCSI
+ tristate "SCSI emulation support"
+ depends on SCSI
+ ---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.
+
+ This is useful if you have an ATAPI device for which no native
+ driver has been written (for example, an ATAPI PD-CD drive);
+ you can then use this emulation together with an appropriate SCSI
+ device driver. In order to do this, say Y here and to "SCSI support"
+ and "SCSI generic support", below. You must then provide the kernel
+ command line "hdx=ide-scsi" (try "man bootparam" or see the
+ documentation of your boot loader (lilo or loadlin) about how to
+ pass options to the kernel at boot time) for devices if you want the
+ native EIDE sub-drivers to skip over the native support, so that
+ this SCSI emulation can be used instead.
+
+ Note that this option does NOT allow you to attach SCSI devices to a
+ box that doesn't have a SCSI host adapter installed.
+
+ If both this SCSI emulation and native ATAPI support are compiled
+ into the kernel, the native support will be used.
+
+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 recover if needed. This is the most
+ basic form of media-forensics.
+
+ If you are unsure, say N here.
+
+comment "IDE chipset support/bugfixes"
+
+config IDE_GENERIC
+ tristate "generic/default IDE chipset support"
+ default y
+ help
+ If unsure, say Y.
+
+config BLK_DEV_CMD640
+ bool "CMD640 chipset bugfix/support"
+ depends on X86
+ ---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: "ide0=cmd640_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.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.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
+ bool "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_IDEPCI
+ bool "PCI IDE chipset support" if PCI
+ default BLK_DEV_IDEDMA_PMAC if PPC_PMAC && BLK_DEV_IDEDMA_PMAC
+ help
+ Say Y here for PCI systems which use IDE drive(s).
+ This option helps the IDE driver to automatically detect and
+ configure all PCI-based IDE interfaces in your system.
+
+config IDEPCI_SHARE_IRQ
+ bool "Sharing PCI IDE interrupts support"
+ depends on PCI && BLK_DEV_IDEPCI
+ help
+ Some ATA/IDE chipsets have hardware support which allows for
+ sharing a single IRQ with other cards. To enable support for
+ this in the ATA/IDE driver, say Y here.
+
+ It is safe to say Y to this question, in most cases.
+ If unsure, say N.
+
+config BLK_DEV_OFFBOARD
+ bool "Boot off-board chipsets first support"
+ depends on PCI && BLK_DEV_IDEPCI
+ 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.
+
+ If you say Y here, and you actually want to reverse the device scan
+ order as explained above, you also need to issue the kernel command
+ line option "ide=reverse". (Try "man bootparam" or see the
+ documentation of your boot loader (lilo or loadlin) about how to
+ pass options to the kernel at boot time.)
+
+ Note that, if you do this, the order of the hd* devices will be
+ rearranged which may require modification of fstab and other files.
+
+ If in doubt, say N.
+
+config BLK_DEV_GENERIC
+ tristate "Generic PCI IDE Chipset Support"
+ depends on BLK_DEV_IDEPCI
+
+config BLK_DEV_OPTI621
+ tristate "OPTi 82C621 chipset enhanced support (EXPERIMENTAL)"
+ depends on PCI && BLK_DEV_IDEPCI && EXPERIMENTAL
+ 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 PCI && BLK_DEV_IDEPCI && X86
+ 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_SL82C105
+ tristate "Winbond SL82c105 support"
+ depends on PCI && (PPC || ARM) && BLK_DEV_IDEPCI
+ 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_IDEDMA_PCI
+ bool "Generic PCI bus-master DMA support"
+ depends on PCI && BLK_DEV_IDEPCI
+ ---help---
+ If your PCI system uses IDE drive(s) (as opposed to SCSI, say) and
+ is capable of bus-master DMA operation (most Pentium PCI systems),
+ you will want to say Y here to reduce CPU overhead. You can then use
+ the "hdparm" utility to enable DMA for drives for which it was not
+ enabled automatically. By default, DMA is not enabled automatically
+ for these drives, but you can change that by saying Y to the
+ following question "Use DMA by default when available". You can get
+ the latest version of the hdparm utility from
+ <ftp://ibiblio.org/pub/Linux/system/hardware/>.
+
+ Read the comments at the beginning of <file:drivers/ide/ide-dma.c>
+ and the file <file:Documentation/ide.txt> for more information.
+
+ It is safe to say Y to this question.
+
+if BLK_DEV_IDEDMA_PCI
+
+config BLK_DEV_IDEDMA_FORCED
+ bool "Force enable legacy 2.0.X HOSTS to use DMA"
+ help
+ This is an old piece of lost code from Linux 2.0 Kernels.
+
+ Generally say N here.
+
+config IDEDMA_PCI_AUTO
+ bool "Use PCI DMA by default when available"
+ ---help---
+ Prior to kernel version 2.1.112, Linux used to automatically use
+ DMA for IDE drives and chipsets which support it. Due to concerns
+ about a couple of cases where buggy hardware may have caused damage,
+ the default is now to NOT use DMA automatically. To revert to the
+ previous behaviour, say Y to this question.
+
+ If you suspect your hardware is at all flakey, say N here.
+ Do NOT email the IDE kernel people regarding this issue!
+
+ It is normally safe to answer Y to this question unless your
+ motherboard uses a VIA VP2 chipset, in which case you should say N.
+
+config IDEDMA_ONLYDISK
+ bool "Enable DMA only for disks "
+ depends on IDEDMA_PCI_AUTO
+ help
+ This is used if you know your ATAPI Devices are going to fail DMA
+ Transfers.
+
+ Generally say N here.
+
+config BLK_DEV_AEC62XX
+ tristate "AEC62XX chipset support"
+ 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"
+ 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.
+
+ If you say Y here, you also need to say Y to "Use DMA by default
+ when available", above. Please read the comments at the top of
+ <file:drivers/ide/pci/alim15x3.c>.
+
+ If unsure, say N.
+
+config WDC_ALI15X3
+ bool "ALI M15x3 WDC support (DANGEROUS)"
+ depends on BLK_DEV_ALI15X3
+ ---help---
+ This allows for UltraDMA support for WDC drives that ignore CRC
+ checking. You are a fool for enabling this option, but there have
+ been requests. DO NOT COMPLAIN IF YOUR DRIVE HAS FS CORRUPTION, IF
+ YOU ENABLE THIS! No one will listen, just laugh for ignoring this
+ SERIOUS WARNING.
+
+ Using this option can allow WDC drives to run at ATA-4/5 transfer
+ rates with only an ATA-2 support structure.
+
+ SAY N!
+
+config BLK_DEV_AMD74XX
+ tristate "AMD and nVidia IDE support"
+ 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
+ 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"
+ 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"
+ 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"
+ help
+ This driver adds detection and support for the CY82C693 chipset
+ used on Digital's PC-Alpha 164SX boards.
+
+ If you say Y here, you need to say Y to "Use DMA by default
+ when available" as well.
+
+config BLK_DEV_CS5520
+ tristate "Cyrix CS5510/20 MediaGX chipset support (VERY EXPERIMENTAL)"
+ depends on EXPERIMENTAL
+ help
+ Include support for PIO tuning an 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"
+ 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_HPT34X
+ tristate "HPT34X chipset support"
+ help
+ This driver adds up to 4 more EIDE devices sharing a single
+ interrupt. The HPT343 chipset in its current form is a non-bootable
+ controller; the HPT345/HPT363 chipset is a bootable (needs BIOS FIX)
+ PCI UDMA controllers. This driver requires dynamic tuning of the
+ chipset during the ide-probe at boot time. It is reported to support
+ DVD II drives, by the manufacturer.
+
+config HPT34X_AUTODMA
+ bool "HPT34X AUTODMA support (EXPERIMENTAL)"
+ depends on BLK_DEV_HPT34X && EXPERIMENTAL
+ help
+ This is a dangerous thing to attempt currently! Please read the
+ comments at the top of <file:drivers/ide/pci/hpt34x.c>. If you say Y
+ here, then say Y to "Use DMA by default when available" as well.
+
+ If unsure, say N.
+
+config BLK_DEV_HPT366
+ tristate "HPT36X/37X chipset support"
+ ---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 or include
+ "ide=reverse" in LILO's append-line.
+
+ 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_SC1200
+ tristate "National SCx200 chipset support"
+ help
+ This driver adds support for the built in IDE on the National
+ SCx200 series of embedded x86 "Geode" systems
+
+config BLK_DEV_PIIX
+ tristate "Intel PIIXn chipsets support"
+ help
+ This driver adds explicit support for Intel PIIX and ICH chips
+ and also for the Efar Victory66 (slc90e66) chip. This allows
+ the kernel to change PIO, DMA and UDMA speeds and to configure
+ the chip to optimum performance.
+
+config BLK_DEV_IT8172
+ bool "IT8172 IDE support"
+ depends on (MIPS_ITE8172 || MIPS_IVR)
+ help
+ Say Y here to support the on-board IDE controller on the Integrated
+ Technology Express, Inc. ITE8172 SBC. Vendor page at
+ <http://www.ite.com.tw/ia/brief_it8172bsp.htm>; picture of the
+ board at <http://www.mvista.com/partners/semiconductor/ite.html>.
+
+config BLK_DEV_NS87415
+ tristate "NS87415 chipset support"
+ help
+ This driver adds detection and support for the NS87415 chip
+ (used in SPARC64, among others).
+
+ 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"
+ 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. This card may require that you say Y to
+ "Special UDMA Feature".
+
+ If you say Y here, you need to say Y to "Use DMA by default when
+ available" as well.
+
+ Please read the comments at the top of
+ <file:drivers/ide/pci/pdc202xx_old.c>.
+
+ If unsure, say N.
+
+config PDC202XX_BURST
+ bool "Special UDMA Feature"
+ depends on BLK_DEV_PDC202XX_OLD
+ help
+ This option causes the pdc202xx driver to enable UDMA modes on the
+ PDC202xx even when the PDC202xx BIOS has not done so.
+
+ It was originally designed for the PDC20246/Ultra33, whose BIOS will
+ only setup UDMA on the first two PDC20246 cards. It has also been
+ used succesfully on a PDC20265/Ultra100, allowing use of UDMA modes
+ when the PDC20265 BIOS has been disabled (for faster boot up).
+
+ 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"
+
+# FIXME - probably wants to be one for old and for new
+config PDC202XX_FORCE
+ bool "Enable controller even if disabled by BIOS"
+ depends on BLK_DEV_PDC202XX_NEW
+ help
+ Enable the PDC202xx controller even if it has been disabled in the BIOS setup.
+
+config BLK_DEV_SVWKS
+ tristate "ServerWorks OSB4/CSB5/CSB6 chipsets support"
+ help
+ This driver adds PIO/(U)DMA support for the ServerWorks OSB4/CSB5
+ chipsets.
+
+config BLK_DEV_SGIIOC4
+ tristate "Silicon Graphics IOC4 chipset support"
+ depends on IA64_SGI_SN2 || IA64_GENERIC
+ 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"
+ 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
+ ---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
+
+ If you say Y here, you need to say Y to "Use DMA by default when
+ available" as well.
+
+ Please read the comments at the top of <file:drivers/ide/pci/sis5513.c>.
+
+config BLK_DEV_SLC90E66
+ tristate "SLC90E66 chipset support"
+ help
+ This driver ensures (U)DMA support for Victroy66 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.
+
+ If you say Y here, you need to say Y to "Use DMA by default when
+ available" as well.
+
+ Please read the comments at the top of
+ <file:drivers/ide/pci/slc90e66.c>.
+
+config BLK_DEV_TRM290
+ tristate "Tekram TRM290 chipset support"
+ 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"
+ 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.
+
+endif
+
+config BLK_DEV_IDE_PMAC
+ bool "Builtin PowerMac IDE support"
+ depends on PPC_PMAC && IDE=y
+ help
+ This driver provides support for the built-in IDE controller on
+ most of the recent Apple Power Macintoshes and PowerBooks.
+ If unsure, say Y.
+
+config BLK_DEV_IDE_PMAC_ATA100FIRST
+ bool "Probe internal 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_IDEDMA_PMAC
+ bool "PowerMac IDE DMA support"
+ depends on BLK_DEV_IDE_PMAC
+ help
+ This option allows the driver for the built-in IDE controller on
+ Power Macintoshes and PowerBooks to use DMA (direct memory access)
+ to transfer data to and from memory. Saying Y is safe and improves
+ performance.
+
+config BLK_DEV_IDE_PMAC_BLINK
+ bool "Blink laptop LED on drive activity"
+ depends on BLK_DEV_IDE_PMAC && ADB_PMU
+ help
+ This option enables the use of the sleep LED as a hard drive
+ activity LED.
+
+config IDE_ARM
+ def_bool ARM && (ARCH_A5K || ARCH_CLPS7500 || ARCH_RPC || ARCH_SHARK)
+
+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 IDEDMA_ICS_AUTO
+ bool "Use ICS DMA by default"
+ depends on BLK_DEV_IDEDMA_ICS
+ help
+ Prior to kernel version 2.1.112, Linux used to automatically use
+ DMA for IDE drives and chipsets which support it. Due to concerns
+ about a couple of cases where buggy hardware may have caused damage,
+ the default is now to NOT use DMA automatically. To revert to the
+ previous behaviour, say Y to this question.
+
+ If you suspect your hardware is at all flakey, say N here.
+ Do NOT email the IDE kernel people regarding this issue!
+
+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 BLK_DEV_IDE_BAST
+ tristate "Simtec BAST / Thorcom VR1000 IDE support"
+ depends on ARM && (ARCH_BAST || MACH_VR1000)
+ help
+ Say Y here if you want to support the onboard IDE channels on the
+ Simtec BAST or the Thorcom VR1000
+
+config BLK_DEV_GAYLE
+ bool "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 builtin 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 driver provides support for the so-called `IDE doublers' (made
+ by various manufacturers, e.g. Eyetech) that can be connected to the
+ builtin IDE interface of some Amiga models. Using such an IDE
+ doubler, you can connect up to four instead of two IDE devices on
+ the Amiga's builtin 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 driver!
+
+ Say Y if you have an IDE doubler. The driver is enabled at kernel
+ runtime using the "ide=doubler" kernel boot parameter.
+
+config BLK_DEV_BUDDHA
+ bool "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
+ bool "Falcon IDE interface support"
+ depends on ATARI
+ help
+ This is the IDE driver for the builtin 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 builtin IDE
+ interface.
+
+config BLK_DEV_MAC_IDE
+ bool "Macintosh Quadra/Powerbook IDE interface support"
+ depends on MAC
+ help
+ This is the IDE driver for the builtin 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
+ builtin IDE interface.
+
+config BLK_DEV_Q40IDE
+ bool "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_MPC8xx_IDE
+ bool "MPC8xx IDE support"
+ depends on 8xx
+ help
+ This option provides support for IDE on Motorola MPC8xx Systems.
+ Please see 'Type of MPC8xx IDE interface' for details.
+
+ If unsure, say N.
+
+choice
+ prompt "Type of MPC8xx IDE interface"
+ depends on BLK_DEV_MPC8xx_IDE
+ default IDE_8xx_PCCARD
+
+config IDE_8xx_PCCARD
+ bool "8xx_PCCARD"
+ ---help---
+ Select how the IDE devices are connected to the MPC8xx system:
+
+ 8xx_PCCARD uses the 8xx internal PCMCIA interface in combination
+ with a PC Card (e.g. ARGOSY portable Hard Disk Adapter),
+ ATA PC Card HDDs or ATA PC Flash Cards (example: TQM8xxL
+ systems)
+
+ 8xx_DIRECT is used for directly connected IDE devices using the 8xx
+ internal PCMCIA interface (example: IVMS8 systems)
+
+ EXT_DIRECT is used for IDE devices directly connected to the 8xx
+ bus using some glue logic, but _not_ the 8xx internal
+ PCMCIA interface (example: IDIF860 systems)
+
+config IDE_8xx_DIRECT
+ bool "8xx_DIRECT"
+
+config IDE_EXT_DIRECT
+ bool "EXT_DIRECT"
+
+endchoice
+
+# no isa -> no vlb
+config IDE_CHIPSETS
+ bool "Other IDE chipset support"
+ depends on ISA
+ ---help---
+ Say Y here if you want to include enhanced support for various IDE
+ interface chipsets used on motherboards and add-on cards. You can
+ then pick your particular IDE chip from among the following options.
+ This enhanced support may be necessary for Linux to be able to
+ access the 3rd/4th drives in some systems. It may also enable
+ setting of higher speed I/O rates to improve system performance with
+ these chipsets. Most of these also require special kernel boot
+ parameters to actually turn on the support at runtime; you can find
+ a list of these in the file <file:Documentation/ide.txt>.
+
+ People with SCSI-only systems can say N here.
+
+if IDE_CHIPSETS
+
+comment "Note: most of these also require special kernel boot parameters"
+
+config BLK_DEV_4DRIVES
+ bool "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 "ide0=four" kernel boot parameter if you say Y
+ here.
+
+config BLK_DEV_ALI14XX
+ tristate "ALI M14xx support"
+ help
+ This driver is enabled at runtime using the "ide0=ali14xx" 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.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 "ide0=dtc2278" 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.txt> and
+ <file:drivers/ide/legacy/dtc2278.c> files for more info.
+
+config BLK_DEV_HT6560B
+ tristate "Holtek HT6560B support"
+ help
+ This driver is enabled at runtime using the "ide0=ht6560b" 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.txt> and
+ <file:drivers/ide/legacy/ht6560b.c> files for more info.
+
+config BLK_DEV_QD65XX
+ tristate "QDI QD65xx support"
+ help
+ This driver is enabled at runtime using the "ide0=qd65xx" kernel
+ boot parameter. It permits faster I/O speeds to be set. See the
+ <file:Documentation/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 "ide0=umc8672" 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.txt> and
+ <file:drivers/ide/legacy/umc8672.c> for more info.
+
+endif
+
+config BLK_DEV_IDEDMA
+ def_bool BLK_DEV_IDEDMA_PCI || BLK_DEV_IDEDMA_PMAC || BLK_DEV_IDEDMA_ICS
+
+config IDEDMA_IVB
+ bool "IGNORE word93 Validation BITS"
+ depends on BLK_DEV_IDEDMA_PCI || BLK_DEV_IDEDMA_PMAC || BLK_DEV_IDEDMA_ICS
+ ---help---
+ There are unclear terms in ATA-4 and ATA-5 standards how certain
+ hardware (an 80c ribbon) should be detected. Different interpretations
+ of the standards have been released in hardware. This causes problems:
+ for example, a host with Ultra Mode 4 (or higher) will not run
+ in that mode with an 80c ribbon.
+
+ If you are experiencing compatibility or performance problems, you
+ MAY try to answering Y here. However, it does not necessarily solve
+ any of your problems, it could even cause more of them.
+
+ It is normally safe to answer Y; however, the default is N.
+
+config IDEDMA_AUTO
+ def_bool IDEDMA_PCI_AUTO || IDEDMA_ICS_AUTO
+
+endif
+
+config BLK_DEV_HD_ONLY
+ bool "Old hard disk (MFM/RLL/IDE) driver"
+ depends on BLK_DEV_IDE=n
+ help
+ There are two drivers for MFM/RLL/IDE hard disks. Most people use
+ the newer enhanced driver, but this old one is still around for two
+ reasons. Some older systems have strange timing problems and seem to
+ work only with the old driver (which itself does not work with some
+ newer systems). The other reason is that the old driver is smaller,
+ since it lacks the enhanced functionality of the new one. This makes
+ it a good choice for systems with very tight memory restrictions, or
+ for systems with only older MFM/RLL/ESDI drives. Choosing the old
+ driver can save 13 KB or so of kernel memory.
+
+ If you are unsure, then just choose the Enhanced IDE/MFM/RLL driver
+ instead of this one. For more detailed information, read the
+ Disk-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+config BLK_DEV_HD
+ def_bool BLK_DEV_HD_IDE || BLK_DEV_HD_ONLY
+
+endif
+
+endmenu
diff --git a/drivers/ide/Makefile b/drivers/ide/Makefile
new file mode 100644
index 000000000000..5be8ad6dc9ed
--- /dev/null
+++ b/drivers/ide/Makefile
@@ -0,0 +1,54 @@
+#
+# Makefile for the kernel ata, atapi, and ide block device drivers.
+#
+# 12 September 2000, Bartlomiej Zolnierkiewicz <bkz@linux-ide.org>
+# Rewritten to use lists instead of if-statements.
+#
+# Note : at this point, these files are compiled on all systems.
+# In the future, some of these should be built conditionally.
+#
+# First come modules that register themselves with the core
+
+EXTRA_CFLAGS += -Idrivers/ide
+
+obj-$(CONFIG_BLK_DEV_IDE) += pci/
+
+ide-core-y += ide.o ide-io.o ide-iops.o ide-lib.o ide-probe.o ide-taskfile.o
+
+ide-core-$(CONFIG_BLK_DEV_CMD640) += pci/cmd640.o
+
+# Core IDE code - must come before legacy
+ide-core-$(CONFIG_BLK_DEV_IDEPCI) += setup-pci.o
+ide-core-$(CONFIG_BLK_DEV_IDEDMA) += ide-dma.o
+ide-core-$(CONFIG_BLK_DEV_IDE_TCQ) += ide-tcq.o
+ide-core-$(CONFIG_PROC_FS) += ide-proc.o
+ide-core-$(CONFIG_BLK_DEV_IDEPNP) += ide-pnp.o
+
+# built-in only drivers from arm/
+ide-core-$(CONFIG_IDE_ARM) += arm/ide_arm.o
+
+# built-in only drivers from legacy/
+ide-core-$(CONFIG_BLK_DEV_BUDDHA) += legacy/buddha.o
+ide-core-$(CONFIG_BLK_DEV_FALCON_IDE) += legacy/falconide.o
+ide-core-$(CONFIG_BLK_DEV_GAYLE) += legacy/gayle.o
+ide-core-$(CONFIG_BLK_DEV_MAC_IDE) += legacy/macide.o
+ide-core-$(CONFIG_BLK_DEV_Q40IDE) += legacy/q40ide.o
+
+# built-in only drivers from ppc/
+ide-core-$(CONFIG_BLK_DEV_MPC8xx_IDE) += ppc/mpc8xx.o
+ide-core-$(CONFIG_BLK_DEV_IDE_PMAC) += ppc/pmac.o
+
+# built-in only drivers from h8300/
+ide-core-$(CONFIG_H8300) += h8300/ide-h8300.o
+
+obj-$(CONFIG_BLK_DEV_IDE) += ide-core.o
+obj-$(CONFIG_IDE_GENERIC) += ide-generic.o
+
+obj-$(CONFIG_BLK_DEV_IDEDISK) += ide-disk.o
+obj-$(CONFIG_BLK_DEV_IDECD) += ide-cd.o
+obj-$(CONFIG_BLK_DEV_IDETAPE) += ide-tape.o
+obj-$(CONFIG_BLK_DEV_IDEFLOPPY) += ide-floppy.o
+
+obj-$(CONFIG_BLK_DEV_IDE) += legacy/ arm/
+obj-$(CONFIG_BLK_DEV_HD) += legacy/
+obj-$(CONFIG_ETRAX_IDE) += cris/
diff --git a/drivers/ide/arm/Makefile b/drivers/ide/arm/Makefile
new file mode 100644
index 000000000000..6a78f0755f26
--- /dev/null
+++ b/drivers/ide/arm/Makefile
@@ -0,0 +1,6 @@
+
+obj-$(CONFIG_BLK_DEV_IDE_ICSIDE) += icside.o
+obj-$(CONFIG_BLK_DEV_IDE_RAPIDE) += rapide.o
+obj-$(CONFIG_BLK_DEV_IDE_BAST) += bast-ide.o
+
+EXTRA_CFLAGS := -Idrivers/ide
diff --git a/drivers/ide/arm/bast-ide.c b/drivers/ide/arm/bast-ide.c
new file mode 100644
index 000000000000..9d474e5fd8dc
--- /dev/null
+++ b/drivers/ide/arm/bast-ide.c
@@ -0,0 +1,71 @@
+/* linux/drivers/ide/arm/bast-ide.c
+ *
+ * Copyright (c) 2003-2004 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * 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/errno.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/mach-types.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/arch/map.h>
+#include <asm/arch/bast-map.h>
+#include <asm/arch/bast-irq.h>
+
+/* list of registered interfaces */
+static ide_hwif_t *ifs[2];
+
+static int __init
+bastide_register(unsigned int base, unsigned int aux, int irq,
+ ide_hwif_t **hwif)
+{
+ hw_regs_t hw;
+ int i;
+
+ memset(&hw, 0, sizeof(hw));
+
+ base += BAST_IDE_CS;
+ aux += BAST_IDE_CS;
+
+ for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
+ hw.io_ports[i] = (unsigned long)base;
+ base += 0x20;
+ }
+
+ hw.io_ports[IDE_CONTROL_OFFSET] = aux + (6 * 0x20);
+ hw.irq = irq;
+
+ ide_register_hw(&hw, hwif);
+
+ return 0;
+}
+
+static int __init bastide_init(void)
+{
+ /* we can treat the VR1000 and the BAST the same */
+
+ if (!(machine_is_bast() || machine_is_vr1000()))
+ return 0;
+
+ printk("BAST: IDE driver, (c) 2003-2004 Simtec Electronics\n");
+
+ bastide_register(BAST_VA_IDEPRI, BAST_VA_IDEPRIAUX, IRQ_IDE0, &ifs[0]);
+ bastide_register(BAST_VA_IDESEC, BAST_VA_IDESECAUX, IRQ_IDE1, &ifs[1]);
+ return 0;
+}
+
+module_init(bastide_init);
+
+MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Simtec BAST / Thorcom VR1000 IDE driver");
diff --git a/drivers/ide/arm/icside.c b/drivers/ide/arm/icside.c
new file mode 100644
index 000000000000..308897e57e4d
--- /dev/null
+++ b/drivers/ide/arm/icside.c
@@ -0,0 +1,870 @@
+/*
+ * linux/drivers/ide/arm/icside.c
+ *
+ * Copyright (c) 1996-2004 Russell King.
+ *
+ * Please note that this platform does not support 32-bit IDE IO.
+ */
+
+#include <linux/config.h>
+#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/hdreg.h>
+#include <linux/ide.h>
+#include <linux/dma-mapping.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/scatterlist.h>
+
+#include <asm/dma.h>
+#include <asm/ecard.h>
+#include <asm/io.h>
+
+#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 type;
+ /* parent device... until the IDE core gets one of its own */
+ struct device *dev;
+ ide_hwif_t *hwif[2];
+};
+
+#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 icside_state *state = hwif->hwif_data;
+ 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);
+}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA_ICS
+
+#ifndef CONFIG_IDEDMA_ICS_AUTO
+#warning CONFIG_IDEDMA_ICS_AUTO=n support is obsolete, and will be removed soon.
+#endif
+
+/*
+ * 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.
+ */
+
+static void icside_build_sglist(ide_drive_t *drive, struct request *rq)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ struct icside_state *state = hwif->hwif_data;
+ 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;
+
+ hwif->sg_nents = dma_map_sg(state->dev, sg, hwif->sg_nents,
+ hwif->sg_dma_direction);
+}
+
+/*
+ * 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 int icside_set_speed(ide_drive_t *drive, u8 xfer_mode)
+{
+ int on = 0, cycle_time = 0, use_dma_info = 0;
+
+ /*
+ * Limit the transfer speed to MW_DMA_2.
+ */
+ if (xfer_mode > XFER_MW_DMA_2)
+ xfer_mode = XFER_MW_DMA_2;
+
+ 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->eide_dma_time > cycle_time)
+ cycle_time = drive->id->eide_dma_time;
+
+ drive->drive_data = cycle_time;
+
+ if (cycle_time && ide_config_drive_speed(drive, xfer_mode) == 0)
+ on = 1;
+ else
+ drive->drive_data = 480;
+
+ printk("%s: %s selected (peak %dMB/s)\n", drive->name,
+ ide_xfer_verbose(xfer_mode), 2000 / drive->drive_data);
+
+ drive->current_speed = xfer_mode;
+
+ return on;
+}
+
+static int icside_dma_host_off(ide_drive_t *drive)
+{
+ return 0;
+}
+
+static int icside_dma_off_quietly(ide_drive_t *drive)
+{
+ drive->using_dma = 0;
+ return icside_dma_host_off(drive);
+}
+
+static int icside_dma_host_on(ide_drive_t *drive)
+{
+ return 0;
+}
+
+static int icside_dma_on(ide_drive_t *drive)
+{
+ drive->using_dma = 1;
+ return icside_dma_host_on(drive);
+}
+
+static int icside_dma_check(ide_drive_t *drive)
+{
+ struct hd_driveid *id = drive->id;
+ ide_hwif_t *hwif = HWIF(drive);
+ int xfer_mode = XFER_PIO_2;
+ int on;
+
+ if (!(id->capability & 1) || !hwif->autodma)
+ goto out;
+
+ /*
+ * Consult the list of known "bad" drives
+ */
+ if (__ide_dma_bad_drive(drive))
+ goto out;
+
+ /*
+ * Enable DMA on any drive that has multiword DMA
+ */
+ if (id->field_valid & 2) {
+ xfer_mode = ide_dma_speed(drive, 0);
+ goto out;
+ }
+
+ /*
+ * Consult the list of known "good" drives
+ */
+ if (__ide_dma_good_drive(drive)) {
+ if (id->eide_dma_time > 150)
+ goto out;
+ xfer_mode = XFER_MW_DMA_1;
+ }
+
+out:
+ on = icside_set_speed(drive, xfer_mode);
+
+ if (on)
+ return icside_dma_on(drive);
+ else
+ return icside_dma_off_quietly(drive);
+}
+
+static int icside_dma_end(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct icside_state *state = hwif->hwif_data;
+
+ drive->waiting_for_dma = 0;
+
+ disable_dma(hwif->hw.dma);
+
+ /* Teardown mappings after DMA has completed. */
+ dma_unmap_sg(state->dev, hwif->sg_table, hwif->sg_nents,
+ hwif->sg_dma_direction);
+
+ return get_dma_residue(hwif->hw.dma) != 0;
+}
+
+static void icside_dma_start(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+
+ /* We can not enable DMA on both channels simultaneously. */
+ BUG_ON(dma_channel_active(hwif->hw.dma));
+ enable_dma(hwif->hw.dma);
+}
+
+static int icside_dma_setup(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ 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(hwif->hw.dma));
+
+ icside_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(hwif->select_data, hwif->config_data);
+
+ /*
+ * Select the correct timing for this drive.
+ */
+ set_dma_speed(hwif->hw.dma, drive->drive_data);
+
+ /*
+ * Tell the DMA engine about the SG table and
+ * data direction.
+ */
+ set_dma_sg(hwif->hw.dma, hwif->sg_table, hwif->sg_nents);
+ set_dma_mode(hwif->hw.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 icside_state *state = hwif->hwif_data;
+
+ return readb(state->irq_port +
+ (hwif->channel ?
+ ICS_ARCIN_V6_INTRSTAT_2 :
+ ICS_ARCIN_V6_INTRSTAT_1)) & 1;
+}
+
+static int icside_dma_timeout(ide_drive_t *drive)
+{
+ printk(KERN_ERR "%s: DMA timeout occurred: ", drive->name);
+
+ if (icside_dma_test_irq(drive))
+ return 0;
+
+ ide_dump_status(drive, "DMA timeout",
+ HWIF(drive)->INB(IDE_STATUS_REG));
+
+ return icside_dma_end(drive);
+}
+
+static int icside_dma_lostirq(ide_drive_t *drive)
+{
+ printk(KERN_ERR "%s: IRQ lost\n", drive->name);
+ return 1;
+}
+
+static void icside_dma_init(ide_hwif_t *hwif)
+{
+ int autodma = 0;
+
+#ifdef CONFIG_IDEDMA_ICS_AUTO
+ autodma = 1;
+#endif
+
+ printk(" %s: SG-DMA", hwif->name);
+
+ hwif->atapi_dma = 1;
+ hwif->mwdma_mask = 7; /* MW0..2 */
+ hwif->swdma_mask = 7; /* SW0..2 */
+
+ hwif->dmatable_cpu = NULL;
+ hwif->dmatable_dma = 0;
+ hwif->speedproc = icside_set_speed;
+ hwif->autodma = autodma;
+
+ hwif->ide_dma_check = icside_dma_check;
+ hwif->ide_dma_host_off = icside_dma_host_off;
+ hwif->ide_dma_off_quietly = icside_dma_off_quietly;
+ hwif->ide_dma_host_on = icside_dma_host_on;
+ hwif->ide_dma_on = icside_dma_on;
+ hwif->dma_setup = icside_dma_setup;
+ hwif->dma_exec_cmd = icside_dma_exec_cmd;
+ hwif->dma_start = icside_dma_start;
+ hwif->ide_dma_end = icside_dma_end;
+ hwif->ide_dma_test_irq = icside_dma_test_irq;
+ hwif->ide_dma_timeout = icside_dma_timeout;
+ hwif->ide_dma_lostirq = icside_dma_lostirq;
+
+ hwif->drives[0].autodma = hwif->autodma;
+ hwif->drives[1].autodma = hwif->autodma;
+
+ printk(" capable%s\n", hwif->autodma ? ", auto-enable" : "");
+}
+#else
+#define icside_dma_init(hwif) (0)
+#endif
+
+static ide_hwif_t *icside_find_hwif(unsigned long dataport)
+{
+ ide_hwif_t *hwif;
+ int index;
+
+ for (index = 0; index < MAX_HWIFS; ++index) {
+ hwif = &ide_hwifs[index];
+ if (hwif->io_ports[IDE_DATA_OFFSET] == dataport)
+ goto found;
+ }
+
+ for (index = 0; index < MAX_HWIFS; ++index) {
+ hwif = &ide_hwifs[index];
+ if (!hwif->io_ports[IDE_DATA_OFFSET])
+ goto found;
+ }
+
+ hwif = NULL;
+found:
+ return hwif;
+}
+
+static ide_hwif_t *
+icside_setup(void __iomem *base, struct cardinfo *info, struct expansion_card *ec)
+{
+ unsigned long port = (unsigned long)base + info->dataoffset;
+ ide_hwif_t *hwif;
+
+ hwif = icside_find_hwif(port);
+ if (hwif) {
+ int i;
+
+ memset(&hwif->hw, 0, sizeof(hw_regs_t));
+
+ /*
+ * Ensure we're using MMIO
+ */
+ default_hwif_mmiops(hwif);
+ hwif->mmio = 2;
+
+ for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
+ hwif->hw.io_ports[i] = port;
+ hwif->io_ports[i] = port;
+ port += 1 << info->stepping;
+ }
+ hwif->hw.io_ports[IDE_CONTROL_OFFSET] = (unsigned long)base + info->ctrloffset;
+ hwif->io_ports[IDE_CONTROL_OFFSET] = (unsigned long)base + info->ctrloffset;
+ hwif->hw.irq = ec->irq;
+ hwif->irq = ec->irq;
+ hwif->noprobe = 0;
+ hwif->chipset = ide_acorn;
+ hwif->gendev.parent = &ec->dev;
+ }
+
+ return hwif;
+}
+
+static int __init
+icside_register_v5(struct icside_state *state, struct expansion_card *ec)
+{
+ ide_hwif_t *hwif;
+ void __iomem *base;
+
+ base = ioremap(ecard_resource_start(ec, ECARD_RES_MEMC),
+ ecard_resource_len(ec, ECARD_RES_MEMC));
+ if (!base)
+ return -ENOMEM;
+
+ state->irq_port = base;
+
+ ec->irqaddr = base + ICS_ARCIN_V5_INTRSTAT;
+ ec->irqmask = 1;
+ ec->irq_data = state;
+ ec->ops = &icside_ops_arcin_v5;
+
+ /*
+ * Be on the safe side - disable interrupts
+ */
+ icside_irqdisable_arcin_v5(ec, 0);
+
+ hwif = icside_setup(base, &icside_cardinfo_v5, ec);
+ if (!hwif) {
+ iounmap(base);
+ return -ENODEV;
+ }
+
+ state->hwif[0] = hwif;
+
+ probe_hwif_init(hwif);
+ create_proc_ide_interfaces();
+
+ return 0;
+}
+
+static int __init
+icside_register_v6(struct icside_state *state, struct expansion_card *ec)
+{
+ ide_hwif_t *hwif, *mate;
+ void __iomem *ioc_base, *easi_base;
+ unsigned int sel = 0;
+ int ret;
+
+ ioc_base = ioremap(ecard_resource_start(ec, ECARD_RES_IOCFAST),
+ ecard_resource_len(ec, ECARD_RES_IOCFAST));
+ if (!ioc_base) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ easi_base = ioc_base;
+
+ if (ecard_resource_flags(ec, ECARD_RES_EASI)) {
+ easi_base = ioremap(ecard_resource_start(ec, ECARD_RES_EASI),
+ ecard_resource_len(ec, ECARD_RES_EASI));
+ if (!easi_base) {
+ ret = -ENOMEM;
+ goto unmap_slot;
+ }
+
+ /*
+ * Enable access to the EASI region.
+ */
+ sel = 1 << 5;
+ }
+
+ writeb(sel, ioc_base);
+
+ ec->irq_data = state;
+ ec->ops = &icside_ops_arcin_v6;
+
+ state->irq_port = easi_base;
+ state->ioc_base = ioc_base;
+
+ /*
+ * Be on the safe side - disable interrupts
+ */
+ icside_irqdisable_arcin_v6(ec, 0);
+
+ /*
+ * Find and register the interfaces.
+ */
+ hwif = icside_setup(easi_base, &icside_cardinfo_v6_1, ec);
+ mate = icside_setup(easi_base, &icside_cardinfo_v6_2, ec);
+
+ if (!hwif || !mate) {
+ ret = -ENODEV;
+ goto unmap_port;
+ }
+
+ state->hwif[0] = hwif;
+ state->hwif[1] = mate;
+
+ hwif->maskproc = icside_maskproc;
+ hwif->channel = 0;
+ hwif->hwif_data = state;
+ hwif->mate = mate;
+ hwif->serialized = 1;
+ hwif->config_data = (unsigned long)ioc_base;
+ hwif->select_data = sel;
+ hwif->hw.dma = ec->dma;
+
+ mate->maskproc = icside_maskproc;
+ mate->channel = 1;
+ mate->hwif_data = state;
+ mate->mate = hwif;
+ mate->serialized = 1;
+ mate->config_data = (unsigned long)ioc_base;
+ mate->select_data = sel | 1;
+ mate->hw.dma = ec->dma;
+
+ if (ec->dma != NO_DMA && !request_dma(ec->dma, hwif->name)) {
+ icside_dma_init(hwif);
+ icside_dma_init(mate);
+ }
+
+ probe_hwif_init(hwif);
+ probe_hwif_init(mate);
+ create_proc_ide_interfaces();
+
+ return 0;
+
+ unmap_port:
+ if (easi_base != ioc_base)
+ iounmap(easi_base);
+ unmap_slot:
+ iounmap(ioc_base);
+ 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 = kmalloc(sizeof(struct icside_state), GFP_KERNEL);
+ if (!state) {
+ ret = -ENOMEM;
+ goto release;
+ }
+
+ memset(state, 0, sizeof(state));
+ state->type = ICS_TYPE_NOTYPE;
+ state->dev = &ec->dev;
+
+ idmem = ioremap(ecard_resource_start(ec, ECARD_RES_IOCFAST),
+ ecard_resource_len(ec, ECARD_RES_IOCFAST));
+ 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;
+ iounmap(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) {
+ ecard_set_drvdata(ec, state);
+ 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);
+ ec->ops = NULL;
+ ec->irq_data = NULL;
+
+ if (state->ioc_base)
+ iounmap(state->ioc_base);
+ if (state->ioc_base != state->irq_port)
+ iounmap(state->irq_port);
+
+ 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);
+}
+
+MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("ICS IDE driver");
+
+module_init(icside_init);
diff --git a/drivers/ide/arm/ide_arm.c b/drivers/ide/arm/ide_arm.c
new file mode 100644
index 000000000000..23488c4d1fcd
--- /dev/null
+++ b/drivers/ide/arm/ide_arm.c
@@ -0,0 +1,43 @@
+/*
+ * ARM/ARM26 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/mach-types.h>
+#include <asm/irq.h>
+
+#ifdef CONFIG_ARM26
+# define IDE_ARM_HOST (machine_is_a5k())
+#else
+# define IDE_ARM_HOST (1)
+#endif
+
+#ifdef CONFIG_ARCH_CLPS7500
+# include <asm/arch/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
+
+void __init ide_arm_init(void)
+{
+ if (IDE_ARM_HOST) {
+ hw_regs_t hw;
+
+ memset(&hw, 0, sizeof(hw));
+ ide_std_init_ports(&hw, IDE_ARM_IO, IDE_ARM_IO + 0x206);
+ hw.irq = IDE_ARM_IRQ;
+ ide_register_hw(&hw, NULL);
+ }
+}
diff --git a/drivers/ide/arm/rapide.c b/drivers/ide/arm/rapide.c
new file mode 100644
index 000000000000..3058217767d6
--- /dev/null
+++ b/drivers/ide/arm/rapide.c
@@ -0,0 +1,125 @@
+/*
+ * linux/drivers/ide/arm/rapide.c
+ *
+ * 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>
+
+/*
+ * Something like this really should be in generic code, but isn't.
+ */
+static ide_hwif_t *
+rapide_locate_hwif(void __iomem *base, void __iomem *ctrl, unsigned int sz, int irq)
+{
+ unsigned long port = (unsigned long)base;
+ ide_hwif_t *hwif;
+ int index, i;
+
+ for (index = 0; index < MAX_HWIFS; ++index) {
+ hwif = ide_hwifs + index;
+ if (hwif->io_ports[IDE_DATA_OFFSET] == port)
+ goto found;
+ }
+
+ for (index = 0; index < MAX_HWIFS; ++index) {
+ hwif = ide_hwifs + index;
+ if (hwif->io_ports[IDE_DATA_OFFSET] == 0)
+ goto found;
+ }
+
+ return NULL;
+
+ found:
+ for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
+ hwif->hw.io_ports[i] = port;
+ hwif->io_ports[i] = port;
+ port += sz;
+ }
+ hwif->hw.io_ports[IDE_CONTROL_OFFSET] = (unsigned long)ctrl;
+ hwif->io_ports[IDE_CONTROL_OFFSET] = (unsigned long)ctrl;
+ hwif->hw.irq = hwif->irq = irq;
+ hwif->mmio = 2;
+ default_hwif_mmiops(hwif);
+
+ return hwif;
+}
+
+static int __devinit
+rapide_probe(struct expansion_card *ec, const struct ecard_id *id)
+{
+ ide_hwif_t *hwif;
+ void __iomem *base;
+ int ret;
+
+ ret = ecard_request_resources(ec);
+ if (ret)
+ goto out;
+
+ base = ioremap(ecard_resource_start(ec, ECARD_RES_MEMC),
+ ecard_resource_len(ec, ECARD_RES_MEMC));
+ if (!base) {
+ ret = -ENOMEM;
+ goto release;
+ }
+
+ hwif = rapide_locate_hwif(base, base + 0x818, 1 << 6, ec->irq);
+ if (hwif) {
+ hwif->hwif_data = base;
+ hwif->gendev.parent = &ec->dev;
+ hwif->noprobe = 0;
+ probe_hwif_init(hwif);
+ create_proc_ide_interfaces();
+ ecard_set_drvdata(ec, hwif);
+ goto out;
+ }
+
+ iounmap(base);
+ release:
+ ecard_release_resources(ec);
+ out:
+ return ret;
+}
+
+static void __devexit rapide_remove(struct expansion_card *ec)
+{
+ ide_hwif_t *hwif = ecard_get_drvdata(ec);
+
+ ecard_set_drvdata(ec, NULL);
+
+ /* there must be a better way */
+ ide_unregister(hwif - ide_hwifs);
+ iounmap(hwif->hwif_data);
+ 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);
+}
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Yellowstone RAPIDE driver");
+
+module_init(rapide_init);
diff --git a/drivers/ide/cris/Makefile b/drivers/ide/cris/Makefile
new file mode 100644
index 000000000000..fdc294325d00
--- /dev/null
+++ b/drivers/ide/cris/Makefile
@@ -0,0 +1,3 @@
+EXTRA_CFLAGS += -Idrivers/ide
+
+obj-$(CONFIG_ETRAX_ARCH_V10) += ide-v10.o
diff --git a/drivers/ide/cris/ide-v10.c b/drivers/ide/cris/ide-v10.c
new file mode 100644
index 000000000000..5b40220d3ddc
--- /dev/null
+++ b/drivers/ide/cris/ide-v10.c
@@ -0,0 +1,842 @@
+/* $Id: ide.c,v 1.4 2004/10/12 07:55:48 starvik Exp $
+ *
+ * Etrax specific IDE functions, like init and PIO-mode setting etc.
+ * Almost the entire ide.c is used for the rest of the Etrax ATA driver.
+ * Copyright (c) 2000-2004 Axis Communications AB
+ *
+ * Authors: Bjorn Wesen (initial version)
+ * Mikael Starvik (pio setup stuff, Linux 2.6 port)
+ */
+
+/* Regarding DMA:
+ *
+ * There are two forms of DMA - "DMA handshaking" between the interface and the drive,
+ * and DMA between the memory and the interface. We can ALWAYS use the latter, since it's
+ * something built-in in the Etrax. However only some drives support the DMA-mode handshaking
+ * on the ATA-bus. The normal PC driver and Triton interface disables memory-if DMA when the
+ * device can't do DMA handshaking for some stupid reason. We don't need to do that.
+ */
+
+#undef REALLY_SLOW_IO /* most systems can safely undef this */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+#include <linux/scatterlist.h>
+
+#include <asm/io.h>
+#include <asm/arch/svinto.h>
+#include <asm/dma.h>
+
+/* number of Etrax DMA descriptors */
+#define MAX_DMA_DESCRS 64
+
+/* number of times to retry busy-flags when reading/writing IDE-registers
+ * this can't be too high because a hung harddisk might cause the watchdog
+ * to trigger (sometimes INB and OUTB are called with irq's disabled)
+ */
+
+#define IDE_REGISTER_TIMEOUT 300
+
+static int e100_read_command = 0;
+
+#define LOWDB(x)
+#define D(x)
+
+static int e100_ide_build_dmatable (ide_drive_t *drive);
+static ide_startstop_t etrax_dma_intr (ide_drive_t *drive);
+
+void
+etrax100_ide_outw(unsigned short data, unsigned long reg) {
+ int timeleft;
+ LOWDB(printk("ow: data 0x%x, reg 0x%x\n", data, reg));
+
+ /* note the lack of handling any timeouts. we stop waiting, but we don't
+ * really notify anybody.
+ */
+
+ timeleft = IDE_REGISTER_TIMEOUT;
+ /* wait for busy flag */
+ while(timeleft && (*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy)))
+ timeleft--;
+
+ /*
+ * Fall through at a timeout, so the ongoing command will be
+ * aborted by the write below, which is expected to be a dummy
+ * command to the command register. This happens when a faulty
+ * drive times out on a command. See comment on timeout in
+ * INB.
+ */
+ if(!timeleft)
+ printk("ATA timeout reg 0x%lx := 0x%x\n", reg, data);
+
+ *R_ATA_CTRL_DATA = reg | data; /* write data to the drive's register */
+
+ timeleft = IDE_REGISTER_TIMEOUT;
+ /* wait for transmitter ready */
+ while(timeleft && !(*R_ATA_STATUS_DATA &
+ IO_MASK(R_ATA_STATUS_DATA, tr_rdy)))
+ timeleft--;
+}
+
+void
+etrax100_ide_outb(unsigned char data, unsigned long reg)
+{
+ etrax100_ide_outw(data, reg);
+}
+
+void
+etrax100_ide_outbsync(ide_drive_t *drive, u8 addr, unsigned long port)
+{
+ etrax100_ide_outw(addr, port);
+}
+
+unsigned short
+etrax100_ide_inw(unsigned long reg) {
+ int status;
+ int timeleft;
+
+ timeleft = IDE_REGISTER_TIMEOUT;
+ /* wait for busy flag */
+ while(timeleft && (*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy)))
+ timeleft--;
+
+ if(!timeleft) {
+ /*
+ * If we're asked to read the status register, like for
+ * example when a command does not complete for an
+ * extended time, but the ATA interface is stuck in a
+ * busy state at the *ETRAX* ATA interface level (as has
+ * happened repeatedly with at least one bad disk), then
+ * the best thing to do is to pretend that we read
+ * "busy" in the status register, so the IDE driver will
+ * time-out, abort the ongoing command and perform a
+ * reset sequence. Note that the subsequent OUT_BYTE
+ * call will also timeout on busy, but as long as the
+ * write is still performed, everything will be fine.
+ */
+ if ((reg & IO_MASK (R_ATA_CTRL_DATA, addr))
+ == IO_FIELD (R_ATA_CTRL_DATA, addr, IDE_STATUS_OFFSET))
+ return BUSY_STAT;
+ else
+ /* For other rare cases we assume 0 is good enough. */
+ return 0;
+ }
+
+ *R_ATA_CTRL_DATA = reg | IO_STATE(R_ATA_CTRL_DATA, rw, read); /* read data */
+
+ timeleft = IDE_REGISTER_TIMEOUT;
+ /* wait for available */
+ while(timeleft && !((status = *R_ATA_STATUS_DATA) &
+ IO_MASK(R_ATA_STATUS_DATA, dav)))
+ timeleft--;
+
+ if(!timeleft)
+ return 0;
+
+ LOWDB(printk("inb: 0x%x from reg 0x%x\n", status & 0xff, reg));
+
+ return (unsigned short)status;
+}
+
+unsigned char
+etrax100_ide_inb(unsigned long reg)
+{
+ return (unsigned char)etrax100_ide_inw(reg);
+}
+
+/* PIO timing (in R_ATA_CONFIG)
+ *
+ * _____________________________
+ * ADDRESS : ________/
+ *
+ * _______________
+ * DIOR : ____________/ \__________
+ *
+ * _______________
+ * DATA : XXXXXXXXXXXXXXXX_______________XXXXXXXX
+ *
+ *
+ * DIOR is unbuffered while address and data is buffered.
+ * This creates two problems:
+ * 1. The DIOR pulse is to early (because it is unbuffered)
+ * 2. The rise time of DIOR is long
+ *
+ * There are at least three different plausible solutions
+ * 1. Use a pad capable of larger currents in Etrax
+ * 2. Use an external buffer
+ * 3. Make the strobe pulse longer
+ *
+ * Some of the strobe timings below are modified to compensate
+ * for this. This implies a slight performance decrease.
+ *
+ * THIS SHOULD NEVER BE CHANGED!
+ *
+ * TODO: Is this true for the latest LX boards still ?
+ */
+
+#define ATA_DMA2_STROBE 4
+#define ATA_DMA2_HOLD 0
+#define ATA_DMA1_STROBE 4
+#define ATA_DMA1_HOLD 1
+#define ATA_DMA0_STROBE 12
+#define ATA_DMA0_HOLD 9
+#define ATA_PIO4_SETUP 1
+#define ATA_PIO4_STROBE 5
+#define ATA_PIO4_HOLD 0
+#define ATA_PIO3_SETUP 1
+#define ATA_PIO3_STROBE 5
+#define ATA_PIO3_HOLD 1
+#define ATA_PIO2_SETUP 1
+#define ATA_PIO2_STROBE 6
+#define ATA_PIO2_HOLD 2
+#define ATA_PIO1_SETUP 2
+#define ATA_PIO1_STROBE 11
+#define ATA_PIO1_HOLD 4
+#define ATA_PIO0_SETUP 4
+#define ATA_PIO0_STROBE 19
+#define ATA_PIO0_HOLD 4
+
+static int e100_dma_check (ide_drive_t *drive);
+static void e100_dma_start(ide_drive_t *drive);
+static int e100_dma_end (ide_drive_t *drive);
+static void e100_ide_input_data (ide_drive_t *drive, void *, unsigned int);
+static void e100_ide_output_data (ide_drive_t *drive, void *, unsigned int);
+static void e100_atapi_input_bytes(ide_drive_t *drive, void *, unsigned int);
+static void e100_atapi_output_bytes(ide_drive_t *drive, void *, unsigned int);
+static int e100_dma_off (ide_drive_t *drive);
+
+
+/*
+ * good_dma_drives() lists the model names (from "hdparm -i")
+ * of drives which do not support mword2 DMA but which are
+ * known to work fine with this interface under Linux.
+ */
+
+const char *good_dma_drives[] = {"Micropolis 2112A",
+ "CONNER CTMA 4000",
+ "CONNER CTT8000-A",
+ NULL};
+
+static void tune_e100_ide(ide_drive_t *drive, byte pio)
+{
+ pio = 4;
+ /* pio = ide_get_best_pio_mode(drive, pio, 4, NULL); */
+
+ /* set pio mode! */
+
+ switch(pio) {
+ case 0:
+ *R_ATA_CONFIG = ( IO_FIELD( R_ATA_CONFIG, enable, 1 ) |
+ IO_FIELD( R_ATA_CONFIG, dma_strobe, ATA_DMA2_STROBE ) |
+ IO_FIELD( R_ATA_CONFIG, dma_hold, ATA_DMA2_HOLD ) |
+ IO_FIELD( R_ATA_CONFIG, pio_setup, ATA_PIO0_SETUP ) |
+ IO_FIELD( R_ATA_CONFIG, pio_strobe, ATA_PIO0_STROBE ) |
+ IO_FIELD( R_ATA_CONFIG, pio_hold, ATA_PIO0_HOLD ) );
+ break;
+ case 1:
+ *R_ATA_CONFIG = ( IO_FIELD( R_ATA_CONFIG, enable, 1 ) |
+ IO_FIELD( R_ATA_CONFIG, dma_strobe, ATA_DMA2_STROBE ) |
+ IO_FIELD( R_ATA_CONFIG, dma_hold, ATA_DMA2_HOLD ) |
+ IO_FIELD( R_ATA_CONFIG, pio_setup, ATA_PIO1_SETUP ) |
+ IO_FIELD( R_ATA_CONFIG, pio_strobe, ATA_PIO1_STROBE ) |
+ IO_FIELD( R_ATA_CONFIG, pio_hold, ATA_PIO1_HOLD ) );
+ break;
+ case 2:
+ *R_ATA_CONFIG = ( IO_FIELD( R_ATA_CONFIG, enable, 1 ) |
+ IO_FIELD( R_ATA_CONFIG, dma_strobe, ATA_DMA2_STROBE ) |
+ IO_FIELD( R_ATA_CONFIG, dma_hold, ATA_DMA2_HOLD ) |
+ IO_FIELD( R_ATA_CONFIG, pio_setup, ATA_PIO2_SETUP ) |
+ IO_FIELD( R_ATA_CONFIG, pio_strobe, ATA_PIO2_STROBE ) |
+ IO_FIELD( R_ATA_CONFIG, pio_hold, ATA_PIO2_HOLD ) );
+ break;
+ case 3:
+ *R_ATA_CONFIG = ( IO_FIELD( R_ATA_CONFIG, enable, 1 ) |
+ IO_FIELD( R_ATA_CONFIG, dma_strobe, ATA_DMA2_STROBE ) |
+ IO_FIELD( R_ATA_CONFIG, dma_hold, ATA_DMA2_HOLD ) |
+ IO_FIELD( R_ATA_CONFIG, pio_setup, ATA_PIO3_SETUP ) |
+ IO_FIELD( R_ATA_CONFIG, pio_strobe, ATA_PIO3_STROBE ) |
+ IO_FIELD( R_ATA_CONFIG, pio_hold, ATA_PIO3_HOLD ) );
+ break;
+ case 4:
+ *R_ATA_CONFIG = ( IO_FIELD( R_ATA_CONFIG, enable, 1 ) |
+ IO_FIELD( R_ATA_CONFIG, dma_strobe, ATA_DMA2_STROBE ) |
+ IO_FIELD( R_ATA_CONFIG, dma_hold, ATA_DMA2_HOLD ) |
+ IO_FIELD( R_ATA_CONFIG, pio_setup, ATA_PIO4_SETUP ) |
+ IO_FIELD( R_ATA_CONFIG, pio_strobe, ATA_PIO4_STROBE ) |
+ IO_FIELD( R_ATA_CONFIG, pio_hold, ATA_PIO4_HOLD ) );
+ break;
+ }
+}
+
+static int e100_dma_setup(ide_drive_t *drive)
+{
+ struct request *rq = drive->hwif->hwgroup->rq;
+
+ if (rq_data_dir(rq)) {
+ e100_read_command = 0;
+
+ RESET_DMA(ATA_TX_DMA_NBR); /* sometimes the DMA channel get stuck so we need to do this */
+ WAIT_DMA(ATA_TX_DMA_NBR);
+ } else {
+ e100_read_command = 1;
+
+ RESET_DMA(ATA_RX_DMA_NBR); /* sometimes the DMA channel get stuck so we need to do this */
+ WAIT_DMA(ATA_RX_DMA_NBR);
+ }
+
+ /* set up the Etrax DMA descriptors */
+ if (e100_ide_build_dmatable(drive)) {
+ ide_map_sg(drive, rq);
+ return 1;
+ }
+
+ return 0;
+}
+
+static void e100_dma_exec_cmd(ide_drive_t *drive, u8 command)
+{
+ /* set the irq handler which will finish the request when DMA is done */
+ ide_set_handler(drive, &etrax_dma_intr, WAIT_CMD, NULL);
+
+ /* issue cmd to drive */
+ etrax100_ide_outb(command, IDE_COMMAND_REG);
+}
+
+void __init
+init_e100_ide (void)
+{
+ volatile unsigned int dummy;
+ int h;
+
+ printk("ide: ETRAX 100LX built-in ATA DMA controller\n");
+
+ /* first fill in some stuff in the ide_hwifs fields */
+
+ for(h = 0; h < MAX_HWIFS; h++) {
+ ide_hwif_t *hwif = &ide_hwifs[h];
+ hwif->mmio = 2;
+ hwif->chipset = ide_etrax100;
+ hwif->tuneproc = &tune_e100_ide;
+ hwif->ata_input_data = &e100_ide_input_data;
+ hwif->ata_output_data = &e100_ide_output_data;
+ hwif->atapi_input_bytes = &e100_atapi_input_bytes;
+ hwif->atapi_output_bytes = &e100_atapi_output_bytes;
+ hwif->ide_dma_check = &e100_dma_check;
+ hwif->ide_dma_end = &e100_dma_end;
+ hwif->dma_setup = &e100_dma_setup;
+ hwif->dma_exec_cmd = &e100_dma_exec_cmd;
+ hwif->dma_start = &e100_dma_start;
+ hwif->OUTB = &etrax100_ide_outb;
+ hwif->OUTW = &etrax100_ide_outw;
+ hwif->OUTBSYNC = &etrax100_ide_outbsync;
+ hwif->INB = &etrax100_ide_inb;
+ hwif->INW = &etrax100_ide_inw;
+ hwif->ide_dma_off_quietly = &e100_dma_off;
+ }
+
+ /* actually reset and configure the etrax100 ide/ata interface */
+
+ *R_ATA_CTRL_DATA = 0;
+ *R_ATA_TRANSFER_CNT = 0;
+ *R_ATA_CONFIG = 0;
+
+ genconfig_shadow = (genconfig_shadow &
+ ~IO_MASK(R_GEN_CONFIG, dma2) &
+ ~IO_MASK(R_GEN_CONFIG, dma3) &
+ ~IO_MASK(R_GEN_CONFIG, ata)) |
+ ( IO_STATE( R_GEN_CONFIG, dma3, ata ) |
+ IO_STATE( R_GEN_CONFIG, dma2, ata ) |
+ IO_STATE( R_GEN_CONFIG, ata, select ) );
+
+ *R_GEN_CONFIG = genconfig_shadow;
+
+ /* pull the chosen /reset-line low */
+
+#ifdef CONFIG_ETRAX_IDE_G27_RESET
+ REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow, 27, 0);
+#endif
+#ifdef CONFIG_ETRAX_IDE_CSE1_16_RESET
+ REG_SHADOW_SET(port_cse1_addr, port_cse1_shadow, 16, 0);
+#endif
+#ifdef CONFIG_ETRAX_IDE_CSP0_8_RESET
+ REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, 8, 0);
+#endif
+#ifdef CONFIG_ETRAX_IDE_PB7_RESET
+ port_pb_dir_shadow = port_pb_dir_shadow |
+ IO_STATE(R_PORT_PB_DIR, dir7, output);
+ *R_PORT_PB_DIR = port_pb_dir_shadow;
+ REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, 7, 1);
+#endif
+
+ /* wait some */
+
+ udelay(25);
+
+ /* de-assert bus-reset */
+
+#ifdef CONFIG_ETRAX_IDE_CSE1_16_RESET
+ REG_SHADOW_SET(port_cse1_addr, port_cse1_shadow, 16, 1);
+#endif
+#ifdef CONFIG_ETRAX_IDE_CSP0_8_RESET
+ REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, 8, 1);
+#endif
+#ifdef CONFIG_ETRAX_IDE_G27_RESET
+ REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow, 27, 1);
+#endif
+
+ /* make a dummy read to set the ata controller in a proper state */
+ dummy = *R_ATA_STATUS_DATA;
+
+ *R_ATA_CONFIG = ( IO_FIELD( R_ATA_CONFIG, enable, 1 ) |
+ IO_FIELD( R_ATA_CONFIG, dma_strobe, ATA_DMA2_STROBE ) |
+ IO_FIELD( R_ATA_CONFIG, dma_hold, ATA_DMA2_HOLD ) |
+ IO_FIELD( R_ATA_CONFIG, pio_setup, ATA_PIO4_SETUP ) |
+ IO_FIELD( R_ATA_CONFIG, pio_strobe, ATA_PIO4_STROBE ) |
+ IO_FIELD( R_ATA_CONFIG, pio_hold, ATA_PIO4_HOLD ) );
+
+ *R_ATA_CTRL_DATA = ( IO_STATE( R_ATA_CTRL_DATA, rw, read) |
+ IO_FIELD( R_ATA_CTRL_DATA, addr, 1 ) );
+
+ while(*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy)); /* wait for busy flag*/
+
+ *R_IRQ_MASK0_SET = ( IO_STATE( R_IRQ_MASK0_SET, ata_irq0, set ) |
+ IO_STATE( R_IRQ_MASK0_SET, ata_irq1, set ) |
+ IO_STATE( R_IRQ_MASK0_SET, ata_irq2, set ) |
+ IO_STATE( R_IRQ_MASK0_SET, ata_irq3, set ) );
+
+ printk("ide: waiting %d seconds for drives to regain consciousness\n",
+ CONFIG_ETRAX_IDE_DELAY);
+
+ h = jiffies + (CONFIG_ETRAX_IDE_DELAY * HZ);
+ while(time_before(jiffies, h)) /* nothing */ ;
+
+ /* reset the dma channels we will use */
+
+ RESET_DMA(ATA_TX_DMA_NBR);
+ RESET_DMA(ATA_RX_DMA_NBR);
+ WAIT_DMA(ATA_TX_DMA_NBR);
+ WAIT_DMA(ATA_RX_DMA_NBR);
+
+}
+
+static int e100_dma_off (ide_drive_t *drive)
+{
+ return 0;
+}
+
+static etrax_dma_descr mydescr;
+
+/*
+ * The following routines are mainly used by the ATAPI drivers.
+ *
+ * These routines will round up any request for an odd number of bytes,
+ * so if an odd bytecount is specified, be sure that there's at least one
+ * extra byte allocated for the buffer.
+ */
+static void
+e100_atapi_input_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount)
+{
+ unsigned long data_reg = IDE_DATA_REG;
+
+ D(printk("atapi_input_bytes, dreg 0x%x, buffer 0x%x, count %d\n",
+ data_reg, buffer, bytecount));
+
+ if(bytecount & 1) {
+ printk("warning, odd bytecount in cdrom_in_bytes = %d.\n", bytecount);
+ bytecount++; /* to round off */
+ }
+
+ /* make sure the DMA channel is available */
+ RESET_DMA(ATA_RX_DMA_NBR);
+ WAIT_DMA(ATA_RX_DMA_NBR);
+
+ /* setup DMA descriptor */
+
+ mydescr.sw_len = bytecount;
+ mydescr.ctrl = d_eol;
+ mydescr.buf = virt_to_phys(buffer);
+
+ /* start the dma channel */
+
+ *R_DMA_CH3_FIRST = virt_to_phys(&mydescr);
+ *R_DMA_CH3_CMD = IO_STATE(R_DMA_CH3_CMD, cmd, start);
+
+ /* initiate a multi word dma read using PIO handshaking */
+
+ *R_ATA_TRANSFER_CNT = IO_FIELD(R_ATA_TRANSFER_CNT, count, bytecount >> 1);
+
+ *R_ATA_CTRL_DATA = data_reg |
+ IO_STATE(R_ATA_CTRL_DATA, rw, read) |
+ IO_STATE(R_ATA_CTRL_DATA, src_dst, dma) |
+ IO_STATE(R_ATA_CTRL_DATA, handsh, pio) |
+ IO_STATE(R_ATA_CTRL_DATA, multi, on) |
+ IO_STATE(R_ATA_CTRL_DATA, dma_size, word);
+
+ /* wait for completion */
+
+ LED_DISK_READ(1);
+ WAIT_DMA(ATA_RX_DMA_NBR);
+ LED_DISK_READ(0);
+
+#if 0
+ /* old polled transfer code
+ * this should be moved into a new function that can do polled
+ * transfers if DMA is not available
+ */
+
+ /* initiate a multi word read */
+
+ *R_ATA_TRANSFER_CNT = wcount << 1;
+
+ *R_ATA_CTRL_DATA = data_reg |
+ IO_STATE(R_ATA_CTRL_DATA, rw, read) |
+ IO_STATE(R_ATA_CTRL_DATA, src_dst, register) |
+ IO_STATE(R_ATA_CTRL_DATA, handsh, pio) |
+ IO_STATE(R_ATA_CTRL_DATA, multi, on) |
+ IO_STATE(R_ATA_CTRL_DATA, dma_size, word);
+
+ /* svinto has a latency until the busy bit actually is set */
+
+ nop(); nop();
+ nop(); nop();
+ nop(); nop();
+ nop(); nop();
+ nop(); nop();
+
+ /* unit should be busy during multi transfer */
+ while((status = *R_ATA_STATUS_DATA) & IO_MASK(R_ATA_STATUS_DATA, busy)) {
+ while(!(status & IO_MASK(R_ATA_STATUS_DATA, dav)))
+ status = *R_ATA_STATUS_DATA;
+ *ptr++ = (unsigned short)(status & 0xffff);
+ }
+#endif
+}
+
+static void
+e100_atapi_output_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount)
+{
+ unsigned long data_reg = IDE_DATA_REG;
+
+ D(printk("atapi_output_bytes, dreg 0x%x, buffer 0x%x, count %d\n",
+ data_reg, buffer, bytecount));
+
+ if(bytecount & 1) {
+ printk("odd bytecount %d in atapi_out_bytes!\n", bytecount);
+ bytecount++;
+ }
+
+ /* make sure the DMA channel is available */
+ RESET_DMA(ATA_TX_DMA_NBR);
+ WAIT_DMA(ATA_TX_DMA_NBR);
+
+ /* setup DMA descriptor */
+
+ mydescr.sw_len = bytecount;
+ mydescr.ctrl = d_eol;
+ mydescr.buf = virt_to_phys(buffer);
+
+ /* start the dma channel */
+
+ *R_DMA_CH2_FIRST = virt_to_phys(&mydescr);
+ *R_DMA_CH2_CMD = IO_STATE(R_DMA_CH2_CMD, cmd, start);
+
+ /* initiate a multi word dma write using PIO handshaking */
+
+ *R_ATA_TRANSFER_CNT = IO_FIELD(R_ATA_TRANSFER_CNT, count, bytecount >> 1);
+
+ *R_ATA_CTRL_DATA = data_reg |
+ IO_STATE(R_ATA_CTRL_DATA, rw, write) |
+ IO_STATE(R_ATA_CTRL_DATA, src_dst, dma) |
+ IO_STATE(R_ATA_CTRL_DATA, handsh, pio) |
+ IO_STATE(R_ATA_CTRL_DATA, multi, on) |
+ IO_STATE(R_ATA_CTRL_DATA, dma_size, word);
+
+ /* wait for completion */
+
+ LED_DISK_WRITE(1);
+ WAIT_DMA(ATA_TX_DMA_NBR);
+ LED_DISK_WRITE(0);
+
+#if 0
+ /* old polled write code - see comment in input_bytes */
+
+ /* wait for busy flag */
+ while(*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy));
+
+ /* initiate a multi word write */
+
+ *R_ATA_TRANSFER_CNT = bytecount >> 1;
+
+ ctrl = data_reg |
+ IO_STATE(R_ATA_CTRL_DATA, rw, write) |
+ IO_STATE(R_ATA_CTRL_DATA, src_dst, register) |
+ IO_STATE(R_ATA_CTRL_DATA, handsh, pio) |
+ IO_STATE(R_ATA_CTRL_DATA, multi, on) |
+ IO_STATE(R_ATA_CTRL_DATA, dma_size, word);
+
+ LED_DISK_WRITE(1);
+
+ /* Etrax will set busy = 1 until the multi pio transfer has finished
+ * and tr_rdy = 1 after each successful word transfer.
+ * When the last byte has been transferred Etrax will first set tr_tdy = 1
+ * and then busy = 0 (not in the same cycle). If we read busy before it
+ * has been set to 0 we will think that we should transfer more bytes
+ * and then tr_rdy would be 0 forever. This is solved by checking busy
+ * in the inner loop.
+ */
+
+ do {
+ *R_ATA_CTRL_DATA = ctrl | *ptr++;
+ while(!(*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, tr_rdy)) &&
+ (*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy)));
+ } while(*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy));
+
+ LED_DISK_WRITE(0);
+#endif
+
+}
+
+/*
+ * This is used for most PIO data transfers *from* the IDE interface
+ */
+static void
+e100_ide_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
+{
+ e100_atapi_input_bytes(drive, buffer, wcount << 2);
+}
+
+/*
+ * This is used for most PIO data transfers *to* the IDE interface
+ */
+static void
+e100_ide_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
+{
+ e100_atapi_output_bytes(drive, buffer, wcount << 2);
+}
+
+/* we only have one DMA channel on the chip for ATA, so we can keep these statically */
+static etrax_dma_descr ata_descrs[MAX_DMA_DESCRS];
+static unsigned int ata_tot_size;
+
+/*
+ * e100_ide_build_dmatable() prepares a dma request.
+ * Returns 0 if all went okay, returns 1 otherwise.
+ */
+static int e100_ide_build_dmatable (ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct scatterlist* sg;
+ struct request *rq = HWGROUP(drive)->rq;
+ unsigned long size, addr;
+ unsigned int count = 0;
+ int i = 0;
+
+ sg = hwif->sg_table;
+
+ ata_tot_size = 0;
+
+ ide_map_sg(drive, rq);
+
+ i = hwif->sg_nents;
+
+ while(i) {
+ /*
+ * Determine addr and size of next buffer area. We assume that
+ * individual virtual buffers are always composed linearly in
+ * physical memory. For example, we assume that any 8kB buffer
+ * is always composed of two adjacent physical 4kB pages rather
+ * than two possibly non-adjacent physical 4kB pages.
+ */
+ /* group sequential buffers into one large buffer */
+ addr = page_to_phys(sg->page) + sg->offset;
+ size = sg_dma_len(sg);
+ while (sg++, --i) {
+ if ((addr + size) != page_to_phys(sg->page) + sg->offset)
+ break;
+ size += sg_dma_len(sg);
+ }
+
+ /* did we run out of descriptors? */
+
+ if(count >= MAX_DMA_DESCRS) {
+ printk("%s: too few DMA descriptors\n", drive->name);
+ return 1;
+ }
+
+ /* however, this case is more difficult - R_ATA_TRANSFER_CNT cannot be more
+ than 65536 words per transfer, so in that case we need to either
+ 1) use a DMA interrupt to re-trigger R_ATA_TRANSFER_CNT and continue with
+ the descriptors, or
+ 2) simply do the request here, and get dma_intr to only ide_end_request on
+ those blocks that were actually set-up for transfer.
+ */
+
+ if(ata_tot_size + size > 131072) {
+ printk("too large total ATA DMA request, %d + %d!\n", ata_tot_size, (int)size);
+ return 1;
+ }
+
+ /* If size > 65536 it has to be splitted into new descriptors. Since we don't handle
+ size > 131072 only one split is necessary */
+
+ if(size > 65536) {
+ /* ok we want to do IO at addr, size bytes. set up a new descriptor entry */
+ ata_descrs[count].sw_len = 0; /* 0 means 65536, this is a 16-bit field */
+ ata_descrs[count].ctrl = 0;
+ ata_descrs[count].buf = addr;
+ ata_descrs[count].next = virt_to_phys(&ata_descrs[count + 1]);
+ count++;
+ ata_tot_size += 65536;
+ /* size and addr should refere to not handled data */
+ size -= 65536;
+ addr += 65536;
+ }
+ /* ok we want to do IO at addr, size bytes. set up a new descriptor entry */
+ if(size == 65536) {
+ ata_descrs[count].sw_len = 0; /* 0 means 65536, this is a 16-bit field */
+ } else {
+ ata_descrs[count].sw_len = size;
+ }
+ ata_descrs[count].ctrl = 0;
+ ata_descrs[count].buf = addr;
+ ata_descrs[count].next = virt_to_phys(&ata_descrs[count + 1]);
+ count++;
+ ata_tot_size += size;
+ }
+
+ if (count) {
+ /* set the end-of-list flag on the last descriptor */
+ ata_descrs[count - 1].ctrl |= d_eol;
+ /* return and say all is ok */
+ return 0;
+ }
+
+ printk("%s: empty DMA table?\n", drive->name);
+ return 1; /* let the PIO routines handle this weirdness */
+}
+
+static int config_drive_for_dma (ide_drive_t *drive)
+{
+ const char **list;
+ struct hd_driveid *id = drive->id;
+
+ if (id && (id->capability & 1)) {
+ /* Enable DMA on any drive that supports mword2 DMA */
+ if ((id->field_valid & 2) && (id->dma_mword & 0x404) == 0x404) {
+ drive->using_dma = 1;
+ return 0; /* DMA enabled */
+ }
+
+ /* Consult the list of known "good" drives */
+ list = good_dma_drives;
+ while (*list) {
+ if (!strcmp(*list++,id->model)) {
+ drive->using_dma = 1;
+ return 0; /* DMA enabled */
+ }
+ }
+ }
+ return 1; /* DMA not enabled */
+}
+
+/*
+ * etrax_dma_intr() is the handler for disk read/write DMA interrupts
+ */
+static ide_startstop_t etrax_dma_intr (ide_drive_t *drive)
+{
+ LED_DISK_READ(0);
+ LED_DISK_WRITE(0);
+
+ return ide_dma_intr(drive);
+}
+
+/*
+ * Functions below initiates/aborts DMA read/write operations on a drive.
+ *
+ * The caller is assumed to have selected the drive and programmed the drive's
+ * sector address using CHS or LBA. All that remains is to prepare for DMA
+ * and then issue the actual read/write DMA/PIO command to the drive.
+ *
+ * Returns 0 if all went well.
+ * Returns 1 if DMA read/write could not be started, in which case
+ * the caller should revert to PIO for the current request.
+ */
+
+static int e100_dma_check(ide_drive_t *drive)
+{
+ return config_drive_for_dma (drive);
+}
+
+static int e100_dma_end(ide_drive_t *drive)
+{
+ /* TODO: check if something went wrong with the DMA */
+ return 0;
+}
+
+static void e100_dma_start(ide_drive_t *drive)
+{
+ if (e100_read_command) {
+ /* begin DMA */
+
+ /* need to do this before RX DMA due to a chip bug
+ * it is enough to just flush the part of the cache that
+ * corresponds to the buffers we start, but since HD transfers
+ * usually are more than 8 kB, it is easier to optimize for the
+ * normal case and just flush the entire cache. its the only
+ * way to be sure! (OB movie quote)
+ */
+ flush_etrax_cache();
+ *R_DMA_CH3_FIRST = virt_to_phys(ata_descrs);
+ *R_DMA_CH3_CMD = IO_STATE(R_DMA_CH3_CMD, cmd, start);
+
+ /* initiate a multi word dma read using DMA handshaking */
+
+ *R_ATA_TRANSFER_CNT =
+ IO_FIELD(R_ATA_TRANSFER_CNT, count, ata_tot_size >> 1);
+
+ *R_ATA_CTRL_DATA =
+ IO_FIELD(R_ATA_CTRL_DATA, data, IDE_DATA_REG) |
+ IO_STATE(R_ATA_CTRL_DATA, rw, read) |
+ IO_STATE(R_ATA_CTRL_DATA, src_dst, dma) |
+ IO_STATE(R_ATA_CTRL_DATA, handsh, dma) |
+ IO_STATE(R_ATA_CTRL_DATA, multi, on) |
+ IO_STATE(R_ATA_CTRL_DATA, dma_size, word);
+
+ LED_DISK_READ(1);
+
+ D(printk("dma read of %d bytes.\n", ata_tot_size));
+
+ } else {
+ /* writing */
+ /* begin DMA */
+
+ *R_DMA_CH2_FIRST = virt_to_phys(ata_descrs);
+ *R_DMA_CH2_CMD = IO_STATE(R_DMA_CH2_CMD, cmd, start);
+
+ /* initiate a multi word dma write using DMA handshaking */
+
+ *R_ATA_TRANSFER_CNT =
+ IO_FIELD(R_ATA_TRANSFER_CNT, count, ata_tot_size >> 1);
+
+ *R_ATA_CTRL_DATA =
+ IO_FIELD(R_ATA_CTRL_DATA, data, IDE_DATA_REG) |
+ IO_STATE(R_ATA_CTRL_DATA, rw, write) |
+ IO_STATE(R_ATA_CTRL_DATA, src_dst, dma) |
+ IO_STATE(R_ATA_CTRL_DATA, handsh, dma) |
+ IO_STATE(R_ATA_CTRL_DATA, multi, on) |
+ IO_STATE(R_ATA_CTRL_DATA, dma_size, word);
+
+ LED_DISK_WRITE(1);
+
+ D(printk("dma write of %d bytes.\n", ata_tot_size));
+ }
+}
diff --git a/drivers/ide/h8300/ide-h8300.c b/drivers/ide/h8300/ide-h8300.c
new file mode 100644
index 000000000000..fb91cb8bf2d2
--- /dev/null
+++ b/drivers/ide/h8300/ide-h8300.c
@@ -0,0 +1,119 @@
+/*
+ * drivers/ide/ide-h8300.c
+ * H8/300 generic IDE interface
+ */
+
+#include <linux/init.h>
+#include <linux/ide.h>
+#include <linux/config.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#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 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);
+}
+
+#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 <= IDE_STATUS_OFFSET; i++)
+ hw->io_ports[i] = CONFIG_H8300_IDE_BASE + H8300_IDE_GAP*i;
+ hw->io_ports[IDE_CONTROL_OFFSET] = CONFIG_H8300_IDE_ALT;
+ hw->irq = EXT_IRQ0 + CONFIG_H8300_IDE_IRQ;
+ hw->dma = NO_DMA;
+ hw->chipset = ide_generic;
+}
+
+static inline void hwif_setup(ide_hwif_t *hwif)
+{
+ default_hwif_iops(hwif);
+
+ hwif->mmio = 2;
+ hwif->OUTW = mm_outw;
+ hwif->OUTSW = mm_outsw;
+ hwif->INW = mm_inw;
+ hwif->INSW = mm_insw;
+ hwif->OUTL = NULL;
+ hwif->INL = NULL;
+ hwif->OUTSL = NULL;
+ hwif->INSL = NULL;
+}
+
+void __init h8300_ide_init(void)
+{
+ hw_regs_t hw;
+ ide_hwif_t *hwif;
+ int idx;
+
+ 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);
+
+ /* register if */
+ idx = ide_register_hw(&hw, &hwif);
+ if (idx == -1) {
+ printk(KERN_ERR "ide-h8300: IDE I/F register failed\n");
+ return;
+ }
+
+ hwif_setup(hwif);
+ printk(KERN_INFO "ide%d: H8/300 generic IDE interface\n", idx);
+ return;
+
+out_busy:
+ printk(KERN_ERR "ide-h8300: IDE I/F resource already used.\n");
+}
diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c
new file mode 100644
index 000000000000..33a020faeabd
--- /dev/null
+++ b/drivers/ide/ide-cd.c
@@ -0,0 +1,3524 @@
+/*
+ * linux/drivers/ide/ide-cd.c
+ *
+ * Copyright (C) 1994, 1995, 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>
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See linux/COPYING for more information.
+ *
+ * ATAPI CD-ROM driver. To be used with ide.c.
+ * 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
+ *
+ * Drives that deviate from these standards will be accommodated as much
+ * as possible via compile time or command-line options. Since I only have
+ * a few drives, you generally need to send me patches...
+ *
+ * ----------------------------------
+ * TO DO LIST:
+ * -Make it so that Pioneer CD DR-A24X and friends don't get screwed up on
+ * boot
+ *
+ * ----------------------------------
+ * 1.00 Oct 31, 1994 -- Initial version.
+ * 1.01 Nov 2, 1994 -- Fixed problem with starting request in
+ * cdrom_check_status.
+ * 1.03 Nov 25, 1994 -- leaving unmask_intr[] as a user-setting (as for disks)
+ * (from mlord) -- minor changes to cdrom_setup()
+ * -- renamed ide_dev_s to ide_drive_t, enable irq on command
+ * 2.00 Nov 27, 1994 -- Generalize packet command interface;
+ * add audio ioctls.
+ * 2.01 Dec 3, 1994 -- Rework packet command interface to handle devices
+ * which send an interrupt when ready for a command.
+ * 2.02 Dec 11, 1994 -- Cache the TOC in the driver.
+ * Don't use SCMD_PLAYAUDIO_TI; it's not included
+ * in the current version of ATAPI.
+ * Try to use LBA instead of track or MSF addressing
+ * when possible.
+ * Don't wait for READY_STAT.
+ * 2.03 Jan 10, 1995 -- Rewrite block read routines to handle block sizes
+ * other than 2k and to move multiple sectors in a
+ * single transaction.
+ * 2.04 Apr 21, 1995 -- Add work-around for Creative Labs CD220E drives.
+ * Thanks to Nick Saw <cwsaw@pts7.pts.mot.com> for
+ * help in figuring this out. Ditto for Acer and
+ * Aztech drives, which seem to have the same problem.
+ * 2.04b May 30, 1995 -- Fix to match changes in ide.c version 3.16 -ml
+ * 2.05 Jun 8, 1995 -- Don't attempt to retry after an illegal request
+ * or data protect error.
+ * Use HWIF and DEV_HWIF macros as in ide.c.
+ * Always try to do a request_sense after
+ * a failed command.
+ * Include an option to give textual descriptions
+ * of ATAPI errors.
+ * Fix a bug in handling the sector cache which
+ * showed up if the drive returned data in 512 byte
+ * blocks (like Pioneer drives). Thanks to
+ * Richard Hirst <srh@gpt.co.uk> for diagnosing this.
+ * Properly supply the page number field in the
+ * MODE_SELECT command.
+ * PLAYAUDIO12 is broken on the Aztech; work around it.
+ * 2.05x Aug 11, 1995 -- lots of data structure renaming/restructuring in ide.c
+ * (my apologies to Scott, but now ide-cd.c is independent)
+ * 3.00 Aug 22, 1995 -- Implement CDROMMULTISESSION ioctl.
+ * Implement CDROMREADAUDIO ioctl (UNTESTED).
+ * Use input_ide_data() and output_ide_data().
+ * Add door locking.
+ * Fix usage count leak in cdrom_open, which happened
+ * when a read-write mount was attempted.
+ * Try to load the disk on open.
+ * Implement CDROMEJECT_SW ioctl (off by default).
+ * Read total cdrom capacity during open.
+ * Rearrange logic in cdrom_decode_status. Issue
+ * request sense commands for failed packet commands
+ * from here instead of from cdrom_queue_packet_command.
+ * Fix a race condition in retrieving error information.
+ * Suppress printing normal unit attention errors and
+ * some drive not ready errors.
+ * Implement CDROMVOLREAD ioctl.
+ * Implement CDROMREADMODE1/2 ioctls.
+ * Fix race condition in setting up interrupt handlers
+ * when the `serialize' option is used.
+ * 3.01 Sep 2, 1995 -- Fix ordering of reenabling interrupts in
+ * cdrom_queue_request.
+ * Another try at using ide_[input,output]_data.
+ * 3.02 Sep 16, 1995 -- Stick total disk capacity in partition table as well.
+ * Make VERBOSE_IDE_CD_ERRORS dump failed command again.
+ * Dump out more information for ILLEGAL REQUEST errs.
+ * Fix handling of errors occurring before the
+ * packet command is transferred.
+ * Fix transfers with odd bytelengths.
+ * 3.03 Oct 27, 1995 -- Some Creative drives have an id of just `CD'.
+ * `DCI-2S10' drives are broken too.
+ * 3.04 Nov 20, 1995 -- So are Vertos drives.
+ * 3.05 Dec 1, 1995 -- Changes to go with overhaul of ide.c and ide-tape.c
+ * 3.06 Dec 16, 1995 -- Add support needed for partitions.
+ * More workarounds for Vertos bugs (based on patches
+ * from Holger Dietze <dietze@aix520.informatik.uni-leipzig.de>).
+ * Try to eliminate byteorder assumptions.
+ * Use atapi_cdrom_subchnl struct definition.
+ * Add STANDARD_ATAPI compilation option.
+ * 3.07 Jan 29, 1996 -- More twiddling for broken drives: Sony 55D,
+ * Vertos 300.
+ * Add NO_DOOR_LOCKING configuration option.
+ * Handle drive_cmd requests w/NULL args (for hdparm -t).
+ * Work around sporadic Sony55e audio play problem.
+ * 3.07a Feb 11, 1996 -- check drive->id for NULL before dereferencing, to fix
+ * problem with "hde=cdrom" with no drive present. -ml
+ * 3.08 Mar 6, 1996 -- More Vertos workarounds.
+ * 3.09 Apr 5, 1996 -- Add CDROMCLOSETRAY ioctl.
+ * Switch to using MSF addressing for audio commands.
+ * Reformat to match kernel tabbing style.
+ * Add CDROM_GET_UPC ioctl.
+ * 3.10 Apr 10, 1996 -- Fix compilation error with STANDARD_ATAPI.
+ * 3.11 Apr 29, 1996 -- Patch from Heiko Eissfeldt <heiko@colossus.escape.de>
+ * to remove redundant verify_area calls.
+ * 3.12 May 7, 1996 -- Rudimentary changer support. Based on patches
+ * from Gerhard Zuber <zuber@berlin.snafu.de>.
+ * Let open succeed even if there's no loaded disc.
+ * 3.13 May 19, 1996 -- Fixes for changer code.
+ * 3.14 May 29, 1996 -- Add work-around for Vertos 600.
+ * (From Hennus Bergman <hennus@sky.ow.nl>.)
+ * 3.15 July 2, 1996 -- Added support for Sanyo 3 CD changers
+ * from Ben Galliart <bgallia@luc.edu> with
+ * special help from Jeff Lightfoot
+ * <jeffml@pobox.com>
+ * 3.15a July 9, 1996 -- Improved Sanyo 3 CD changer identification
+ * 3.16 Jul 28, 1996 -- Fix from Gadi to reduce kernel stack usage for ioctl.
+ * 3.17 Sep 17, 1996 -- Tweak audio reads for some drives.
+ * Start changing CDROMLOADFROMSLOT to CDROM_SELECT_DISC.
+ * 3.18 Oct 31, 1996 -- Added module and DMA support.
+ *
+ *
+ * 4.00 Nov 5, 1996 -- New ide-cd maintainer,
+ * Erik B. Andersen <andersee@debian.org>
+ * -- Newer Creative drives don't always set the error
+ * register correctly. Make sure we see media changes
+ * regardless.
+ * -- Integrate with generic cdrom driver.
+ * -- CDROMGETSPINDOWN and CDROMSETSPINDOWN ioctls, based on
+ * a patch from Ciro Cattuto <>.
+ * -- Call set_device_ro.
+ * -- Implement CDROMMECHANISMSTATUS and CDROMSLOTTABLE
+ * ioctls, based on patch by Erik Andersen
+ * -- Add some probes of drive capability during setup.
+ *
+ * 4.01 Nov 11, 1996 -- Split into ide-cd.c and ide-cd.h
+ * -- Removed CDROMMECHANISMSTATUS and CDROMSLOTTABLE
+ * ioctls in favor of a generalized approach
+ * using the generic cdrom driver.
+ * -- Fully integrated with the 2.1.X kernel.
+ * -- Other stuff that I forgot (lots of changes)
+ *
+ * 4.02 Dec 01, 1996 -- Applied patch from Gadi Oxman <gadio@netvision.net.il>
+ * to fix the drive door locking problems.
+ *
+ * 4.03 Dec 04, 1996 -- Added DSC overlap support.
+ * 4.04 Dec 29, 1996 -- Added CDROMREADRAW ioclt based on patch
+ * by Ales Makarov (xmakarov@sun.felk.cvut.cz)
+ *
+ * 4.05 Nov 20, 1997 -- Modified to print more drive info on init
+ * Minor other changes
+ * Fix errors on CDROMSTOP (If you have a "Dolphin",
+ * you must define IHAVEADOLPHIN)
+ * Added identifier so new Sanyo CD-changer works
+ * Better detection if door locking isn't supported
+ *
+ * 4.06 Dec 17, 1997 -- fixed endless "tray open" messages -ml
+ * 4.07 Dec 17, 1997 -- fallback to set pc->stat on "tray open"
+ * 4.08 Dec 18, 1997 -- spew less noise when tray is empty
+ * -- fix speed display for ACER 24X, 18X
+ * 4.09 Jan 04, 1998 -- fix handling of the last block so we return
+ * an end of file instead of an I/O error (Gadi)
+ * 4.10 Jan 24, 1998 -- fixed a bug so now changers can change to a new
+ * slot when there is no disc in the current slot.
+ * -- Fixed a memory leak where info->changer_info was
+ * malloc'ed but never free'd when closing the device.
+ * -- Cleaned up the global namespace a bit by making more
+ * functions static that should already have been.
+ * 4.11 Mar 12, 1998 -- Added support for the CDROM_SELECT_SPEED ioctl
+ * based on a patch for 2.0.33 by Jelle Foks
+ * <jelle@scintilla.utwente.nl>, a patch for 2.0.33
+ * by Toni Giorgino <toni@pcape2.pi.infn.it>, the SCSI
+ * version, and my own efforts. -erik
+ * -- Fixed a stupid bug which egcs was kind enough to
+ * inform me of where "Illegal mode for this track"
+ * was never returned due to a comparison on data
+ * types of limited range.
+ * 4.12 Mar 29, 1998 -- Fixed bug in CDROM_SELECT_SPEED so write speed is
+ * now set ionly for CD-R and CD-RW drives. I had
+ * removed this support because it produced errors.
+ * It produced errors _only_ for non-writers. duh.
+ * 4.13 May 05, 1998 -- Suppress useless "in progress of becoming ready"
+ * messages, since this is not an error.
+ * -- Change error messages to be const
+ * -- Remove a "\t" which looks ugly in the syslogs
+ * 4.14 July 17, 1998 -- Change to pointing to .ps version of ATAPI spec
+ * since the .pdf version doesn't seem to work...
+ * -- Updated the TODO list to something more current.
+ *
+ * 4.15 Aug 25, 1998 -- Updated ide-cd.h to respect mechine endianess,
+ * patch thanks to "Eddie C. Dost" <ecd@skynet.be>
+ *
+ * 4.50 Oct 19, 1998 -- New maintainers!
+ * Jens Axboe <axboe@image.dk>
+ * Chris Zwilling <chris@cloudnet.com>
+ *
+ * 4.51 Dec 23, 1998 -- Jens Axboe <axboe@image.dk>
+ * - ide_cdrom_reset enabled since the ide subsystem
+ * handles resets fine now. <axboe@image.dk>
+ * - Transfer size fix for Samsung CD-ROMs, thanks to
+ * "Ville Hallik" <ville.hallik@mail.ee>.
+ * - other minor stuff.
+ *
+ * 4.52 Jan 19, 1999 -- Jens Axboe <axboe@image.dk>
+ * - Detect DVD-ROM/RAM drives
+ *
+ * 4.53 Feb 22, 1999 - Include other model Samsung and one Goldstar
+ * drive in transfer size limit.
+ * - Fix the I/O error when doing eject without a medium
+ * loaded on some drives.
+ * - CDROMREADMODE2 is now implemented through
+ * CDROMREADRAW, since many drives don't support
+ * MODE2 (even though ATAPI 2.6 says they must).
+ * - Added ignore parameter to ide-cd (as a module), eg
+ * insmod ide-cd ignore='hda hdb'
+ * Useful when using ide-cd in conjunction with
+ * ide-scsi. TODO: non-modular way of doing the
+ * same.
+ *
+ * 4.54 Aug 5, 1999 - Support for MMC2 class commands through the generic
+ * packet interface to cdrom.c.
+ * - Unified audio ioctl support, most of it.
+ * - cleaned up various deprecated verify_area().
+ * - Added ide_cdrom_packet() as the interface for
+ * the Uniform generic_packet().
+ * - bunch of other stuff, will fill in logs later.
+ * - report 1 slot for non-changers, like the other
+ * cd-rom drivers. don't report select disc for
+ * non-changers as well.
+ * - mask out audio playing, if the device can't do it.
+ *
+ * 4.55 Sep 1, 1999 - Eliminated the rest of the audio ioctls, except
+ * for CDROMREADTOC[ENTRY|HEADER]. Some of the drivers
+ * use this independently of the actual audio handling.
+ * They will disappear later when I get the time to
+ * do it cleanly.
+ * - Minimize the TOC reading - only do it when we
+ * know a media change has occurred.
+ * - Moved all the CDROMREADx ioctls to the Uniform layer.
+ * - Heiko Eissfeldt <heiko@colossus.escape.de> supplied
+ * some fixes for CDI.
+ * - CD-ROM leaving door locked fix from Andries
+ * Brouwer <Andries.Brouwer@cwi.nl>
+ * - Erik Andersen <andersen@xmission.com> unified
+ * commands across the various drivers and how
+ * sense errors are handled.
+ *
+ * 4.56 Sep 12, 1999 - Removed changer support - it is now in the
+ * Uniform layer.
+ * - Added partition based multisession handling.
+ * - Mode sense and mode select moved to the
+ * Uniform layer.
+ * - Fixed a problem with WPI CDS-32X drive - it
+ * failed the capabilities
+ *
+ * 4.57 Apr 7, 2000 - Fixed sense reporting.
+ * - Fixed possible oops in ide_cdrom_get_last_session()
+ * - Fix locking mania and make ide_cdrom_reset relock
+ * - Stop spewing errors to log when magicdev polls with
+ * TEST_UNIT_READY on some drives.
+ * - Various fixes from Tobias Ringstrom:
+ * tray if it was locked prior to the reset.
+ * - cdrom_read_capacity returns one frame too little.
+ * - Fix real capacity reporting.
+ *
+ * 4.58 May 1, 2000 - Clean up ACER50 stuff.
+ * - Fix small problem with ide_cdrom_capacity
+ *
+ * 4.59 Aug 11, 2000 - Fix changer problem in cdrom_read_toc, we weren't
+ * correctly sensing a disc change.
+ * - Rearranged some code
+ * - Use extended sense on drives that support it for
+ * correctly reporting tray status -- from
+ * Michael D Johnson <johnsom@orst.edu>
+ * 4.60 Dec 17, 2003 - Add mt rainier support
+ * - Bump timeout for packet commands, matches sr
+ * - Odd stuff
+ * 4.61 Jan 22, 2004 - support hardware sector sizes other than 2kB,
+ * Pascal Schmidt <der.eremit@email.de>
+ *
+ *************************************************************************/
+
+#define IDECD_VERSION "4.61"
+
+#include <linux/config.h>
+#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 <scsi/scsi.h> /* For SCSI -> ATAPI command conversion */
+
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/byteorder.h>
+#include <asm/uaccess.h>
+#include <asm/unaligned.h>
+
+#include "ide-cd.h"
+
+static DECLARE_MUTEX(idecd_ref_sem);
+
+#define to_ide_cd(obj) container_of(obj, struct cdrom_info, kref)
+
+#define ide_cd_g(disk) \
+ container_of((disk)->private_data, struct cdrom_info, driver)
+
+static struct cdrom_info *ide_cd_get(struct gendisk *disk)
+{
+ struct cdrom_info *cd = NULL;
+
+ down(&idecd_ref_sem);
+ cd = ide_cd_g(disk);
+ if (cd)
+ kref_get(&cd->kref);
+ up(&idecd_ref_sem);
+ return cd;
+}
+
+static void ide_cd_release(struct kref *);
+
+static void ide_cd_put(struct cdrom_info *cd)
+{
+ down(&idecd_ref_sem);
+ kref_put(&cd->kref, ide_cd_release);
+ up(&idecd_ref_sem);
+}
+
+/****************************************************************************
+ * 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)
+{
+ struct cdrom_info *info = drive->driver_data;
+
+ CDROM_STATE_FLAGS (drive)->media_changed = 1;
+ CDROM_STATE_FLAGS (drive)->toc_valid = 0;
+ info->nsectors_buffered = 0;
+}
+
+static int cdrom_log_sense(ide_drive_t *drive, struct request *rq,
+ struct request_sense *sense)
+{
+ int log = 0;
+
+ if (!sense || !rq || (rq->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)
+ log = 0;
+ 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)
+{
+ 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;
+
+#if VERBOSE_IDE_CD_ERRORS
+ {
+ int i;
+ const char *s;
+ char buf[80];
+
+ printk ("ATAPI device %s:\n", drive->name);
+ if (sense->error_code==0x70)
+ printk(" Error: ");
+ else if (sense->error_code==0x71)
+ printk(" Deferred Error: ");
+ else if (sense->error_code == 0x7f)
+ printk(" Vendor-specific Error: ");
+ else
+ printk(" Unknown Error Type: ");
+
+ if (sense->sense_key < ARY_LEN(sense_key_texts))
+ s = sense_key_texts[sense->sense_key];
+ else
+ s = "bad sense key!";
+
+ printk("%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 = ARY_LEN(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= ARY_LEN (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<sizeof (failed_command->cmd); i++)
+ printk ("%02x ", failed_command->cmd[i]);
+ printk ("\"\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 (" bit %d", sense->sks[0] & 0x07);
+
+ printk ("\n");
+ }
+ }
+
+#else /* not VERBOSE_IDE_CD_ERRORS */
+
+ /* 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",
+ drive->name,
+ sense->error_code, sense->sense_key,
+ sense->asc, sense->ascq);
+#endif /* not VERBOSE_IDE_CD_ERRORS */
+}
+
+/*
+ * Initialize a ide-cd packet command request
+ */
+static void cdrom_prepare_request(ide_drive_t *drive, struct request *rq)
+{
+ struct cdrom_info *cd = drive->driver_data;
+
+ ide_init_drive_cmd(rq);
+ rq->flags = REQ_PC;
+ rq->rq_disk = cd->disk;
+}
+
+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;
+
+ if (sense == NULL)
+ sense = &info->sense_data;
+
+ /* stuff the sense request in front of our current request */
+ cdrom_prepare_request(drive, rq);
+
+ rq->data = sense;
+ rq->cmd[0] = GPCMD_REQUEST_SENSE;
+ rq->cmd[4] = rq->data_len = 18;
+
+ rq->flags = REQ_SENSE;
+
+ /* NOTE! Save the failed command in "rq->buffer" */
+ rq->buffer = (void *) failed_command;
+
+ (void) ide_do_drive_cmd(drive, rq, ide_preempt);
+}
+
+static void cdrom_end_request (ide_drive_t *drive, int uptodate)
+{
+ struct request *rq = HWGROUP(drive)->rq;
+ int nsectors = rq->hard_cur_sectors;
+
+ if ((rq->flags & REQ_SENSE) && uptodate) {
+ /*
+ * For REQ_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;
+ }
+
+ /*
+ * now end failed request
+ */
+ spin_lock_irqsave(&ide_lock, flags);
+ end_that_request_chunk(failed, 0, failed->data_len);
+ end_that_request_last(failed);
+ spin_unlock_irqrestore(&ide_lock, flags);
+ }
+
+ cdrom_analyze_sense_data(drive, failed, 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_end_request(drive, uptodate, nsectors);
+}
+
+/* Returns 0 if the request should be continued.
+ Returns 1 if the request was ended. */
+static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret)
+{
+ struct request *rq = HWGROUP(drive)->rq;
+ int stat, err, sense_key;
+
+ /* Check for errors. */
+ stat = HWIF(drive)->INB(IDE_STATUS_REG);
+ if (stat_ret)
+ *stat_ret = stat;
+
+ if (OK_STAT(stat, good_stat, BAD_R_STAT))
+ return 0;
+
+ /* Get the IDE error register. */
+ err = HWIF(drive)->INB(IDE_ERROR_REG);
+ sense_key = err >> 4;
+
+ if (rq == NULL) {
+ printk("%s: missing rq in cdrom_decode_status\n", drive->name);
+ return 1;
+ }
+
+ if (rq->flags & REQ_SENSE) {
+ /* 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->flags |= REQ_FAILED;
+ cdrom_end_request(drive, 0);
+ ide_error(drive, "request sense failure", stat);
+ return 1;
+
+ } else if (rq->flags & (REQ_PC | REQ_BLOCK_PC)) {
+ /* All other functions, except for READ. */
+ unsigned long flags;
+
+ /*
+ * if we have an error, pass back CHECK_CONDITION as the
+ * scsi status byte
+ */
+ if ((rq->flags & REQ_BLOCK_PC) && !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);
+ /*printk("%s: media changed\n",drive->name);*/
+ return 0;
+ } else if (!(rq->flags & REQ_QUIET)) {
+ /* Otherwise, print an error. */
+ ide_dump_status(drive, "packet command error", stat);
+ }
+
+ rq->flags |= REQ_FAILED;
+
+ /*
+ * instead of playing games with moving completions around,
+ * remove failed request completely and end it when the
+ * request sense has completed
+ */
+ if (stat & ERR_STAT) {
+ 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);
+
+ } 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 ("%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 (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 (drive, "media error (bad sector)", stat);
+ do_end_request = 1;
+ } else if (sense_key == BLANK_CHECK) {
+ /* Disk appears blank ?? */
+ ide_dump_status (drive, "media error (blank)", stat);
+ do_end_request = 1;
+ } else if ((err & ~ABRT_ERR) != 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;
+ }
+
+ if (do_end_request)
+ cdrom_end_request(drive, 0);
+
+ /* If we got a CHECK_CONDITION status,
+ queue a request sense command. */
+ if ((stat & ERR_STAT) != 0)
+ cdrom_queue_request_sense(drive, NULL, NULL);
+ } else {
+ blk_dump_rq_flags(rq, "ide-cd: bad rq");
+ cdrom_end_request(drive, 0);
+ }
+
+ /* Retry, or handle the next request. */
+ return 1;
+}
+
+static int cdrom_timer_expiry(ide_drive_t *drive)
+{
+ struct request *rq = HWGROUP(drive)->rq;
+ unsigned long wait = 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->flags & REQ_QUIET))
+ printk(KERN_INFO "ide-cd: 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_startstop_t startstop;
+ struct cdrom_info *info = drive->driver_data;
+ ide_hwif_t *hwif = drive->hwif;
+
+ /* Wait for the controller to be idle. */
+ if (ide_wait_stat(&startstop, drive, 0, BUSY_STAT, WAIT_READY))
+ return startstop;
+
+ if (info->dma)
+ info->dma = !hwif->dma_setup(drive);
+
+ /* Set up the controller registers. */
+ /* FIXME: for Virtual DMA we must check harder */
+ HWIF(drive)->OUTB(info->dma, IDE_FEATURE_REG);
+ HWIF(drive)->OUTB(0, IDE_IREASON_REG);
+ HWIF(drive)->OUTB(0, IDE_SECTOR_REG);
+
+ HWIF(drive)->OUTB(xferlen & 0xff, IDE_BCOUNTL_REG);
+ HWIF(drive)->OUTB(xferlen >> 8 , IDE_BCOUNTH_REG);
+ if (IDE_CONTROL_REG)
+ HWIF(drive)->OUTB(drive->ctl, IDE_CONTROL_REG);
+
+ if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) {
+ /* packet command */
+ ide_execute_command(drive, WIN_PACKETCMD, handler, ATAPI_WAIT_PC, cdrom_timer_expiry);
+ return ide_started;
+ } else {
+ unsigned long flags;
+
+ /* packet command */
+ spin_lock_irqsave(&ide_lock, flags);
+ hwif->OUTBSYNC(drive, WIN_PACKETCMD, IDE_COMMAND_REG);
+ ndelay(400);
+ spin_unlock_irqrestore(&ide_lock, flags);
+
+ 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. */
+/*
+ * changed 5 parameters to 3 for dvd-ram
+ * struct packet_command *pc; now packet_command_t *pc;
+ */
+#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;
+ struct cdrom_info *info = drive->driver_data;
+ ide_startstop_t startstop;
+
+ if (CDROM_CONFIG_FLAGS(drive)->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, DRQ_STAT, NULL))
+ return ide_stopped;
+ } else {
+ /* Otherwise, we must wait for DRQ to get set. */
+ if (ide_wait_stat(&startstop, drive, DRQ_STAT,
+ BUSY_STAT, 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(drive)->atapi_output_bytes(drive, rq->cmd, cmd_len);
+
+ /* Start the DMA if need be */
+ if (info->dma)
+ hwif->dma_start(drive);
+
+ return ide_started;
+}
+
+/****************************************************************************
+ * Block read functions.
+ */
+
+/*
+ * Buffer up to SECTORS_TO_TRANSFER sectors from the drive in our sector
+ * buffer. Once the first sector is added, any subsequent sectors are
+ * assumed to be continuous (until the buffer is cleared). For the first
+ * sector added, SECTOR is its sector number. (SECTOR is then ignored until
+ * the buffer is cleared.)
+ */
+static void cdrom_buffer_sectors (ide_drive_t *drive, unsigned long sector,
+ int sectors_to_transfer)
+{
+ struct cdrom_info *info = drive->driver_data;
+
+ /* Number of sectors to read into the buffer. */
+ int sectors_to_buffer = min_t(int, sectors_to_transfer,
+ (SECTOR_BUFFER_SIZE >> SECTOR_BITS) -
+ info->nsectors_buffered);
+
+ char *dest;
+
+ /* If we couldn't get a buffer, don't try to buffer anything... */
+ if (info->buffer == NULL)
+ sectors_to_buffer = 0;
+
+ /* If this is the first sector in the buffer, remember its number. */
+ if (info->nsectors_buffered == 0)
+ info->sector_buffered = sector;
+
+ /* Read the data into the buffer. */
+ dest = info->buffer + info->nsectors_buffered * SECTOR_SIZE;
+ while (sectors_to_buffer > 0) {
+ HWIF(drive)->atapi_input_bytes(drive, dest, SECTOR_SIZE);
+ --sectors_to_buffer;
+ --sectors_to_transfer;
+ ++info->nsectors_buffered;
+ dest += SECTOR_SIZE;
+ }
+
+ /* Throw away any remaining data. */
+ while (sectors_to_transfer > 0) {
+ static char dum[SECTOR_SIZE];
+ HWIF(drive)->atapi_input_bytes(drive, dum, sizeof (dum));
+ --sectors_to_transfer;
+ }
+}
+
+/*
+ * 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 inline
+int cdrom_read_check_ireason (ide_drive_t *drive, int len, int ireason)
+{
+ if (ireason == 2)
+ return 0;
+ else if (ireason == 0) {
+ /* Whoops... The drive is expecting to receive data from us! */
+ printk(KERN_ERR "%s: read_intr: Drive wants to transfer data the "
+ "wrong way!\n", drive->name);
+
+ /* Throw some data at the drive so it doesn't hang
+ and quit this request. */
+ while (len > 0) {
+ int dum = 0;
+ HWIF(drive)->atapi_output_bytes(drive, &dum, sizeof (dum));
+ len -= sizeof (dum);
+ }
+ } else if (ireason == 1) {
+ /* Some drives (ASUS) seem to tell us that status
+ * info is available. just get it and ignore.
+ */
+ (void) HWIF(drive)->INB(IDE_STATUS_REG);
+ return 0;
+ } else {
+ /* Drive wants a command packet, or invalid ireason... */
+ printk(KERN_ERR "%s: read_intr: bad interrupt reason %x\n", drive->name,
+ ireason);
+ }
+
+ cdrom_end_request(drive, 0);
+ return -1;
+}
+
+/*
+ * Interrupt routine. Called when a read request has completed.
+ */
+static ide_startstop_t cdrom_read_intr (ide_drive_t *drive)
+{
+ int stat;
+ int ireason, len, sectors_to_transfer, nskip;
+ struct cdrom_info *info = drive->driver_data;
+ u8 lowcyl = 0, highcyl = 0;
+ int dma = info->dma, dma_error = 0;
+
+ struct request *rq = HWGROUP(drive)->rq;
+
+ /*
+ * handle dma case
+ */
+ if (dma) {
+ info->dma = 0;
+ if ((dma_error = HWIF(drive)->ide_dma_end(drive)))
+ __ide_dma_off(drive);
+ }
+
+ if (cdrom_decode_status(drive, 0, &stat))
+ return ide_stopped;
+
+ if (dma) {
+ if (!dma_error) {
+ ide_end_request(drive, 1, rq->nr_sectors);
+ return ide_stopped;
+ } else
+ return ide_error(drive, "dma error", stat);
+ }
+
+ /* Read the interrupt reason and the transfer length. */
+ ireason = HWIF(drive)->INB(IDE_IREASON_REG) & 0x3;
+ lowcyl = HWIF(drive)->INB(IDE_BCOUNTL_REG);
+ highcyl = HWIF(drive)->INB(IDE_BCOUNTH_REG);
+
+ len = lowcyl + (256 * highcyl);
+
+ /* If DRQ is clear, the command has completed. */
+ if ((stat & DRQ_STAT) == 0) {
+ /* If we're not done filling the current buffer, complain.
+ Otherwise, complete the command normally. */
+ if (rq->current_nr_sectors > 0) {
+ printk (KERN_ERR "%s: cdrom_read_intr: data underrun (%d blocks)\n",
+ drive->name, rq->current_nr_sectors);
+ rq->flags |= REQ_FAILED;
+ cdrom_end_request(drive, 0);
+ } else
+ cdrom_end_request(drive, 1);
+ return ide_stopped;
+ }
+
+ /* Check that the drive is expecting to do the same thing we are. */
+ if (cdrom_read_check_ireason (drive, len, ireason))
+ return ide_stopped;
+
+ /* 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. */
+ if ((len % SECTOR_SIZE) != 0) {
+ printk (KERN_ERR "%s: cdrom_read_intr: Bad transfer size %d\n",
+ drive->name, len);
+ if (CDROM_CONFIG_FLAGS(drive)->limit_nframes)
+ printk (KERN_ERR " This drive is not supported by this version of the driver\n");
+ else {
+ printk (KERN_ERR " Trying to limit transfer sizes\n");
+ CDROM_CONFIG_FLAGS(drive)->limit_nframes = 1;
+ }
+ cdrom_end_request(drive, 0);
+ return ide_stopped;
+ }
+
+ /* The number of sectors we need to read from the drive. */
+ sectors_to_transfer = len / SECTOR_SIZE;
+
+ /* 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), sectors_to_transfer);
+
+ while (nskip > 0) {
+ /* We need to throw away a sector. */
+ static char dum[SECTOR_SIZE];
+ HWIF(drive)->atapi_input_bytes(drive, dum, sizeof (dum));
+
+ --rq->current_nr_sectors;
+ --nskip;
+ --sectors_to_transfer;
+ }
+
+ /* Now loop while we still have data to read from the drive. */
+ while (sectors_to_transfer > 0) {
+ int this_transfer;
+
+ /* If we've filled the present buffer but there's another
+ chained buffer after it, move on. */
+ if (rq->current_nr_sectors == 0 && rq->nr_sectors)
+ cdrom_end_request(drive, 1);
+
+ /* If the buffers are full, cache the rest of the data in our
+ internal buffer. */
+ if (rq->current_nr_sectors == 0) {
+ cdrom_buffer_sectors(drive, rq->sector, sectors_to_transfer);
+ sectors_to_transfer = 0;
+ } else {
+ /* Transfer data to the buffers.
+ Figure out how many sectors we can transfer
+ to the current buffer. */
+ this_transfer = min_t(int, sectors_to_transfer,
+ rq->current_nr_sectors);
+
+ /* Read this_transfer sectors
+ into the current buffer. */
+ while (this_transfer > 0) {
+ HWIF(drive)->atapi_input_bytes(drive, rq->buffer, SECTOR_SIZE);
+ rq->buffer += SECTOR_SIZE;
+ --rq->nr_sectors;
+ --rq->current_nr_sectors;
+ ++rq->sector;
+ --this_transfer;
+ --sectors_to_transfer;
+ }
+ }
+ }
+
+ /* Done moving data! Wait for another interrupt. */
+ ide_set_handler(drive, &cdrom_read_intr, ATAPI_WAIT_PC, NULL);
+ return ide_started;
+}
+
+/*
+ * Try to satisfy some of the current read request from our cached data.
+ * Returns nonzero if the request has been completed, zero otherwise.
+ */
+static int cdrom_read_from_buffer (ide_drive_t *drive)
+{
+ struct cdrom_info *info = drive->driver_data;
+ struct request *rq = HWGROUP(drive)->rq;
+ unsigned short sectors_per_frame;
+
+ sectors_per_frame = queue_hardsect_size(drive->queue) >> SECTOR_BITS;
+
+ /* Can't do anything if there's no buffer. */
+ if (info->buffer == NULL) return 0;
+
+ /* Loop while this request needs data and the next block is present
+ in our cache. */
+ while (rq->nr_sectors > 0 &&
+ rq->sector >= info->sector_buffered &&
+ rq->sector < info->sector_buffered + info->nsectors_buffered) {
+ if (rq->current_nr_sectors == 0)
+ cdrom_end_request(drive, 1);
+
+ memcpy (rq->buffer,
+ info->buffer +
+ (rq->sector - info->sector_buffered) * SECTOR_SIZE,
+ SECTOR_SIZE);
+ rq->buffer += SECTOR_SIZE;
+ --rq->current_nr_sectors;
+ --rq->nr_sectors;
+ ++rq->sector;
+ }
+
+ /* If we've satisfied the current request,
+ terminate it successfully. */
+ if (rq->nr_sectors == 0) {
+ cdrom_end_request(drive, 1);
+ return -1;
+ }
+
+ /* Move on to the next buffer if needed. */
+ if (rq->current_nr_sectors == 0)
+ cdrom_end_request(drive, 1);
+
+ /* If this condition does not hold, then the kluge i use to
+ represent the number of sectors to skip at the start of a transfer
+ will fail. I think that this will never happen, but let's be
+ paranoid and check. */
+ if (rq->current_nr_sectors < bio_cur_sectors(rq->bio) &&
+ (rq->sector & (sectors_per_frame - 1))) {
+ printk(KERN_ERR "%s: cdrom_read_from_buffer: buffer botch (%ld)\n",
+ drive->name, (long)rq->sector);
+ cdrom_end_request(drive, 0);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Routine to send a read packet command to the drive.
+ * This is usually called directly from cdrom_start_read.
+ * 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_read_continuation (ide_drive_t *drive)
+{
+ struct request *rq = HWGROUP(drive)->rq;
+ unsigned short sectors_per_frame;
+ int nskip;
+
+ sectors_per_frame = queue_hardsect_size(drive->queue) >> SECTOR_BITS;
+
+ /* If the requested sector doesn't start on a cdrom block boundary,
+ we must adjust the start of the transfer so that it does,
+ and remember to skip the first few sectors.
+ If the 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 CURRENT_NR_SECTORS
+ is larger than the buffer size. */
+ nskip = rq->sector & (sectors_per_frame - 1);
+ if (nskip > 0) {
+ /* Sanity check... */
+ if (rq->current_nr_sectors != bio_cur_sectors(rq->bio) &&
+ (rq->sector & (sectors_per_frame - 1))) {
+ printk(KERN_ERR "%s: cdrom_start_read_continuation: buffer botch (%u)\n",
+ drive->name, 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;
+
+ /* Send the command to the drive and return. */
+ return cdrom_transfer_packet_command(drive, rq, &cdrom_read_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;
+
+ if (cdrom_decode_status(drive, 0, &stat))
+ return ide_stopped;
+ CDROM_CONFIG_FLAGS(drive)->seeking = 1;
+
+ if (retry && time_after(jiffies, info->start_seek + IDECD_SEEK_TIMER)) {
+ if (--retry == 0) {
+ /*
+ * this condition is far too common, to bother
+ * users about it
+ */
+ /* printk("%s: disabled DSC seek overlap\n", drive->name);*/
+ drive->dsc_overlap = 0;
+ }
+ }
+ return ide_stopped;
+}
+
+static ide_startstop_t cdrom_start_seek_continuation (ide_drive_t *drive)
+{
+ struct request *rq = HWGROUP(drive)->rq;
+ sector_t frame = rq->sector;
+
+ sector_div(frame, queue_hardsect_size(drive->queue) >> SECTOR_BITS);
+
+ memset(rq->cmd, 0, sizeof(rq->cmd));
+ rq->cmd[0] = GPCMD_SEEK;
+ put_unaligned(cpu_to_be32(frame), (unsigned int *) &rq->cmd[2]);
+
+ rq->timeout = ATAPI_WAIT_PC;
+ return cdrom_transfer_packet_command(drive, rq, &cdrom_seek_intr);
+}
+
+static ide_startstop_t cdrom_start_seek (ide_drive_t *drive, unsigned int block)
+{
+ struct cdrom_info *info = drive->driver_data;
+
+ info->dma = 0;
+ info->cmd = 0;
+ info->start_seek = jiffies;
+ return cdrom_start_packet_command(drive, 0, cdrom_start_seek_continuation);
+}
+
+/* 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 restore_request (struct request *rq)
+{
+ 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->hard_cur_sectors = rq->current_nr_sectors = bio_cur_sectors(rq->bio);
+ rq->hard_nr_sectors = rq->nr_sectors;
+ rq->hard_sector = rq->sector;
+ rq->q->prep_rq_fn(rq->q, rq);
+}
+
+/*
+ * Start a read request from the CD-ROM.
+ */
+static ide_startstop_t cdrom_start_read (ide_drive_t *drive, unsigned int block)
+{
+ struct cdrom_info *info = drive->driver_data;
+ struct request *rq = HWGROUP(drive)->rq;
+ unsigned short sectors_per_frame;
+
+ sectors_per_frame = queue_hardsect_size(drive->queue) >> SECTOR_BITS;
+
+ /* We may be retrying this request after an error. Fix up
+ any weirdness which might be present in the request packet. */
+ restore_request(rq);
+
+ /* Satisfy whatever we can of this request from our cached sector. */
+ if (cdrom_read_from_buffer(drive))
+ return ide_stopped;
+
+ blk_attempt_remerge(drive->queue, rq);
+
+ /* Clear the local sector buffer. */
+ info->nsectors_buffered = 0;
+
+ /* use dma, if possible. */
+ info->dma = drive->using_dma;
+ if ((rq->sector & (sectors_per_frame - 1)) ||
+ (rq->nr_sectors & (sectors_per_frame - 1)))
+ info->dma = 0;
+
+ info->cmd = READ;
+
+ /* Start sending the read request to the drive. */
+ return cdrom_start_packet_command(drive, 32768, cdrom_start_read_continuation);
+}
+
+/****************************************************************************
+ * Execute all other packet commands.
+ */
+
+/* Interrupt routine for packet command completion. */
+static ide_startstop_t cdrom_pc_intr (ide_drive_t *drive)
+{
+ int ireason, len, thislen;
+ struct request *rq = HWGROUP(drive)->rq;
+ u8 lowcyl = 0, highcyl = 0;
+ int stat;
+
+ /* Check for errors. */
+ if (cdrom_decode_status(drive, 0, &stat))
+ return ide_stopped;
+
+ /* Read the interrupt reason and the transfer length. */
+ ireason = HWIF(drive)->INB(IDE_IREASON_REG);
+ lowcyl = HWIF(drive)->INB(IDE_BCOUNTL_REG);
+ highcyl = HWIF(drive)->INB(IDE_BCOUNTH_REG);
+
+ len = lowcyl + (256 * highcyl);
+
+ /* If DRQ is clear, the command has completed.
+ Complain if we still have data left to transfer. */
+ if ((stat & DRQ_STAT) == 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) {
+ *(unsigned char *)rq->data++ = 0;
+ --rq->data_len;
+ }
+ }
+
+ if (rq->data_len == 0)
+ cdrom_end_request(drive, 1);
+ else {
+ /* Comment this out, because this always happens
+ right after a reset occurs, and it is annoying to
+ always print expected stuff. */
+ /*
+ printk ("%s: cdrom_pc_intr: data underrun %d\n",
+ drive->name, pc->buflen);
+ */
+ rq->flags |= REQ_FAILED;
+ cdrom_end_request(drive, 0);
+ }
+ return ide_stopped;
+ }
+
+ /* Figure out how much data to transfer. */
+ thislen = rq->data_len;
+ if (thislen > len) thislen = len;
+
+ /* The drive wants to be written to. */
+ if ((ireason & 3) == 0) {
+ if (!rq->data) {
+ blk_dump_rq_flags(rq, "cdrom_pc_intr, write");
+ goto confused;
+ }
+ /* Transfer the data. */
+ HWIF(drive)->atapi_output_bytes(drive, rq->data, thislen);
+
+ /* If we haven't moved enough data to satisfy the drive,
+ add some padding. */
+ while (len > thislen) {
+ int dum = 0;
+ HWIF(drive)->atapi_output_bytes(drive, &dum, sizeof(dum));
+ len -= sizeof(dum);
+ }
+
+ /* Keep count of how much data we've moved. */
+ rq->data += thislen;
+ rq->data_len -= thislen;
+ }
+
+ /* Same drill for reading. */
+ else if ((ireason & 3) == 2) {
+ if (!rq->data) {
+ blk_dump_rq_flags(rq, "cdrom_pc_intr, write");
+ goto confused;
+ }
+ /* Transfer the data. */
+ HWIF(drive)->atapi_input_bytes(drive, rq->data, thislen);
+
+ /* If we haven't moved enough data to satisfy the drive,
+ add some padding. */
+ while (len > thislen) {
+ int dum = 0;
+ HWIF(drive)->atapi_input_bytes(drive, &dum, sizeof(dum));
+ len -= sizeof(dum);
+ }
+
+ /* Keep count of how much data we've moved. */
+ rq->data += thislen;
+ rq->data_len -= thislen;
+
+ if (rq->flags & REQ_SENSE)
+ rq->sense_len += thislen;
+ } else {
+confused:
+ printk (KERN_ERR "%s: cdrom_pc_intr: The drive "
+ "appears confused (ireason = 0x%02x)\n",
+ drive->name, ireason);
+ rq->flags |= REQ_FAILED;
+ }
+
+ /* Now we wait for another interrupt. */
+ ide_set_handler(drive, &cdrom_pc_intr, ATAPI_WAIT_PC, cdrom_timer_expiry);
+ return ide_started;
+}
+
+static ide_startstop_t cdrom_do_pc_continuation (ide_drive_t *drive)
+{
+ struct request *rq = HWGROUP(drive)->rq;
+
+ if (!rq->timeout)
+ rq->timeout = ATAPI_WAIT_PC;
+
+ /* Send the command to the drive and return. */
+ return cdrom_transfer_packet_command(drive, rq, &cdrom_pc_intr);
+}
+
+
+static ide_startstop_t cdrom_do_packet_command (ide_drive_t *drive)
+{
+ int len;
+ struct request *rq = HWGROUP(drive)->rq;
+ struct cdrom_info *info = drive->driver_data;
+
+ info->dma = 0;
+ info->cmd = 0;
+ rq->flags &= ~REQ_FAILED;
+ len = rq->data_len;
+
+ /* Start sending the command to the drive. */
+ return cdrom_start_packet_command(drive, len, cdrom_do_pc_continuation);
+}
+
+
+static
+int cdrom_queue_packet_command(ide_drive_t *drive, struct request *rq)
+{
+ struct request_sense sense;
+ int retries = 10;
+ unsigned int flags = rq->flags;
+
+ if (rq->sense == NULL)
+ rq->sense = &sense;
+
+ /* Start of retry loop. */
+ do {
+ int error;
+ unsigned long time = jiffies;
+ rq->flags = flags;
+
+ error = ide_do_drive_cmd(drive, rq, ide_wait);
+ time = jiffies - time;
+
+ /* FIXME: we should probably abort/retry or something
+ * in case of failure */
+ if (rq->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 = rq->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 ((rq->flags & REQ_FAILED) && retries >= 0);
+
+ /* Return an error if the command failed. */
+ return (rq->flags & REQ_FAILED) ? -EIO : 0;
+}
+
+/*
+ * Write handling
+ */
+static inline int cdrom_write_check_ireason(ide_drive_t *drive, int len, int ireason)
+{
+ /* Two notes about IDE interrupt reason here - 0 means that
+ * the drive wants to receive data from us, 2 means that
+ * the drive is expecting to transfer data to us.
+ */
+ if (ireason == 0)
+ return 0;
+ else if (ireason == 2) {
+ /* Whoops... The drive wants to send data. */
+ printk(KERN_ERR "%s: write_intr: wrong transfer direction!\n",
+ drive->name);
+
+ while (len > 0) {
+ int dum = 0;
+ HWIF(drive)->atapi_input_bytes(drive, &dum, sizeof(dum));
+ len -= sizeof(dum);
+ }
+ } else {
+ /* Drive wants a command packet, or invalid ireason... */
+ printk(KERN_ERR "%s: write_intr: bad interrupt reason %x\n",
+ drive->name, ireason);
+ }
+
+ cdrom_end_request(drive, 0);
+ return 1;
+}
+
+static void post_transform_command(struct request *req)
+{
+ u8 *c = req->cmd;
+ char *ibuf;
+
+ if (!blk_pc_request(req))
+ return;
+
+ if (req->bio)
+ ibuf = bio_data(req->bio);
+ else
+ ibuf = req->data;
+
+ if (!ibuf)
+ return;
+
+ /*
+ * set ansi-revision and response data as atapi
+ */
+ if (c[0] == GPCMD_INQUIRY) {
+ ibuf[2] |= 2;
+ ibuf[3] = (ibuf[3] & 0xf0) | 2;
+ }
+}
+
+typedef void (xfer_func_t)(ide_drive_t *, void *, u32);
+
+/*
+ * best way to deal with dma that is not sector aligned right now... note
+ * that in this path we are not using ->data or ->buffer at all. this irs
+ * can replace cdrom_pc_intr, cdrom_read_intr, and cdrom_write_intr in the
+ * future.
+ */
+static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
+{
+ struct cdrom_info *info = drive->driver_data;
+ struct request *rq = HWGROUP(drive)->rq;
+ int dma_error, dma, stat, ireason, len, thislen;
+ u8 lowcyl, highcyl;
+ xfer_func_t *xferfunc;
+ unsigned long flags;
+
+ /* Check for errors. */
+ dma_error = 0;
+ dma = info->dma;
+ if (dma) {
+ info->dma = 0;
+ dma_error = HWIF(drive)->ide_dma_end(drive);
+ }
+
+ if (cdrom_decode_status(drive, 0, &stat))
+ return ide_stopped;
+
+ /*
+ * using dma, transfer is complete now
+ */
+ if (dma) {
+ if (dma_error) {
+ printk(KERN_ERR "ide-cd: dma error\n");
+ __ide_dma_off(drive);
+ return ide_error(drive, "dma error", stat);
+ }
+
+ end_that_request_chunk(rq, 1, rq->data_len);
+ rq->data_len = 0;
+ goto end_request;
+ }
+
+ /*
+ * ok we fall to pio :/
+ */
+ ireason = HWIF(drive)->INB(IDE_IREASON_REG) & 0x3;
+ lowcyl = HWIF(drive)->INB(IDE_BCOUNTL_REG);
+ highcyl = HWIF(drive)->INB(IDE_BCOUNTH_REG);
+
+ len = lowcyl + (256 * highcyl);
+ thislen = rq->data_len;
+ if (thislen > len)
+ thislen = len;
+
+ /*
+ * If DRQ is clear, the command has completed.
+ */
+ if ((stat & DRQ_STAT) == 0)
+ goto end_request;
+
+ /*
+ * check which way to transfer data
+ */
+ if (rq_data_dir(rq) == WRITE) {
+ /*
+ * write to drive
+ */
+ if (cdrom_write_check_ireason(drive, len, ireason))
+ return ide_stopped;
+
+ xferfunc = HWIF(drive)->atapi_output_bytes;
+ } else {
+ /*
+ * read from drive
+ */
+ if (cdrom_read_check_ireason(drive, len, ireason))
+ return ide_stopped;
+
+ xferfunc = HWIF(drive)->atapi_input_bytes;
+ }
+
+ /*
+ * transfer data
+ */
+ while (thislen > 0) {
+ int blen = blen = rq->data_len;
+ char *ptr = rq->data;
+
+ /*
+ * bio backed?
+ */
+ if (rq->bio) {
+ ptr = bio_data(rq->bio);
+ blen = bio_iovec(rq->bio)->bv_len;
+ }
+
+ if (!ptr) {
+ printk(KERN_ERR "%s: confused, missing data\n", drive->name);
+ break;
+ }
+
+ if (blen > thislen)
+ blen = thislen;
+
+ xferfunc(drive, ptr, blen);
+
+ thislen -= blen;
+ len -= blen;
+ rq->data_len -= blen;
+
+ if (rq->bio)
+ end_that_request_chunk(rq, 1, blen);
+ else
+ rq->data += blen;
+ }
+
+ /*
+ * pad, if necessary
+ */
+ if (len > 0) {
+ while (len > 0) {
+ int pad = 0;
+
+ xferfunc(drive, &pad, sizeof(pad));
+ len -= sizeof(pad);
+ }
+ }
+
+ if (HWGROUP(drive)->handler != NULL)
+ BUG();
+
+ ide_set_handler(drive, cdrom_newpc_intr, rq->timeout, NULL);
+ return ide_started;
+
+end_request:
+ if (!rq->data_len)
+ post_transform_command(rq);
+
+ spin_lock_irqsave(&ide_lock, flags);
+ blkdev_dequeue_request(rq);
+ end_that_request_last(rq);
+ HWGROUP(drive)->rq = NULL;
+ spin_unlock_irqrestore(&ide_lock, flags);
+ return ide_stopped;
+}
+
+static ide_startstop_t cdrom_write_intr(ide_drive_t *drive)
+{
+ int stat, ireason, len, sectors_to_transfer, uptodate;
+ struct cdrom_info *info = drive->driver_data;
+ int dma_error = 0, dma = info->dma;
+ u8 lowcyl = 0, highcyl = 0;
+
+ struct request *rq = HWGROUP(drive)->rq;
+
+ /* Check for errors. */
+ if (dma) {
+ info->dma = 0;
+ if ((dma_error = HWIF(drive)->ide_dma_end(drive))) {
+ printk(KERN_ERR "ide-cd: write dma error\n");
+ __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);
+
+ ide_end_request(drive, 1, rq->nr_sectors);
+ return ide_stopped;
+ }
+
+ /* Read the interrupt reason and the transfer length. */
+ ireason = HWIF(drive)->INB(IDE_IREASON_REG);
+ lowcyl = HWIF(drive)->INB(IDE_BCOUNTL_REG);
+ highcyl = HWIF(drive)->INB(IDE_BCOUNTH_REG);
+
+ len = lowcyl + (256 * highcyl);
+
+ /* If DRQ is clear, the command has completed. */
+ if ((stat & DRQ_STAT) == 0) {
+ /* If we're not done writing, complain.
+ * Otherwise, complete the command normally.
+ */
+ uptodate = 1;
+ if (rq->current_nr_sectors > 0) {
+ printk(KERN_ERR "%s: write_intr: data underrun (%d blocks)\n",
+ drive->name, rq->current_nr_sectors);
+ uptodate = 0;
+ }
+ cdrom_end_request(drive, uptodate);
+ return ide_stopped;
+ }
+
+ /* Check that the drive is expecting to do the same thing we are. */
+ if (cdrom_write_check_ireason(drive, len, ireason))
+ return ide_stopped;
+
+ sectors_to_transfer = len / SECTOR_SIZE;
+
+ /*
+ * now loop and write out the data
+ */
+ while (sectors_to_transfer > 0) {
+ int this_transfer;
+
+ if (!rq->current_nr_sectors) {
+ printk(KERN_ERR "ide-cd: write_intr: oops\n");
+ break;
+ }
+
+ /*
+ * Figure out how many sectors we can transfer
+ */
+ this_transfer = min_t(int, sectors_to_transfer, rq->current_nr_sectors);
+
+ while (this_transfer > 0) {
+ HWIF(drive)->atapi_output_bytes(drive, rq->buffer, SECTOR_SIZE);
+ rq->buffer += SECTOR_SIZE;
+ --rq->nr_sectors;
+ --rq->current_nr_sectors;
+ ++rq->sector;
+ --this_transfer;
+ --sectors_to_transfer;
+ }
+
+ /*
+ * current buffer complete, move on
+ */
+ if (rq->current_nr_sectors == 0 && rq->nr_sectors)
+ cdrom_end_request(drive, 1);
+ }
+
+ /* re-arm handler */
+ ide_set_handler(drive, &cdrom_write_intr, ATAPI_WAIT_PC, NULL);
+ return ide_started;
+}
+
+static ide_startstop_t cdrom_start_write_cont(ide_drive_t *drive)
+{
+ struct request *rq = HWGROUP(drive)->rq;
+
+#if 0 /* the immediate bit */
+ rq->cmd[1] = 1 << 3;
+#endif
+ rq->timeout = ATAPI_WAIT_PC;
+
+ return cdrom_transfer_packet_command(drive, rq, cdrom_write_intr);
+}
+
+static ide_startstop_t cdrom_start_write(ide_drive_t *drive, struct request *rq)
+{
+ struct cdrom_info *info = drive->driver_data;
+ struct gendisk *g = info->disk;
+ unsigned short sectors_per_frame = queue_hardsect_size(drive->queue) >> SECTOR_BITS;
+
+ /*
+ * writes *must* be hardware frame aligned
+ */
+ if ((rq->nr_sectors & (sectors_per_frame - 1)) ||
+ (rq->sector & (sectors_per_frame - 1))) {
+ cdrom_end_request(drive, 0);
+ return ide_stopped;
+ }
+
+ /*
+ * disk has become write protected
+ */
+ if (g->policy) {
+ cdrom_end_request(drive, 0);
+ return ide_stopped;
+ }
+
+ /*
+ * for dvd-ram and such media, it's a really big deal to get
+ * big writes all the time. so scour the queue and attempt to
+ * remerge requests, often the plugging will not have had time
+ * to do this properly
+ */
+ blk_attempt_remerge(drive->queue, rq);
+
+ info->nsectors_buffered = 0;
+
+ /* use dma, if possible. we don't need to check more, since we
+ * know that the transfer is always (at least!) frame aligned */
+ info->dma = drive->using_dma ? 1 : 0;
+ info->cmd = WRITE;
+
+ info->devinfo.media_written = 1;
+
+ /* Start sending the write request to the drive. */
+ return cdrom_start_packet_command(drive, 32768, cdrom_start_write_cont);
+}
+
+static ide_startstop_t cdrom_do_newpc_cont(ide_drive_t *drive)
+{
+ struct request *rq = HWGROUP(drive)->rq;
+
+ if (!rq->timeout)
+ rq->timeout = ATAPI_WAIT_PC;
+
+ return cdrom_transfer_packet_command(drive, rq, cdrom_newpc_intr);
+}
+
+static ide_startstop_t cdrom_do_block_pc(ide_drive_t *drive, struct request *rq)
+{
+ struct cdrom_info *info = drive->driver_data;
+
+ rq->flags |= REQ_QUIET;
+
+ info->dma = 0;
+ info->cmd = 0;
+
+ /*
+ * sg request
+ */
+ if (rq->bio) {
+ int mask = drive->queue->dma_alignment;
+ unsigned long addr = (unsigned long) page_address(bio_page(rq->bio));
+
+ info->cmd = rq_data_dir(rq);
+ info->dma = drive->using_dma;
+
+ /*
+ * check if dma is safe
+ */
+ if ((rq->data_len & mask) || (addr & mask))
+ info->dma = 0;
+ }
+
+ /* Start sending the command to the drive. */
+ return cdrom_start_packet_command(drive, rq->data_len, cdrom_do_newpc_cont);
+}
+
+/****************************************************************************
+ * cdrom driver request routine.
+ */
+static ide_startstop_t
+ide_do_rw_cdrom (ide_drive_t *drive, struct request *rq, sector_t block)
+{
+ ide_startstop_t action;
+ struct cdrom_info *info = drive->driver_data;
+
+ if (blk_fs_request(rq)) {
+ if (CDROM_CONFIG_FLAGS(drive)->seeking) {
+ unsigned long elapsed = jiffies - info->start_seek;
+ int stat = HWIF(drive)->INB(IDE_STATUS_REG);
+
+ if ((stat & SEEK_STAT) != SEEK_STAT) {
+ if (elapsed < IDECD_SEEK_TIMEOUT) {
+ ide_stall_queue(drive, IDECD_SEEK_TIMER);
+ return ide_stopped;
+ }
+ printk (KERN_ERR "%s: DSC timeout\n", drive->name);
+ }
+ CDROM_CONFIG_FLAGS(drive)->seeking = 0;
+ }
+ if ((rq_data_dir(rq) == READ) && IDE_LARGE_SEEK(info->last_block, block, IDECD_SEEK_THRESHOLD) && drive->dsc_overlap) {
+ action = cdrom_start_seek(drive, block);
+ } else {
+ if (rq_data_dir(rq) == READ)
+ action = cdrom_start_read(drive, block);
+ else
+ action = cdrom_start_write(drive, rq);
+ }
+ info->last_block = block;
+ return action;
+ } else if (rq->flags & (REQ_PC | REQ_SENSE)) {
+ return cdrom_do_packet_command(drive);
+ } else if (rq->flags & REQ_BLOCK_PC) {
+ return cdrom_do_block_pc(drive, rq);
+ } else if (rq->flags & REQ_SPECIAL) {
+ /*
+ * right now this can only be a reset...
+ */
+ cdrom_end_request(drive, 1);
+ return ide_stopped;
+ }
+
+ blk_dump_rq_flags(rq, "ide-cd bad flags");
+ cdrom_end_request(drive, 0);
+ return ide_stopped;
+}
+
+
+
+/****************************************************************************
+ * 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.
+ */
+
+#if ! STANDARD_ATAPI
+static inline
+int bin2bcd (int x)
+{
+ return (x%10) | ((x/10) << 4);
+}
+
+
+static inline
+int bcd2bin (int x)
+{
+ return (x >> 4) * 10 + (x & 0x0f);
+}
+
+static
+void msf_from_bcd (struct atapi_msf *msf)
+{
+ msf->minute = bcd2bin (msf->minute);
+ msf->second = bcd2bin (msf->second);
+ msf->frame = bcd2bin (msf->frame);
+}
+
+#endif /* not STANDARD_ATAPI */
+
+
+static inline
+void lba_to_msf (int lba, byte *m, byte *s, byte *f)
+{
+ lba += CD_MSF_OFFSET;
+ lba &= 0xffffff; /* negative lbas use only 24 bits */
+ *m = lba / (CD_SECS * CD_FRAMES);
+ lba %= (CD_SECS * CD_FRAMES);
+ *s = lba / CD_FRAMES;
+ *f = lba % CD_FRAMES;
+}
+
+
+static inline
+int msf_to_lba (byte m, byte s, byte f)
+{
+ return (((m * CD_SECS) + s) * CD_FRAMES + f) - CD_MSF_OFFSET;
+}
+
+static int cdrom_check_status(ide_drive_t *drive, struct request_sense *sense)
+{
+ struct request req;
+ struct cdrom_info *info = drive->driver_data;
+ struct cdrom_device_info *cdi = &info->devinfo;
+
+ cdrom_prepare_request(drive, &req);
+
+ req.sense = sense;
+ req.cmd[0] = GPCMD_TEST_UNIT_READY;
+ req.flags |= REQ_QUIET;
+
+#if ! STANDARD_ATAPI
+ /* the Sanyo 3 CD changer uses byte 7 of TEST_UNIT_READY to
+ switch CDs instead of supporting the LOAD_UNLOAD opcode */
+
+ req.cmd[7] = cdi->sanyo_slot % 3;
+#endif /* not STANDARD_ATAPI */
+
+ return cdrom_queue_packet_command(drive, &req);
+}
+
+
+/* Lock the door if LOCKFLAG is nonzero; unlock it otherwise. */
+static int
+cdrom_lockdoor(ide_drive_t *drive, int lockflag, struct request_sense *sense)
+{
+ struct request_sense my_sense;
+ struct request req;
+ int stat;
+
+ if (sense == NULL)
+ sense = &my_sense;
+
+ /* If the drive cannot lock the door, just pretend. */
+ if (CDROM_CONFIG_FLAGS(drive)->no_doorlock) {
+ stat = 0;
+ } else {
+ cdrom_prepare_request(drive, &req);
+ req.sense = sense;
+ req.cmd[0] = GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL;
+ req.cmd[4] = lockflag ? 1 : 0;
+ stat = cdrom_queue_packet_command(drive, &req);
+ }
+
+ /* 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);
+ CDROM_CONFIG_FLAGS(drive)->no_doorlock = 1;
+ stat = 0;
+ }
+
+ /* no medium, that's alright. */
+ if (stat != 0 && sense->sense_key == NOT_READY && sense->asc == 0x3a)
+ stat = 0;
+
+ if (stat == 0)
+ CDROM_STATE_FLAGS(drive)->door_locked = lockflag;
+
+ return stat;
+}
+
+
+/* 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 request req;
+ char loej = 0x02;
+
+ if (CDROM_CONFIG_FLAGS(drive)->no_eject && !ejectflag)
+ return -EDRIVE_CANT_DO_THIS;
+
+ /* reload fails on some drives, if the tray is locked */
+ if (CDROM_STATE_FLAGS(drive)->door_locked && ejectflag)
+ return 0;
+
+ cdrom_prepare_request(drive, &req);
+
+ /* only tell drive to close tray if open, if it can do that */
+ if (ejectflag && !CDROM_CONFIG_FLAGS(drive)->close_tray)
+ loej = 0;
+
+ req.sense = sense;
+ req.cmd[0] = GPCMD_START_STOP_UNIT;
+ req.cmd[4] = loej | (ejectflag != 0);
+ return cdrom_queue_packet_command(drive, &req);
+}
+
+static int cdrom_read_capacity(ide_drive_t *drive, unsigned long *capacity,
+ unsigned long *sectors_per_frame,
+ struct request_sense *sense)
+{
+ struct {
+ __u32 lba;
+ __u32 blocklen;
+ } capbuf;
+
+ int stat;
+ struct request req;
+
+ cdrom_prepare_request(drive, &req);
+
+ req.sense = sense;
+ req.cmd[0] = GPCMD_READ_CDVD_CAPACITY;
+ req.data = (char *)&capbuf;
+ req.data_len = sizeof(capbuf);
+
+ stat = cdrom_queue_packet_command(drive, &req);
+ if (stat == 0) {
+ *capacity = 1 + be32_to_cpu(capbuf.lba);
+ *sectors_per_frame =
+ be32_to_cpu(capbuf.blocklen) >> SECTOR_BITS;
+ }
+
+ return stat;
+}
+
+static int cdrom_read_tocentry(ide_drive_t *drive, int trackno, int msf_flag,
+ int format, char *buf, int buflen,
+ struct request_sense *sense)
+{
+ struct request req;
+
+ cdrom_prepare_request(drive, &req);
+
+ req.sense = sense;
+ req.data = buf;
+ req.data_len = buflen;
+ req.flags |= REQ_QUIET;
+ req.cmd[0] = GPCMD_READ_TOC_PMA_ATIP;
+ req.cmd[6] = trackno;
+ req.cmd[7] = (buflen >> 8);
+ req.cmd[8] = (buflen & 0xff);
+ req.cmd[9] = (format << 6);
+
+ if (msf_flag)
+ req.cmd[1] = 2;
+
+ return cdrom_queue_packet_command(drive, &req);
+}
+
+
+/* Try to read the entire TOC for the disk into our internal buffer. */
+static int cdrom_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;
+
+ if (toc == NULL) {
+ /* Try to allocate space. */
+ toc = (struct atapi_toc *) kmalloc (sizeof (struct atapi_toc),
+ GFP_KERNEL);
+ info->toc = toc;
+ if (toc == NULL) {
+ printk (KERN_ERR "%s: No cdrom TOC buffer!\n", drive->name);
+ return -ENOMEM;
+ }
+ }
+
+ /* Check to see if the existing data is still valid.
+ If it is, just return. */
+ (void) cdrom_check_status(drive, sense);
+
+ if (CDROM_STATE_FLAGS(drive)->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);
+ 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 ! STANDARD_ATAPI
+ if (CDROM_CONFIG_FLAGS(drive)->toctracks_as_bcd) {
+ toc->hdr.first_track = bcd2bin(toc->hdr.first_track);
+ toc->hdr.last_track = bcd2bin(toc->hdr.last_track);
+ }
+#endif /* not STANDARD_ATAPI */
+
+ 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 ! STANDARD_ATAPI
+ if (CDROM_CONFIG_FLAGS(drive)->toctracks_as_bcd) {
+ toc->hdr.first_track = bin2bcd(CDROM_LEADOUT);
+ toc->hdr.last_track = bin2bcd(CDROM_LEADOUT);
+ } else
+#endif /* not STANDARD_ATAPI */
+ {
+ toc->hdr.first_track = CDROM_LEADOUT;
+ toc->hdr.last_track = CDROM_LEADOUT;
+ }
+ }
+
+ if (stat)
+ return stat;
+
+ toc->hdr.toc_length = ntohs (toc->hdr.toc_length);
+
+#if ! STANDARD_ATAPI
+ if (CDROM_CONFIG_FLAGS(drive)->toctracks_as_bcd) {
+ toc->hdr.first_track = bcd2bin(toc->hdr.first_track);
+ toc->hdr.last_track = bcd2bin(toc->hdr.last_track);
+ }
+#endif /* not STANDARD_ATAPI */
+
+ for (i=0; i<=ntracks; i++) {
+#if ! STANDARD_ATAPI
+ if (CDROM_CONFIG_FLAGS(drive)->tocaddr_as_bcd) {
+ if (CDROM_CONFIG_FLAGS(drive)->toctracks_as_bcd)
+ toc->ent[i].track = bcd2bin(toc->ent[i].track);
+ msf_from_bcd(&toc->ent[i].addr.msf);
+ }
+#endif /* not STANDARD_ATAPI */
+ 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);
+ }
+
+ /* Read the multisession information. */
+ 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.first_track = ms_tmp.hdr.last_track = CDROM_LEADOUT;
+ toc->last_session_lba = msf_to_lba(0, 2, 0); /* 0m 2s 0f */
+ }
+
+#if ! STANDARD_ATAPI
+ if (CDROM_CONFIG_FLAGS(drive)->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);
+ }
+#endif /* not STANDARD_ATAPI */
+
+ 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);
+ }
+
+ /* Remember that we've read this stuff. */
+ CDROM_STATE_FLAGS(drive)->toc_valid = 1;
+
+ return 0;
+}
+
+
+static int cdrom_read_subchannel(ide_drive_t *drive, int format, char *buf,
+ int buflen, struct request_sense *sense)
+{
+ struct request req;
+
+ cdrom_prepare_request(drive, &req);
+
+ req.sense = sense;
+ req.data = buf;
+ req.data_len = buflen;
+ req.cmd[0] = GPCMD_READ_SUBCHANNEL;
+ req.cmd[1] = 2; /* MSF addressing */
+ req.cmd[2] = 0x40; /* request subQ data */
+ req.cmd[3] = format;
+ req.cmd[7] = (buflen >> 8);
+ req.cmd[8] = (buflen & 0xff);
+ return cdrom_queue_packet_command(drive, &req);
+}
+
+/* ATAPI cdrom drives are free to select the speed you request or any slower
+ rate :-( Requesting too fast a speed will _not_ produce an error. */
+static int cdrom_select_speed(ide_drive_t *drive, int speed,
+ struct request_sense *sense)
+{
+ struct request req;
+ cdrom_prepare_request(drive, &req);
+
+ req.sense = sense;
+ if (speed == 0)
+ speed = 0xffff; /* set to max */
+ else
+ speed *= 177; /* Nx to kbytes/s */
+
+ req.cmd[0] = GPCMD_SET_SPEED;
+ /* Read Drive speed in kbytes/second MSB */
+ req.cmd[2] = (speed >> 8) & 0xff;
+ /* Read Drive speed in kbytes/second LSB */
+ req.cmd[3] = speed & 0xff;
+ if (CDROM_CONFIG_FLAGS(drive)->cd_r ||
+ CDROM_CONFIG_FLAGS(drive)->cd_rw ||
+ CDROM_CONFIG_FLAGS(drive)->dvd_r) {
+ /* Write Drive speed in kbytes/second MSB */
+ req.cmd[4] = (speed >> 8) & 0xff;
+ /* Write Drive speed in kbytes/second LSB */
+ req.cmd[5] = speed & 0xff;
+ }
+
+ return cdrom_queue_packet_command(drive, &req);
+}
+
+static int cdrom_play_audio(ide_drive_t *drive, int lba_start, int lba_end)
+{
+ struct request_sense sense;
+ struct request req;
+
+ cdrom_prepare_request(drive, &req);
+
+ req.sense = &sense;
+ req.cmd[0] = GPCMD_PLAY_AUDIO_MSF;
+ lba_to_msf(lba_start, &req.cmd[3], &req.cmd[4], &req.cmd[5]);
+ lba_to_msf(lba_end-1, &req.cmd[6], &req.cmd[7], &req.cmd[8]);
+
+ return cdrom_queue_packet_command(drive, &req);
+}
+
+static int cdrom_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 (!CDROM_STATE_FLAGS(drive)->toc_valid)
+ 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;
+}
+
+/* the generic packet interface to cdrom.c */
+static int ide_cdrom_packet(struct cdrom_device_info *cdi,
+ struct packet_command *cgc)
+{
+ struct request req;
+ ide_drive_t *drive = (ide_drive_t*) cdi->handle;
+
+ 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. */
+ cdrom_prepare_request(drive, &req);
+ memcpy(req.cmd, cgc->cmd, CDROM_PACKET_SIZE);
+ if (cgc->sense)
+ memset(cgc->sense, 0, sizeof(struct request_sense));
+ req.data = cgc->buffer;
+ req.data_len = cgc->buflen;
+ req.timeout = cgc->timeout;
+
+ if (cgc->quiet)
+ req.flags |= REQ_QUIET;
+
+ req.sense = cgc->sense;
+ cgc->stat = cdrom_queue_packet_command(drive, &req);
+ if (!cgc->stat)
+ cgc->buflen -= req.data_len;
+ return cgc->stat;
+}
+
+static
+int ide_cdrom_dev_ioctl (struct cdrom_device_info *cdi,
+ unsigned int cmd, unsigned long arg)
+{
+ struct packet_command cgc;
+ char buffer[16];
+ int stat;
+
+ init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_UNKNOWN);
+
+ /* These will be moved into the Uniform layer shortly... */
+ switch (cmd) {
+ case CDROMSETSPINDOWN: {
+ char spindown;
+
+ if (copy_from_user(&spindown, (void __user *) arg, sizeof(char)))
+ return -EFAULT;
+
+ if ((stat = cdrom_mode_sense(cdi, &cgc, GPMODE_CDROM_PAGE, 0)))
+ return stat;
+
+ buffer[11] = (buffer[11] & 0xf0) | (spindown & 0x0f);
+
+ return cdrom_mode_select(cdi, &cgc);
+ }
+
+ case CDROMGETSPINDOWN: {
+ char spindown;
+
+ if ((stat = cdrom_mode_sense(cdi, &cgc, GPMODE_CDROM_PAGE, 0)))
+ return stat;
+
+ spindown = buffer[11] & 0x0f;
+
+ if (copy_to_user((void __user *) arg, &spindown, sizeof (char)))
+ return -EFAULT;
+
+ return 0;
+ }
+
+ default:
+ return -EINVAL;
+ }
+
+}
+
+static
+int ide_cdrom_audio_ioctl (struct cdrom_device_info *cdi,
+ unsigned int cmd, void *arg)
+
+{
+ ide_drive_t *drive = (ide_drive_t*) cdi->handle;
+ struct cdrom_info *info = drive->driver_data;
+ int stat;
+
+ switch (cmd) {
+ /*
+ * emulate PLAY_AUDIO_TI command with PLAY_AUDIO_10, since
+ * atapi doesn't support it
+ */
+ case CDROMPLAYTRKIND: {
+ unsigned long lba_start, lba_end;
+ struct cdrom_ti *ti = (struct cdrom_ti *)arg;
+ struct atapi_toc_entry *first_toc, *last_toc;
+
+ stat = cdrom_get_toc_entry(drive, ti->cdti_trk0, &first_toc);
+ if (stat)
+ return stat;
+
+ stat = cdrom_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;
+
+ return cdrom_play_audio(drive, lba_start, lba_end);
+ }
+
+ case CDROMREADTOCHDR: {
+ struct cdrom_tochdr *tochdr = (struct cdrom_tochdr *) arg;
+ struct atapi_toc *toc;
+
+ /* Make sure our saved TOC is valid. */
+ stat = cdrom_read_toc(drive, NULL);
+ if (stat) return stat;
+
+ toc = info->toc;
+ tochdr->cdth_trk0 = toc->hdr.first_track;
+ tochdr->cdth_trk1 = toc->hdr.last_track;
+
+ return 0;
+ }
+
+ case CDROMREADTOCENTRY: {
+ struct cdrom_tocentry *tocentry = (struct cdrom_tocentry*) arg;
+ struct atapi_toc_entry *toce;
+
+ stat = cdrom_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;
+ }
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static
+int ide_cdrom_reset (struct cdrom_device_info *cdi)
+{
+ ide_drive_t *drive = (ide_drive_t*) cdi->handle;
+ struct request_sense sense;
+ struct request req;
+ int ret;
+
+ cdrom_prepare_request(drive, &req);
+ req.flags = REQ_SPECIAL | REQ_QUIET;
+ ret = ide_do_drive_cmd(drive, &req, ide_wait);
+
+ /*
+ * A reset will unlock the door. If it was previously locked,
+ * lock it again.
+ */
+ if (CDROM_STATE_FLAGS(drive)->door_locked)
+ (void) cdrom_lockdoor(drive, 1, &sense);
+
+ return ret;
+}
+
+
+static
+int ide_cdrom_tray_move (struct cdrom_device_info *cdi, int position)
+{
+ ide_drive_t *drive = (ide_drive_t*) cdi->handle;
+ struct request_sense sense;
+
+ if (position) {
+ int stat = cdrom_lockdoor(drive, 0, &sense);
+ if (stat) return stat;
+ }
+
+ return cdrom_eject(drive, !position, &sense);
+}
+
+static
+int ide_cdrom_lock_door (struct cdrom_device_info *cdi, int lock)
+{
+ ide_drive_t *drive = (ide_drive_t*) cdi->handle;
+ return cdrom_lockdoor(drive, lock, NULL);
+}
+
+static
+int ide_cdrom_select_speed (struct cdrom_device_info *cdi, int speed)
+{
+ ide_drive_t *drive = (ide_drive_t*) cdi->handle;
+ struct request_sense sense;
+ int stat;
+
+ if ((stat = cdrom_select_speed(drive, speed, &sense)) < 0)
+ return stat;
+
+ cdi->speed = CDROM_STATE_FLAGS(drive)->current_speed;
+ return 0;
+}
+
+/*
+ * 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
+ */
+static
+int ide_cdrom_drive_status (struct cdrom_device_info *cdi, int slot_nr)
+{
+ ide_drive_t *drive = (ide_drive_t*) 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) {
+ if (sense.ascq == 1)
+ return CDS_NO_DISC;
+ else if (sense.ascq == 0 || sense.ascq == 2)
+ return CDS_TRAY_OPEN;
+ }
+ }
+
+ return CDS_DRIVE_NOT_READY;
+}
+
+static
+int ide_cdrom_get_last_session (struct cdrom_device_info *cdi,
+ struct cdrom_multisession *ms_info)
+{
+ struct atapi_toc *toc;
+ ide_drive_t *drive = (ide_drive_t*) cdi->handle;
+ struct cdrom_info *info = drive->driver_data;
+ struct request_sense sense;
+ int ret;
+
+ if (!CDROM_STATE_FLAGS(drive)->toc_valid || info->toc == NULL)
+ if ((ret = cdrom_read_toc(drive, &sense)))
+ return ret;
+
+ toc = info->toc;
+ ms_info->addr.lba = toc->last_session_lba;
+ ms_info->xa_flag = toc->xa_flag;
+
+ return 0;
+}
+
+static
+int ide_cdrom_get_mcn (struct cdrom_device_info *cdi,
+ struct cdrom_mcn *mcn_info)
+{
+ int stat;
+ char mcnbuf[24];
+ ide_drive_t *drive = (ide_drive_t*) cdi->handle;
+
+/* get MCN */
+ if ((stat = cdrom_read_subchannel(drive, 2, mcnbuf, sizeof (mcnbuf), NULL)))
+ return stat;
+
+ memcpy (mcn_info->medium_catalog_number, mcnbuf+9,
+ sizeof (mcn_info->medium_catalog_number)-1);
+ mcn_info->medium_catalog_number[sizeof (mcn_info->medium_catalog_number)-1]
+ = '\0';
+
+ return 0;
+}
+
+
+
+/****************************************************************************
+ * Other driver requests (open, close, check media change).
+ */
+
+static
+int ide_cdrom_check_media_change_real (struct cdrom_device_info *cdi,
+ int slot_nr)
+{
+ ide_drive_t *drive = (ide_drive_t*) cdi->handle;
+ int retval;
+
+ if (slot_nr == CDSL_CURRENT) {
+ (void) cdrom_check_status(drive, NULL);
+ retval = CDROM_STATE_FLAGS(drive)->media_changed;
+ CDROM_STATE_FLAGS(drive)->media_changed = 0;
+ return retval;
+ } else {
+ return -EINVAL;
+ }
+}
+
+
+static
+int ide_cdrom_open_real (struct cdrom_device_info *cdi, int purpose)
+{
+ return 0;
+}
+
+/*
+ * Close down the device. Invalidate all cached blocks.
+ */
+
+static
+void ide_cdrom_release_real (struct cdrom_device_info *cdi)
+{
+ ide_drive_t *drive = cdi->handle;
+
+ if (!cdi->use_count)
+ CDROM_STATE_FLAGS(drive)->toc_valid = 0;
+}
+
+
+
+/****************************************************************************
+ * Device initialization.
+ */
+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,
+ .dev_ioctl = ide_cdrom_dev_ioctl,
+ .capability = 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_IOCTLS | 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,
+ .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;
+
+ devinfo->ops = &ide_cdrom_dops;
+ devinfo->mask = 0;
+ devinfo->speed = CDROM_STATE_FLAGS(drive)->current_speed;
+ devinfo->capacity = nslots;
+ devinfo->handle = (void *) drive;
+ strcpy(devinfo->name, drive->name);
+
+ /* set capability mask to match the probe. */
+ if (!CDROM_CONFIG_FLAGS(drive)->cd_r)
+ devinfo->mask |= CDC_CD_R;
+ if (!CDROM_CONFIG_FLAGS(drive)->cd_rw)
+ devinfo->mask |= CDC_CD_RW;
+ if (!CDROM_CONFIG_FLAGS(drive)->dvd)
+ devinfo->mask |= CDC_DVD;
+ if (!CDROM_CONFIG_FLAGS(drive)->dvd_r)
+ devinfo->mask |= CDC_DVD_R;
+ if (!CDROM_CONFIG_FLAGS(drive)->dvd_ram)
+ devinfo->mask |= CDC_DVD_RAM;
+ if (!CDROM_CONFIG_FLAGS(drive)->is_changer)
+ devinfo->mask |= CDC_SELECT_DISC;
+ if (!CDROM_CONFIG_FLAGS(drive)->audio_play)
+ devinfo->mask |= CDC_PLAY_AUDIO;
+ if (!CDROM_CONFIG_FLAGS(drive)->close_tray)
+ devinfo->mask |= CDC_CLOSE_TRAY;
+ if (!CDROM_CONFIG_FLAGS(drive)->mo_drive)
+ devinfo->mask |= CDC_MO_DRIVE;
+
+ devinfo->disk = info->disk;
+ return register_cdrom(devinfo);
+}
+
+static
+int ide_cdrom_get_capabilities(ide_drive_t *drive, struct atapi_capabilities_page *cap)
+{
+ struct cdrom_info *info = drive->driver_data;
+ struct cdrom_device_info *cdi = &info->devinfo;
+ struct packet_command cgc;
+ int stat, attempts = 3, size = sizeof(*cap);
+
+ /*
+ * ACER50 (and others?) require the full spec length mode sense
+ * page capabilities size, but older drives break.
+ */
+ if (!(!strcmp(drive->id->model, "ATAPI CD ROM DRIVE 50X MAX") ||
+ !strcmp(drive->id->model, "WPI CDS-32X")))
+ size -= sizeof(cap->pad);
+
+ init_cdrom_command(&cgc, cap, 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;
+}
+
+static
+int ide_cdrom_probe_capabilities (ide_drive_t *drive)
+{
+ struct cdrom_info *info = drive->driver_data;
+ struct cdrom_device_info *cdi = &info->devinfo;
+ struct atapi_capabilities_page cap;
+ int nslots = 1;
+
+ if (drive->media == ide_optical) {
+ CDROM_CONFIG_FLAGS(drive)->mo_drive = 1;
+ CDROM_CONFIG_FLAGS(drive)->ram = 1;
+ printk(KERN_ERR "%s: ATAPI magneto-optical drive\n", drive->name);
+ return nslots;
+ }
+
+ if (CDROM_CONFIG_FLAGS(drive)->nec260 ||
+ !strcmp(drive->id->model,"STINGRAY 8422 IDE 8X CD-ROM 7-27-95")) {
+ CDROM_CONFIG_FLAGS(drive)->no_eject = 0;
+ CDROM_CONFIG_FLAGS(drive)->audio_play = 1;
+ 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 = (ide_drive_t *) drive;
+ cdi->ops = &ide_cdrom_dops;
+
+ if (ide_cdrom_get_capabilities(drive, &cap))
+ return 0;
+
+ if (cap.lock == 0)
+ CDROM_CONFIG_FLAGS(drive)->no_doorlock = 1;
+ if (cap.eject)
+ CDROM_CONFIG_FLAGS(drive)->no_eject = 0;
+ if (cap.cd_r_write)
+ CDROM_CONFIG_FLAGS(drive)->cd_r = 1;
+ if (cap.cd_rw_write) {
+ CDROM_CONFIG_FLAGS(drive)->cd_rw = 1;
+ CDROM_CONFIG_FLAGS(drive)->ram = 1;
+ }
+ if (cap.test_write)
+ CDROM_CONFIG_FLAGS(drive)->test_write = 1;
+ if (cap.dvd_ram_read || cap.dvd_r_read || cap.dvd_rom)
+ CDROM_CONFIG_FLAGS(drive)->dvd = 1;
+ if (cap.dvd_ram_write) {
+ CDROM_CONFIG_FLAGS(drive)->dvd_ram = 1;
+ CDROM_CONFIG_FLAGS(drive)->ram = 1;
+ }
+ if (cap.dvd_r_write)
+ CDROM_CONFIG_FLAGS(drive)->dvd_r = 1;
+ if (cap.audio_play)
+ CDROM_CONFIG_FLAGS(drive)->audio_play = 1;
+ if (cap.mechtype == mechtype_caddy || cap.mechtype == mechtype_popup)
+ CDROM_CONFIG_FLAGS(drive)->close_tray = 0;
+
+ /* Some drives used by Apple don't advertise audio play
+ * but they do support reading TOC & audio datas
+ */
+ if (strcmp(drive->id->model, "MATSHITADVD-ROM SR-8187") == 0 ||
+ strcmp(drive->id->model, "MATSHITADVD-ROM SR-8186") == 0 ||
+ strcmp(drive->id->model, "MATSHITADVD-ROM SR-8176") == 0 ||
+ strcmp(drive->id->model, "MATSHITADVD-ROM SR-8174") == 0)
+ CDROM_CONFIG_FLAGS(drive)->audio_play = 1;
+
+#if ! STANDARD_ATAPI
+ if (cdi->sanyo_slot > 0) {
+ CDROM_CONFIG_FLAGS(drive)->is_changer = 1;
+ nslots = 3;
+ }
+
+ else
+#endif /* not STANDARD_ATAPI */
+ if (cap.mechtype == mechtype_individual_changer ||
+ cap.mechtype == mechtype_cartridge_changer) {
+ if ((nslots = cdrom_number_of_slots(cdi)) > 1) {
+ CDROM_CONFIG_FLAGS(drive)->is_changer = 1;
+ CDROM_CONFIG_FLAGS(drive)->supp_disc_present = 1;
+ }
+ }
+
+ /* The ACER/AOpen 24X cdrom has the speed fields byte-swapped */
+ if (!drive->id->model[0] &&
+ !strncmp(drive->id->fw_rev, "241N", 4)) {
+ CDROM_STATE_FLAGS(drive)->current_speed =
+ (((unsigned int)cap.curspeed) + (176/2)) / 176;
+ CDROM_CONFIG_FLAGS(drive)->max_speed =
+ (((unsigned int)cap.maxspeed) + (176/2)) / 176;
+ } else {
+ CDROM_STATE_FLAGS(drive)->current_speed =
+ (ntohs(cap.curspeed) + (176/2)) / 176;
+ CDROM_CONFIG_FLAGS(drive)->max_speed =
+ (ntohs(cap.maxspeed) + (176/2)) / 176;
+ }
+
+ /* don't print speed if the drive reported 0.
+ */
+ printk(KERN_INFO "%s: ATAPI", drive->name);
+ if (CDROM_CONFIG_FLAGS(drive)->max_speed)
+ printk(" %dX", CDROM_CONFIG_FLAGS(drive)->max_speed);
+ printk(" %s", CDROM_CONFIG_FLAGS(drive)->dvd ? "DVD-ROM" : "CD-ROM");
+
+ if (CDROM_CONFIG_FLAGS(drive)->dvd_r|CDROM_CONFIG_FLAGS(drive)->dvd_ram)
+ printk(" DVD%s%s",
+ (CDROM_CONFIG_FLAGS(drive)->dvd_r)? "-R" : "",
+ (CDROM_CONFIG_FLAGS(drive)->dvd_ram)? "-RAM" : "");
+
+ if (CDROM_CONFIG_FLAGS(drive)->cd_r|CDROM_CONFIG_FLAGS(drive)->cd_rw)
+ printk(" CD%s%s",
+ (CDROM_CONFIG_FLAGS(drive)->cd_r)? "-R" : "",
+ (CDROM_CONFIG_FLAGS(drive)->cd_rw)? "/RW" : "");
+
+ if (CDROM_CONFIG_FLAGS(drive)->is_changer)
+ printk(" changer w/%d slots", nslots);
+ else
+ printk(" drive");
+
+ printk(", %dkB Cache", be16_to_cpu(cap.buffer_size));
+
+ if (drive->using_dma)
+ ide_dma_verbose(drive);
+
+ printk("\n");
+
+ return nslots;
+}
+
+static void ide_cdrom_add_settings(ide_drive_t *drive)
+{
+ ide_add_setting(drive, "dsc_overlap", SETTING_RW, -1, -1, TYPE_BYTE, 0, 1, 1, 1, &drive->dsc_overlap, NULL);
+}
+
+/*
+ * standard prep_rq_fn that builds 10 byte cmds
+ */
+static int ide_cdrom_prep_fs(request_queue_t *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, sizeof(rq->cmd));
+
+ 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(request_queue_t *q, struct request *rq)
+{
+ if (rq->flags & REQ_CMD)
+ return ide_cdrom_prep_fs(q, rq);
+ else if (rq->flags & REQ_BLOCK_PC)
+ return ide_cdrom_prep_pc(rq);
+
+ return 0;
+}
+
+static
+int ide_cdrom_setup (ide_drive_t *drive)
+{
+ struct cdrom_info *info = drive->driver_data;
+ struct cdrom_device_info *cdi = &info->devinfo;
+ int nslots;
+
+ blk_queue_prep_rq(drive->queue, ide_cdrom_prep_fn);
+ blk_queue_dma_alignment(drive->queue, 31);
+ drive->queue->unplug_delay = (1 * HZ) / 1000;
+ if (!drive->queue->unplug_delay)
+ drive->queue->unplug_delay = 1;
+
+ drive->special.all = 0;
+
+ CDROM_STATE_FLAGS(drive)->media_changed = 1;
+ CDROM_STATE_FLAGS(drive)->toc_valid = 0;
+ CDROM_STATE_FLAGS(drive)->door_locked = 0;
+
+#if NO_DOOR_LOCKING
+ CDROM_CONFIG_FLAGS(drive)->no_doorlock = 1;
+#else
+ CDROM_CONFIG_FLAGS(drive)->no_doorlock = 0;
+#endif
+
+ CDROM_CONFIG_FLAGS(drive)->drq_interrupt = ((drive->id->config & 0x0060) == 0x20);
+ CDROM_CONFIG_FLAGS(drive)->is_changer = 0;
+ CDROM_CONFIG_FLAGS(drive)->cd_r = 0;
+ CDROM_CONFIG_FLAGS(drive)->cd_rw = 0;
+ CDROM_CONFIG_FLAGS(drive)->test_write = 0;
+ CDROM_CONFIG_FLAGS(drive)->dvd = 0;
+ CDROM_CONFIG_FLAGS(drive)->dvd_r = 0;
+ CDROM_CONFIG_FLAGS(drive)->dvd_ram = 0;
+ CDROM_CONFIG_FLAGS(drive)->no_eject = 1;
+ CDROM_CONFIG_FLAGS(drive)->supp_disc_present = 0;
+ CDROM_CONFIG_FLAGS(drive)->audio_play = 0;
+ CDROM_CONFIG_FLAGS(drive)->close_tray = 1;
+
+ /* limit transfer size per interrupt. */
+ CDROM_CONFIG_FLAGS(drive)->limit_nframes = 0;
+ /* a testament to the nice quality of Samsung drives... */
+ if (!strcmp(drive->id->model, "SAMSUNG CD-ROM SCR-2430"))
+ CDROM_CONFIG_FLAGS(drive)->limit_nframes = 1;
+ else if (!strcmp(drive->id->model, "SAMSUNG CD-ROM SCR-2432"))
+ CDROM_CONFIG_FLAGS(drive)->limit_nframes = 1;
+ /* the 3231 model does not support the SET_CD_SPEED command */
+ else if (!strcmp(drive->id->model, "SAMSUNG CD-ROM SCR-3231"))
+ cdi->mask |= CDC_SELECT_SPEED;
+
+#if ! STANDARD_ATAPI
+ /* by default Sanyo 3 CD changer support is turned off and
+ ATAPI Rev 2.2+ standard support for CD changers is used */
+ cdi->sanyo_slot = 0;
+
+ CDROM_CONFIG_FLAGS(drive)->nec260 = 0;
+ CDROM_CONFIG_FLAGS(drive)->toctracks_as_bcd = 0;
+ CDROM_CONFIG_FLAGS(drive)->tocaddr_as_bcd = 0;
+ CDROM_CONFIG_FLAGS(drive)->playmsf_as_bcd = 0;
+ CDROM_CONFIG_FLAGS(drive)->subchan_as_bcd = 0;
+
+ if (strcmp (drive->id->model, "V003S0DS") == 0 &&
+ drive->id->fw_rev[4] == '1' &&
+ drive->id->fw_rev[6] <= '2') {
+ /* Vertos 300.
+ Some versions of this drive like to talk BCD. */
+ CDROM_CONFIG_FLAGS(drive)->toctracks_as_bcd = 1;
+ CDROM_CONFIG_FLAGS(drive)->tocaddr_as_bcd = 1;
+ CDROM_CONFIG_FLAGS(drive)->playmsf_as_bcd = 1;
+ CDROM_CONFIG_FLAGS(drive)->subchan_as_bcd = 1;
+ }
+
+ else if (strcmp (drive->id->model, "V006E0DS") == 0 &&
+ drive->id->fw_rev[4] == '1' &&
+ drive->id->fw_rev[6] <= '2') {
+ /* Vertos 600 ESD. */
+ CDROM_CONFIG_FLAGS(drive)->toctracks_as_bcd = 1;
+ }
+ else if (strcmp(drive->id->model, "NEC CD-ROM DRIVE:260") == 0 &&
+ strncmp(drive->id->fw_rev, "1.01", 4) == 0) { /* FIXME */
+ /* Old NEC260 (not R).
+ This drive was released before the 1.2 version
+ of the spec. */
+ CDROM_CONFIG_FLAGS(drive)->tocaddr_as_bcd = 1;
+ CDROM_CONFIG_FLAGS(drive)->playmsf_as_bcd = 1;
+ CDROM_CONFIG_FLAGS(drive)->subchan_as_bcd = 1;
+ CDROM_CONFIG_FLAGS(drive)->nec260 = 1;
+ }
+ else if (strcmp(drive->id->model, "WEARNES CDD-120") == 0 &&
+ strncmp(drive->id->fw_rev, "A1.1", 4) == 0) { /* FIXME */
+ /* Wearnes */
+ CDROM_CONFIG_FLAGS(drive)->playmsf_as_bcd = 1;
+ CDROM_CONFIG_FLAGS(drive)->subchan_as_bcd = 1;
+ }
+ /* Sanyo 3 CD changer uses a non-standard command
+ for CD changing */
+ else if ((strcmp(drive->id->model, "CD-ROM CDR-C3 G") == 0) ||
+ (strcmp(drive->id->model, "CD-ROM CDR-C3G") == 0) ||
+ (strcmp(drive->id->model, "CD-ROM CDR_C36") == 0)) {
+ /* uses CD in slot 0 when value is set to 3 */
+ cdi->sanyo_slot = 3;
+ }
+#endif /* not STANDARD_ATAPI */
+
+ info->toc = NULL;
+ info->buffer = NULL;
+ info->sector_buffered = 0;
+ info->nsectors_buffered = 0;
+ info->changer_info = NULL;
+ info->last_block = 0;
+ info->start_seek = 0;
+
+ nslots = ide_cdrom_probe_capabilities (drive);
+
+ /*
+ * set correct block size
+ */
+ blk_queue_hardsect_size(drive->queue, CD_FRAMESIZE);
+
+ if (drive->autotune == IDE_TUNE_DEFAULT ||
+ drive->autotune == IDE_TUNE_AUTO)
+ drive->dsc_overlap = (drive->next != drive);
+#if 0
+ drive->dsc_overlap = (HWIF(drive)->no_dsc) ? 0 : 1;
+ if (HWIF(drive)->no_dsc) {
+ printk(KERN_INFO "ide-cd: %s: disabling DSC overlap\n",
+ drive->name);
+ drive->dsc_overlap = 0;
+ }
+#endif
+
+ if (ide_cdrom_register(drive, nslots)) {
+ printk (KERN_ERR "%s: ide_cdrom_setup failed to register device with the cdrom driver.\n", drive->name);
+ info->devinfo.handle = NULL;
+ return 1;
+ }
+ ide_cdrom_add_settings(drive);
+ return 0;
+}
+
+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 ide_cdrom_cleanup(ide_drive_t *drive)
+{
+ struct cdrom_info *info = drive->driver_data;
+
+ if (ide_unregister_subdriver(drive)) {
+ printk(KERN_ERR "%s: %s: failed to ide_unregister_subdriver\n",
+ __FUNCTION__, drive->name);
+ return 1;
+ }
+
+ del_gendisk(info->disk);
+
+ ide_cd_put(info);
+
+ return 0;
+}
+
+static void ide_cd_release(struct kref *kref)
+{
+ struct cdrom_info *info = to_ide_cd(kref);
+ struct cdrom_device_info *devinfo = &info->devinfo;
+ ide_drive_t *drive = info->drive;
+ struct gendisk *g = info->disk;
+
+ if (info->buffer != NULL)
+ kfree(info->buffer);
+ if (info->toc != NULL)
+ kfree(info->toc);
+ if (info->changer_info != NULL)
+ kfree(info->changer_info);
+ if (devinfo->handle == drive && unregister_cdrom(devinfo))
+ printk(KERN_ERR "%s: %s failed to unregister device from the cdrom "
+ "driver.\n", __FUNCTION__, drive->name);
+ drive->dsc_overlap = 0;
+ drive->driver_data = NULL;
+ blk_queue_prep_rq(drive->queue, NULL);
+ g->private_data = NULL;
+ put_disk(g);
+ kfree(info);
+}
+
+static int ide_cdrom_attach (ide_drive_t *drive);
+
+#ifdef CONFIG_PROC_FS
+static int proc_idecd_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_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 }
+};
+#else
+# define idecd_proc NULL
+#endif
+
+static ide_driver_t ide_cdrom_driver = {
+ .owner = THIS_MODULE,
+ .name = "ide-cdrom",
+ .version = IDECD_VERSION,
+ .media = ide_cdrom,
+ .busy = 0,
+ .supports_dsc_overlap = 1,
+ .cleanup = ide_cdrom_cleanup,
+ .do_request = ide_do_rw_cdrom,
+ .end_request = ide_end_request,
+ .error = __ide_error,
+ .abort = __ide_abort,
+ .proc = idecd_proc,
+ .attach = ide_cdrom_attach,
+ .drives = LIST_HEAD_INIT(ide_cdrom_driver.drives),
+};
+
+static int idecd_open(struct inode * inode, struct file * file)
+{
+ struct gendisk *disk = inode->i_bdev->bd_disk;
+ struct cdrom_info *info;
+ ide_drive_t *drive;
+ int rc = -ENOMEM;
+
+ if (!(info = ide_cd_get(disk)))
+ return -ENXIO;
+
+ drive = info->drive;
+
+ drive->usage++;
+
+ if (!info->buffer)
+ info->buffer = kmalloc(SECTOR_BUFFER_SIZE,
+ GFP_KERNEL|__GFP_REPEAT);
+ if (!info->buffer || (rc = cdrom_open(&info->devinfo, inode, file)))
+ drive->usage--;
+
+ if (rc < 0)
+ ide_cd_put(info);
+
+ return rc;
+}
+
+static int idecd_release(struct inode * inode, struct file * file)
+{
+ struct gendisk *disk = inode->i_bdev->bd_disk;
+ struct cdrom_info *info = ide_cd_g(disk);
+ ide_drive_t *drive = info->drive;
+
+ cdrom_release (&info->devinfo, file);
+ drive->usage--;
+
+ ide_cd_put(info);
+
+ return 0;
+}
+
+static int idecd_ioctl (struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct block_device *bdev = inode->i_bdev;
+ struct cdrom_info *info = ide_cd_g(bdev->bd_disk);
+ int err;
+
+ err = generic_ide_ioctl(info->drive, file, bdev, cmd, arg);
+ if (err == -EINVAL)
+ err = cdrom_ioctl(file, &info->devinfo, inode, cmd, arg);
+
+ return err;
+}
+
+static int idecd_media_changed(struct gendisk *disk)
+{
+ struct cdrom_info *info = ide_cd_g(disk);
+ return cdrom_media_changed(&info->devinfo);
+}
+
+static int idecd_revalidate_disk(struct gendisk *disk)
+{
+ struct cdrom_info *info = ide_cd_g(disk);
+ struct request_sense sense;
+ cdrom_read_toc(info->drive, &sense);
+ return 0;
+}
+
+static struct block_device_operations idecd_ops = {
+ .owner = THIS_MODULE,
+ .open = idecd_open,
+ .release = idecd_release,
+ .ioctl = idecd_ioctl,
+ .media_changed = idecd_media_changed,
+ .revalidate_disk= idecd_revalidate_disk
+};
+
+/* options */
+static char *ignore = NULL;
+
+module_param(ignore, charp, 0400);
+MODULE_DESCRIPTION("ATAPI CD-ROM Driver");
+
+static int ide_cdrom_attach (ide_drive_t *drive)
+{
+ struct cdrom_info *info;
+ struct gendisk *g;
+ struct request_sense sense;
+
+ if (!strstr("ide-cdrom", drive->driver_req))
+ goto failed;
+ if (!drive->present)
+ 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 "ide-cd: ignoring drive %s\n", drive->name);
+ goto failed;
+ }
+ }
+ if (drive->scsi) {
+ printk(KERN_INFO "ide-cd: passing drive %s to ide-scsi emulation.\n", drive->name);
+ goto failed;
+ }
+ info = (struct cdrom_info *) kmalloc (sizeof (struct cdrom_info), GFP_KERNEL);
+ if (info == NULL) {
+ printk(KERN_ERR "%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);
+
+ if (ide_register_subdriver(drive, &ide_cdrom_driver)) {
+ printk(KERN_ERR "%s: Failed to register the driver with ide.c\n",
+ drive->name);
+ goto out_put_disk;
+ }
+ memset(info, 0, sizeof (struct cdrom_info));
+
+ kref_init(&info->kref);
+
+ info->drive = drive;
+ info->driver = &ide_cdrom_driver;
+ info->disk = g;
+
+ g->private_data = &info->driver;
+
+ drive->driver_data = info;
+
+ DRIVER(drive)->busy++;
+ g->minors = 1;
+ snprintf(g->devfs_name, sizeof(g->devfs_name),
+ "%s/cd", drive->devfs_name);
+ g->driverfs_dev = &drive->gendev;
+ g->flags = GENHD_FL_CD | GENHD_FL_REMOVABLE;
+ if (ide_cdrom_setup(drive)) {
+ struct cdrom_device_info *devinfo = &info->devinfo;
+ DRIVER(drive)->busy--;
+ ide_unregister_subdriver(drive);
+ if (info->buffer != NULL)
+ kfree(info->buffer);
+ if (info->toc != NULL)
+ kfree(info->toc);
+ if (info->changer_info != NULL)
+ kfree(info->changer_info);
+ if (devinfo->handle == drive && unregister_cdrom(devinfo))
+ printk (KERN_ERR "%s: ide_cdrom_cleanup failed to unregister device from the cdrom driver.\n", drive->name);
+ kfree(info);
+ drive->driver_data = NULL;
+ goto failed;
+ }
+ DRIVER(drive)->busy--;
+
+ cdrom_read_toc(drive, &sense);
+ g->fops = &idecd_ops;
+ g->flags |= GENHD_FL_REMOVABLE;
+ add_disk(g);
+ return 0;
+
+out_put_disk:
+ put_disk(g);
+out_free_cd:
+ kfree(info);
+failed:
+ return 1;
+}
+
+static void __exit ide_cdrom_exit(void)
+{
+ ide_unregister_driver(&ide_cdrom_driver);
+}
+
+static int ide_cdrom_init(void)
+{
+ ide_register_driver(&ide_cdrom_driver);
+ return 0;
+}
+
+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 000000000000..7ca3e5afc665
--- /dev/null
+++ b/drivers/ide/ide-cd.h
@@ -0,0 +1,746 @@
+/*
+ * linux/drivers/ide/ide_cd.h
+ *
+ * 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>
+
+/* Turn this on to have the driver print out the meanings of the
+ ATAPI error codes. This will use up additional kernel-space
+ memory, though. */
+
+#ifndef VERBOSE_IDE_CD_ERRORS
+#define VERBOSE_IDE_CD_ERRORS 1
+#endif
+
+
+/* Turning this on will remove code to work around various nonstandard
+ ATAPI implementations. If you know your drive follows the standard,
+ this will give you a slightly smaller kernel. */
+
+#ifndef STANDARD_ATAPI
+#define STANDARD_ATAPI 0
+#endif
+
+
+/* Turning this on will disable the door-locking functionality.
+ This is apparently needed for supermount. */
+
+#ifndef NO_DOOR_LOCKING
+#define NO_DOOR_LOCKING 0
+#endif
+
+/*
+ * 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)
+#define SECTORS_BUFFER (SECTOR_BUFFER_SIZE >> SECTOR_BITS)
+#define SECTORS_MAX (131072 >> SECTOR_BITS)
+
+#define BLOCKS_PER_FRAME (CD_FRAMESIZE / BLOCK_SIZE)
+
+/* special command codes for strategy routine. */
+#define PACKET_COMMAND 4315
+#define REQUEST_SENSE_COMMAND 4316
+#define RESET_DRIVE_COMMAND 4317
+
+
+/* Configuration flags. These describe the capabilities of the drive.
+ They generally do not change after initialization, unless we learn
+ more about the drive from stuff failing. */
+struct ide_cd_config_flags {
+ __u8 drq_interrupt : 1; /* Device sends an interrupt when ready
+ for a packet command. */
+ __u8 no_doorlock : 1; /* Drive cannot lock the door. */
+ __u8 no_eject : 1; /* Drive cannot eject the disc. */
+ __u8 nec260 : 1; /* Drive is a pre-1.2 NEC 260 drive. */
+ __u8 playmsf_as_bcd : 1; /* PLAYMSF command takes BCD args. */
+ __u8 tocaddr_as_bcd : 1; /* TOC addresses are in BCD. */
+ __u8 toctracks_as_bcd : 1; /* TOC track numbers are in BCD. */
+ __u8 subchan_as_bcd : 1; /* Subchannel info is in BCD. */
+ __u8 is_changer : 1; /* Drive is a changer. */
+ __u8 cd_r : 1; /* Drive can write to CD-R media . */
+ __u8 cd_rw : 1; /* Drive can write to CD-R/W media . */
+ __u8 dvd : 1; /* Drive is a DVD-ROM */
+ __u8 dvd_r : 1; /* Drive can write DVD-R */
+ __u8 dvd_ram : 1; /* Drive can write DVD-RAM */
+ __u8 ram : 1; /* generic WRITE (dvd-ram/mrw) */
+ __u8 test_write : 1; /* Drive can fake writes */
+ __u8 supp_disc_present : 1; /* Changer can report exact contents
+ of slots. */
+ __u8 limit_nframes : 1; /* Drive does not provide data in
+ multiples of SECTOR_SIZE when more
+ than one interrupt is needed. */
+ __u8 seeking : 1; /* Seeking in progress */
+ __u8 audio_play : 1; /* can do audio related commands */
+ __u8 close_tray : 1; /* can close the tray */
+ __u8 writing : 1; /* pseudo write in progress */
+ __u8 mo_drive : 1; /* drive is an MO device */
+ __u8 reserved : 2;
+ byte max_speed; /* Max speed of the drive */
+};
+#define CDROM_CONFIG_FLAGS(drive) (&(((struct cdrom_info *)(drive->driver_data))->config_flags))
+
+
+/* State flags. These give information about the current state of the
+ drive, and will change during normal operation. */
+struct ide_cd_state_flags {
+ __u8 media_changed : 1; /* Driver has noticed a media change. */
+ __u8 toc_valid : 1; /* Saved TOC information is current. */
+ __u8 door_locked : 1; /* We think that the drive door is locked. */
+ __u8 writing : 1; /* the drive is currently writing */
+ __u8 reserved : 4;
+ byte current_speed; /* Current speed of the drive */
+};
+
+#define CDROM_STATE_FLAGS(drive) (&(((struct cdrom_info *)(drive->driver_data))->state_flags))
+
+/* 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. */
+};
+
+
+/* This structure is annoyingly close to, but not identical with,
+ the cdrom_subchnl structure from cdrom.h. */
+struct atapi_cdrom_subchnl {
+ u_char acdsc_reserved;
+ u_char acdsc_audiostatus;
+ u_short acdsc_length;
+ u_char acdsc_format;
+
+#if defined(__BIG_ENDIAN_BITFIELD)
+ u_char acdsc_ctrl: 4;
+ u_char acdsc_adr: 4;
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
+ u_char acdsc_adr: 4;
+ u_char acdsc_ctrl: 4;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+ u_char acdsc_trk;
+ u_char acdsc_ind;
+ union {
+ struct atapi_msf msf;
+ int lba;
+ } acdsc_absaddr;
+ union {
+ struct atapi_msf msf;
+ int lba;
+ } acdsc_reladdr;
+};
+
+
+
+/* This should probably go into cdrom.h along with the other
+ * generic stuff now in the Mt. Fuji spec.
+ */
+struct atapi_capabilities_page {
+ struct mode_page_header header;
+#if defined(__BIG_ENDIAN_BITFIELD)
+ __u8 parameters_saveable : 1;
+ __u8 reserved1 : 1;
+ __u8 page_code : 6;
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
+ __u8 page_code : 6;
+ __u8 reserved1 : 1;
+ __u8 parameters_saveable : 1;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+
+ byte page_length;
+
+#if defined(__BIG_ENDIAN_BITFIELD)
+ __u8 reserved2 : 2;
+ /* Drive supports reading of DVD-RAM discs */
+ __u8 dvd_ram_read : 1;
+ /* Drive supports reading of DVD-R discs */
+ __u8 dvd_r_read : 1;
+ /* Drive supports reading of DVD-ROM discs */
+ __u8 dvd_rom : 1;
+ /* Drive supports reading CD-R discs with addressing method 2 */
+ __u8 method2 : 1; /* reserved in 1.2 */
+ /* Drive can read from CD-R/W (CD-E) discs (orange book, part III) */
+ __u8 cd_rw_read : 1; /* reserved in 1.2 */
+ /* Drive supports read from CD-R discs (orange book, part II) */
+ __u8 cd_r_read : 1; /* reserved in 1.2 */
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
+ /* Drive supports read from CD-R discs (orange book, part II) */
+ __u8 cd_r_read : 1; /* reserved in 1.2 */
+ /* Drive can read from CD-R/W (CD-E) discs (orange book, part III) */
+ __u8 cd_rw_read : 1; /* reserved in 1.2 */
+ /* Drive supports reading CD-R discs with addressing method 2 */
+ __u8 method2 : 1;
+ /* Drive supports reading of DVD-ROM discs */
+ __u8 dvd_rom : 1;
+ /* Drive supports reading of DVD-R discs */
+ __u8 dvd_r_read : 1;
+ /* Drive supports reading of DVD-RAM discs */
+ __u8 dvd_ram_read : 1;
+ __u8 reserved2 : 2;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+
+#if defined(__BIG_ENDIAN_BITFIELD)
+ __u8 reserved3 : 2;
+ /* Drive can write DVD-RAM discs */
+ __u8 dvd_ram_write : 1;
+ /* Drive can write DVD-R discs */
+ __u8 dvd_r_write : 1;
+ __u8 reserved3a : 1;
+ /* Drive can fake writes */
+ __u8 test_write : 1;
+ /* Drive can write to CD-R/W (CD-E) discs (orange book, part III) */
+ __u8 cd_rw_write : 1; /* reserved in 1.2 */
+ /* Drive supports write to CD-R discs (orange book, part II) */
+ __u8 cd_r_write : 1; /* reserved in 1.2 */
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
+ /* Drive can write to CD-R discs (orange book, part II) */
+ __u8 cd_r_write : 1; /* reserved in 1.2 */
+ /* Drive can write to CD-R/W (CD-E) discs (orange book, part III) */
+ __u8 cd_rw_write : 1; /* reserved in 1.2 */
+ /* Drive can fake writes */
+ __u8 test_write : 1;
+ __u8 reserved3a : 1;
+ /* Drive can write DVD-R discs */
+ __u8 dvd_r_write : 1;
+ /* Drive can write DVD-RAM discs */
+ __u8 dvd_ram_write : 1;
+ __u8 reserved3 : 2;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+
+#if defined(__BIG_ENDIAN_BITFIELD)
+ __u8 reserved4 : 1;
+ /* Drive can read multisession discs. */
+ __u8 multisession : 1;
+ /* Drive can read mode 2, form 2 data. */
+ __u8 mode2_form2 : 1;
+ /* Drive can read mode 2, form 1 (XA) data. */
+ __u8 mode2_form1 : 1;
+ /* Drive supports digital output on port 2. */
+ __u8 digport2 : 1;
+ /* Drive supports digital output on port 1. */
+ __u8 digport1 : 1;
+ /* Drive can deliver a composite audio/video data stream. */
+ __u8 composite : 1;
+ /* Drive supports audio play operations. */
+ __u8 audio_play : 1;
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
+ /* Drive supports audio play operations. */
+ __u8 audio_play : 1;
+ /* Drive can deliver a composite audio/video data stream. */
+ __u8 composite : 1;
+ /* Drive supports digital output on port 1. */
+ __u8 digport1 : 1;
+ /* Drive supports digital output on port 2. */
+ __u8 digport2 : 1;
+ /* Drive can read mode 2, form 1 (XA) data. */
+ __u8 mode2_form1 : 1;
+ /* Drive can read mode 2, form 2 data. */
+ __u8 mode2_form2 : 1;
+ /* Drive can read multisession discs. */
+ __u8 multisession : 1;
+ __u8 reserved4 : 1;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+
+#if defined(__BIG_ENDIAN_BITFIELD)
+ __u8 reserved5 : 1;
+ /* Drive can return Media Catalog Number (UPC) info. */
+ __u8 upc : 1;
+ /* Drive can return International Standard Recording Code info. */
+ __u8 isrc : 1;
+ /* Drive supports C2 error pointers. */
+ __u8 c2_pointers : 1;
+ /* R-W data will be returned deinterleaved and error corrected. */
+ __u8 rw_corr : 1;
+ /* Subchannel reads can return combined R-W information. */
+ __u8 rw_supported : 1;
+ /* Drive can continue a read cdda operation from a loss of streaming.*/
+ __u8 cdda_accurate : 1;
+ /* Drive can read Red Book audio data. */
+ __u8 cdda : 1;
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
+ /* Drive can read Red Book audio data. */
+ __u8 cdda : 1;
+ /* Drive can continue a read cdda operation from a loss of streaming.*/
+ __u8 cdda_accurate : 1;
+ /* Subchannel reads can return combined R-W information. */
+ __u8 rw_supported : 1;
+ /* R-W data will be returned deinterleaved and error corrected. */
+ __u8 rw_corr : 1;
+ /* Drive supports C2 error pointers. */
+ __u8 c2_pointers : 1;
+ /* Drive can return International Standard Recording Code info. */
+ __u8 isrc : 1;
+ /* Drive can return Media Catalog Number (UPC) info. */
+ __u8 upc : 1;
+ __u8 reserved5 : 1;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+
+#if defined(__BIG_ENDIAN_BITFIELD)
+ /* Drive mechanism types. */
+ mechtype_t mechtype : 3;
+ __u8 reserved6 : 1;
+ /* Drive can eject a disc or changer cartridge. */
+ __u8 eject : 1;
+ /* State of prevent/allow jumper. */
+ __u8 prevent_jumper : 1;
+ /* Present state of door lock. */
+ __u8 lock_state : 1;
+ /* Drive can lock the door. */
+ __u8 lock : 1;
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
+
+ /* Drive can lock the door. */
+ __u8 lock : 1;
+ /* Present state of door lock. */
+ __u8 lock_state : 1;
+ /* State of prevent/allow jumper. */
+ __u8 prevent_jumper : 1;
+ /* Drive can eject a disc or changer cartridge. */
+ __u8 eject : 1;
+ __u8 reserved6 : 1;
+ /* Drive mechanism types. */
+ mechtype_t mechtype : 3;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+
+#if defined(__BIG_ENDIAN_BITFIELD)
+ __u8 reserved7 : 4;
+ /* Drive supports software slot selection. */
+ __u8 sss : 1; /* reserved in 1.2 */
+ /* Changer can report exact contents of slots. */
+ __u8 disc_present : 1; /* reserved in 1.2 */
+ /* Audio for each channel can be muted independently. */
+ __u8 separate_mute : 1;
+ /* Audio level for each channel can be controlled independently. */
+ __u8 separate_volume : 1;
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
+
+ /* Audio level for each channel can be controlled independently. */
+ __u8 separate_volume : 1;
+ /* Audio for each channel can be muted independently. */
+ __u8 separate_mute : 1;
+ /* Changer can report exact contents of slots. */
+ __u8 disc_present : 1; /* reserved in 1.2 */
+ /* Drive supports software slot selection. */
+ __u8 sss : 1; /* reserved in 1.2 */
+ __u8 reserved7 : 4;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+
+ /* Note: the following four fields are returned in big-endian form. */
+ /* Maximum speed (in kB/s). */
+ unsigned short maxspeed;
+ /* Number of discrete volume levels. */
+ unsigned short n_vol_levels;
+ /* Size of cache in drive, in kB. */
+ unsigned short buffer_size;
+ /* Current speed (in kB/s). */
+ unsigned short curspeed;
+ char pad[4];
+};
+
+
+struct atapi_mechstat_header {
+#if defined(__BIG_ENDIAN_BITFIELD)
+ __u8 fault : 1;
+ __u8 changer_state : 2;
+ __u8 curslot : 5;
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
+ __u8 curslot : 5;
+ __u8 changer_state : 2;
+ __u8 fault : 1;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+
+#if defined(__BIG_ENDIAN_BITFIELD)
+ __u8 mech_state : 3;
+ __u8 door_open : 1;
+ __u8 reserved1 : 4;
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
+ __u8 reserved1 : 4;
+ __u8 door_open : 1;
+ __u8 mech_state : 3;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+
+ byte curlba[3];
+ byte nslots;
+ __u16 slot_tablelen;
+};
+
+
+struct atapi_slot {
+#if defined(__BIG_ENDIAN_BITFIELD)
+ __u8 disc_present : 1;
+ __u8 reserved1 : 6;
+ __u8 change : 1;
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
+ __u8 change : 1;
+ __u8 reserved1 : 6;
+ __u8 disc_present : 1;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+
+ byte reserved2[3];
+};
+
+struct atapi_changer_info {
+ struct atapi_mechstat_header hdr;
+ struct atapi_slot slots[0];
+};
+
+/* 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;
+
+ unsigned long sector_buffered;
+ unsigned long nsectors_buffered;
+ unsigned char *buffer;
+
+ /* The result of the last successful request sense command
+ on this device. */
+ struct request_sense sense_data;
+
+ struct request request_sense_request;
+ int dma;
+ int cmd;
+ unsigned long last_block;
+ unsigned long start_seek;
+ /* Buffer to hold mechanism status and changer slot table. */
+ struct atapi_changer_info *changer_info;
+
+ struct ide_cd_config_flags config_flags;
+ struct ide_cd_state_flags state_flags;
+
+ /* Per-device info needed by cdrom.c generic driver. */
+ struct cdrom_device_info devinfo;
+
+ unsigned long write_timeout;
+};
+
+/****************************************************************************
+ * Descriptions of ATAPI error codes.
+ */
+
+#define ARY_LEN(a) ((sizeof(a) / sizeof(a[0])))
+
+/* This stuff should be in cdrom.h, since it is now generic... */
+
+/* ATAPI sense keys (from table 140 of ATAPI 2.6) */
+#define NO_SENSE 0x00
+#define RECOVERED_ERROR 0x01
+#define NOT_READY 0x02
+#define MEDIUM_ERROR 0x03
+#define HARDWARE_ERROR 0x04
+#define ILLEGAL_REQUEST 0x05
+#define UNIT_ATTENTION 0x06
+#define DATA_PROTECT 0x07
+#define BLANK_CHECK 0x08
+#define ABORTED_COMMAND 0x0b
+#define MISCOMPARE 0x0e
+
+
+
+/* This stuff should be in cdrom.h, since it is now generic... */
+#if VERBOSE_IDE_CD_ERRORS
+
+ /* 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" },
+};
+#endif
+
+
+#endif /* _IDE_CD_H */
diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c
new file mode 100644
index 000000000000..5d54f7756100
--- /dev/null
+++ b/drivers/ide/ide-disk.c
@@ -0,0 +1,1280 @@
+/*
+ * linux/drivers/ide/ide-disk.c Version 1.18 Mar 05, 2003
+ *
+ * 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 <alan@redhat.com>
+ */
+
+/*
+ * 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.
+ *
+ * Version 1.00 move disk only code from ide.c to ide-disk.c
+ * support optional byte-swapping of all data
+ * Version 1.01 fix previous byte-swapping code
+ * Version 1.02 remove ", LBA" from drive identification msgs
+ * Version 1.03 fix display of id->buf_size for big-endian
+ * Version 1.04 add /proc configurable settings and S.M.A.R.T support
+ * Version 1.05 add capacity support for ATA3 >= 8GB
+ * Version 1.06 get boot-up messages to show full cyl count
+ * Version 1.07 disable door-locking if it fails
+ * Version 1.08 fixed CHS/LBA translations for ATA4 > 8GB,
+ * process of adding new ATA4 compliance.
+ * fixed problems in allowing fdisk to see
+ * the entire disk.
+ * Version 1.09 added increment of rq->sector in ide_multwrite
+ * added UDMA 3/4 reporting
+ * Version 1.10 request queue changes, Ultra DMA 100
+ * Version 1.11 added 48-bit lba
+ * Version 1.12 adding taskfile io access method
+ * Version 1.13 added standby and flush-cache for notifier
+ * Version 1.14 added acoustic-wcache
+ * Version 1.15 convert all calls to ide_raw_taskfile
+ * since args will return register content.
+ * Version 1.16 added suspend-resume-checkpower
+ * Version 1.17 do flush on standy, do flush on ATA < ATA6
+ * fix wcache setup.
+ */
+
+#define IDEDISK_VERSION "1.18"
+
+#undef REALLY_SLOW_IO /* most systems can safely undef this */
+
+//#define DEBUG
+
+#include <linux/config.h>
+#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>
+
+#define _IDE_DISK
+
+#include <linux/ide.h>
+
+#include <asm/byteorder.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/div64.h>
+
+struct ide_disk_obj {
+ ide_drive_t *drive;
+ ide_driver_t *driver;
+ struct gendisk *disk;
+ struct kref kref;
+};
+
+static DECLARE_MUTEX(idedisk_ref_sem);
+
+#define to_ide_disk(obj) container_of(obj, struct ide_disk_obj, kref)
+
+#define ide_disk_g(disk) \
+ container_of((disk)->private_data, struct ide_disk_obj, driver)
+
+static struct ide_disk_obj *ide_disk_get(struct gendisk *disk)
+{
+ struct ide_disk_obj *idkp = NULL;
+
+ down(&idedisk_ref_sem);
+ idkp = ide_disk_g(disk);
+ if (idkp)
+ kref_get(&idkp->kref);
+ up(&idedisk_ref_sem);
+ return idkp;
+}
+
+static void ide_disk_release(struct kref *);
+
+static void ide_disk_put(struct ide_disk_obj *idkp)
+{
+ down(&idedisk_ref_sem);
+ kref_put(&idkp->kref, ide_disk_release);
+ up(&idedisk_ref_sem);
+}
+
+/*
+ * lba_capacity_is_ok() performs a sanity check on the claimed "lba_capacity"
+ * value for this drive (from its reported identification information).
+ *
+ * Returns: 1 if lba_capacity looks sensible
+ * 0 otherwise
+ *
+ * It is called only once for each drive.
+ */
+static int lba_capacity_is_ok (struct hd_driveid *id)
+{
+ unsigned long lba_sects, chs_sects, head, tail;
+
+ /*
+ * The ATA spec tells large drives to return
+ * C/H/S = 16383/16/63 independent of their size.
+ * Some drives can be jumpered to use 15 heads instead of 16.
+ * Some drives can be jumpered to use 4092 cyls instead of 16383.
+ */
+ if ((id->cyls == 16383
+ || (id->cyls == 4092 && id->cur_cyls == 16383)) &&
+ id->sectors == 63 &&
+ (id->heads == 15 || id->heads == 16) &&
+ (id->lba_capacity >= 16383*63*id->heads))
+ return 1;
+
+ lba_sects = id->lba_capacity;
+ chs_sects = id->cyls * id->heads * id->sectors;
+
+ /* perform a rough sanity check on lba_sects: within 10% is OK */
+ if ((lba_sects - chs_sects) < chs_sects/10)
+ return 1;
+
+ /* some drives have the word order reversed */
+ head = ((lba_sects >> 16) & 0xffff);
+ tail = (lba_sects & 0xffff);
+ lba_sects = (head | (tail << 16));
+ if ((lba_sects - chs_sects) < chs_sects/10) {
+ id->lba_capacity = lba_sects;
+ return 1; /* lba_capacity is (now) good */
+ }
+
+ return 0; /* lba_capacity value may be bad */
+}
+
+/*
+ * __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);
+ unsigned int dma = drive->using_dma;
+ u8 lba48 = (drive->addressing == 1) ? 1 : 0;
+ task_ioreg_t command = WIN_NOP;
+ ata_nsector_t nsectors;
+
+ nsectors.all = (u16) rq->nr_sectors;
+
+ if (hwif->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);
+ }
+
+ if (IDE_CONTROL_REG)
+ hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
+
+ /* FIXME: SELECT_MASK(drive, 0) ? */
+
+ if (drive->select.b.lba) {
+ if (lba48) {
+ task_ioreg_t tasklets[10];
+
+ pr_debug("%s: LBA=0x%012llx\n", drive->name, block);
+
+ tasklets[0] = 0;
+ tasklets[1] = 0;
+ tasklets[2] = nsectors.b.low;
+ tasklets[3] = nsectors.b.high;
+ tasklets[4] = (task_ioreg_t) block;
+ tasklets[5] = (task_ioreg_t) (block>>8);
+ tasklets[6] = (task_ioreg_t) (block>>16);
+ tasklets[7] = (task_ioreg_t) (block>>24);
+ if (sizeof(block) == 4) {
+ tasklets[8] = (task_ioreg_t) 0;
+ tasklets[9] = (task_ioreg_t) 0;
+ } else {
+ tasklets[8] = (task_ioreg_t)((u64)block >> 32);
+ tasklets[9] = (task_ioreg_t)((u64)block >> 40);
+ }
+#ifdef DEBUG
+ printk("%s: 0x%02x%02x 0x%02x%02x%02x%02x%02x%02x\n",
+ drive->name, tasklets[3], tasklets[2],
+ tasklets[9], tasklets[8], tasklets[7],
+ tasklets[6], tasklets[5], tasklets[4]);
+#endif
+ hwif->OUTB(tasklets[1], IDE_FEATURE_REG);
+ hwif->OUTB(tasklets[3], IDE_NSECTOR_REG);
+ hwif->OUTB(tasklets[7], IDE_SECTOR_REG);
+ hwif->OUTB(tasklets[8], IDE_LCYL_REG);
+ hwif->OUTB(tasklets[9], IDE_HCYL_REG);
+
+ hwif->OUTB(tasklets[0], IDE_FEATURE_REG);
+ hwif->OUTB(tasklets[2], IDE_NSECTOR_REG);
+ hwif->OUTB(tasklets[4], IDE_SECTOR_REG);
+ hwif->OUTB(tasklets[5], IDE_LCYL_REG);
+ hwif->OUTB(tasklets[6], IDE_HCYL_REG);
+ hwif->OUTB(0x00|drive->select.all,IDE_SELECT_REG);
+ } else {
+ hwif->OUTB(0x00, IDE_FEATURE_REG);
+ hwif->OUTB(nsectors.b.low, IDE_NSECTOR_REG);
+ hwif->OUTB(block, IDE_SECTOR_REG);
+ hwif->OUTB(block>>=8, IDE_LCYL_REG);
+ hwif->OUTB(block>>=8, IDE_HCYL_REG);
+ hwif->OUTB(((block>>8)&0x0f)|drive->select.all,IDE_SELECT_REG);
+ }
+ } else {
+ unsigned int sect,head,cyl,track;
+ track = (int)block / drive->sect;
+ sect = (int)block % drive->sect + 1;
+ hwif->OUTB(sect, IDE_SECTOR_REG);
+ head = track % drive->head;
+ cyl = track / drive->head;
+
+ pr_debug("%s: CHS=%u/%u/%u\n", drive->name, cyl, head, sect);
+
+ hwif->OUTB(0x00, IDE_FEATURE_REG);
+ hwif->OUTB(nsectors.b.low, IDE_NSECTOR_REG);
+ hwif->OUTB(cyl, IDE_LCYL_REG);
+ hwif->OUTB(cyl>>8, IDE_HCYL_REG);
+ hwif->OUTB(head|drive->select.all,IDE_SELECT_REG);
+ }
+
+ if (dma) {
+ if (!hwif->dma_setup(drive)) {
+ if (rq_data_dir(rq)) {
+ command = lba48 ? WIN_WRITEDMA_EXT : WIN_WRITEDMA;
+ if (drive->vdma)
+ command = lba48 ? WIN_WRITE_EXT: WIN_WRITE;
+ } else {
+ command = lba48 ? WIN_READDMA_EXT : WIN_READDMA;
+ if (drive->vdma)
+ command = lba48 ? WIN_READ_EXT: WIN_READ;
+ }
+ hwif->dma_exec_cmd(drive, command);
+ hwif->dma_start(drive);
+ return ide_started;
+ }
+ /* fallback to PIO */
+ ide_init_sg_cmd(drive, rq);
+ }
+
+ if (rq_data_dir(rq) == READ) {
+
+ if (drive->mult_count) {
+ hwif->data_phase = TASKFILE_MULTI_IN;
+ command = lba48 ? WIN_MULTREAD_EXT : WIN_MULTREAD;
+ } else {
+ hwif->data_phase = TASKFILE_IN;
+ command = lba48 ? WIN_READ_EXT : WIN_READ;
+ }
+
+ ide_execute_command(drive, command, &task_in_intr, WAIT_CMD, NULL);
+ return ide_started;
+ } else {
+ if (drive->mult_count) {
+ hwif->data_phase = TASKFILE_MULTI_OUT;
+ command = lba48 ? WIN_MULTWRITE_EXT : WIN_MULTWRITE;
+ } else {
+ hwif->data_phase = TASKFILE_OUT;
+ command = lba48 ? WIN_WRITE_EXT : WIN_WRITE;
+ }
+
+ /* FIXME: ->OUTBSYNC ? */
+ hwif->OUTB(command, IDE_COMMAND_REG);
+
+ return pre_task_out_intr(drive, rq);
+ }
+}
+
+/*
+ * 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->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;
+ }
+
+ pr_debug("%s: %sing: block=%llu, sectors=%lu, buffer=0x%08lx\n",
+ drive->name, rq_data_dir(rq) == READ ? "read" : "writ",
+ 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 unsigned long idedisk_read_native_max_address(ide_drive_t *drive)
+{
+ ide_task_t args;
+ unsigned long addr = 0;
+
+ /* Create IDE/ATA command request structure */
+ memset(&args, 0, sizeof(ide_task_t));
+ args.tfRegister[IDE_SELECT_OFFSET] = 0x40;
+ args.tfRegister[IDE_COMMAND_OFFSET] = WIN_READ_NATIVE_MAX;
+ args.command_type = IDE_DRIVE_TASK_NO_DATA;
+ args.handler = &task_no_data_intr;
+ /* submit command request */
+ ide_raw_taskfile(drive, &args, NULL);
+
+ /* if OK, compute maximum address value */
+ if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) {
+ addr = ((args.tfRegister[IDE_SELECT_OFFSET] & 0x0f) << 24)
+ | ((args.tfRegister[ IDE_HCYL_OFFSET] ) << 16)
+ | ((args.tfRegister[ IDE_LCYL_OFFSET] ) << 8)
+ | ((args.tfRegister[IDE_SECTOR_OFFSET] ));
+ addr++; /* since the return value is (maxlba - 1), we add 1 */
+ }
+ return addr;
+}
+
+static unsigned long long idedisk_read_native_max_address_ext(ide_drive_t *drive)
+{
+ ide_task_t args;
+ unsigned long long addr = 0;
+
+ /* Create IDE/ATA command request structure */
+ memset(&args, 0, sizeof(ide_task_t));
+
+ args.tfRegister[IDE_SELECT_OFFSET] = 0x40;
+ args.tfRegister[IDE_COMMAND_OFFSET] = WIN_READ_NATIVE_MAX_EXT;
+ args.command_type = IDE_DRIVE_TASK_NO_DATA;
+ args.handler = &task_no_data_intr;
+ /* submit command request */
+ ide_raw_taskfile(drive, &args, NULL);
+
+ /* if OK, compute maximum address value */
+ if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) {
+ u32 high = (args.hobRegister[IDE_HCYL_OFFSET] << 16) |
+ (args.hobRegister[IDE_LCYL_OFFSET] << 8) |
+ args.hobRegister[IDE_SECTOR_OFFSET];
+ u32 low = ((args.tfRegister[IDE_HCYL_OFFSET])<<16) |
+ ((args.tfRegister[IDE_LCYL_OFFSET])<<8) |
+ (args.tfRegister[IDE_SECTOR_OFFSET]);
+ addr = ((__u64)high << 24) | low;
+ addr++; /* since the return value is (maxlba - 1), we add 1 */
+ }
+ return addr;
+}
+
+/*
+ * Sets maximum virtual LBA address of the drive.
+ * Returns new maximum virtual LBA address (> 0) or 0 on failure.
+ */
+static unsigned long idedisk_set_max_address(ide_drive_t *drive, unsigned long addr_req)
+{
+ ide_task_t args;
+ unsigned long addr_set = 0;
+
+ addr_req--;
+ /* Create IDE/ATA command request structure */
+ memset(&args, 0, sizeof(ide_task_t));
+ args.tfRegister[IDE_SECTOR_OFFSET] = ((addr_req >> 0) & 0xff);
+ args.tfRegister[IDE_LCYL_OFFSET] = ((addr_req >> 8) & 0xff);
+ args.tfRegister[IDE_HCYL_OFFSET] = ((addr_req >> 16) & 0xff);
+ args.tfRegister[IDE_SELECT_OFFSET] = ((addr_req >> 24) & 0x0f) | 0x40;
+ args.tfRegister[IDE_COMMAND_OFFSET] = WIN_SET_MAX;
+ args.command_type = IDE_DRIVE_TASK_NO_DATA;
+ args.handler = &task_no_data_intr;
+ /* submit command request */
+ ide_raw_taskfile(drive, &args, NULL);
+ /* if OK, read new maximum address value */
+ if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) {
+ addr_set = ((args.tfRegister[IDE_SELECT_OFFSET] & 0x0f) << 24)
+ | ((args.tfRegister[ IDE_HCYL_OFFSET] ) << 16)
+ | ((args.tfRegister[ IDE_LCYL_OFFSET] ) << 8)
+ | ((args.tfRegister[IDE_SECTOR_OFFSET] ));
+ addr_set++;
+ }
+ return addr_set;
+}
+
+static unsigned long long idedisk_set_max_address_ext(ide_drive_t *drive, unsigned long long addr_req)
+{
+ ide_task_t args;
+ unsigned long long addr_set = 0;
+
+ addr_req--;
+ /* Create IDE/ATA command request structure */
+ memset(&args, 0, sizeof(ide_task_t));
+ args.tfRegister[IDE_SECTOR_OFFSET] = ((addr_req >> 0) & 0xff);
+ args.tfRegister[IDE_LCYL_OFFSET] = ((addr_req >>= 8) & 0xff);
+ args.tfRegister[IDE_HCYL_OFFSET] = ((addr_req >>= 8) & 0xff);
+ args.tfRegister[IDE_SELECT_OFFSET] = 0x40;
+ args.tfRegister[IDE_COMMAND_OFFSET] = WIN_SET_MAX_EXT;
+ args.hobRegister[IDE_SECTOR_OFFSET] = (addr_req >>= 8) & 0xff;
+ args.hobRegister[IDE_LCYL_OFFSET] = (addr_req >>= 8) & 0xff;
+ args.hobRegister[IDE_HCYL_OFFSET] = (addr_req >>= 8) & 0xff;
+ args.hobRegister[IDE_SELECT_OFFSET] = 0x40;
+ args.hobRegister[IDE_CONTROL_OFFSET_HOB]= (drive->ctl|0x80);
+ args.command_type = IDE_DRIVE_TASK_NO_DATA;
+ args.handler = &task_no_data_intr;
+ /* submit command request */
+ ide_raw_taskfile(drive, &args, NULL);
+ /* if OK, compute maximum address value */
+ if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) {
+ u32 high = (args.hobRegister[IDE_HCYL_OFFSET] << 16) |
+ (args.hobRegister[IDE_LCYL_OFFSET] << 8) |
+ args.hobRegister[IDE_SECTOR_OFFSET];
+ u32 low = ((args.tfRegister[IDE_HCYL_OFFSET])<<16) |
+ ((args.tfRegister[IDE_LCYL_OFFSET])<<8) |
+ (args.tfRegister[IDE_SECTOR_OFFSET]);
+ addr_set = ((__u64)high << 24) | low;
+ addr_set++;
+ }
+ 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;
+}
+
+/*
+ * Bits 10 of command_set_1 and cfs_enable_1 must be equal,
+ * so on non-buggy drives we need test only one.
+ * However, we should also check whether these fields are valid.
+ */
+static inline int idedisk_supports_hpa(const struct hd_driveid *id)
+{
+ return (id->command_set_1 & 0x0400) && (id->cfs_enable_1 & 0x0400);
+}
+
+/*
+ * The same here.
+ */
+static inline int idedisk_supports_lba48(const struct hd_driveid *id)
+{
+ return (id->command_set_2 & 0x0400) && (id->cfs_enable_2 & 0x0400)
+ && id->lba_capacity_2;
+}
+
+static inline void idedisk_check_hpa(ide_drive_t *drive)
+{
+ unsigned long long capacity, set_max;
+ int lba48 = idedisk_supports_lba48(drive->id);
+
+ capacity = drive->capacity64;
+ if (lba48)
+ set_max = idedisk_read_native_max_address_ext(drive);
+ else
+ set_max = idedisk_read_native_max_address(drive);
+
+ 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));
+
+ if (lba48)
+ set_max = idedisk_set_max_address_ext(drive, set_max);
+ else
+ set_max = idedisk_set_max_address(drive, set_max);
+ if (set_max) {
+ drive->capacity64 = set_max;
+ printk(KERN_INFO "%s: Host Protected Area disabled.\n",
+ drive->name);
+ }
+}
+
+/*
+ * Compute drive->capacity, the full capacity of the drive
+ * Called with drive->id != NULL.
+ *
+ * To compute capacity, this uses either of
+ *
+ * 1. CHS value set by user (whatever user sets will be trusted)
+ * 2. LBA value from target drive (require new ATA feature)
+ * 3. LBA value from system BIOS (new one is OK, old one may break)
+ * 4. CHS value from system BIOS (traditional style)
+ *
+ * in above order (i.e., if value of higher priority is available,
+ * reset will be ignored).
+ */
+static void init_idedisk_capacity (ide_drive_t *drive)
+{
+ struct hd_driveid *id = drive->id;
+ /*
+ * If this drive supports the Host Protected Area feature set,
+ * then we may need to change our opinion about the drive's capacity.
+ */
+ int hpa = idedisk_supports_hpa(id);
+
+ if (idedisk_supports_lba48(id)) {
+ /* drive speaks 48-bit LBA */
+ drive->select.b.lba = 1;
+ drive->capacity64 = id->lba_capacity_2;
+ if (hpa)
+ idedisk_check_hpa(drive);
+ } else if ((id->capability & 2) && lba_capacity_is_ok(id)) {
+ /* drive speaks 28-bit LBA */
+ drive->select.b.lba = 1;
+ drive->capacity64 = id->lba_capacity;
+ if (hpa)
+ idedisk_check_hpa(drive);
+ } else {
+ /* drive speaks boring old 28-bit CHS */
+ drive->capacity64 = drive->cyl * drive->head * drive->sect;
+ }
+}
+
+static sector_t idedisk_capacity (ide_drive_t *drive)
+{
+ return drive->capacity64 - drive->sect0;
+}
+
+#ifdef CONFIG_PROC_FS
+
+static int smart_enable(ide_drive_t *drive)
+{
+ ide_task_t args;
+
+ memset(&args, 0, sizeof(ide_task_t));
+ args.tfRegister[IDE_FEATURE_OFFSET] = SMART_ENABLE;
+ args.tfRegister[IDE_LCYL_OFFSET] = SMART_LCYL_PASS;
+ args.tfRegister[IDE_HCYL_OFFSET] = SMART_HCYL_PASS;
+ args.tfRegister[IDE_COMMAND_OFFSET] = WIN_SMART;
+ args.command_type = IDE_DRIVE_TASK_NO_DATA;
+ args.handler = &task_no_data_intr;
+ return ide_raw_taskfile(drive, &args, NULL);
+}
+
+static int get_smart_values(ide_drive_t *drive, u8 *buf)
+{
+ ide_task_t args;
+
+ memset(&args, 0, sizeof(ide_task_t));
+ args.tfRegister[IDE_FEATURE_OFFSET] = SMART_READ_VALUES;
+ args.tfRegister[IDE_NSECTOR_OFFSET] = 0x01;
+ args.tfRegister[IDE_LCYL_OFFSET] = SMART_LCYL_PASS;
+ args.tfRegister[IDE_HCYL_OFFSET] = SMART_HCYL_PASS;
+ args.tfRegister[IDE_COMMAND_OFFSET] = WIN_SMART;
+ args.command_type = IDE_DRIVE_TASK_IN;
+ args.data_phase = TASKFILE_IN;
+ args.handler = &task_in_intr;
+ (void) smart_enable(drive);
+ return ide_raw_taskfile(drive, &args, buf);
+}
+
+static int get_smart_thresholds(ide_drive_t *drive, u8 *buf)
+{
+ ide_task_t args;
+ memset(&args, 0, sizeof(ide_task_t));
+ args.tfRegister[IDE_FEATURE_OFFSET] = SMART_READ_THRESHOLDS;
+ args.tfRegister[IDE_NSECTOR_OFFSET] = 0x01;
+ args.tfRegister[IDE_LCYL_OFFSET] = SMART_LCYL_PASS;
+ args.tfRegister[IDE_HCYL_OFFSET] = SMART_HCYL_PASS;
+ args.tfRegister[IDE_COMMAND_OFFSET] = WIN_SMART;
+ args.command_type = IDE_DRIVE_TASK_IN;
+ args.data_phase = TASKFILE_IN;
+ args.handler = &task_in_intr;
+ (void) smart_enable(drive);
+ return ide_raw_taskfile(drive, &args, buf);
+}
+
+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->id_read)
+ len = sprintf(out,"%i\n", drive->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)idedisk_capacity(drive));
+ PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+}
+
+static int proc_idedisk_read_smart_thresholds
+ (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;
+
+ if (!get_smart_thresholds(drive, page)) {
+ unsigned short *val = (unsigned short *) page;
+ char *out = ((char *)val) + (SECTOR_WORDS * 4);
+ page = out;
+ do {
+ out += sprintf(out, "%04x%c", le16_to_cpu(*val), (++i & 7) ? ' ' : '\n');
+ val += 1;
+ } while (i < (SECTOR_WORDS * 2));
+ len = out - page;
+ }
+ PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+}
+
+static int proc_idedisk_read_smart_values
+ (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;
+
+ if (!get_smart_values(drive, page)) {
+ unsigned short *val = (unsigned short *) page;
+ char *out = ((char *)val) + (SECTOR_WORDS * 4);
+ page = out;
+ do {
+ out += sprintf(out, "%04x%c", le16_to_cpu(*val), (++i & 7) ? ' ' : '\n');
+ val += 1;
+ } while (i < (SECTOR_WORDS * 2));
+ len = out - page;
+ }
+ PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+}
+
+static ide_proc_entry_t idedisk_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_smart_values, NULL },
+ { "smart_thresholds", S_IFREG|S_IRUSR, proc_idedisk_read_smart_thresholds, NULL },
+ { NULL, 0, NULL, NULL }
+};
+
+#else
+
+#define idedisk_proc NULL
+
+#endif /* CONFIG_PROC_FS */
+
+static void idedisk_end_flush(request_queue_t *q, struct request *flush_rq)
+{
+ ide_drive_t *drive = q->queuedata;
+ struct request *rq = flush_rq->end_io_data;
+ int good_sectors = rq->hard_nr_sectors;
+ int bad_sectors;
+ sector_t sector;
+
+ if (flush_rq->errors & ABRT_ERR) {
+ printk(KERN_ERR "%s: barrier support doesn't work\n", drive->name);
+ blk_queue_ordered(drive->queue, QUEUE_ORDERED_NONE);
+ blk_queue_issue_flush_fn(drive->queue, NULL);
+ good_sectors = 0;
+ } else if (flush_rq->errors) {
+ good_sectors = 0;
+ if (blk_barrier_preflush(rq)) {
+ sector = ide_get_error_location(drive,flush_rq->buffer);
+ if ((sector >= rq->hard_sector) &&
+ (sector < rq->hard_sector + rq->hard_nr_sectors))
+ good_sectors = sector - rq->hard_sector;
+ }
+ }
+
+ if (flush_rq->errors)
+ printk(KERN_ERR "%s: failed barrier write: "
+ "sector=%Lx(good=%d/bad=%d)\n",
+ drive->name, (unsigned long long)rq->sector,
+ good_sectors,
+ (int) (rq->hard_nr_sectors-good_sectors));
+
+ bad_sectors = rq->hard_nr_sectors - good_sectors;
+
+ if (good_sectors)
+ __ide_end_request(drive, rq, 1, good_sectors);
+ if (bad_sectors)
+ __ide_end_request(drive, rq, 0, bad_sectors);
+}
+
+static int idedisk_prepare_flush(request_queue_t *q, struct request *rq)
+{
+ ide_drive_t *drive = q->queuedata;
+
+ if (!drive->wcache)
+ return 0;
+
+ memset(rq->cmd, 0, sizeof(rq->cmd));
+
+ if (ide_id_has_flush_cache_ext(drive->id) &&
+ (drive->capacity64 >= (1UL << 28)))
+ rq->cmd[0] = WIN_FLUSH_CACHE_EXT;
+ else
+ rq->cmd[0] = WIN_FLUSH_CACHE;
+
+
+ rq->flags |= REQ_DRIVE_TASK | REQ_SOFTBARRIER;
+ rq->buffer = rq->cmd;
+ return 1;
+}
+
+static int idedisk_issue_flush(request_queue_t *q, struct gendisk *disk,
+ sector_t *error_sector)
+{
+ ide_drive_t *drive = q->queuedata;
+ struct request *rq;
+ int ret;
+
+ if (!drive->wcache)
+ return 0;
+
+ rq = blk_get_request(q, WRITE, __GFP_WAIT);
+
+ idedisk_prepare_flush(q, rq);
+
+ ret = blk_execute_rq(q, disk, rq);
+
+ /*
+ * if we failed and caller wants error offset, get it
+ */
+ if (ret && error_sector)
+ *error_sector = ide_get_error_location(drive, rq->cmd);
+
+ blk_put_request(rq);
+ return ret;
+}
+
+/*
+ * 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;
+
+ if (drive->special.b.set_multmode)
+ return -EBUSY;
+ ide_init_drive_cmd (&rq);
+ rq.flags = REQ_DRIVE_CMD;
+ drive->mult_req = arg;
+ drive->special.b.set_multmode = 1;
+ (void) ide_do_drive_cmd (drive, &rq, ide_wait);
+ return (drive->mult_count == arg) ? 0 : -EIO;
+}
+
+static int set_nowerr(ide_drive_t *drive, int arg)
+{
+ if (ide_spin_wait_hwgroup(drive))
+ return -EBUSY;
+ drive->nowerr = arg;
+ drive->bad_wstat = arg ? BAD_R_STAT : BAD_W_STAT;
+ spin_unlock_irq(&ide_lock);
+ return 0;
+}
+
+static int write_cache(ide_drive_t *drive, int arg)
+{
+ ide_task_t args;
+ int err;
+
+ if (!ide_id_has_flush_cache(drive->id))
+ return 1;
+
+ memset(&args, 0, sizeof(ide_task_t));
+ args.tfRegister[IDE_FEATURE_OFFSET] = (arg) ?
+ SETFEATURES_EN_WCACHE : SETFEATURES_DIS_WCACHE;
+ args.tfRegister[IDE_COMMAND_OFFSET] = WIN_SETFEATURES;
+ args.command_type = IDE_DRIVE_TASK_NO_DATA;
+ args.handler = &task_no_data_intr;
+
+ err = ide_raw_taskfile(drive, &args, NULL);
+ if (err)
+ return err;
+
+ drive->wcache = arg;
+ return 0;
+}
+
+static int do_idedisk_flushcache (ide_drive_t *drive)
+{
+ ide_task_t args;
+
+ memset(&args, 0, sizeof(ide_task_t));
+ if (ide_id_has_flush_cache_ext(drive->id))
+ args.tfRegister[IDE_COMMAND_OFFSET] = WIN_FLUSH_CACHE_EXT;
+ else
+ args.tfRegister[IDE_COMMAND_OFFSET] = WIN_FLUSH_CACHE;
+ args.command_type = IDE_DRIVE_TASK_NO_DATA;
+ args.handler = &task_no_data_intr;
+ return ide_raw_taskfile(drive, &args, NULL);
+}
+
+static int set_acoustic (ide_drive_t *drive, int arg)
+{
+ ide_task_t args;
+
+ memset(&args, 0, sizeof(ide_task_t));
+ args.tfRegister[IDE_FEATURE_OFFSET] = (arg) ? SETFEATURES_EN_AAM :
+ SETFEATURES_DIS_AAM;
+ args.tfRegister[IDE_NSECTOR_OFFSET] = arg;
+ args.tfRegister[IDE_COMMAND_OFFSET] = WIN_SETFEATURES;
+ args.command_type = IDE_DRIVE_TASK_NO_DATA;
+ args.handler = &task_no_data_intr;
+ ide_raw_taskfile(drive, &args, NULL);
+ drive->acoustic = arg;
+ return 0;
+}
+
+/*
+ * drive->addressing:
+ * 0: 28-bit
+ * 1: 48-bit
+ * 2: 48-bit capable doing 28-bit
+ */
+static int set_lba_addressing(ide_drive_t *drive, int arg)
+{
+ drive->addressing = 0;
+
+ if (HWIF(drive)->no_lba48)
+ return 0;
+
+ if (!idedisk_supports_lba48(drive->id))
+ return -EIO;
+ drive->addressing = arg;
+ return 0;
+}
+
+static void idedisk_add_settings(ide_drive_t *drive)
+{
+ struct hd_driveid *id = drive->id;
+
+ ide_add_setting(drive, "bios_cyl", SETTING_RW, -1, -1, TYPE_INT, 0, 65535, 1, 1, &drive->bios_cyl, NULL);
+ ide_add_setting(drive, "bios_head", SETTING_RW, -1, -1, TYPE_BYTE, 0, 255, 1, 1, &drive->bios_head, NULL);
+ ide_add_setting(drive, "bios_sect", SETTING_RW, -1, -1, TYPE_BYTE, 0, 63, 1, 1, &drive->bios_sect, NULL);
+ ide_add_setting(drive, "address", SETTING_RW, HDIO_GET_ADDRESS, HDIO_SET_ADDRESS, TYPE_INTA, 0, 2, 1, 1, &drive->addressing, set_lba_addressing);
+ ide_add_setting(drive, "bswap", SETTING_READ, -1, -1, TYPE_BYTE, 0, 1, 1, 1, &drive->bswap, NULL);
+ ide_add_setting(drive, "multcount", id ? SETTING_RW : SETTING_READ, HDIO_GET_MULTCOUNT, HDIO_SET_MULTCOUNT, TYPE_BYTE, 0, id ? id->max_multsect : 0, 1, 1, &drive->mult_count, set_multcount);
+ ide_add_setting(drive, "nowerr", SETTING_RW, HDIO_GET_NOWERR, HDIO_SET_NOWERR, TYPE_BYTE, 0, 1, 1, 1, &drive->nowerr, set_nowerr);
+ ide_add_setting(drive, "lun", SETTING_RW, -1, -1, TYPE_INT, 0, 7, 1, 1, &drive->lun, NULL);
+ ide_add_setting(drive, "wcache", SETTING_RW, HDIO_GET_WCACHE, HDIO_SET_WCACHE, TYPE_BYTE, 0, 1, 1, 1, &drive->wcache, write_cache);
+ ide_add_setting(drive, "acoustic", SETTING_RW, HDIO_GET_ACOUSTIC, HDIO_SET_ACOUSTIC, TYPE_BYTE, 0, 254, 1, 1, &drive->acoustic, set_acoustic);
+ ide_add_setting(drive, "failures", SETTING_RW, -1, -1, TYPE_INT, 0, 65535, 1, 1, &drive->failures, NULL);
+ ide_add_setting(drive, "max_failures", SETTING_RW, -1, -1, TYPE_INT, 0, 65535, 1, 1, &drive->max_failures, NULL);
+}
+
+static void idedisk_setup (ide_drive_t *drive)
+{
+ struct hd_driveid *id = drive->id;
+ unsigned long long capacity;
+ int barrier;
+
+ idedisk_add_settings(drive);
+
+ if (drive->id_read == 0)
+ return;
+
+ /*
+ * CompactFlash cards and their brethern look just like hard drives
+ * to us, but they are removable and don't have a doorlock mechanism.
+ */
+ if (drive->removable && !(drive->is_flash)) {
+ /*
+ * Removable disks (eg. SYQUEST); ignore 'WD' drives
+ */
+ if (id->model[0] != 'W' || id->model[1] != 'D') {
+ drive->doorlocking = 1;
+ }
+ }
+
+ (void)set_lba_addressing(drive, 1);
+
+ if (drive->addressing == 1) {
+ ide_hwif_t *hwif = HWIF(drive);
+ int max_s = 2048;
+
+ if (max_s > hwif->rqsize)
+ max_s = hwif->rqsize;
+
+ blk_queue_max_sectors(drive->queue, max_s);
+ }
+
+ printk(KERN_INFO "%s: max request size: %dKiB\n", drive->name, drive->queue->max_sectors / 2);
+
+ /* calculate drive capacity, and select LBA if possible */
+ init_idedisk_capacity (drive);
+
+ /* limit drive capacity to 137GB if LBA48 cannot be used */
+ if (drive->addressing == 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->no_lba48_dma && drive->addressing) {
+ 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->addressing = 0;
+ }
+
+ /*
+ * if possible, give fdisk access to more of the drive,
+ * by correcting bios_cyls:
+ */
+ capacity = idedisk_capacity (drive);
+ if (!drive->forced_geom) {
+
+ if (idedisk_supports_lba48(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->buf_size)
+ printk (" w/%dKiB Cache", id->buf_size/2);
+
+ printk(", CHS=%d/%d/%d",
+ drive->bios_cyl, drive->bios_head, drive->bios_sect);
+ if (drive->using_dma)
+ ide_dma_verbose(drive);
+ printk("\n");
+
+ drive->no_io_32bit = id->dword_io ? 1 : 0;
+
+ /* write cache enabled? */
+ if ((id->csfo & 1) || (id->cfs_enable_1 & (1 << 5)))
+ drive->wcache = 1;
+
+ write_cache(drive, 1);
+
+ /*
+ * 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.
+ */
+ barrier = 0;
+ if (ide_id_has_flush_cache(id))
+ barrier = 1;
+ if (drive->addressing == 1) {
+ /* Can't issue the correct flush ? */
+ if (capacity > (1ULL << 28) && !ide_id_has_flush_cache_ext(id))
+ barrier = 0;
+ }
+
+ printk(KERN_INFO "%s: cache flushes %ssupported\n",
+ drive->name, barrier ? "" : "not ");
+ if (barrier) {
+ blk_queue_ordered(drive->queue, QUEUE_ORDERED_FLUSH);
+ drive->queue->prepare_flush_fn = idedisk_prepare_flush;
+ drive->queue->end_flush_fn = idedisk_end_flush;
+ blk_queue_issue_flush_fn(drive->queue, idedisk_issue_flush);
+ }
+}
+
+static void ide_cacheflush_p(ide_drive_t *drive)
+{
+ if (!drive->wcache || !ide_id_has_flush_cache(drive->id))
+ return;
+
+ if (do_idedisk_flushcache(drive))
+ printk(KERN_INFO "%s: wcache flush failed!\n", drive->name);
+}
+
+static int idedisk_cleanup (ide_drive_t *drive)
+{
+ struct ide_disk_obj *idkp = drive->driver_data;
+ struct gendisk *g = idkp->disk;
+
+ ide_cacheflush_p(drive);
+ if (ide_unregister_subdriver(drive))
+ return 1;
+ del_gendisk(g);
+
+ ide_disk_put(idkp);
+
+ return 0;
+}
+
+static void ide_disk_release(struct kref *kref)
+{
+ struct ide_disk_obj *idkp = to_ide_disk(kref);
+ ide_drive_t *drive = idkp->drive;
+ struct gendisk *g = idkp->disk;
+
+ drive->driver_data = NULL;
+ drive->devfs_name[0] = '\0';
+ g->private_data = NULL;
+ put_disk(g);
+ kfree(idkp);
+}
+
+static int idedisk_attach(ide_drive_t *drive);
+
+static void ide_device_shutdown(struct device *dev)
+{
+ ide_drive_t *drive = container_of(dev, ide_drive_t, gendev);
+
+#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
+ ide_cacheflush_p(drive);
+ return;
+ }
+
+ printk("Shutdown: %s\n", drive->name);
+ dev->bus->suspend(dev, PMSG_SUSPEND);
+}
+
+/*
+ * IDE subdriver functions, registered with ide.c
+ */
+static ide_driver_t idedisk_driver = {
+ .owner = THIS_MODULE,
+ .gen_driver = {
+ .shutdown = ide_device_shutdown,
+ },
+ .name = "ide-disk",
+ .version = IDEDISK_VERSION,
+ .media = ide_disk,
+ .busy = 0,
+ .supports_dsc_overlap = 0,
+ .cleanup = idedisk_cleanup,
+ .do_request = ide_do_rw_disk,
+ .end_request = ide_end_request,
+ .error = __ide_error,
+ .abort = __ide_abort,
+ .proc = idedisk_proc,
+ .attach = idedisk_attach,
+ .drives = LIST_HEAD_INIT(idedisk_driver.drives),
+};
+
+static int idedisk_open(struct inode *inode, struct file *filp)
+{
+ struct gendisk *disk = inode->i_bdev->bd_disk;
+ struct ide_disk_obj *idkp;
+ ide_drive_t *drive;
+
+ if (!(idkp = ide_disk_get(disk)))
+ return -ENXIO;
+
+ drive = idkp->drive;
+
+ drive->usage++;
+ if (drive->removable && drive->usage == 1) {
+ ide_task_t args;
+ memset(&args, 0, sizeof(ide_task_t));
+ args.tfRegister[IDE_COMMAND_OFFSET] = WIN_DOORLOCK;
+ args.command_type = IDE_DRIVE_TASK_NO_DATA;
+ args.handler = &task_no_data_intr;
+ check_disk_change(inode->i_bdev);
+ /*
+ * Ignore the return code from door_lock,
+ * since the open() has already succeeded,
+ * and the door_lock is irrelevant at this point.
+ */
+ if (drive->doorlocking && ide_raw_taskfile(drive, &args, NULL))
+ drive->doorlocking = 0;
+ }
+ return 0;
+}
+
+static int idedisk_release(struct inode *inode, struct file *filp)
+{
+ struct gendisk *disk = inode->i_bdev->bd_disk;
+ struct ide_disk_obj *idkp = ide_disk_g(disk);
+ ide_drive_t *drive = idkp->drive;
+
+ if (drive->usage == 1)
+ ide_cacheflush_p(drive);
+ if (drive->removable && drive->usage == 1) {
+ ide_task_t args;
+ memset(&args, 0, sizeof(ide_task_t));
+ args.tfRegister[IDE_COMMAND_OFFSET] = WIN_DOORUNLOCK;
+ args.command_type = IDE_DRIVE_TASK_NO_DATA;
+ args.handler = &task_no_data_intr;
+ if (drive->doorlocking && ide_raw_taskfile(drive, &args, NULL))
+ drive->doorlocking = 0;
+ }
+ drive->usage--;
+
+ ide_disk_put(idkp);
+
+ return 0;
+}
+
+static int idedisk_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct block_device *bdev = inode->i_bdev;
+ struct ide_disk_obj *idkp = ide_disk_g(bdev->bd_disk);
+ return generic_ide_ioctl(idkp->drive, file, bdev, cmd, arg);
+}
+
+static int idedisk_media_changed(struct gendisk *disk)
+{
+ struct ide_disk_obj *idkp = ide_disk_g(disk);
+ ide_drive_t *drive = idkp->drive;
+
+ /* do not scan partitions twice if this is a removable device */
+ if (drive->attach) {
+ drive->attach = 0;
+ return 0;
+ }
+ /* if removable, always assume it was changed */
+ return drive->removable;
+}
+
+static int idedisk_revalidate_disk(struct gendisk *disk)
+{
+ struct ide_disk_obj *idkp = ide_disk_g(disk);
+ set_capacity(disk, idedisk_capacity(idkp->drive));
+ return 0;
+}
+
+static struct block_device_operations idedisk_ops = {
+ .owner = THIS_MODULE,
+ .open = idedisk_open,
+ .release = idedisk_release,
+ .ioctl = idedisk_ioctl,
+ .media_changed = idedisk_media_changed,
+ .revalidate_disk= idedisk_revalidate_disk
+};
+
+MODULE_DESCRIPTION("ATA DISK Driver");
+
+static int idedisk_attach(ide_drive_t *drive)
+{
+ struct ide_disk_obj *idkp;
+ struct gendisk *g;
+
+ /* strstr("foo", "") is non-NULL */
+ if (!strstr("ide-disk", drive->driver_req))
+ goto failed;
+ if (!drive->present)
+ goto failed;
+ if (drive->media != ide_disk)
+ goto failed;
+
+ idkp = kmalloc(sizeof(*idkp), GFP_KERNEL);
+ if (!idkp)
+ goto failed;
+
+ g = alloc_disk(1 << PARTN_BITS);
+ if (!g)
+ goto out_free_idkp;
+
+ ide_init_disk(g, drive);
+
+ if (ide_register_subdriver(drive, &idedisk_driver)) {
+ printk (KERN_ERR "ide-disk: %s: Failed to register the driver with ide.c\n", drive->name);
+ goto out_put_disk;
+ }
+
+ memset(idkp, 0, sizeof(*idkp));
+
+ kref_init(&idkp->kref);
+
+ idkp->drive = drive;
+ idkp->driver = &idedisk_driver;
+ idkp->disk = g;
+
+ g->private_data = &idkp->driver;
+
+ drive->driver_data = idkp;
+
+ DRIVER(drive)->busy++;
+ idedisk_setup(drive);
+ if ((!drive->head || drive->head > 16) && !drive->select.b.lba) {
+ printk(KERN_ERR "%s: INVALID GEOMETRY: %d PHYSICAL HEADS?\n",
+ drive->name, drive->head);
+ drive->attach = 0;
+ } else
+ drive->attach = 1;
+ DRIVER(drive)->busy--;
+ g->minors = 1 << PARTN_BITS;
+ strcpy(g->devfs_name, drive->devfs_name);
+ g->driverfs_dev = &drive->gendev;
+ g->flags = drive->removable ? GENHD_FL_REMOVABLE : 0;
+ set_capacity(g, idedisk_capacity(drive));
+ g->fops = &idedisk_ops;
+ add_disk(g);
+ return 0;
+
+out_put_disk:
+ put_disk(g);
+out_free_idkp:
+ kfree(idkp);
+failed:
+ return 1;
+}
+
+static void __exit idedisk_exit (void)
+{
+ ide_unregister_driver(&idedisk_driver);
+}
+
+static int idedisk_init (void)
+{
+ return ide_register_driver(&idedisk_driver);
+}
+
+module_init(idedisk_init);
+module_exit(idedisk_exit);
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c
new file mode 100644
index 000000000000..2d2eefb610dd
--- /dev/null
+++ b/drivers/ide/ide-dma.c
@@ -0,0 +1,959 @@
+/*
+ * linux/drivers/ide/ide-dma.c Version 4.10 June 9, 2000
+ *
+ * Copyright (c) 1999-2000 Andre Hedrick <andre@linux-ide.org>
+ * May be copied or modified under the terms of the GNU General Public License
+ */
+
+/*
+ * Special Thanks to Mark for his Six years of work.
+ *
+ * Copyright (c) 1995-1998 Mark Lord
+ * May be copied or modified under the terms of the GNU General Public License
+ */
+
+/*
+ * This module provides support for the bus-master IDE DMA functions
+ * of various PCI chipsets, including the Intel PIIX (i82371FB for
+ * the 430 FX chipset), the PIIX3 (i82371SB for the 430 HX/VX and
+ * 440 chipsets), and the PIIX4 (i82371AB for the 430 TX chipset)
+ * ("PIIX" stands for "PCI ISA IDE Xcellerator").
+ *
+ * Pretty much the same code works for other IDE PCI bus-mastering chipsets.
+ *
+ * DMA is supported for all IDE devices (disk drives, cdroms, tapes, floppies).
+ *
+ * By default, DMA support is prepared for use, but is currently enabled only
+ * for drives which already have DMA enabled (UltraDMA or mode 2 multi/single),
+ * or which are recognized as "good" (see table below). Drives with only mode0
+ * or mode1 (multi/single) DMA should also work with this chipset/driver
+ * (eg. MC2112A) but are not enabled by default.
+ *
+ * Use "hdparm -i" to view modes supported by a given drive.
+ *
+ * The hdparm-3.5 (or later) utility can be used for manually enabling/disabling
+ * DMA support, but must be (re-)compiled against this kernel version or later.
+ *
+ * To enable DMA, use "hdparm -d1 /dev/hd?" on a per-drive basis after booting.
+ * If problems arise, ide.c will disable DMA operation after a few retries.
+ * This error recovery mechanism works and has been extremely well exercised.
+ *
+ * IDE drives, depending on their vintage, may support several different modes
+ * of DMA operation. The boot-time modes are indicated with a "*" in
+ * the "hdparm -i" listing, and can be changed with *knowledgeable* use of
+ * the "hdparm -X" feature. There is seldom a need to do this, as drives
+ * normally power-up with their "best" PIO/DMA modes enabled.
+ *
+ * Testing has been done with a rather extensive number of drives,
+ * with Quantum & Western Digital models generally outperforming the pack,
+ * and Fujitsu & Conner (and some Seagate which are really Conner) drives
+ * showing more lackluster throughput.
+ *
+ * Keep an eye on /var/adm/messages for "DMA disabled" messages.
+ *
+ * Some people have reported trouble with Intel Zappa motherboards.
+ * This can be fixed by upgrading the AMI BIOS to version 1.00.04.BS0,
+ * available from ftp://ftp.intel.com/pub/bios/10004bs0.exe
+ * (thanks to Glen Morrell <glen@spin.Stanford.edu> for researching this).
+ *
+ * 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!
+ *
+ * And, yes, Intel Zappa boards really *do* use both PIIX IDE ports.
+ *
+ * ATA-66/100 and recovery functions, I forgot the rest......
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/ide.h>
+#include <linux/delay.h>
+#include <linux/scatterlist.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+struct drive_list_entry {
+ const char *id_model;
+ const char *id_firmware;
+};
+
+static const struct drive_list_entry drive_whitelist [] = {
+
+ { "Micropolis 2112A" , "ALL" },
+ { "CONNER CTMA 4000" , "ALL" },
+ { "CONNER CTT8000-A" , "ALL" },
+ { "ST34342A" , "ALL" },
+ { NULL , NULL }
+};
+
+static const struct drive_list_entry drive_blacklist [] = {
+
+ { "WDC AC11000H" , "ALL" },
+ { "WDC AC22100H" , "ALL" },
+ { "WDC AC32500H" , "ALL" },
+ { "WDC AC33100H" , "ALL" },
+ { "WDC AC31600H" , "ALL" },
+ { "WDC AC32100H" , "24.09P07" },
+ { "WDC AC23200L" , "21.10N21" },
+ { "Compaq CRD-8241B" , "ALL" },
+ { "CRD-8400B" , "ALL" },
+ { "CRD-8480B", "ALL" },
+ { "CRD-8482B", "ALL" },
+ { "CRD-84" , "ALL" },
+ { "SanDisk SDP3B" , "ALL" },
+ { "SanDisk SDP3B-64" , "ALL" },
+ { "SANYO CD-ROM CRD" , "ALL" },
+ { "HITACHI CDR-8" , "ALL" },
+ { "HITACHI CDR-8335" , "ALL" },
+ { "HITACHI CDR-8435" , "ALL" },
+ { "Toshiba CD-ROM XM-6202B" , "ALL" },
+ { "CD-532E-A" , "ALL" },
+ { "E-IDE CD-ROM CR-840", "ALL" },
+ { "CD-ROM Drive/F5A", "ALL" },
+ { "WPI CDD-820", "ALL" },
+ { "SAMSUNG CD-ROM SC-148C", "ALL" },
+ { "SAMSUNG CD-ROM SC", "ALL" },
+ { "SanDisk SDP3B-64" , "ALL" },
+ { "SAMSUNG CD-ROM SN-124", "ALL" },
+ { "ATAPI CD-ROM DRIVE 40X MAXIMUM", "ALL" },
+ { "_NEC DV5800A", "ALL" },
+ { NULL , NULL }
+
+};
+
+/**
+ * in_drive_list - look for drive in black/white list
+ * @id: drive identifier
+ * @drive_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.
+ */
+
+static int in_drive_list(struct hd_driveid *id, const struct drive_list_entry *drive_table)
+{
+ for ( ; drive_table->id_model ; drive_table++)
+ if ((!strcmp(drive_table->id_model, id->model)) &&
+ ((strstr(drive_table->id_firmware, id->fw_rev)) ||
+ (!strcmp(drive_table->id_firmware, "ALL"))))
+ return 1;
+ return 0;
+}
+
+/**
+ * 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)
+{
+ u8 stat = 0, dma_stat = 0;
+
+ dma_stat = HWIF(drive)->ide_dma_end(drive);
+ stat = HWIF(drive)->INB(IDE_STATUS_REG); /* get drive status */
+ if (OK_STAT(stat,DRIVE_READY,drive->bad_wstat|DRQ_STAT)) {
+ if (!dma_stat) {
+ struct request *rq = HWGROUP(drive)->rq;
+
+ 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);
+ return ide_stopped;
+ }
+ printk(KERN_ERR "%s: dma_intr: bad DMA status (dma_stat=%x)\n",
+ drive->name, dma_stat);
+ }
+ return ide_error(drive, "dma_intr", stat);
+}
+
+EXPORT_SYMBOL_GPL(ide_dma_intr);
+
+#ifdef CONFIG_BLK_DEV_IDEDMA_PCI
+/**
+ * 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 PCI mapping magic necessary to access the source or
+ * target buffers of a request via PCI 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 = HWIF(drive);
+ struct scatterlist *sg = hwif->sg_table;
+
+ if ((rq->flags & REQ_DRIVE_TASKFILE) && rq->nr_sectors > 256)
+ BUG();
+
+ ide_map_sg(drive, rq);
+
+ if (rq_data_dir(rq) == READ)
+ hwif->sg_dma_direction = PCI_DMA_FROMDEVICE;
+ else
+ hwif->sg_dma_direction = PCI_DMA_TODEVICE;
+
+ return pci_map_sg(hwif->pci_dev, sg, hwif->sg_nents, hwif->sg_dma_direction);
+}
+
+EXPORT_SYMBOL_GPL(ide_build_sglist);
+
+/**
+ * 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. The code
+ * knows about the 64K wrap bug in the CS5530.
+ *
+ * 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 = HWIF(drive);
+ unsigned int *table = 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 = i = ide_build_sglist(drive, rq);
+
+ if (!i)
+ return 0;
+
+ sg = hwif->sg_table;
+ while (i) {
+ u32 cur_addr;
+ u32 cur_len;
+
+ 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) {
+ printk(KERN_ERR "%s: DMA table too small\n", drive->name);
+ goto use_pio_instead;
+ } else {
+ u32 xcount, 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;
+ if (xcount == 0x0000) {
+ /*
+ * Most chipsets correctly interpret a length of 0x0000 as 64KB,
+ * but at least one (e.g. CS5530) misinterprets it as zero (!).
+ * So here we break the 64KB entry into two 32KB entries instead.
+ */
+ if (count++ >= PRD_ENTRIES) {
+ printk(KERN_ERR "%s: DMA table too small\n", drive->name);
+ 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;
+ }
+ }
+
+ sg++;
+ i--;
+ }
+
+ if (count) {
+ if (!is_trm290)
+ *--table |= cpu_to_le32(0x80000000);
+ return count;
+ }
+ printk(KERN_ERR "%s: empty DMA table?\n", drive->name);
+use_pio_instead:
+ pci_unmap_sg(hwif->pci_dev,
+ hwif->sg_table,
+ hwif->sg_nents,
+ hwif->sg_dma_direction);
+ return 0; /* revert to PIO for this request */
+}
+
+EXPORT_SYMBOL_GPL(ide_build_dmatable);
+
+/**
+ * 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)
+{
+ struct pci_dev *dev = HWIF(drive)->pci_dev;
+ struct scatterlist *sg = HWIF(drive)->sg_table;
+ int nents = HWIF(drive)->sg_nents;
+
+ pci_unmap_sg(dev, sg, nents, HWIF(drive)->sg_dma_direction);
+}
+
+EXPORT_SYMBOL_GPL(ide_destroy_dmatable);
+
+/**
+ * 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.
+ */
+
+static int config_drive_for_dma (ide_drive_t *drive)
+{
+ struct hd_driveid *id = drive->id;
+ ide_hwif_t *hwif = HWIF(drive);
+
+ if ((id->capability & 1) && hwif->autodma) {
+ /*
+ * Enable DMA on any drive that has
+ * UltraDMA (mode 0/1/2/3/4/5/6) enabled
+ */
+ if ((id->field_valid & 4) && ((id->dma_ultra >> 8) & 0x7f))
+ return hwif->ide_dma_on(drive);
+ /*
+ * Enable DMA on any drive that has mode2 DMA
+ * (multi or single) enabled
+ */
+ if (id->field_valid & 2) /* regular DMA */
+ if ((id->dma_mword & 0x404) == 0x404 ||
+ (id->dma_1word & 0x404) == 0x404)
+ return hwif->ide_dma_on(drive);
+
+ /* Consult the list of known "good" drives */
+ if (__ide_dma_good_drive(drive))
+ return hwif->ide_dma_on(drive);
+ }
+// if (hwif->tuneproc != NULL) hwif->tuneproc(drive, 255);
+ return hwif->ide_dma_off_quietly(drive);
+}
+
+/**
+ * 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 = HWIF(drive);
+ u8 dma_stat = hwif->INB(hwif->dma_status);
+
+ printk(KERN_WARNING "%s: dma_timer_expiry: dma status == 0x%02x\n",
+ drive->name, dma_stat);
+
+ if ((dma_stat & 0x18) == 0x18) /* BUSY Stupid Early Timer !! */
+ return WAIT_CMD;
+
+ HWGROUP(drive)->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 */
+}
+
+/**
+ * __ide_dma_host_off - Generic DMA kill
+ * @drive: drive to control
+ *
+ * Perform the generic IDE controller DMA off operation. This
+ * works for most IDE bus mastering controllers
+ */
+
+int __ide_dma_host_off (ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ u8 unit = (drive->select.b.unit & 0x01);
+ u8 dma_stat = hwif->INB(hwif->dma_status);
+
+ hwif->OUTB((dma_stat & ~(1<<(5+unit))), hwif->dma_status);
+ return 0;
+}
+
+EXPORT_SYMBOL(__ide_dma_host_off);
+
+/**
+ * __ide_dma_host_off_quietly - Generic DMA kill
+ * @drive: drive to control
+ *
+ * Turn off the current DMA on this IDE controller.
+ */
+
+int __ide_dma_off_quietly (ide_drive_t *drive)
+{
+ drive->using_dma = 0;
+ ide_toggle_bounce(drive, 0);
+
+ if (HWIF(drive)->ide_dma_host_off(drive))
+ return 1;
+
+ return 0;
+}
+
+EXPORT_SYMBOL(__ide_dma_off_quietly);
+#endif /* CONFIG_BLK_DEV_IDEDMA_PCI */
+
+/**
+ * __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.
+ */
+
+int __ide_dma_off (ide_drive_t *drive)
+{
+ printk(KERN_INFO "%s: DMA disabled\n", drive->name);
+ return HWIF(drive)->ide_dma_off_quietly(drive);
+}
+
+EXPORT_SYMBOL(__ide_dma_off);
+
+#ifdef CONFIG_BLK_DEV_IDEDMA_PCI
+/**
+ * __ide_dma_host_on - Enable DMA on a host
+ * @drive: drive to enable for DMA
+ *
+ * Enable DMA on an IDE controller following generic bus mastering
+ * IDE controller behaviour
+ */
+
+int __ide_dma_host_on (ide_drive_t *drive)
+{
+ if (drive->using_dma) {
+ ide_hwif_t *hwif = HWIF(drive);
+ u8 unit = (drive->select.b.unit & 0x01);
+ u8 dma_stat = hwif->INB(hwif->dma_status);
+
+ hwif->OUTB((dma_stat|(1<<(5+unit))), hwif->dma_status);
+ return 0;
+ }
+ return 1;
+}
+
+EXPORT_SYMBOL(__ide_dma_host_on);
+
+/**
+ * __ide_dma_on - Enable DMA on a device
+ * @drive: drive to enable DMA on
+ *
+ * Enable IDE DMA for a device on this IDE controller.
+ */
+
+int __ide_dma_on (ide_drive_t *drive)
+{
+ /* consult the list of known "bad" drives */
+ if (__ide_dma_bad_drive(drive))
+ return 1;
+
+ drive->using_dma = 1;
+ ide_toggle_bounce(drive, 1);
+
+ if (HWIF(drive)->ide_dma_host_on(drive))
+ return 1;
+
+ return 0;
+}
+
+EXPORT_SYMBOL(__ide_dma_on);
+
+/**
+ * __ide_dma_check - check DMA setup
+ * @drive: drive to check
+ *
+ * Don't use - due for extermination
+ */
+
+int __ide_dma_check (ide_drive_t *drive)
+{
+ return config_drive_for_dma(drive);
+}
+
+EXPORT_SYMBOL(__ide_dma_check);
+
+/**
+ * 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 = 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 */
+ hwif->OUTL(hwif->dmatable_dma, hwif->dma_prdtable);
+
+ /* specify r/w */
+ hwif->OUTB(reading, hwif->dma_command);
+
+ /* read dma_status for INTR & ERROR flags */
+ dma_stat = hwif->INB(hwif->dma_status);
+
+ /* clear INTR & ERROR flags */
+ hwif->OUTB(dma_stat|6, hwif->dma_status);
+ drive->waiting_for_dma = 1;
+ return 0;
+}
+
+EXPORT_SYMBOL_GPL(ide_dma_setup);
+
+static 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);
+}
+
+void ide_dma_start(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ u8 dma_cmd = hwif->INB(hwif->dma_command);
+
+ /* 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.
+ */
+ /* start DMA */
+ hwif->OUTB(dma_cmd|1, hwif->dma_command);
+ hwif->dma = 1;
+ 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 = HWIF(drive);
+ u8 dma_stat = 0, dma_cmd = 0;
+
+ drive->waiting_for_dma = 0;
+ /* get dma_command mode */
+ dma_cmd = hwif->INB(hwif->dma_command);
+ /* stop DMA */
+ hwif->OUTB(dma_cmd&~1, hwif->dma_command);
+ /* get DMA status */
+ dma_stat = hwif->INB(hwif->dma_status);
+ /* clear the INTR & ERROR bits */
+ hwif->OUTB(dma_stat|6, hwif->dma_status);
+ /* purge DMA mappings */
+ ide_destroy_dmatable(drive);
+ /* verify good DMA status */
+ hwif->dma = 0;
+ wmb();
+ return (dma_stat & 7) != 4 ? (0x10 | dma_stat) : 0;
+}
+
+EXPORT_SYMBOL(__ide_dma_end);
+
+/* returns 1 if dma irq issued, 0 otherwise */
+static int __ide_dma_test_irq(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ u8 dma_stat = hwif->INB(hwif->dma_status);
+
+#if 0 /* do not set unless you know what you are doing */
+ if (dma_stat & 4) {
+ u8 stat = hwif->INB(IDE_STATUS_REG);
+ hwif->OUTB(hwif->dma_status, dma_stat & 0xE4);
+ }
+#endif
+ /* return 1 if INTR asserted */
+ if ((dma_stat & 4) == 4)
+ return 1;
+ if (!drive->waiting_for_dma)
+ printk(KERN_WARNING "%s: (%s) called while not waiting\n",
+ drive->name, __FUNCTION__);
+ return 0;
+}
+#endif /* CONFIG_BLK_DEV_IDEDMA_PCI */
+
+int __ide_dma_bad_drive (ide_drive_t *drive)
+{
+ struct hd_driveid *id = drive->id;
+
+ int blacklist = in_drive_list(id, drive_blacklist);
+ if (blacklist) {
+ printk(KERN_WARNING "%s: Disabling (U)DMA for %s (blacklisted)\n",
+ drive->name, id->model);
+ return blacklist;
+ }
+ return 0;
+}
+
+EXPORT_SYMBOL(__ide_dma_bad_drive);
+
+int __ide_dma_good_drive (ide_drive_t *drive)
+{
+ struct hd_driveid *id = drive->id;
+ return in_drive_list(id, drive_whitelist);
+}
+
+EXPORT_SYMBOL(__ide_dma_good_drive);
+
+int ide_use_dma(ide_drive_t *drive)
+{
+ struct hd_driveid *id = drive->id;
+ ide_hwif_t *hwif = drive->hwif;
+
+ /* consult the list of known "bad" drives */
+ if (__ide_dma_bad_drive(drive))
+ return 0;
+
+ /* capable of UltraDMA modes */
+ if (id->field_valid & 4) {
+ if (hwif->ultra_mask & id->dma_ultra)
+ return 1;
+ }
+
+ /* capable of regular DMA modes */
+ if (id->field_valid & 2) {
+ if (hwif->mwdma_mask & id->dma_mword)
+ return 1;
+ if (hwif->swdma_mask & id->dma_1word)
+ return 1;
+ }
+
+ /* consult the list of known "good" drives */
+ if (__ide_dma_good_drive(drive) && id->eide_dma_time < 150)
+ return 1;
+
+ return 0;
+}
+
+EXPORT_SYMBOL_GPL(ide_use_dma);
+
+void ide_dma_verbose(ide_drive_t *drive)
+{
+ struct hd_driveid *id = drive->id;
+ ide_hwif_t *hwif = HWIF(drive);
+
+ if (id->field_valid & 4) {
+ if ((id->dma_ultra >> 8) && (id->dma_mword >> 8))
+ goto bug_dma_off;
+ if (id->dma_ultra & ((id->dma_ultra >> 8) & hwif->ultra_mask)) {
+ if (((id->dma_ultra >> 11) & 0x1F) &&
+ eighty_ninty_three(drive)) {
+ if ((id->dma_ultra >> 15) & 1) {
+ printk(", UDMA(mode 7)");
+ } else if ((id->dma_ultra >> 14) & 1) {
+ printk(", UDMA(133)");
+ } else if ((id->dma_ultra >> 13) & 1) {
+ printk(", UDMA(100)");
+ } else if ((id->dma_ultra >> 12) & 1) {
+ printk(", UDMA(66)");
+ } else if ((id->dma_ultra >> 11) & 1) {
+ printk(", UDMA(44)");
+ } else
+ goto mode_two;
+ } else {
+ mode_two:
+ if ((id->dma_ultra >> 10) & 1) {
+ printk(", UDMA(33)");
+ } else if ((id->dma_ultra >> 9) & 1) {
+ printk(", UDMA(25)");
+ } else if ((id->dma_ultra >> 8) & 1) {
+ printk(", UDMA(16)");
+ }
+ }
+ } else {
+ printk(", (U)DMA"); /* Can be BIOS-enabled! */
+ }
+ } else if (id->field_valid & 2) {
+ if ((id->dma_mword >> 8) && (id->dma_1word >> 8))
+ goto bug_dma_off;
+ printk(", DMA");
+ } else if (id->field_valid & 1) {
+ printk(", BUG");
+ }
+ return;
+bug_dma_off:
+ printk(", BUG DMA OFF");
+ hwif->ide_dma_off_quietly(drive);
+ return;
+}
+
+EXPORT_SYMBOL(ide_dma_verbose);
+
+#ifdef CONFIG_BLK_DEV_IDEDMA_PCI
+int __ide_dma_lostirq (ide_drive_t *drive)
+{
+ printk("%s: DMA interrupt recovery\n", drive->name);
+ return 1;
+}
+
+EXPORT_SYMBOL(__ide_dma_lostirq);
+
+int __ide_dma_timeout (ide_drive_t *drive)
+{
+ printk(KERN_ERR "%s: timeout waiting for DMA\n", drive->name);
+ if (HWIF(drive)->ide_dma_test_irq(drive))
+ return 0;
+
+ return HWIF(drive)->ide_dma_end(drive);
+}
+
+EXPORT_SYMBOL(__ide_dma_timeout);
+
+/*
+ * Needed for allowing full modular support of ide-driver
+ */
+static int ide_release_dma_engine(ide_hwif_t *hwif)
+{
+ if (hwif->dmatable_cpu) {
+ pci_free_consistent(hwif->pci_dev,
+ PRD_ENTRIES * PRD_BYTES,
+ hwif->dmatable_cpu,
+ hwif->dmatable_dma);
+ hwif->dmatable_cpu = NULL;
+ }
+ return 1;
+}
+
+static int ide_release_iomio_dma(ide_hwif_t *hwif)
+{
+ if ((hwif->dma_extra) && (hwif->channel == 0))
+ release_region((hwif->dma_base + 16), hwif->dma_extra);
+ release_region(hwif->dma_base, 8);
+ if (hwif->dma_base2)
+ release_region(hwif->dma_base, 8);
+ return 1;
+}
+
+/*
+ * Needed for allowing full modular support of ide-driver
+ */
+int ide_release_dma (ide_hwif_t *hwif)
+{
+ if (hwif->mmio == 2)
+ return 1;
+ if (hwif->chipset == ide_etrax100)
+ return 1;
+
+ ide_release_dma_engine(hwif);
+ return ide_release_iomio_dma(hwif);
+}
+
+static int ide_allocate_dma_engine(ide_hwif_t *hwif)
+{
+ hwif->dmatable_cpu = pci_alloc_consistent(hwif->pci_dev,
+ PRD_ENTRIES * PRD_BYTES,
+ &hwif->dmatable_dma);
+
+ if (hwif->dmatable_cpu)
+ return 0;
+
+ printk(KERN_ERR "%s: -- Error, unable to allocate%s DMA table(s).\n",
+ hwif->cds->name, !hwif->dmatable_cpu ? " CPU" : "");
+
+ ide_release_dma_engine(hwif);
+ return 1;
+}
+
+static int ide_mapped_mmio_dma(ide_hwif_t *hwif, unsigned long base, unsigned int ports)
+{
+ printk(KERN_INFO " %s: MMIO-DMA ", hwif->name);
+
+ hwif->dma_base = base;
+ if (hwif->cds->extra && hwif->channel == 0)
+ hwif->dma_extra = hwif->cds->extra;
+
+ if(hwif->mate)
+ hwif->dma_master = (hwif->channel) ? hwif->mate->dma_base : base;
+ else
+ hwif->dma_master = base;
+ return 0;
+}
+
+static int ide_iomio_dma(ide_hwif_t *hwif, unsigned long base, unsigned int ports)
+{
+ printk(KERN_INFO " %s: BM-DMA at 0x%04lx-0x%04lx",
+ hwif->name, base, base + ports - 1);
+ if (!request_region(base, ports, hwif->name)) {
+ printk(" -- Error, ports in use.\n");
+ return 1;
+ }
+ hwif->dma_base = base;
+ if ((hwif->cds->extra) && (hwif->channel == 0)) {
+ request_region(base+16, hwif->cds->extra, hwif->cds->name);
+ hwif->dma_extra = hwif->cds->extra;
+ }
+
+ if(hwif->mate)
+ hwif->dma_master = (hwif->channel) ? hwif->mate->dma_base : base;
+ else
+ hwif->dma_master = base;
+ if (hwif->dma_base2) {
+ if (!request_region(hwif->dma_base2, ports, hwif->name))
+ {
+ printk(" -- Error, secondary ports in use.\n");
+ release_region(base, ports);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int ide_dma_iobase(ide_hwif_t *hwif, unsigned long base, unsigned int ports)
+{
+ if (hwif->mmio == 2)
+ return ide_mapped_mmio_dma(hwif, base,ports);
+ BUG_ON(hwif->mmio == 1);
+ return ide_iomio_dma(hwif, base, ports);
+}
+
+/*
+ * This can be called for a dynamically installed interface. Don't __init it
+ */
+void ide_setup_dma (ide_hwif_t *hwif, unsigned long dma_base, unsigned int num_ports)
+{
+ if (ide_dma_iobase(hwif, dma_base, num_ports))
+ return;
+
+ if (ide_allocate_dma_engine(hwif)) {
+ ide_release_dma(hwif);
+ return;
+ }
+
+ if (!(hwif->dma_command))
+ hwif->dma_command = hwif->dma_base;
+ if (!(hwif->dma_vendor1))
+ hwif->dma_vendor1 = (hwif->dma_base + 1);
+ if (!(hwif->dma_status))
+ hwif->dma_status = (hwif->dma_base + 2);
+ if (!(hwif->dma_vendor3))
+ hwif->dma_vendor3 = (hwif->dma_base + 3);
+ if (!(hwif->dma_prdtable))
+ hwif->dma_prdtable = (hwif->dma_base + 4);
+
+ if (!hwif->ide_dma_off_quietly)
+ hwif->ide_dma_off_quietly = &__ide_dma_off_quietly;
+ if (!hwif->ide_dma_host_off)
+ hwif->ide_dma_host_off = &__ide_dma_host_off;
+ if (!hwif->ide_dma_on)
+ hwif->ide_dma_on = &__ide_dma_on;
+ if (!hwif->ide_dma_host_on)
+ hwif->ide_dma_host_on = &__ide_dma_host_on;
+ if (!hwif->ide_dma_check)
+ hwif->ide_dma_check = &__ide_dma_check;
+ if (!hwif->dma_setup)
+ hwif->dma_setup = &ide_dma_setup;
+ if (!hwif->dma_exec_cmd)
+ hwif->dma_exec_cmd = &ide_dma_exec_cmd;
+ if (!hwif->dma_start)
+ hwif->dma_start = &ide_dma_start;
+ if (!hwif->ide_dma_end)
+ hwif->ide_dma_end = &__ide_dma_end;
+ if (!hwif->ide_dma_test_irq)
+ hwif->ide_dma_test_irq = &__ide_dma_test_irq;
+ if (!hwif->ide_dma_timeout)
+ hwif->ide_dma_timeout = &__ide_dma_timeout;
+ if (!hwif->ide_dma_lostirq)
+ hwif->ide_dma_lostirq = &__ide_dma_lostirq;
+
+ if (hwif->chipset != ide_trm290) {
+ u8 dma_stat = hwif->INB(hwif->dma_status);
+ printk(", BIOS settings: %s:%s, %s:%s",
+ hwif->drives[0].name, (dma_stat & 0x20) ? "DMA" : "pio",
+ hwif->drives[1].name, (dma_stat & 0x40) ? "DMA" : "pio");
+ }
+ printk("\n");
+
+ if (!(hwif->dma_master))
+ BUG();
+}
+
+EXPORT_SYMBOL_GPL(ide_setup_dma);
+#endif /* CONFIG_BLK_DEV_IDEDMA_PCI */
diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c
new file mode 100644
index 000000000000..36c0b74a4e45
--- /dev/null
+++ b/drivers/ide/ide-floppy.c
@@ -0,0 +1,2211 @@
+/*
+ * linux/drivers/ide/ide-floppy.c Version 0.99 Feb 24 2002
+ *
+ * Copyright (C) 1996 - 1999 Gadi Oxman <gadio@netvision.net.il>
+ * Copyright (C) 2000 - 2002 Paul Bristow <paul@paulbristow.net>
+ */
+
+/*
+ * IDE ATAPI floppy driver.
+ *
+ * The driver currently doesn't have any fancy features, just the bare
+ * minimum read/write support.
+ *
+ * This driver supports the following IDE floppy drives:
+ *
+ * LS-120/240 SuperDisk
+ * Iomega Zip 100/250
+ * Iomega PC Card Clik!/PocketZip
+ *
+ * Many thanks to Lode Leroy <Lode.Leroy@www.ibase.be>, who tested so many
+ * ALPHA patches to this driver on an EASYSTOR LS-120 ATAPI floppy drive.
+ *
+ * Ver 0.1 Oct 17 96 Initial test version, mostly based on ide-tape.c.
+ * Ver 0.2 Oct 31 96 Minor changes.
+ * Ver 0.3 Dec 2 96 Fixed error recovery bug.
+ * Ver 0.4 Jan 26 97 Add support for the HDIO_GETGEO ioctl.
+ * Ver 0.5 Feb 21 97 Add partitions support.
+ * Use the minimum of the LBA and CHS capacities.
+ * Avoid hwgroup->rq == NULL on the last irq.
+ * Fix potential null dereferencing with DEBUG_LOG.
+ * Ver 0.8 Dec 7 97 Increase irq timeout from 10 to 50 seconds.
+ * Add media write-protect detection.
+ * Issue START command only if TEST UNIT READY fails.
+ * Add work-around for IOMEGA ZIP revision 21.D.
+ * Remove idefloppy_get_capabilities().
+ * Ver 0.9 Jul 4 99 Fix a bug which might have caused the number of
+ * bytes requested on each interrupt to be zero.
+ * Thanks to <shanos@es.co.nz> for pointing this out.
+ * Ver 0.9.sv Jan 6 01 Sam Varshavchik <mrsam@courier-mta.com>
+ * Implement low level formatting. Reimplemented
+ * IDEFLOPPY_CAPABILITIES_PAGE, since we need the srfp
+ * bit. My LS-120 drive barfs on
+ * IDEFLOPPY_CAPABILITIES_PAGE, but maybe it's just me.
+ * Compromise by not reporting a failure to get this
+ * mode page. Implemented four IOCTLs in order to
+ * implement formatting. IOCTls begin with 0x4600,
+ * 0x46 is 'F' as in Format.
+ * Jan 9 01 Userland option to select format verify.
+ * Added PC_SUPPRESS_ERROR flag - some idefloppy drives
+ * do not implement IDEFLOPPY_CAPABILITIES_PAGE, and
+ * return a sense error. Suppress error reporting in
+ * this particular case in order to avoid spurious
+ * errors in syslog. The culprit is
+ * idefloppy_get_capability_page(), so move it to
+ * idefloppy_begin_format() so that it's not used
+ * unless absolutely necessary.
+ * If drive does not support format progress indication
+ * monitor the dsc bit in the status register.
+ * Also, O_NDELAY on open will allow the device to be
+ * opened without a disk available. This can be used to
+ * open an unformatted disk, or get the device capacity.
+ * Ver 0.91 Dec 11 99 Added IOMEGA Clik! drive support by
+ * <paul@paulbristow.net>
+ * Ver 0.92 Oct 22 00 Paul Bristow became official maintainer for this
+ * driver. Included Powerbook internal zip kludge.
+ * Ver 0.93 Oct 24 00 Fixed bugs for Clik! drive
+ * no disk on insert and disk change now works
+ * Ver 0.94 Oct 27 00 Tidied up to remove strstr(Clik) everywhere
+ * Ver 0.95 Nov 7 00 Brought across to kernel 2.4
+ * Ver 0.96 Jan 7 01 Actually in line with release version of 2.4.0
+ * including set_bit patch from Rusty Russell
+ * Ver 0.97 Jul 22 01 Merge 0.91-0.96 onto 0.9.sv for ac series
+ * Ver 0.97.sv Aug 3 01 Backported from 2.4.7-ac3
+ * Ver 0.98 Oct 26 01 Split idefloppy_transfer_pc into two pieces to
+ * fix a lost interrupt problem. It appears the busy
+ * bit was being deasserted by my IOMEGA ATAPI ZIP 100
+ * drive before the drive was actually ready.
+ * Ver 0.98a Oct 29 01 Expose delay value so we can play.
+ * Ver 0.99 Feb 24 02 Remove duplicate code, modify clik! detection code
+ * to support new PocketZip drives
+ */
+
+#define IDEFLOPPY_VERSION "0.99.newide"
+
+#include <linux/config.h>
+#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/major.h>
+#include <linux/errno.h>
+#include <linux/genhd.h>
+#include <linux/slab.h>
+#include <linux/cdrom.h>
+#include <linux/ide.h>
+#include <linux/bitops.h>
+
+#include <asm/byteorder.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/unaligned.h>
+
+/*
+ * The following are used to debug the driver.
+ */
+#define IDEFLOPPY_DEBUG_LOG 0
+#define IDEFLOPPY_DEBUG_INFO 0
+#define IDEFLOPPY_DEBUG_BUGS 1
+
+/* #define IDEFLOPPY_DEBUG(fmt, args...) printk(KERN_INFO fmt, ## args) */
+#define IDEFLOPPY_DEBUG( fmt, args... )
+
+#if IDEFLOPPY_DEBUG_LOG
+#define debug_log printk
+#else
+#define debug_log(fmt, args... ) do {} while(0)
+#endif
+
+
+/*
+ * Some drives require a longer irq timeout.
+ */
+#define IDEFLOPPY_WAIT_CMD (5 * WAIT_CMD)
+
+/*
+ * 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
+
+/*
+ * With each packet command, we allocate a buffer of
+ * IDEFLOPPY_PC_BUFFER_SIZE bytes.
+ */
+#define IDEFLOPPY_PC_BUFFER_SIZE 256
+
+/*
+ * In various places in the driver, we need to allocate storage
+ * for packet commands and requests, which will remain valid while
+ * we leave the driver to wait for an interrupt or a timeout event.
+ */
+#define IDEFLOPPY_PC_STACK (10 + IDEFLOPPY_MAX_PC_RETRIES)
+
+/*
+ * Our view of a packet command.
+ */
+typedef struct idefloppy_packet_command_s {
+ u8 c[12]; /* Actual packet bytes */
+ int retries; /* On each retry, we increment retries */
+ int error; /* Error code */
+ int request_transfer; /* Bytes to transfer */
+ int actually_transferred; /* Bytes actually transferred */
+ int buffer_size; /* Size of our data buffer */
+ int b_count; /* Missing/Available data on the current buffer */
+ struct request *rq; /* The corresponding request */
+ u8 *buffer; /* Data buffer */
+ u8 *current_position; /* Pointer into the above buffer */
+ void (*callback) (ide_drive_t *); /* Called when this packet command is completed */
+ u8 pc_buffer[IDEFLOPPY_PC_BUFFER_SIZE]; /* Temporary buffer */
+ unsigned long flags; /* Status/Action bit flags: long for set_bit */
+} idefloppy_pc_t;
+
+/*
+ * Packet command flag bits.
+ */
+#define PC_ABORT 0 /* Set when an error is considered normal - We won't retry */
+#define PC_DMA_RECOMMENDED 2 /* 1 when we prefer to use DMA if possible */
+#define PC_DMA_IN_PROGRESS 3 /* 1 while DMA in progress */
+#define PC_DMA_ERROR 4 /* 1 when encountered problem during DMA */
+#define PC_WRITING 5 /* Data direction */
+
+#define PC_SUPPRESS_ERROR 6 /* Suppress error reporting */
+
+/*
+ * Removable Block Access Capabilities Page
+ */
+typedef struct {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ unsigned page_code :6; /* Page code - Should be 0x1b */
+ unsigned reserved1_6 :1; /* Reserved */
+ unsigned ps :1; /* Should be 0 */
+#elif defined(__BIG_ENDIAN_BITFIELD)
+ unsigned ps :1; /* Should be 0 */
+ unsigned reserved1_6 :1; /* Reserved */
+ unsigned page_code :6; /* Page code - Should be 0x1b */
+#else
+#error "Bitfield endianness not defined! Check your byteorder.h"
+#endif
+ u8 page_length; /* Page Length - Should be 0xa */
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ unsigned reserved2 :6;
+ unsigned srfp :1; /* Supports reporting progress of format */
+ unsigned sflp :1; /* System floppy type device */
+ unsigned tlun :3; /* Total logical units supported by the device */
+ unsigned reserved3 :3;
+ unsigned sml :1; /* Single / Multiple lun supported */
+ unsigned ncd :1; /* Non cd optical device */
+#elif defined(__BIG_ENDIAN_BITFIELD)
+ unsigned sflp :1; /* System floppy type device */
+ unsigned srfp :1; /* Supports reporting progress of format */
+ unsigned reserved2 :6;
+ unsigned ncd :1; /* Non cd optical device */
+ unsigned sml :1; /* Single / Multiple lun supported */
+ unsigned reserved3 :3;
+ unsigned tlun :3; /* Total logical units supported by the device */
+#else
+#error "Bitfield endianness not defined! Check your byteorder.h"
+#endif
+ u8 reserved[8];
+} idefloppy_capabilities_page_t;
+
+/*
+ * Flexible disk page.
+ */
+typedef struct {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ unsigned page_code :6; /* Page code - Should be 0x5 */
+ unsigned reserved1_6 :1; /* Reserved */
+ unsigned ps :1; /* The device is capable of saving the page */
+#elif defined(__BIG_ENDIAN_BITFIELD)
+ unsigned ps :1; /* The device is capable of saving the page */
+ unsigned reserved1_6 :1; /* Reserved */
+ unsigned page_code :6; /* Page code - Should be 0x5 */
+#else
+#error "Bitfield endianness not defined! Check your byteorder.h"
+#endif
+ u8 page_length; /* Page Length - Should be 0x1e */
+ u16 transfer_rate; /* In kilobits per second */
+ u8 heads, sectors; /* Number of heads, Number of sectors per track */
+ u16 sector_size; /* Byes per sector */
+ u16 cyls; /* Number of cylinders */
+ u8 reserved10[10];
+ u8 motor_delay; /* Motor off delay */
+ u8 reserved21[7];
+ u16 rpm; /* Rotations per minute */
+ u8 reserved30[2];
+} idefloppy_flexible_disk_page_t;
+
+/*
+ * Format capacity
+ */
+typedef struct {
+ u8 reserved[3];
+ u8 length; /* Length of the following descriptors in bytes */
+} idefloppy_capacity_header_t;
+
+typedef struct {
+ u32 blocks; /* Number of blocks */
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ unsigned dc :2; /* Descriptor Code */
+ unsigned reserved :6;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+ unsigned reserved :6;
+ unsigned dc :2; /* Descriptor Code */
+#else
+#error "Bitfield endianness not defined! Check your byteorder.h"
+#endif
+ u8 length_msb; /* Block Length (MSB)*/
+ u16 length; /* Block Length */
+} idefloppy_capacity_descriptor_t;
+
+#define CAPACITY_INVALID 0x00
+#define CAPACITY_UNFORMATTED 0x01
+#define CAPACITY_CURRENT 0x02
+#define CAPACITY_NO_CARTRIDGE 0x03
+
+/*
+ * 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 a variable
+ * of type idefloppy_floppy_t, defined below.
+ */
+typedef struct ide_floppy_obj {
+ ide_drive_t *drive;
+ ide_driver_t *driver;
+ struct gendisk *disk;
+ struct kref kref;
+
+ /* Current packet command */
+ idefloppy_pc_t *pc;
+ /* Last failed packet command */
+ idefloppy_pc_t *failed_pc;
+ /* Packet command stack */
+ idefloppy_pc_t pc_stack[IDEFLOPPY_PC_STACK];
+ /* Next free packet command storage space */
+ int pc_stack_index;
+ struct request rq_stack[IDEFLOPPY_PC_STACK];
+ /* We implement a circular array */
+ int rq_stack_index;
+
+ /*
+ * Last error information
+ */
+ u8 sense_key, asc, ascq;
+ /* delay this long before sending packet command */
+ u8 ticks;
+ int progress_indication;
+
+ /*
+ * Device information
+ */
+ /* Current format */
+ int blocks, block_size, bs_factor;
+ /* Last format capacity */
+ idefloppy_capacity_descriptor_t capacity;
+ /* Copy of the flexible disk page */
+ idefloppy_flexible_disk_page_t flexible_disk_page;
+ /* Write protect */
+ int wp;
+ /* Supports format progress report */
+ int srfp;
+ /* Status/Action flags */
+ unsigned long flags;
+} idefloppy_floppy_t;
+
+#define IDEFLOPPY_TICKS_DELAY 3 /* default delay for ZIP 100 */
+
+/*
+ * Floppy flag bits values.
+ */
+#define IDEFLOPPY_DRQ_INTERRUPT 0 /* DRQ interrupt device */
+#define IDEFLOPPY_MEDIA_CHANGED 1 /* Media may have changed */
+#define IDEFLOPPY_USE_READ12 2 /* Use READ12/WRITE12 or READ10/WRITE10 */
+#define IDEFLOPPY_FORMAT_IN_PROGRESS 3 /* Format in progress */
+#define IDEFLOPPY_CLIK_DRIVE 4 /* Avoid commands not supported in Clik drive */
+#define IDEFLOPPY_ZIP_DRIVE 5 /* Requires BH algorithm for packets */
+
+/*
+ * ATAPI floppy drive packet commands
+ */
+#define IDEFLOPPY_FORMAT_UNIT_CMD 0x04
+#define IDEFLOPPY_INQUIRY_CMD 0x12
+#define IDEFLOPPY_MODE_SELECT_CMD 0x55
+#define IDEFLOPPY_MODE_SENSE_CMD 0x5a
+#define IDEFLOPPY_READ10_CMD 0x28
+#define IDEFLOPPY_READ12_CMD 0xa8
+#define IDEFLOPPY_READ_CAPACITY_CMD 0x23
+#define IDEFLOPPY_REQUEST_SENSE_CMD 0x03
+#define IDEFLOPPY_PREVENT_REMOVAL_CMD 0x1e
+#define IDEFLOPPY_SEEK_CMD 0x2b
+#define IDEFLOPPY_START_STOP_CMD 0x1b
+#define IDEFLOPPY_TEST_UNIT_READY_CMD 0x00
+#define IDEFLOPPY_VERIFY_CMD 0x2f
+#define IDEFLOPPY_WRITE10_CMD 0x2a
+#define IDEFLOPPY_WRITE12_CMD 0xaa
+#define IDEFLOPPY_WRITE_VERIFY_CMD 0x2e
+
+/*
+ * Defines for the mode sense command
+ */
+#define MODE_SENSE_CURRENT 0x00
+#define MODE_SENSE_CHANGEABLE 0x01
+#define MODE_SENSE_DEFAULT 0x02
+#define MODE_SENSE_SAVED 0x03
+
+/*
+ * 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
+
+#if 0
+/*
+ * Special requests for our block device strategy routine.
+ */
+#define IDEFLOPPY_FIRST_RQ 90
+
+/*
+ * IDEFLOPPY_PC_RQ is used to queue a packet command in the request queue.
+ */
+#define IDEFLOPPY_PC_RQ 90
+
+#define IDEFLOPPY_LAST_RQ 90
+
+/*
+ * A macro which can be used to check if a given request command
+ * originated in the driver or in the buffer cache layer.
+ */
+#define IDEFLOPPY_RQ_CMD(cmd) ((cmd >= IDEFLOPPY_FIRST_RQ) && (cmd <= IDEFLOPPY_LAST_RQ))
+
+#endif
+
+/*
+ * Error codes which are returned in rq->errors to the higher part
+ * of the driver.
+ */
+#define IDEFLOPPY_ERROR_GENERAL 101
+
+/*
+ * The following is used to format the general configuration word of
+ * the ATAPI IDENTIFY DEVICE command.
+ */
+struct idefloppy_id_gcw {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ unsigned packet_size :2; /* Packet Size */
+ unsigned reserved234 :3; /* Reserved */
+ unsigned drq_type :2; /* Command packet DRQ type */
+ unsigned removable :1; /* Removable media */
+ unsigned device_type :5; /* Device type */
+ unsigned reserved13 :1; /* Reserved */
+ unsigned protocol :2; /* Protocol type */
+#elif defined(__BIG_ENDIAN_BITFIELD)
+ unsigned protocol :2; /* Protocol type */
+ unsigned reserved13 :1; /* Reserved */
+ unsigned device_type :5; /* Device type */
+ unsigned removable :1; /* Removable media */
+ unsigned drq_type :2; /* Command packet DRQ type */
+ unsigned reserved234 :3; /* Reserved */
+ unsigned packet_size :2; /* Packet Size */
+#else
+#error "Bitfield endianness not defined! Check your byteorder.h"
+#endif
+};
+
+/*
+ * INQUIRY packet command - Data Format
+ */
+typedef struct {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ unsigned device_type :5; /* Peripheral Device Type */
+ unsigned reserved0_765 :3; /* Peripheral Qualifier - Reserved */
+ unsigned reserved1_6t0 :7; /* Reserved */
+ unsigned rmb :1; /* Removable Medium Bit */
+ unsigned ansi_version :3; /* ANSI Version */
+ unsigned ecma_version :3; /* ECMA Version */
+ unsigned iso_version :2; /* ISO Version */
+ unsigned response_format :4; /* Response Data Format */
+ unsigned reserved3_45 :2; /* Reserved */
+ unsigned reserved3_6 :1; /* TrmIOP - Reserved */
+ unsigned reserved3_7 :1; /* AENC - Reserved */
+#elif defined(__BIG_ENDIAN_BITFIELD)
+ unsigned reserved0_765 :3; /* Peripheral Qualifier - Reserved */
+ unsigned device_type :5; /* Peripheral Device Type */
+ unsigned rmb :1; /* Removable Medium Bit */
+ unsigned reserved1_6t0 :7; /* Reserved */
+ unsigned iso_version :2; /* ISO Version */
+ unsigned ecma_version :3; /* ECMA Version */
+ unsigned ansi_version :3; /* ANSI Version */
+ unsigned reserved3_7 :1; /* AENC - Reserved */
+ unsigned reserved3_6 :1; /* TrmIOP - Reserved */
+ unsigned reserved3_45 :2; /* Reserved */
+ unsigned response_format :4; /* Response Data Format */
+#else
+#error "Bitfield endianness not defined! Check your byteorder.h"
+#endif
+ u8 additional_length; /* Additional Length (total_length-4) */
+ u8 rsv5, rsv6, rsv7; /* Reserved */
+ u8 vendor_id[8]; /* Vendor Identification */
+ u8 product_id[16]; /* Product Identification */
+ u8 revision_level[4]; /* Revision Level */
+ u8 vendor_specific[20]; /* Vendor Specific - Optional */
+ u8 reserved56t95[40]; /* Reserved - Optional */
+ /* Additional information may be returned */
+} idefloppy_inquiry_result_t;
+
+/*
+ * REQUEST SENSE packet command result - Data Format.
+ */
+typedef struct {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ unsigned error_code :7; /* Current error (0x70) */
+ unsigned valid :1; /* The information field conforms to SFF-8070i */
+ u8 reserved1 :8; /* Reserved */
+ unsigned sense_key :4; /* Sense Key */
+ unsigned reserved2_4 :1; /* Reserved */
+ unsigned ili :1; /* Incorrect Length Indicator */
+ unsigned reserved2_67 :2;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+ unsigned valid :1; /* The information field conforms to SFF-8070i */
+ unsigned error_code :7; /* Current error (0x70) */
+ u8 reserved1 :8; /* Reserved */
+ unsigned reserved2_67 :2;
+ unsigned ili :1; /* Incorrect Length Indicator */
+ unsigned reserved2_4 :1; /* Reserved */
+ unsigned sense_key :4; /* Sense Key */
+#else
+#error "Bitfield endianness not defined! Check your byteorder.h"
+#endif
+ u32 information __attribute__ ((packed));
+ u8 asl; /* Additional sense length (n-7) */
+ u32 command_specific; /* Additional command specific information */
+ u8 asc; /* Additional Sense Code */
+ u8 ascq; /* Additional Sense Code Qualifier */
+ u8 replaceable_unit_code; /* Field Replaceable Unit Code */
+ u8 sksv[3];
+ u8 pad[2]; /* Padding to 20 bytes */
+} idefloppy_request_sense_result_t;
+
+/*
+ * Pages of the SELECT SENSE / MODE SENSE packet commands.
+ */
+#define IDEFLOPPY_CAPABILITIES_PAGE 0x1b
+#define IDEFLOPPY_FLEXIBLE_DISK_PAGE 0x05
+
+/*
+ * Mode Parameter Header for the MODE SENSE packet command
+ */
+typedef struct {
+ u16 mode_data_length; /* Length of the following data transfer */
+ u8 medium_type; /* Medium Type */
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ unsigned reserved3 :7;
+ unsigned wp :1; /* Write protect */
+#elif defined(__BIG_ENDIAN_BITFIELD)
+ unsigned wp :1; /* Write protect */
+ unsigned reserved3 :7;
+#else
+#error "Bitfield endianness not defined! Check your byteorder.h"
+#endif
+ u8 reserved[4];
+} idefloppy_mode_parameter_header_t;
+
+static DECLARE_MUTEX(idefloppy_ref_sem);
+
+#define to_ide_floppy(obj) container_of(obj, struct ide_floppy_obj, kref)
+
+#define ide_floppy_g(disk) \
+ container_of((disk)->private_data, struct ide_floppy_obj, driver)
+
+static struct ide_floppy_obj *ide_floppy_get(struct gendisk *disk)
+{
+ struct ide_floppy_obj *floppy = NULL;
+
+ down(&idefloppy_ref_sem);
+ floppy = ide_floppy_g(disk);
+ if (floppy)
+ kref_get(&floppy->kref);
+ up(&idefloppy_ref_sem);
+ return floppy;
+}
+
+static void ide_floppy_release(struct kref *);
+
+static void ide_floppy_put(struct ide_floppy_obj *floppy)
+{
+ down(&idefloppy_ref_sem);
+ kref_put(&floppy->kref, ide_floppy_release);
+ up(&idefloppy_ref_sem);
+}
+
+/*
+ * Too bad. The drive wants to send us data which we are not ready to accept.
+ * Just throw it away.
+ */
+static void idefloppy_discard_data (ide_drive_t *drive, unsigned int bcount)
+{
+ while (bcount--)
+ (void) HWIF(drive)->INB(IDE_DATA_REG);
+}
+
+#if IDEFLOPPY_DEBUG_BUGS
+static void idefloppy_write_zeros (ide_drive_t *drive, unsigned int bcount)
+{
+ while (bcount--)
+ HWIF(drive)->OUTB(0, IDE_DATA_REG);
+}
+#endif /* IDEFLOPPY_DEBUG_BUGS */
+
+
+/*
+ * idefloppy_do_end_request is used to finish servicing a request.
+ *
+ * For read/write requests, we will call ide_end_request to pass to the
+ * next buffer.
+ */
+static int idefloppy_do_end_request(ide_drive_t *drive, int uptodate, int nsecs)
+{
+ idefloppy_floppy_t *floppy = drive->driver_data;
+ struct request *rq = HWGROUP(drive)->rq;
+ int error;
+
+ debug_log(KERN_INFO "Reached idefloppy_end_request\n");
+
+ 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 (!(rq->flags & REQ_SPECIAL)) { //if (!IDEFLOPPY_RQ_CMD (rq->cmd)) {
+ /* 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_input_buffers (ide_drive_t *drive, idefloppy_pc_t *pc, unsigned int bcount)
+{
+ struct request *rq = pc->rq;
+ struct bio_vec *bvec;
+ struct bio *bio;
+ unsigned long flags;
+ char *data;
+ int count, i, done = 0;
+
+ rq_for_each_bio(bio, rq) {
+ bio_for_each_segment(bvec, bio, i) {
+ if (!bcount)
+ break;
+
+ count = min(bvec->bv_len, bcount);
+
+ data = bvec_kmap_irq(bvec, &flags);
+ drive->hwif->atapi_input_bytes(drive, data, count);
+ bvec_kunmap_irq(data, &flags);
+
+ bcount -= count;
+ pc->b_count += count;
+ done += count;
+ }
+ }
+
+ idefloppy_do_end_request(drive, 1, done >> 9);
+
+ if (bcount) {
+ printk(KERN_ERR "%s: leftover data in idefloppy_input_buffers, bcount == %d\n", drive->name, bcount);
+ idefloppy_discard_data(drive, bcount);
+ }
+}
+
+static void idefloppy_output_buffers (ide_drive_t *drive, idefloppy_pc_t *pc, unsigned int bcount)
+{
+ struct request *rq = pc->rq;
+ struct bio *bio;
+ struct bio_vec *bvec;
+ unsigned long flags;
+ int count, i, done = 0;
+ char *data;
+
+ rq_for_each_bio(bio, rq) {
+ bio_for_each_segment(bvec, bio, i) {
+ if (!bcount)
+ break;
+
+ count = min(bvec->bv_len, bcount);
+
+ data = bvec_kmap_irq(bvec, &flags);
+ drive->hwif->atapi_output_bytes(drive, data, count);
+ bvec_kunmap_irq(data, &flags);
+
+ bcount -= count;
+ pc->b_count += count;
+ done += count;
+ }
+ }
+
+ idefloppy_do_end_request(drive, 1, done >> 9);
+
+ if (bcount) {
+ printk(KERN_ERR "%s: leftover data in idefloppy_output_buffers, bcount == %d\n", drive->name, bcount);
+ idefloppy_write_zeros(drive, bcount);
+ }
+}
+
+static void idefloppy_update_buffers (ide_drive_t *drive, idefloppy_pc_t *pc)
+{
+ struct request *rq = pc->rq;
+ struct bio *bio = rq->bio;
+
+ while ((bio = rq->bio) != NULL)
+ idefloppy_do_end_request(drive, 1, 0);
+}
+
+/*
+ * idefloppy_queue_pc_head generates 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 idefloppy_queue_pc_head (ide_drive_t *drive,idefloppy_pc_t *pc,struct request *rq)
+{
+ struct ide_floppy_obj *floppy = drive->driver_data;
+
+ ide_init_drive_cmd(rq);
+ rq->buffer = (char *) pc;
+ rq->flags = REQ_SPECIAL; //rq->cmd = IDEFLOPPY_PC_RQ;
+ rq->rq_disk = floppy->disk;
+ (void) ide_do_drive_cmd(drive, rq, ide_preempt);
+}
+
+static idefloppy_pc_t *idefloppy_next_pc_storage (ide_drive_t *drive)
+{
+ idefloppy_floppy_t *floppy = drive->driver_data;
+
+ if (floppy->pc_stack_index == IDEFLOPPY_PC_STACK)
+ floppy->pc_stack_index=0;
+ return (&floppy->pc_stack[floppy->pc_stack_index++]);
+}
+
+static struct request *idefloppy_next_rq_storage (ide_drive_t *drive)
+{
+ idefloppy_floppy_t *floppy = drive->driver_data;
+
+ if (floppy->rq_stack_index == IDEFLOPPY_PC_STACK)
+ floppy->rq_stack_index = 0;
+ return (&floppy->rq_stack[floppy->rq_stack_index++]);
+}
+
+/*
+ * idefloppy_analyze_error is called on each failed packet command retry
+ * to analyze the request sense.
+ */
+static void idefloppy_analyze_error (ide_drive_t *drive,idefloppy_request_sense_result_t *result)
+{
+ idefloppy_floppy_t *floppy = drive->driver_data;
+
+ floppy->sense_key = result->sense_key;
+ floppy->asc = result->asc;
+ floppy->ascq = result->ascq;
+ floppy->progress_indication = result->sksv[0] & 0x80 ?
+ (u16)get_unaligned((u16 *)(result->sksv+1)):0x10000;
+ if (floppy->failed_pc)
+ debug_log(KERN_INFO "ide-floppy: pc = %x, sense key = %x, "
+ "asc = %x, ascq = %x\n", floppy->failed_pc->c[0],
+ result->sense_key, result->asc, result->ascq);
+ else
+ debug_log(KERN_INFO "ide-floppy: sense key = %x, asc = %x, "
+ "ascq = %x\n", result->sense_key,
+ result->asc, result->ascq);
+}
+
+static void idefloppy_request_sense_callback (ide_drive_t *drive)
+{
+ idefloppy_floppy_t *floppy = drive->driver_data;
+
+ debug_log(KERN_INFO "ide-floppy: Reached %s\n", __FUNCTION__);
+
+ if (!floppy->pc->error) {
+ idefloppy_analyze_error(drive,(idefloppy_request_sense_result_t *) floppy->pc->buffer);
+ idefloppy_do_end_request(drive, 1, 0);
+ } else {
+ printk(KERN_ERR "Error in REQUEST SENSE itself - Aborting request!\n");
+ idefloppy_do_end_request(drive, 0, 0);
+ }
+}
+
+/*
+ * General packet command callback function.
+ */
+static void idefloppy_pc_callback (ide_drive_t *drive)
+{
+ idefloppy_floppy_t *floppy = drive->driver_data;
+
+ debug_log(KERN_INFO "ide-floppy: Reached %s\n", __FUNCTION__);
+
+ idefloppy_do_end_request(drive, floppy->pc->error ? 0 : 1, 0);
+}
+
+/*
+ * idefloppy_init_pc initializes a packet command.
+ */
+static void idefloppy_init_pc (idefloppy_pc_t *pc)
+{
+ memset(pc->c, 0, 12);
+ pc->retries = 0;
+ pc->flags = 0;
+ pc->request_transfer = 0;
+ pc->buffer = pc->pc_buffer;
+ pc->buffer_size = IDEFLOPPY_PC_BUFFER_SIZE;
+ pc->callback = &idefloppy_pc_callback;
+}
+
+static void idefloppy_create_request_sense_cmd (idefloppy_pc_t *pc)
+{
+ idefloppy_init_pc(pc);
+ pc->c[0] = IDEFLOPPY_REQUEST_SENSE_CMD;
+ pc->c[4] = 255;
+ pc->request_transfer = 18;
+ pc->callback = &idefloppy_request_sense_callback;
+}
+
+/*
+ * idefloppy_retry_pc is 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.
+ */
+static void idefloppy_retry_pc (ide_drive_t *drive)
+{
+ idefloppy_pc_t *pc;
+ struct request *rq;
+ atapi_error_t error;
+
+ error.all = HWIF(drive)->INB(IDE_ERROR_REG);
+ pc = idefloppy_next_pc_storage(drive);
+ rq = idefloppy_next_rq_storage(drive);
+ idefloppy_create_request_sense_cmd(pc);
+ idefloppy_queue_pc_head(drive, pc, rq);
+}
+
+/*
+ * idefloppy_pc_intr is the usual interrupt handler which will be called
+ * during a packet command.
+ */
+static ide_startstop_t idefloppy_pc_intr (ide_drive_t *drive)
+{
+ idefloppy_floppy_t *floppy = drive->driver_data;
+ atapi_status_t status;
+ atapi_bcount_t bcount;
+ atapi_ireason_t ireason;
+ idefloppy_pc_t *pc = floppy->pc;
+ struct request *rq = pc->rq;
+ unsigned int temp;
+
+ debug_log(KERN_INFO "ide-floppy: Reached %s interrupt handler\n",
+ __FUNCTION__);
+
+ if (test_bit(PC_DMA_IN_PROGRESS, &pc->flags)) {
+ if (HWIF(drive)->ide_dma_end(drive)) {
+ set_bit(PC_DMA_ERROR, &pc->flags);
+ } else {
+ pc->actually_transferred = pc->request_transfer;
+ idefloppy_update_buffers(drive, pc);
+ }
+ debug_log(KERN_INFO "ide-floppy: DMA finished\n");
+ }
+
+ /* Clear the interrupt */
+ status.all = HWIF(drive)->INB(IDE_STATUS_REG);
+
+ if (!status.b.drq) { /* No more interrupts */
+ debug_log(KERN_INFO "Packet command completed, %d bytes "
+ "transferred\n", pc->actually_transferred);
+ clear_bit(PC_DMA_IN_PROGRESS, &pc->flags);
+
+ local_irq_enable();
+
+ if (status.b.check || test_bit(PC_DMA_ERROR, &pc->flags)) {
+ /* Error detected */
+ debug_log(KERN_INFO "ide-floppy: %s: I/O error\n",
+ drive->name);
+ rq->errors++;
+ if (pc->c[0] == IDEFLOPPY_REQUEST_SENSE_CMD) {
+ printk(KERN_ERR "ide-floppy: I/O error in "
+ "request sense command\n");
+ return ide_do_reset(drive);
+ }
+ /* Retry operation */
+ idefloppy_retry_pc(drive);
+ /* queued, but not started */
+ return ide_stopped;
+ }
+ pc->error = 0;
+ if (floppy->failed_pc == pc)
+ floppy->failed_pc = NULL;
+ /* Command finished - Call the callback function */
+ pc->callback(drive);
+ return ide_stopped;
+ }
+
+ if (test_and_clear_bit(PC_DMA_IN_PROGRESS, &pc->flags)) {
+ printk(KERN_ERR "ide-floppy: The floppy wants to issue "
+ "more interrupts in DMA mode\n");
+ (void)__ide_dma_off(drive);
+ return ide_do_reset(drive);
+ }
+
+ /* Get the number of bytes to transfer */
+ bcount.b.high = HWIF(drive)->INB(IDE_BCOUNTH_REG);
+ bcount.b.low = HWIF(drive)->INB(IDE_BCOUNTL_REG);
+ /* on this interrupt */
+ ireason.all = HWIF(drive)->INB(IDE_IREASON_REG);
+
+ if (ireason.b.cod) {
+ printk(KERN_ERR "ide-floppy: CoD != 0 in idefloppy_pc_intr\n");
+ return ide_do_reset(drive);
+ }
+ if (ireason.b.io == test_bit(PC_WRITING, &pc->flags)) {
+ /* Hopefully, we will never get here */
+ printk(KERN_ERR "ide-floppy: We wanted to %s, ",
+ ireason.b.io ? "Write":"Read");
+ printk(KERN_ERR "but the floppy wants us to %s !\n",
+ ireason.b.io ? "Read":"Write");
+ return ide_do_reset(drive);
+ }
+ if (!test_bit(PC_WRITING, &pc->flags)) {
+ /* Reading - Check that we have enough space */
+ temp = pc->actually_transferred + bcount.all;
+ if (temp > pc->request_transfer) {
+ if (temp > pc->buffer_size) {
+ printk(KERN_ERR "ide-floppy: The floppy wants "
+ "to send us more data than expected "
+ "- discarding data\n");
+ idefloppy_discard_data(drive,bcount.all);
+ if (HWGROUP(drive)->handler != NULL)
+ BUG();
+ ide_set_handler(drive,
+ &idefloppy_pc_intr,
+ IDEFLOPPY_WAIT_CMD,
+ NULL);
+ return ide_started;
+ }
+ debug_log(KERN_NOTICE "ide-floppy: The floppy wants to "
+ "send us more data than expected - "
+ "allowing transfer\n");
+ }
+ }
+ if (test_bit(PC_WRITING, &pc->flags)) {
+ if (pc->buffer != NULL)
+ /* Write the current buffer */
+ HWIF(drive)->atapi_output_bytes(drive,
+ pc->current_position,
+ bcount.all);
+ else
+ idefloppy_output_buffers(drive, pc, bcount.all);
+ } else {
+ if (pc->buffer != NULL)
+ /* Read the current buffer */
+ HWIF(drive)->atapi_input_bytes(drive,
+ pc->current_position,
+ bcount.all);
+ else
+ idefloppy_input_buffers(drive, pc, bcount.all);
+ }
+ /* Update the current position */
+ pc->actually_transferred += bcount.all;
+ pc->current_position += bcount.all;
+
+ if (HWGROUP(drive)->handler != NULL)
+ BUG();
+ ide_set_handler(drive, &idefloppy_pc_intr, IDEFLOPPY_WAIT_CMD, NULL); /* And set the interrupt handler again */
+ return ide_started;
+}
+
+/*
+ * This is the original routine that did the packet transfer.
+ * It fails at high speeds on the Iomega ZIP drive, so there's a slower version
+ * for that drive below. The algorithm is chosen based on drive type
+ */
+static ide_startstop_t idefloppy_transfer_pc (ide_drive_t *drive)
+{
+ ide_startstop_t startstop;
+ idefloppy_floppy_t *floppy = drive->driver_data;
+ atapi_ireason_t ireason;
+
+ if (ide_wait_stat(&startstop, drive, DRQ_STAT, BUSY_STAT, WAIT_READY)) {
+ printk(KERN_ERR "ide-floppy: Strange, packet command "
+ "initiated yet DRQ isn't asserted\n");
+ return startstop;
+ }
+ ireason.all = HWIF(drive)->INB(IDE_IREASON_REG);
+ if (!ireason.b.cod || ireason.b.io) {
+ printk(KERN_ERR "ide-floppy: (IO,CoD) != (0,1) while "
+ "issuing a packet command\n");
+ return ide_do_reset(drive);
+ }
+ if (HWGROUP(drive)->handler != NULL)
+ BUG();
+ /* Set the interrupt routine */
+ ide_set_handler(drive, &idefloppy_pc_intr, IDEFLOPPY_WAIT_CMD, NULL);
+ /* Send the actual packet */
+ HWIF(drive)->atapi_output_bytes(drive, floppy->pc->c, 12);
+ return ide_started;
+}
+
+
+/*
+ * What we have here is a classic case of a top half / bottom half
+ * interrupt service routine. In interrupt mode, the device sends
+ * an interrupt to signal it's ready to receive a packet. However,
+ * we need to delay about 2-3 ticks before issuing the packet or we
+ * gets in trouble.
+ *
+ * So, follow carefully. transfer_pc1 is called as an interrupt (or
+ * directly). In either case, when the device says it's ready for a
+ * packet, we schedule the packet transfer to occur about 2-3 ticks
+ * later in transfer_pc2.
+ */
+static int idefloppy_transfer_pc2 (ide_drive_t *drive)
+{
+ idefloppy_floppy_t *floppy = drive->driver_data;
+
+ /* Send the actual packet */
+ HWIF(drive)->atapi_output_bytes(drive, floppy->pc->c, 12);
+ /* Timeout for the packet command */
+ return IDEFLOPPY_WAIT_CMD;
+}
+
+static ide_startstop_t idefloppy_transfer_pc1 (ide_drive_t *drive)
+{
+ idefloppy_floppy_t *floppy = drive->driver_data;
+ ide_startstop_t startstop;
+ atapi_ireason_t ireason;
+
+ if (ide_wait_stat(&startstop, drive, DRQ_STAT, BUSY_STAT, WAIT_READY)) {
+ printk(KERN_ERR "ide-floppy: Strange, packet command "
+ "initiated yet DRQ isn't asserted\n");
+ return startstop;
+ }
+ ireason.all = HWIF(drive)->INB(IDE_IREASON_REG);
+ if (!ireason.b.cod || ireason.b.io) {
+ printk(KERN_ERR "ide-floppy: (IO,CoD) != (0,1) "
+ "while issuing a packet command\n");
+ return ide_do_reset(drive);
+ }
+ /*
+ * The following delay solves a problem with ATAPI Zip 100 drives
+ * where the Busy flag was apparently being deasserted before the
+ * unit was ready to receive data. This was happening on a
+ * 1200 MHz Athlon system. 10/26/01 25msec is too short,
+ * 40 and 50msec work well. idefloppy_pc_intr will not be actually
+ * used until after the packet is moved in about 50 msec.
+ */
+ if (HWGROUP(drive)->handler != NULL)
+ BUG();
+ ide_set_handler(drive,
+ &idefloppy_pc_intr, /* service routine for packet command */
+ floppy->ticks, /* wait this long before "failing" */
+ &idefloppy_transfer_pc2); /* fail == transfer_pc2 */
+ return ide_started;
+}
+
+/**
+ * idefloppy_should_report_error()
+ *
+ * Supresses error messages resulting from Medium not present
+ */
+static inline int idefloppy_should_report_error(idefloppy_floppy_t *floppy)
+{
+ if (floppy->sense_key == 0x02 &&
+ floppy->asc == 0x3a &&
+ floppy->ascq == 0x00)
+ return 0;
+ return 1;
+}
+
+/*
+ * Issue a packet command
+ */
+static ide_startstop_t idefloppy_issue_pc (ide_drive_t *drive, idefloppy_pc_t *pc)
+{
+ idefloppy_floppy_t *floppy = drive->driver_data;
+ ide_hwif_t *hwif = drive->hwif;
+ atapi_feature_t feature;
+ atapi_bcount_t bcount;
+ ide_handler_t *pkt_xfer_routine;
+
+#if IDEFLOPPY_DEBUG_BUGS
+ if (floppy->pc->c[0] == IDEFLOPPY_REQUEST_SENSE_CMD &&
+ pc->c[0] == IDEFLOPPY_REQUEST_SENSE_CMD) {
+ printk(KERN_ERR "ide-floppy: possible ide-floppy.c bug - "
+ "Two request sense in serial were issued\n");
+ }
+#endif /* IDEFLOPPY_DEBUG_BUGS */
+
+ if (floppy->failed_pc == NULL &&
+ pc->c[0] != IDEFLOPPY_REQUEST_SENSE_CMD)
+ floppy->failed_pc = pc;
+ /* Set the current packet command */
+ floppy->pc = pc;
+
+ if (pc->retries > IDEFLOPPY_MAX_PC_RETRIES ||
+ test_bit(PC_ABORT, &pc->flags)) {
+ /*
+ * We will "abort" retrying a packet command in case
+ * a legitimate error code was received.
+ */
+ if (!test_bit(PC_ABORT, &pc->flags)) {
+ if (!test_bit(PC_SUPPRESS_ERROR, &pc->flags)) {
+ if (idefloppy_should_report_error(floppy))
+ printk(KERN_ERR "ide-floppy: %s: I/O error, "
+ "pc = %2x, key = %2x, "
+ "asc = %2x, ascq = %2x\n",
+ drive->name, pc->c[0],
+ floppy->sense_key,
+ floppy->asc, floppy->ascq);
+ }
+ /* Giving up */
+ pc->error = IDEFLOPPY_ERROR_GENERAL;
+ }
+ floppy->failed_pc = NULL;
+ pc->callback(drive);
+ return ide_stopped;
+ }
+
+ debug_log(KERN_INFO "Retry number - %d\n",pc->retries);
+
+ pc->retries++;
+ /* We haven't transferred any data yet */
+ pc->actually_transferred = 0;
+ pc->current_position = pc->buffer;
+ bcount.all = min(pc->request_transfer, 63 * 1024);
+
+ if (test_and_clear_bit(PC_DMA_ERROR, &pc->flags)) {
+ (void)__ide_dma_off(drive);
+ }
+ feature.all = 0;
+
+ if (test_bit(PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma)
+ feature.b.dma = !hwif->dma_setup(drive);
+
+ if (IDE_CONTROL_REG)
+ HWIF(drive)->OUTB(drive->ctl, IDE_CONTROL_REG);
+ /* Use PIO/DMA */
+ HWIF(drive)->OUTB(feature.all, IDE_FEATURE_REG);
+ HWIF(drive)->OUTB(bcount.b.high, IDE_BCOUNTH_REG);
+ HWIF(drive)->OUTB(bcount.b.low, IDE_BCOUNTL_REG);
+ HWIF(drive)->OUTB(drive->select.all, IDE_SELECT_REG);
+
+ if (feature.b.dma) { /* Begin DMA, if necessary */
+ set_bit(PC_DMA_IN_PROGRESS, &pc->flags);
+ hwif->dma_start(drive);
+ }
+
+ /* Can we transfer the packet when we get the interrupt or wait? */
+ if (test_bit(IDEFLOPPY_ZIP_DRIVE, &floppy->flags)) {
+ /* wait */
+ pkt_xfer_routine = &idefloppy_transfer_pc1;
+ } else {
+ /* immediate */
+ pkt_xfer_routine = &idefloppy_transfer_pc;
+ }
+
+ if (test_bit (IDEFLOPPY_DRQ_INTERRUPT, &floppy->flags)) {
+ /* Issue the packet command */
+ ide_execute_command(drive, WIN_PACKETCMD,
+ pkt_xfer_routine,
+ IDEFLOPPY_WAIT_CMD,
+ NULL);
+ return ide_started;
+ } else {
+ /* Issue the packet command */
+ HWIF(drive)->OUTB(WIN_PACKETCMD, IDE_COMMAND_REG);
+ return (*pkt_xfer_routine) (drive);
+ }
+}
+
+static void idefloppy_rw_callback (ide_drive_t *drive)
+{
+ debug_log(KERN_INFO "ide-floppy: Reached idefloppy_rw_callback\n");
+
+ idefloppy_do_end_request(drive, 1, 0);
+ return;
+}
+
+static void idefloppy_create_prevent_cmd (idefloppy_pc_t *pc, int prevent)
+{
+ debug_log(KERN_INFO "ide-floppy: creating prevent removal command, "
+ "prevent = %d\n", prevent);
+
+ idefloppy_init_pc(pc);
+ pc->c[0] = IDEFLOPPY_PREVENT_REMOVAL_CMD;
+ pc->c[4] = prevent;
+}
+
+static void idefloppy_create_read_capacity_cmd (idefloppy_pc_t *pc)
+{
+ idefloppy_init_pc(pc);
+ pc->c[0] = IDEFLOPPY_READ_CAPACITY_CMD;
+ pc->c[7] = 255;
+ pc->c[8] = 255;
+ pc->request_transfer = 255;
+}
+
+static void idefloppy_create_format_unit_cmd (idefloppy_pc_t *pc, int b, int l,
+ int flags)
+{
+ idefloppy_init_pc(pc);
+ pc->c[0] = IDEFLOPPY_FORMAT_UNIT_CMD;
+ pc->c[1] = 0x17;
+
+ memset(pc->buffer, 0, 12);
+ pc->buffer[1] = 0xA2;
+ /* Default format list header, u8 1: FOV/DCRT/IMM bits set */
+
+ if (flags & 1) /* Verify bit on... */
+ pc->buffer[1] ^= 0x20; /* ... turn off DCRT bit */
+ pc->buffer[3] = 8;
+
+ put_unaligned(htonl(b), (unsigned int *)(&pc->buffer[4]));
+ put_unaligned(htonl(l), (unsigned int *)(&pc->buffer[8]));
+ pc->buffer_size=12;
+ set_bit(PC_WRITING, &pc->flags);
+}
+
+/*
+ * A mode sense command is used to "sense" floppy parameters.
+ */
+static void idefloppy_create_mode_sense_cmd (idefloppy_pc_t *pc, u8 page_code, u8 type)
+{
+ u16 length = sizeof(idefloppy_mode_parameter_header_t);
+
+ idefloppy_init_pc(pc);
+ pc->c[0] = IDEFLOPPY_MODE_SENSE_CMD;
+ pc->c[1] = 0;
+ pc->c[2] = page_code + (type << 6);
+
+ switch (page_code) {
+ case IDEFLOPPY_CAPABILITIES_PAGE:
+ length += 12;
+ break;
+ case IDEFLOPPY_FLEXIBLE_DISK_PAGE:
+ length += 32;
+ break;
+ default:
+ printk(KERN_ERR "ide-floppy: unsupported page code "
+ "in create_mode_sense_cmd\n");
+ }
+ put_unaligned(htons(length), (u16 *) &pc->c[7]);
+ pc->request_transfer = length;
+}
+
+static void idefloppy_create_start_stop_cmd (idefloppy_pc_t *pc, int start)
+{
+ idefloppy_init_pc(pc);
+ pc->c[0] = IDEFLOPPY_START_STOP_CMD;
+ pc->c[4] = start;
+}
+
+static void idefloppy_create_test_unit_ready_cmd(idefloppy_pc_t *pc)
+{
+ idefloppy_init_pc(pc);
+ pc->c[0] = IDEFLOPPY_TEST_UNIT_READY_CMD;
+}
+
+static void idefloppy_create_rw_cmd (idefloppy_floppy_t *floppy, idefloppy_pc_t *pc, struct request *rq, unsigned long sector)
+{
+ int block = sector / floppy->bs_factor;
+ int blocks = rq->nr_sectors / floppy->bs_factor;
+ int cmd = rq_data_dir(rq);
+
+ debug_log("create_rw1%d_cmd: block == %d, blocks == %d\n",
+ 2 * test_bit (IDEFLOPPY_USE_READ12, &floppy->flags),
+ block, blocks);
+
+ idefloppy_init_pc(pc);
+ if (test_bit(IDEFLOPPY_USE_READ12, &floppy->flags)) {
+ pc->c[0] = cmd == READ ? IDEFLOPPY_READ12_CMD : IDEFLOPPY_WRITE12_CMD;
+ put_unaligned(htonl(blocks), (unsigned int *) &pc->c[6]);
+ } else {
+ pc->c[0] = cmd == READ ? IDEFLOPPY_READ10_CMD : IDEFLOPPY_WRITE10_CMD;
+ put_unaligned(htons(blocks), (unsigned short *) &pc->c[7]);
+ }
+ put_unaligned(htonl(block), (unsigned int *) &pc->c[2]);
+ pc->callback = &idefloppy_rw_callback;
+ pc->rq = rq;
+ pc->b_count = cmd == READ ? 0 : rq->bio->bi_size;
+ if (rq->flags & REQ_RW)
+ set_bit(PC_WRITING, &pc->flags);
+ pc->buffer = NULL;
+ pc->request_transfer = pc->buffer_size = blocks * floppy->block_size;
+ set_bit(PC_DMA_RECOMMENDED, &pc->flags);
+}
+
+static int
+idefloppy_blockpc_cmd(idefloppy_floppy_t *floppy, idefloppy_pc_t *pc, struct request *rq)
+{
+ /*
+ * just support eject for now, it would not be hard to make the
+ * REQ_BLOCK_PC support fully-featured
+ */
+ if (rq->cmd[0] != IDEFLOPPY_START_STOP_CMD)
+ return 1;
+
+ idefloppy_init_pc(pc);
+ memcpy(pc->c, rq->cmd, sizeof(pc->c));
+ return 0;
+}
+
+/*
+ * idefloppy_do_request is our request handling function.
+ */
+static ide_startstop_t idefloppy_do_request (ide_drive_t *drive, struct request *rq, sector_t block_s)
+{
+ idefloppy_floppy_t *floppy = drive->driver_data;
+ idefloppy_pc_t *pc;
+ unsigned long block = (unsigned long)block_s;
+
+ debug_log(KERN_INFO "rq_status: %d, dev: %s, flags: %lx, errors: %d\n",
+ rq->rq_status,
+ rq->rq_disk ? rq->rq_disk->disk_name ? "?",
+ rq->flags, rq->errors);
+ debug_log(KERN_INFO "sector: %ld, nr_sectors: %ld, "
+ "current_nr_sectors: %d\n", (long)rq->sector,
+ rq->nr_sectors, rq->current_nr_sectors);
+
+ if (rq->errors >= ERROR_MAX) {
+ if (floppy->failed_pc != NULL) {
+ if (idefloppy_should_report_error(floppy))
+ printk(KERN_ERR "ide-floppy: %s: I/O error, pc = %2x,"
+ " key = %2x, asc = %2x, ascq = %2x\n",
+ drive->name, floppy->failed_pc->c[0],
+ floppy->sense_key, floppy->asc, floppy->ascq);
+ }
+ else
+ printk(KERN_ERR "ide-floppy: %s: I/O error\n",
+ drive->name);
+ idefloppy_do_end_request(drive, 0, 0);
+ return ide_stopped;
+ }
+ if (rq->flags & REQ_CMD) {
+ if (((long)rq->sector % floppy->bs_factor) ||
+ (rq->nr_sectors % floppy->bs_factor)) {
+ printk("%s: unsupported r/w request size\n",
+ drive->name);
+ idefloppy_do_end_request(drive, 0, 0);
+ return ide_stopped;
+ }
+ pc = idefloppy_next_pc_storage(drive);
+ idefloppy_create_rw_cmd(floppy, pc, rq, block);
+ } else if (rq->flags & REQ_SPECIAL) {
+ pc = (idefloppy_pc_t *) rq->buffer;
+ } else if (rq->flags & REQ_BLOCK_PC) {
+ pc = idefloppy_next_pc_storage(drive);
+ if (idefloppy_blockpc_cmd(floppy, pc, rq)) {
+ idefloppy_do_end_request(drive, 0, 0);
+ return ide_stopped;
+ }
+ } else {
+ blk_dump_rq_flags(rq,
+ "ide-floppy: unsupported command in queue");
+ idefloppy_do_end_request(drive, 0, 0);
+ return ide_stopped;
+ }
+
+ pc->rq = rq;
+ return idefloppy_issue_pc(drive, pc);
+}
+
+/*
+ * idefloppy_queue_pc_tail adds a special packet command request to the
+ * tail of the request queue, and waits for it to be serviced.
+ */
+static int idefloppy_queue_pc_tail (ide_drive_t *drive,idefloppy_pc_t *pc)
+{
+ struct ide_floppy_obj *floppy = drive->driver_data;
+ struct request rq;
+
+ ide_init_drive_cmd (&rq);
+ rq.buffer = (char *) pc;
+ rq.flags = REQ_SPECIAL; // rq.cmd = IDEFLOPPY_PC_RQ;
+ rq.rq_disk = floppy->disk;
+
+ return ide_do_drive_cmd(drive, &rq, ide_wait);
+}
+
+/*
+ * Look at the flexible disk page parameters. We will ignore the CHS
+ * capacity parameters and use the LBA parameters instead.
+ */
+static int idefloppy_get_flexible_disk_page (ide_drive_t *drive)
+{
+ idefloppy_floppy_t *floppy = drive->driver_data;
+ idefloppy_pc_t pc;
+ idefloppy_mode_parameter_header_t *header;
+ idefloppy_flexible_disk_page_t *page;
+ int capacity, lba_capacity;
+
+ idefloppy_create_mode_sense_cmd(&pc, IDEFLOPPY_FLEXIBLE_DISK_PAGE, MODE_SENSE_CURRENT);
+ if (idefloppy_queue_pc_tail(drive,&pc)) {
+ printk(KERN_ERR "ide-floppy: Can't get flexible disk "
+ "page parameters\n");
+ return 1;
+ }
+ header = (idefloppy_mode_parameter_header_t *) pc.buffer;
+ floppy->wp = header->wp;
+ set_disk_ro(floppy->disk, floppy->wp);
+ page = (idefloppy_flexible_disk_page_t *) (header + 1);
+
+ page->transfer_rate = ntohs(page->transfer_rate);
+ page->sector_size = ntohs(page->sector_size);
+ page->cyls = ntohs(page->cyls);
+ page->rpm = ntohs(page->rpm);
+ capacity = page->cyls * page->heads * page->sectors * page->sector_size;
+ if (memcmp (page, &floppy->flexible_disk_page, sizeof (idefloppy_flexible_disk_page_t)))
+ printk(KERN_INFO "%s: %dkB, %d/%d/%d CHS, %d kBps, "
+ "%d sector size, %d rpm\n",
+ drive->name, capacity / 1024, page->cyls,
+ page->heads, page->sectors,
+ page->transfer_rate / 8, page->sector_size, page->rpm);
+
+ floppy->flexible_disk_page = *page;
+ drive->bios_cyl = page->cyls;
+ drive->bios_head = page->heads;
+ drive->bios_sect = page->sectors;
+ lba_capacity = floppy->blocks * floppy->block_size;
+ if (capacity < lba_capacity) {
+ printk(KERN_NOTICE "%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;
+ }
+ return 0;
+}
+
+static int idefloppy_get_capability_page(ide_drive_t *drive)
+{
+ idefloppy_floppy_t *floppy = drive->driver_data;
+ idefloppy_pc_t pc;
+ idefloppy_mode_parameter_header_t *header;
+ idefloppy_capabilities_page_t *page;
+
+ floppy->srfp = 0;
+ idefloppy_create_mode_sense_cmd(&pc, IDEFLOPPY_CAPABILITIES_PAGE,
+ MODE_SENSE_CURRENT);
+
+ set_bit(PC_SUPPRESS_ERROR, &pc.flags);
+ if (idefloppy_queue_pc_tail(drive,&pc)) {
+ return 1;
+ }
+
+ header = (idefloppy_mode_parameter_header_t *) pc.buffer;
+ page= (idefloppy_capabilities_page_t *)(header+1);
+ floppy->srfp = page->srfp;
+ return (0);
+}
+
+/*
+ * Determine if a media is present in the floppy drive, and if so,
+ * its LBA capacity.
+ */
+static int idefloppy_get_capacity (ide_drive_t *drive)
+{
+ idefloppy_floppy_t *floppy = drive->driver_data;
+ idefloppy_pc_t pc;
+ idefloppy_capacity_header_t *header;
+ idefloppy_capacity_descriptor_t *descriptor;
+ int i, descriptors, rc = 1, blocks, length;
+
+ drive->bios_cyl = 0;
+ drive->bios_head = drive->bios_sect = 0;
+ floppy->blocks = floppy->bs_factor = 0;
+ set_capacity(floppy->disk, 0);
+
+ idefloppy_create_read_capacity_cmd(&pc);
+ if (idefloppy_queue_pc_tail(drive, &pc)) {
+ printk(KERN_ERR "ide-floppy: Can't get floppy parameters\n");
+ return 1;
+ }
+ header = (idefloppy_capacity_header_t *) pc.buffer;
+ descriptors = header->length / sizeof(idefloppy_capacity_descriptor_t);
+ descriptor = (idefloppy_capacity_descriptor_t *) (header + 1);
+
+ for (i = 0; i < descriptors; i++, descriptor++) {
+ blocks = descriptor->blocks = ntohl(descriptor->blocks);
+ length = descriptor->length = ntohs(descriptor->length);
+
+ if (!i)
+ {
+ switch (descriptor->dc) {
+ /* Clik! drive returns this instead of CAPACITY_CURRENT */
+ case CAPACITY_UNFORMATTED:
+ if (!test_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags))
+ /*
+ * If it is not a clik drive, break out
+ * (maintains previous driver behaviour)
+ */
+ break;
+ case CAPACITY_CURRENT:
+ /* Normal Zip/LS-120 disks */
+ if (memcmp(descriptor, &floppy->capacity, sizeof (idefloppy_capacity_descriptor_t)))
+ printk(KERN_INFO "%s: %dkB, %d blocks, %d "
+ "sector size\n", drive->name,
+ blocks * length / 1024, blocks, length);
+ floppy->capacity = *descriptor;
+ if (!length || length % 512) {
+ printk(KERN_NOTICE "%s: %d bytes block size "
+ "not supported\n", drive->name, length);
+ } else {
+ floppy->blocks = blocks;
+ floppy->block_size = length;
+ if ((floppy->bs_factor = length / 512) != 1)
+ printk(KERN_NOTICE "%s: warning: non "
+ "512 bytes block size not "
+ "fully supported\n",
+ drive->name);
+ 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 "%s: No disk in drive\n", drive->name);
+ break;
+ case CAPACITY_INVALID:
+ printk(KERN_ERR "%s: Invalid capacity for disk "
+ "in drive\n", drive->name);
+ break;
+ }
+ }
+ if (!i) {
+ debug_log( "Descriptor 0 Code: %d\n",
+ descriptor->dc);
+ }
+ debug_log( "Descriptor %d: %dkB, %d blocks, %d "
+ "sector size\n", i, blocks * length / 1024, blocks,
+ length);
+ }
+
+ /* Clik! disk does not support get_flexible_disk_page */
+ if (!test_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags)) {
+ (void) idefloppy_get_flexible_disk_page(drive);
+ }
+
+ set_capacity(floppy->disk, floppy->blocks * floppy->bs_factor);
+ return rc;
+}
+
+/*
+** Obtain the list of formattable capacities.
+** Very similar to idefloppy_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 idefloppy_get_format_capacities(ide_drive_t *drive, int __user *arg)
+{
+ idefloppy_pc_t pc;
+ idefloppy_capacity_header_t *header;
+ idefloppy_capacity_descriptor_t *descriptor;
+ int i, descriptors, blocks, length;
+ int u_array_size;
+ int u_index;
+ int __user *argp;
+
+ if (get_user(u_array_size, arg))
+ return (-EFAULT);
+
+ if (u_array_size <= 0)
+ return (-EINVAL);
+
+ idefloppy_create_read_capacity_cmd(&pc);
+ if (idefloppy_queue_pc_tail(drive, &pc)) {
+ printk(KERN_ERR "ide-floppy: Can't get floppy parameters\n");
+ return (-EIO);
+ }
+ header = (idefloppy_capacity_header_t *) pc.buffer;
+ descriptors = header->length /
+ sizeof(idefloppy_capacity_descriptor_t);
+ descriptor = (idefloppy_capacity_descriptor_t *) (header + 1);
+
+ 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=0; i<descriptors; i++, descriptor++) {
+ if (u_index >= u_array_size)
+ break; /* User-supplied buffer too small */
+ if (i == 0)
+ continue; /* Skip the first descriptor */
+
+ blocks = ntohl(descriptor->blocks);
+ length = ntohs(descriptor->length);
+
+ 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);
+}
+
+/*
+** 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.
+*/
+
+static int idefloppy_begin_format(ide_drive_t *drive, int __user *arg)
+{
+ int blocks;
+ int length;
+ int flags;
+ idefloppy_pc_t pc;
+
+ if (get_user(blocks, arg) ||
+ get_user(length, arg+1) ||
+ get_user(flags, arg+2)) {
+ return (-EFAULT);
+ }
+
+ /* Get the SFRP bit */
+ (void) idefloppy_get_capability_page(drive);
+ idefloppy_create_format_unit_cmd(&pc, blocks, length, flags);
+ if (idefloppy_queue_pc_tail(drive, &pc)) {
+ return (-EIO);
+ }
+
+ return (0);
+}
+
+/*
+** Get ATAPI_FORMAT_UNIT progress indication.
+**
+** Userland gives a pointer to an int. The int is set to a progresss
+** 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 idefloppy_get_format_progress(ide_drive_t *drive, int __user *arg)
+{
+ idefloppy_floppy_t *floppy = drive->driver_data;
+ idefloppy_pc_t pc;
+ int progress_indication = 0x10000;
+
+ if (floppy->srfp) {
+ idefloppy_create_request_sense_cmd(&pc);
+ if (idefloppy_queue_pc_tail(drive, &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 {
+ atapi_status_t status;
+ unsigned long flags;
+
+ local_irq_save(flags);
+ status.all = HWIF(drive)->INB(IDE_STATUS_REG);
+ local_irq_restore(flags);
+
+ progress_indication = !status.b.dsc ? 0 : 0x10000;
+ }
+ if (put_user(progress_indication, arg))
+ return (-EFAULT);
+
+ return (0);
+}
+
+/*
+ * Return the current floppy capacity.
+ */
+static sector_t idefloppy_capacity (ide_drive_t *drive)
+{
+ idefloppy_floppy_t *floppy = drive->driver_data;
+ unsigned long capacity = floppy->blocks * floppy->bs_factor;
+
+ return capacity;
+}
+
+/*
+ * idefloppy_identify_device checks if we can support a drive,
+ * based on the ATAPI IDENTIFY command results.
+ */
+static int idefloppy_identify_device (ide_drive_t *drive,struct hd_driveid *id)
+{
+ struct idefloppy_id_gcw gcw;
+#if IDEFLOPPY_DEBUG_INFO
+ u16 mask,i;
+ char buffer[80];
+#endif /* IDEFLOPPY_DEBUG_INFO */
+
+ *((u16 *) &gcw) = id->config;
+
+#ifdef CONFIG_PPC
+ /* kludge for Apple PowerBook internal zip */
+ if ((gcw.device_type == 5) &&
+ !strstr(id->model, "CD-ROM") &&
+ strstr(id->model, "ZIP"))
+ gcw.device_type = 0;
+#endif
+
+#if IDEFLOPPY_DEBUG_INFO
+ printk(KERN_INFO "Dumping ATAPI Identify Device floppy parameters\n");
+ switch (gcw.protocol) {
+ case 0: case 1: sprintf(buffer, "ATA");break;
+ case 2: sprintf(buffer, "ATAPI");break;
+ case 3: sprintf(buffer, "Reserved (Unknown to ide-floppy)");break;
+ }
+ printk(KERN_INFO "Protocol Type: %s\n", buffer);
+ switch (gcw.device_type) {
+ case 0: sprintf(buffer, "Direct-access Device");break;
+ case 1: sprintf(buffer, "Streaming Tape Device");break;
+ case 2: case 3: case 4: sprintf (buffer, "Reserved");break;
+ case 5: sprintf(buffer, "CD-ROM Device");break;
+ case 6: sprintf(buffer, "Reserved");
+ case 7: sprintf(buffer, "Optical memory Device");break;
+ case 0x1f: sprintf(buffer, "Unknown or no Device type");break;
+ default: sprintf(buffer, "Reserved");
+ }
+ printk(KERN_INFO "Device Type: %x - %s\n", gcw.device_type, buffer);
+ printk(KERN_INFO "Removable: %s\n",gcw.removable ? "Yes":"No");
+ switch (gcw.drq_type) {
+ case 0: sprintf(buffer, "Microprocessor DRQ");break;
+ case 1: sprintf(buffer, "Interrupt DRQ");break;
+ case 2: sprintf(buffer, "Accelerated DRQ");break;
+ case 3: sprintf(buffer, "Reserved");break;
+ }
+ printk(KERN_INFO "Command Packet DRQ Type: %s\n", buffer);
+ switch (gcw.packet_size) {
+ case 0: sprintf(buffer, "12 bytes");break;
+ case 1: sprintf(buffer, "16 bytes");break;
+ default: sprintf(buffer, "Reserved");break;
+ }
+ printk(KERN_INFO "Command Packet Size: %s\n", buffer);
+ printk(KERN_INFO "Model: %.40s\n",id->model);
+ printk(KERN_INFO "Firmware Revision: %.8s\n",id->fw_rev);
+ printk(KERN_INFO "Serial Number: %.20s\n",id->serial_no);
+ printk(KERN_INFO "Write buffer size(?): %d bytes\n",id->buf_size*512);
+ printk(KERN_INFO "DMA: %s",id->capability & 0x01 ? "Yes\n":"No\n");
+ printk(KERN_INFO "LBA: %s",id->capability & 0x02 ? "Yes\n":"No\n");
+ printk(KERN_INFO "IORDY can be disabled: %s",id->capability & 0x04 ? "Yes\n":"No\n");
+ printk(KERN_INFO "IORDY supported: %s",id->capability & 0x08 ? "Yes\n":"Unknown\n");
+ printk(KERN_INFO "ATAPI overlap supported: %s",id->capability & 0x20 ? "Yes\n":"No\n");
+ printk(KERN_INFO "PIO Cycle Timing Category: %d\n",id->tPIO);
+ printk(KERN_INFO "DMA Cycle Timing Category: %d\n",id->tDMA);
+ printk(KERN_INFO "Single Word DMA supported modes:\n");
+ for (i=0,mask=1;i<8;i++,mask=mask << 1) {
+ if (id->dma_1word & mask)
+ printk(KERN_INFO " Mode %d%s\n", i,
+ (id->dma_1word & (mask << 8)) ? " (active)" : "");
+ }
+ printk(KERN_INFO "Multi Word DMA supported modes:\n");
+ for (i=0,mask=1;i<8;i++,mask=mask << 1) {
+ if (id->dma_mword & mask)
+ printk(KERN_INFO " Mode %d%s\n", i,
+ (id->dma_mword & (mask << 8)) ? " (active)" : "");
+ }
+ if (id->field_valid & 0x0002) {
+ printk(KERN_INFO "Enhanced PIO Modes: %s\n",
+ id->eide_pio_modes & 1 ? "Mode 3":"None");
+ if (id->eide_dma_min == 0)
+ sprintf(buffer, "Not supported");
+ else
+ sprintf(buffer, "%d ns",id->eide_dma_min);
+ printk(KERN_INFO "Minimum Multi-word DMA cycle per word: %s\n", buffer);
+ if (id->eide_dma_time == 0)
+ sprintf(buffer, "Not supported");
+ else
+ sprintf(buffer, "%d ns",id->eide_dma_time);
+ printk(KERN_INFO "Manufacturer\'s Recommended Multi-word cycle: %s\n", buffer);
+ if (id->eide_pio == 0)
+ sprintf(buffer, "Not supported");
+ else
+ sprintf(buffer, "%d ns",id->eide_pio);
+ printk(KERN_INFO "Minimum PIO cycle without IORDY: %s\n",
+ buffer);
+ if (id->eide_pio_iordy == 0)
+ sprintf(buffer, "Not supported");
+ else
+ sprintf(buffer, "%d ns",id->eide_pio_iordy);
+ printk(KERN_INFO "Minimum PIO cycle with IORDY: %s\n", buffer);
+ } else
+ printk(KERN_INFO "According to the device, fields 64-70 are not valid.\n");
+#endif /* IDEFLOPPY_DEBUG_INFO */
+
+ if (gcw.protocol != 2)
+ printk(KERN_ERR "ide-floppy: Protocol is not ATAPI\n");
+ else if (gcw.device_type != 0)
+ printk(KERN_ERR "ide-floppy: Device type is not set to floppy\n");
+ else if (!gcw.removable)
+ printk(KERN_ERR "ide-floppy: The removable flag is not set\n");
+ else if (gcw.drq_type == 3) {
+ printk(KERN_ERR "ide-floppy: Sorry, DRQ type %d not supported\n", gcw.drq_type);
+ } else if (gcw.packet_size != 0) {
+ printk(KERN_ERR "ide-floppy: Packet size is not 12 bytes long\n");
+ } else
+ return 1;
+ return 0;
+}
+
+static void idefloppy_add_settings(ide_drive_t *drive)
+{
+ idefloppy_floppy_t *floppy = drive->driver_data;
+
+/*
+ * drive setting name read/write ioctl ioctl data type min max mul_factor div_factor data pointer set function
+ */
+ ide_add_setting(drive, "bios_cyl", SETTING_RW, -1, -1, TYPE_INT, 0, 1023, 1, 1, &drive->bios_cyl, NULL);
+ ide_add_setting(drive, "bios_head", SETTING_RW, -1, -1, TYPE_BYTE, 0, 255, 1, 1, &drive->bios_head, NULL);
+ ide_add_setting(drive, "bios_sect", SETTING_RW, -1, -1, TYPE_BYTE, 0, 63, 1, 1, &drive->bios_sect, NULL);
+ ide_add_setting(drive, "ticks", SETTING_RW, -1, -1, TYPE_BYTE, 0, 255, 1, 1, &floppy->ticks, NULL);
+}
+
+/*
+ * Driver initialization.
+ */
+static void idefloppy_setup (ide_drive_t *drive, idefloppy_floppy_t *floppy)
+{
+ struct idefloppy_id_gcw gcw;
+
+ *((u16 *) &gcw) = drive->id->config;
+ floppy->pc = floppy->pc_stack;
+ if (gcw.drq_type == 1)
+ set_bit(IDEFLOPPY_DRQ_INTERRUPT, &floppy->flags);
+ /*
+ * 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(drive->id->model, "IOMEGA ZIP 100 ATAPI", 20)) {
+ set_bit(IDEFLOPPY_ZIP_DRIVE, &floppy->flags);
+ /* This value will be visible in the /proc/ide/hdx/settings */
+ floppy->ticks = IDEFLOPPY_TICKS_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(drive->id->model, "IOMEGA Clik!", 11) == 0) {
+ blk_queue_max_sectors(drive->queue, 64);
+ set_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags);
+ }
+
+
+ (void) idefloppy_get_capacity(drive);
+ idefloppy_add_settings(drive);
+}
+
+static int idefloppy_cleanup (ide_drive_t *drive)
+{
+ idefloppy_floppy_t *floppy = drive->driver_data;
+ struct gendisk *g = floppy->disk;
+
+ if (ide_unregister_subdriver(drive))
+ return 1;
+
+ del_gendisk(g);
+
+ ide_floppy_put(floppy);
+
+ return 0;
+}
+
+static void ide_floppy_release(struct kref *kref)
+{
+ struct ide_floppy_obj *floppy = to_ide_floppy(kref);
+ ide_drive_t *drive = floppy->drive;
+ struct gendisk *g = floppy->disk;
+
+ drive->driver_data = NULL;
+ g->private_data = NULL;
+ put_disk(g);
+ kfree(floppy);
+}
+
+#ifdef CONFIG_PROC_FS
+
+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)idefloppy_capacity(drive));
+ PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+}
+
+static ide_proc_entry_t idefloppy_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 }
+};
+
+#else
+
+#define idefloppy_proc NULL
+
+#endif /* CONFIG_PROC_FS */
+
+static int idefloppy_attach(ide_drive_t *drive);
+
+/*
+ * IDE subdriver functions, registered with ide.c
+ */
+static ide_driver_t idefloppy_driver = {
+ .owner = THIS_MODULE,
+ .name = "ide-floppy",
+ .version = IDEFLOPPY_VERSION,
+ .media = ide_floppy,
+ .busy = 0,
+ .supports_dsc_overlap = 0,
+ .cleanup = idefloppy_cleanup,
+ .do_request = idefloppy_do_request,
+ .end_request = idefloppy_do_end_request,
+ .error = __ide_error,
+ .abort = __ide_abort,
+ .proc = idefloppy_proc,
+ .attach = idefloppy_attach,
+ .drives = LIST_HEAD_INIT(idefloppy_driver.drives),
+};
+
+static int idefloppy_open(struct inode *inode, struct file *filp)
+{
+ struct gendisk *disk = inode->i_bdev->bd_disk;
+ struct ide_floppy_obj *floppy;
+ ide_drive_t *drive;
+ idefloppy_pc_t pc;
+ int ret = 0;
+
+ debug_log(KERN_INFO "Reached idefloppy_open\n");
+
+ if (!(floppy = ide_floppy_get(disk)))
+ return -ENXIO;
+
+ drive = floppy->drive;
+
+ drive->usage++;
+
+ if (drive->usage == 1) {
+ clear_bit(IDEFLOPPY_FORMAT_IN_PROGRESS, &floppy->flags);
+ /* Just in case */
+
+ idefloppy_create_test_unit_ready_cmd(&pc);
+ if (idefloppy_queue_pc_tail(drive, &pc)) {
+ idefloppy_create_start_stop_cmd(&pc, 1);
+ (void) idefloppy_queue_pc_tail(drive, &pc);
+ }
+
+ if (idefloppy_get_capacity (drive)
+ && (filp->f_flags & O_NDELAY) == 0
+ /*
+ ** 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
+ */
+ ) {
+ drive->usage--;
+ ret = -EIO;
+ goto out_put_floppy;
+ }
+
+ if (floppy->wp && (filp->f_mode & 2)) {
+ drive->usage--;
+ ret = -EROFS;
+ goto out_put_floppy;
+ }
+ set_bit(IDEFLOPPY_MEDIA_CHANGED, &floppy->flags);
+ /* IOMEGA Clik! drives do not support lock/unlock commands */
+ if (!test_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags)) {
+ idefloppy_create_prevent_cmd(&pc, 1);
+ (void) idefloppy_queue_pc_tail(drive, &pc);
+ }
+ check_disk_change(inode->i_bdev);
+ } else if (test_bit(IDEFLOPPY_FORMAT_IN_PROGRESS, &floppy->flags)) {
+ drive->usage--;
+ ret = -EBUSY;
+ goto out_put_floppy;
+ }
+ return 0;
+
+out_put_floppy:
+ ide_floppy_put(floppy);
+ return ret;
+}
+
+static int idefloppy_release(struct inode *inode, struct file *filp)
+{
+ struct gendisk *disk = inode->i_bdev->bd_disk;
+ struct ide_floppy_obj *floppy = ide_floppy_g(disk);
+ ide_drive_t *drive = floppy->drive;
+ idefloppy_pc_t pc;
+
+ debug_log(KERN_INFO "Reached idefloppy_release\n");
+
+ if (drive->usage == 1) {
+ /* IOMEGA Clik! drives do not support lock/unlock commands */
+ if (!test_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags)) {
+ idefloppy_create_prevent_cmd(&pc, 0);
+ (void) idefloppy_queue_pc_tail(drive, &pc);
+ }
+
+ clear_bit(IDEFLOPPY_FORMAT_IN_PROGRESS, &floppy->flags);
+ }
+ drive->usage--;
+
+ ide_floppy_put(floppy);
+
+ return 0;
+}
+
+static int idefloppy_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct block_device *bdev = inode->i_bdev;
+ struct ide_floppy_obj *floppy = ide_floppy_g(bdev->bd_disk);
+ ide_drive_t *drive = floppy->drive;
+ void __user *argp = (void __user *)arg;
+ int err = generic_ide_ioctl(drive, file, bdev, cmd, arg);
+ int prevent = (arg) ? 1 : 0;
+ idefloppy_pc_t pc;
+ if (err != -EINVAL)
+ return err;
+
+ switch (cmd) {
+ case CDROMEJECT:
+ prevent = 0;
+ /* fall through */
+ case CDROM_LOCKDOOR:
+ if (drive->usage > 1)
+ return -EBUSY;
+
+ /* The IOMEGA Clik! Drive doesn't support this command - no room for an eject mechanism */
+ if (!test_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags)) {
+ idefloppy_create_prevent_cmd(&pc, prevent);
+ (void) idefloppy_queue_pc_tail(drive, &pc);
+ }
+ if (cmd == CDROMEJECT) {
+ idefloppy_create_start_stop_cmd(&pc, 2);
+ (void) idefloppy_queue_pc_tail(drive, &pc);
+ }
+ return 0;
+ case IDEFLOPPY_IOCTL_FORMAT_SUPPORTED:
+ return 0;
+ case IDEFLOPPY_IOCTL_FORMAT_GET_CAPACITY:
+ return idefloppy_get_format_capacities(drive, argp);
+ case IDEFLOPPY_IOCTL_FORMAT_START:
+
+ if (!(file->f_mode & 2))
+ return -EPERM;
+
+ if (drive->usage > 1) {
+ /* Don't format if someone is using the disk */
+
+ clear_bit(IDEFLOPPY_FORMAT_IN_PROGRESS,
+ &floppy->flags);
+ return -EBUSY;
+ }
+
+ set_bit(IDEFLOPPY_FORMAT_IN_PROGRESS, &floppy->flags);
+
+ err = idefloppy_begin_format(drive, argp);
+ if (err)
+ clear_bit(IDEFLOPPY_FORMAT_IN_PROGRESS, &floppy->flags);
+ return err;
+ /*
+ ** Note, the bit will be cleared when the device is
+ ** closed. This is the cleanest way to handle the
+ ** situation where the drive does not support
+ ** format progress reporting.
+ */
+ case IDEFLOPPY_IOCTL_FORMAT_GET_PROGRESS:
+ return idefloppy_get_format_progress(drive, argp);
+ }
+ return -EINVAL;
+}
+
+static int idefloppy_media_changed(struct gendisk *disk)
+{
+ struct ide_floppy_obj *floppy = ide_floppy_g(disk);
+ ide_drive_t *drive = floppy->drive;
+
+ /* do not scan partitions twice if this is a removable device */
+ if (drive->attach) {
+ drive->attach = 0;
+ return 0;
+ }
+ return test_and_clear_bit(IDEFLOPPY_MEDIA_CHANGED, &floppy->flags);
+}
+
+static int idefloppy_revalidate_disk(struct gendisk *disk)
+{
+ struct ide_floppy_obj *floppy = ide_floppy_g(disk);
+ set_capacity(disk, idefloppy_capacity(floppy->drive));
+ return 0;
+}
+
+static struct block_device_operations idefloppy_ops = {
+ .owner = THIS_MODULE,
+ .open = idefloppy_open,
+ .release = idefloppy_release,
+ .ioctl = idefloppy_ioctl,
+ .media_changed = idefloppy_media_changed,
+ .revalidate_disk= idefloppy_revalidate_disk
+};
+
+static int idefloppy_attach (ide_drive_t *drive)
+{
+ idefloppy_floppy_t *floppy;
+ struct gendisk *g;
+
+ if (!strstr("ide-floppy", drive->driver_req))
+ goto failed;
+ if (!drive->present)
+ goto failed;
+ if (drive->media != ide_floppy)
+ goto failed;
+ if (!idefloppy_identify_device (drive, drive->id)) {
+ printk (KERN_ERR "ide-floppy: %s: not supported by this version of ide-floppy\n", drive->name);
+ goto failed;
+ }
+ if (drive->scsi) {
+ printk("ide-floppy: passing drive %s to ide-scsi emulation.\n", drive->name);
+ goto failed;
+ }
+ if ((floppy = (idefloppy_floppy_t *) kmalloc (sizeof (idefloppy_floppy_t), GFP_KERNEL)) == NULL) {
+ printk (KERN_ERR "ide-floppy: %s: Can't allocate a floppy structure\n", drive->name);
+ goto failed;
+ }
+
+ g = alloc_disk(1 << PARTN_BITS);
+ if (!g)
+ goto out_free_floppy;
+
+ ide_init_disk(g, drive);
+
+ if (ide_register_subdriver(drive, &idefloppy_driver)) {
+ printk (KERN_ERR "ide-floppy: %s: Failed to register the driver with ide.c\n", drive->name);
+ goto out_put_disk;
+ }
+
+ memset(floppy, 0, sizeof(*floppy));
+
+ kref_init(&floppy->kref);
+
+ floppy->drive = drive;
+ floppy->driver = &idefloppy_driver;
+ floppy->disk = g;
+
+ g->private_data = &floppy->driver;
+
+ drive->driver_data = floppy;
+
+ DRIVER(drive)->busy++;
+ idefloppy_setup (drive, floppy);
+ DRIVER(drive)->busy--;
+ g->minors = 1 << PARTN_BITS;
+ g->driverfs_dev = &drive->gendev;
+ strcpy(g->devfs_name, drive->devfs_name);
+ g->flags = drive->removable ? GENHD_FL_REMOVABLE : 0;
+ g->fops = &idefloppy_ops;
+ drive->attach = 1;
+ add_disk(g);
+ return 0;
+
+out_put_disk:
+ put_disk(g);
+out_free_floppy:
+ kfree(floppy);
+failed:
+ return 1;
+}
+
+MODULE_DESCRIPTION("ATAPI FLOPPY Driver");
+
+static void __exit idefloppy_exit (void)
+{
+ ide_unregister_driver(&idefloppy_driver);
+}
+
+/*
+ * idefloppy_init will register the driver for each floppy.
+ */
+static int idefloppy_init (void)
+{
+ printk("ide-floppy driver " IDEFLOPPY_VERSION "\n");
+ ide_register_driver(&idefloppy_driver);
+ return 0;
+}
+
+module_init(idefloppy_init);
+module_exit(idefloppy_exit);
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/ide-generic.c b/drivers/ide/ide-generic.c
new file mode 100644
index 000000000000..99fd56151131
--- /dev/null
+++ b/drivers/ide/ide-generic.c
@@ -0,0 +1,32 @@
+/*
+ * generic/default IDE host driver
+ *
+ * Copyright (C) 2004 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/ide.h>
+
+static int __init ide_generic_init(void)
+{
+ if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET])
+ ide_get_lock(NULL, NULL); /* for atari only */
+
+ (void)ideprobe_init();
+
+ if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET])
+ ide_release_lock(); /* for atari only */
+
+ create_proc_ide_interfaces();
+
+ return 0;
+}
+
+module_init(ide_generic_init);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c
new file mode 100644
index 000000000000..248e3cc8b352
--- /dev/null
+++ b/drivers/ide/ide-io.c
@@ -0,0 +1,1681 @@
+/*
+ * 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/config.h>
+#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/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 <asm/byteorder.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/bitops.h>
+
+int __ide_end_request(ide_drive_t *drive, struct request *rq, int uptodate,
+ int nr_sectors)
+{
+ int ret = 1;
+
+ BUG_ON(!(rq->flags & REQ_STARTED));
+
+ /*
+ * if failfast is set on a request, override number of sectors and
+ * complete the whole request right now
+ */
+ if (blk_noretry_request(rq) && end_io_error(uptodate))
+ nr_sectors = rq->hard_nr_sectors;
+
+ if (!blk_fs_request(rq) && end_io_error(uptodate) && !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->state == DMA_PIO_RETRY && drive->retry_pio <= 3) {
+ drive->state = 0;
+ HWGROUP(drive)->hwif->ide_dma_on(drive);
+ }
+
+ if (!end_that_request_first(rq, uptodate, nr_sectors)) {
+ add_disk_randomness(rq->rq_disk);
+
+ if (blk_rq_tagged(rq))
+ blk_queue_end_tag(drive->queue, rq);
+
+ blkdev_dequeue_request(rq);
+ HWGROUP(drive)->rq = NULL;
+ end_that_request_last(rq);
+ ret = 0;
+ }
+ return ret;
+}
+EXPORT_SYMBOL(__ide_end_request);
+
+/**
+ * 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)
+{
+ struct request *rq;
+ unsigned long flags;
+ int ret = 1;
+
+ spin_lock_irqsave(&ide_lock, flags);
+ rq = HWGROUP(drive)->rq;
+
+ if (!nr_sectors)
+ nr_sectors = rq->hard_cur_sectors;
+
+ if (blk_complete_barrier_rq_locked(drive->queue, rq, nr_sectors))
+ ret = rq->nr_sectors != 0;
+ else
+ ret = __ide_end_request(drive, rq, uptodate, nr_sectors);
+
+ spin_unlock_irqrestore(&ide_lock, flags);
+ return ret;
+}
+EXPORT_SYMBOL(ide_end_request);
+
+/*
+ * Power Management state machine. This one is rather trivial for now,
+ * we should probably add more, like switching back to PIO on suspend
+ * to help some BIOSes, re-do the door locking on resume, etc...
+ */
+
+enum {
+ ide_pm_flush_cache = ide_pm_state_start_suspend,
+ idedisk_pm_standby,
+
+ idedisk_pm_idle = ide_pm_state_start_resume,
+ ide_pm_restore_dma,
+};
+
+static void ide_complete_power_step(ide_drive_t *drive, struct request *rq, u8 stat, u8 error)
+{
+ if (drive->media != ide_disk)
+ return;
+
+ switch (rq->pm->pm_step) {
+ case ide_pm_flush_cache: /* Suspend step 1 (flush cache) complete */
+ if (rq->pm->pm_state == 4)
+ rq->pm->pm_step = ide_pm_state_completed;
+ else
+ rq->pm->pm_step = idedisk_pm_standby;
+ break;
+ case idedisk_pm_standby: /* Suspend step 2 (standby) complete */
+ rq->pm->pm_step = ide_pm_state_completed;
+ break;
+ case idedisk_pm_idle: /* Resume step 1 (idle) complete */
+ rq->pm->pm_step = ide_pm_restore_dma;
+ break;
+ }
+}
+
+static ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request *rq)
+{
+ ide_task_t *args = rq->special;
+
+ memset(args, 0, sizeof(*args));
+
+ if (drive->media != ide_disk) {
+ /* skip idedisk_pm_idle for ATAPI devices */
+ if (rq->pm->pm_step == idedisk_pm_idle)
+ rq->pm->pm_step = ide_pm_restore_dma;
+ }
+
+ switch (rq->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 (!drive->wcache || !ide_id_has_flush_cache(drive->id)) {
+ ide_complete_power_step(drive, rq, 0, 0);
+ return ide_stopped;
+ }
+ if (ide_id_has_flush_cache_ext(drive->id))
+ args->tfRegister[IDE_COMMAND_OFFSET] = WIN_FLUSH_CACHE_EXT;
+ else
+ args->tfRegister[IDE_COMMAND_OFFSET] = WIN_FLUSH_CACHE;
+ args->command_type = IDE_DRIVE_TASK_NO_DATA;
+ args->handler = &task_no_data_intr;
+ return do_rw_taskfile(drive, args);
+
+ case idedisk_pm_standby: /* Suspend step 2 (standby) */
+ args->tfRegister[IDE_COMMAND_OFFSET] = WIN_STANDBYNOW1;
+ args->command_type = IDE_DRIVE_TASK_NO_DATA;
+ args->handler = &task_no_data_intr;
+ return do_rw_taskfile(drive, args);
+
+ case idedisk_pm_idle: /* Resume step 1 (idle) */
+ args->tfRegister[IDE_COMMAND_OFFSET] = WIN_IDLEIMMEDIATE;
+ args->command_type = IDE_DRIVE_TASK_NO_DATA;
+ args->handler = task_no_data_intr;
+ return do_rw_taskfile(drive, args);
+
+ case ide_pm_restore_dma: /* Resume step 2 (restore DMA) */
+ /*
+ * Right now, all we do is call hwif->ide_dma_check(drive),
+ * we could be smarter and check for current xfer_speed
+ * in struct drive etc...
+ */
+ if ((drive->id->capability & 1) == 0)
+ break;
+ if (drive->hwif->ide_dma_check == NULL)
+ break;
+ drive->hwif->ide_dma_check(drive);
+ break;
+ }
+ rq->pm->pm_step = ide_pm_state_completed;
+ return ide_stopped;
+}
+
+/**
+ * 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->blocked = 0;
+ blk_start_queue(drive->queue);
+ }
+ blkdev_dequeue_request(rq);
+ HWGROUP(drive)->rq = NULL;
+ end_that_request_last(rq);
+ spin_unlock_irqrestore(&ide_lock, flags);
+}
+
+/*
+ * FIXME: probably move this somewhere else, name is bad too :)
+ */
+u64 ide_get_error_location(ide_drive_t *drive, char *args)
+{
+ u32 high, low;
+ u8 hcyl, lcyl, sect;
+ u64 sector;
+
+ high = 0;
+ hcyl = args[5];
+ lcyl = args[4];
+ sect = args[3];
+
+ if (ide_id_has_flush_cache_ext(drive->id)) {
+ low = (hcyl << 16) | (lcyl << 8) | sect;
+ HWIF(drive)->OUTB(drive->ctl|0x80, IDE_CONTROL_REG);
+ high = ide_read_24(drive);
+ } else {
+ u8 cur = HWIF(drive)->INB(IDE_SELECT_REG);
+ if (cur & 0x40) {
+ high = cur & 0xf;
+ low = (hcyl << 16) | (lcyl << 8) | sect;
+ } else {
+ low = hcyl * drive->head * drive->sect;
+ low += lcyl * drive->sect;
+ low += sect - 1;
+ }
+ }
+
+ sector = ((u64) high << 24) | low;
+ return sector;
+}
+EXPORT_SYMBOL(ide_get_error_location);
+
+/**
+ * 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)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ unsigned long flags;
+ struct request *rq;
+
+ spin_lock_irqsave(&ide_lock, flags);
+ rq = HWGROUP(drive)->rq;
+ spin_unlock_irqrestore(&ide_lock, flags);
+
+ if (rq->flags & REQ_DRIVE_CMD) {
+ u8 *args = (u8 *) rq->buffer;
+ if (rq->errors == 0)
+ rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
+
+ if (args) {
+ args[0] = stat;
+ args[1] = err;
+ args[2] = hwif->INB(IDE_NSECTOR_REG);
+ }
+ } else if (rq->flags & REQ_DRIVE_TASK) {
+ u8 *args = (u8 *) rq->buffer;
+ if (rq->errors == 0)
+ rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
+
+ if (args) {
+ args[0] = stat;
+ args[1] = err;
+ args[2] = hwif->INB(IDE_NSECTOR_REG);
+ args[3] = hwif->INB(IDE_SECTOR_REG);
+ args[4] = hwif->INB(IDE_LCYL_REG);
+ args[5] = hwif->INB(IDE_HCYL_REG);
+ args[6] = hwif->INB(IDE_SELECT_REG);
+ }
+ } else if (rq->flags & REQ_DRIVE_TASKFILE) {
+ ide_task_t *args = (ide_task_t *) rq->special;
+ if (rq->errors == 0)
+ rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
+
+ if (args) {
+ if (args->tf_in_flags.b.data) {
+ u16 data = hwif->INW(IDE_DATA_REG);
+ args->tfRegister[IDE_DATA_OFFSET] = (data) & 0xFF;
+ args->hobRegister[IDE_DATA_OFFSET] = (data >> 8) & 0xFF;
+ }
+ args->tfRegister[IDE_ERROR_OFFSET] = err;
+ /* be sure we're looking at the low order bits */
+ hwif->OUTB(drive->ctl & ~0x80, IDE_CONTROL_REG);
+ args->tfRegister[IDE_NSECTOR_OFFSET] = hwif->INB(IDE_NSECTOR_REG);
+ args->tfRegister[IDE_SECTOR_OFFSET] = hwif->INB(IDE_SECTOR_REG);
+ args->tfRegister[IDE_LCYL_OFFSET] = hwif->INB(IDE_LCYL_REG);
+ args->tfRegister[IDE_HCYL_OFFSET] = hwif->INB(IDE_HCYL_REG);
+ args->tfRegister[IDE_SELECT_OFFSET] = hwif->INB(IDE_SELECT_REG);
+ args->tfRegister[IDE_STATUS_OFFSET] = stat;
+
+ if (drive->addressing == 1) {
+ hwif->OUTB(drive->ctl|0x80, IDE_CONTROL_REG);
+ args->hobRegister[IDE_FEATURE_OFFSET] = hwif->INB(IDE_FEATURE_REG);
+ args->hobRegister[IDE_NSECTOR_OFFSET] = hwif->INB(IDE_NSECTOR_REG);
+ args->hobRegister[IDE_SECTOR_OFFSET] = hwif->INB(IDE_SECTOR_REG);
+ args->hobRegister[IDE_LCYL_OFFSET] = hwif->INB(IDE_LCYL_REG);
+ args->hobRegister[IDE_HCYL_OFFSET] = hwif->INB(IDE_HCYL_REG);
+ }
+ }
+ } else if (blk_pm_request(rq)) {
+#ifdef DEBUG_PM
+ printk("%s: complete_power_step(step: %d, stat: %x, err: %x)\n",
+ drive->name, rq->pm->pm_step, stat, err);
+#endif
+ ide_complete_power_step(drive, rq, stat, err);
+ if (rq->pm->pm_step == ide_pm_state_completed)
+ ide_complete_pm_request(drive, rq);
+ return;
+ }
+
+ spin_lock_irqsave(&ide_lock, flags);
+ blkdev_dequeue_request(rq);
+ HWGROUP(drive)->rq = NULL;
+ rq->errors = err;
+ end_that_request_last(rq);
+ spin_unlock_irqrestore(&ide_lock, flags);
+}
+
+EXPORT_SYMBOL(ide_end_drive_cmd);
+
+/**
+ * try_to_flush_leftover_data - flush junk
+ * @drive: drive to flush
+ *
+ * try_to_flush_leftover_data() is invoked in response to a drive
+ * unexpectedly having its DRQ_STAT bit set. As an alternative to
+ * resetting the drive, this routine tries to clear the condition
+ * by read a sector's worth of data from the drive. Of course,
+ * this may not help if the drive is *waiting* for data from *us*.
+ */
+static void try_to_flush_leftover_data (ide_drive_t *drive)
+{
+ int i = (drive->mult_count ? drive->mult_count : 1) * SECTOR_WORDS;
+
+ if (drive->media != ide_disk)
+ return;
+ while (i > 0) {
+ u32 buffer[16];
+ u32 wcount = (i > 16) ? 16 : i;
+
+ i -= wcount;
+ HWIF(drive)->ata_input_data(drive, buffer, wcount);
+ }
+}
+
+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 & BUSY_STAT || ((stat & WRERR_STAT) && !drive->nowerr)) {
+ /* other bits are useless when BUSY */
+ rq->errors |= ERROR_RESET;
+ } else if (stat & ERR_STAT) {
+ /* err has different meaning on cdrom and tape */
+ if (err == ABRT_ERR) {
+ if (drive->select.b.lba &&
+ /* some newer drives don't support WIN_SPECIFY */
+ hwif->INB(IDE_COMMAND_REG) == WIN_SPECIFY)
+ return ide_stopped;
+ } else if ((err & BAD_CRC) == BAD_CRC) {
+ /* UDMA crc error, just retry the operation */
+ drive->crc_count++;
+ } else if (err & (BBD_ERR | ECC_ERR)) {
+ /* retries won't help these */
+ rq->errors = ERROR_MAX;
+ } else if (err & TRK0_ERR) {
+ /* help it find track zero */
+ rq->errors |= ERROR_RECAL;
+ }
+ }
+
+ if ((stat & DRQ_STAT) && rq_data_dir(rq) == READ)
+ try_to_flush_leftover_data(drive);
+
+ if (hwif->INB(IDE_STATUS_REG) & (BUSY_STAT|DRQ_STAT))
+ /* force an abort */
+ hwif->OUTB(WIN_IDLEIMMEDIATE, IDE_COMMAND_REG);
+
+ if (rq->errors >= ERROR_MAX || blk_noretry_request(rq))
+ ide_kill_rq(drive, rq);
+ else {
+ 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 & BUSY_STAT || ((stat & WRERR_STAT) && !drive->nowerr)) {
+ /* other bits are useless when BUSY */
+ rq->errors |= ERROR_RESET;
+ } else {
+ /* add decoding error stuff */
+ }
+
+ if (hwif->INB(IDE_STATUS_REG) & (BUSY_STAT|DRQ_STAT))
+ /* force an abort */
+ hwif->OUTB(WIN_IDLEIMMEDIATE, IDE_COMMAND_REG);
+
+ 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 (rq->flags & (REQ_DRIVE_CMD | REQ_DRIVE_TASK | REQ_DRIVE_TASKFILE)) {
+ 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);
+
+ide_startstop_t __ide_abort(ide_drive_t *drive, struct request *rq)
+{
+ if (drive->media != ide_disk)
+ rq->errors |= ERROR_RESET;
+
+ ide_kill_rq(drive, rq);
+
+ return ide_stopped;
+}
+
+EXPORT_SYMBOL_GPL(__ide_abort);
+
+/**
+ * ide_abort - abort pending IDE operatins
+ * @drive: drive the error occurred on
+ * @msg: message to report
+ *
+ * ide_abort kills and cleans up when we are about to do a
+ * host initiated reset on active commands. Longer term we
+ * want handlers to have sensible abort handling themselves
+ *
+ * This differs fundamentally from ide_error because in
+ * this case the command is doing just fine when we
+ * blow it away.
+ */
+
+ide_startstop_t ide_abort(ide_drive_t *drive, const char *msg)
+{
+ struct request *rq;
+
+ if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL)
+ return ide_stopped;
+
+ /* retry only "normal" I/O: */
+ if (rq->flags & (REQ_DRIVE_CMD | REQ_DRIVE_TASK | REQ_DRIVE_TASKFILE)) {
+ rq->errors = 1;
+ ide_end_drive_cmd(drive, BUSY_STAT, 0);
+ return ide_stopped;
+ }
+
+ if (rq->rq_disk) {
+ ide_driver_t *drv;
+
+ drv = *(ide_driver_t **)rq->rq_disk->private_data;
+ return drv->abort(drive, rq);
+ } else
+ return __ide_abort(drive, rq);
+}
+
+/**
+ * ide_cmd - issue a simple drive command
+ * @drive: drive the command is for
+ * @cmd: command byte
+ * @nsect: sector byte
+ * @handler: handler for the command completion
+ *
+ * Issue a simple drive command with interrupts.
+ * The drive must be selected beforehand.
+ */
+
+static void ide_cmd (ide_drive_t *drive, u8 cmd, u8 nsect,
+ ide_handler_t *handler)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ if (IDE_CONTROL_REG)
+ hwif->OUTB(drive->ctl,IDE_CONTROL_REG); /* clear nIEN */
+ SELECT_MASK(drive,0);
+ hwif->OUTB(nsect,IDE_NSECTOR_REG);
+ ide_execute_command(drive, cmd, handler, WAIT_CMD, NULL);
+}
+
+/**
+ * drive_cmd_intr - drive command completion interrupt
+ * @drive: drive the completion interrupt occurred on
+ *
+ * drive_cmd_intr() is invoked on completion of a special DRIVE_CMD.
+ * We do any necessary daya reading and then wait for the drive to
+ * go non busy. At that point we may read the error data and complete
+ * the request
+ */
+
+static ide_startstop_t drive_cmd_intr (ide_drive_t *drive)
+{
+ struct request *rq = HWGROUP(drive)->rq;
+ ide_hwif_t *hwif = HWIF(drive);
+ u8 *args = (u8 *) rq->buffer;
+ u8 stat = hwif->INB(IDE_STATUS_REG);
+ int retries = 10;
+
+ local_irq_enable();
+ if ((stat & DRQ_STAT) && args && args[3]) {
+ u8 io_32bit = drive->io_32bit;
+ drive->io_32bit = 0;
+ hwif->ata_input_data(drive, &args[4], args[3] * SECTOR_WORDS);
+ drive->io_32bit = io_32bit;
+ while (((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) && retries--)
+ udelay(100);
+ }
+
+ if (!OK_STAT(stat, READY_STAT, BAD_STAT))
+ return ide_error(drive, "drive_cmd", stat);
+ /* calls ide_end_drive_cmd */
+ ide_end_drive_cmd(drive, stat, hwif->INB(IDE_ERROR_REG));
+ return ide_stopped;
+}
+
+static void ide_init_specify_cmd(ide_drive_t *drive, ide_task_t *task)
+{
+ task->tfRegister[IDE_NSECTOR_OFFSET] = drive->sect;
+ task->tfRegister[IDE_SECTOR_OFFSET] = drive->sect;
+ task->tfRegister[IDE_LCYL_OFFSET] = drive->cyl;
+ task->tfRegister[IDE_HCYL_OFFSET] = drive->cyl>>8;
+ task->tfRegister[IDE_SELECT_OFFSET] = ((drive->head-1)|drive->select.all)&0xBF;
+ task->tfRegister[IDE_COMMAND_OFFSET] = WIN_SPECIFY;
+
+ task->handler = &set_geometry_intr;
+}
+
+static void ide_init_restore_cmd(ide_drive_t *drive, ide_task_t *task)
+{
+ task->tfRegister[IDE_NSECTOR_OFFSET] = drive->sect;
+ task->tfRegister[IDE_COMMAND_OFFSET] = WIN_RESTORE;
+
+ task->handler = &recal_intr;
+}
+
+static void ide_init_setmult_cmd(ide_drive_t *drive, ide_task_t *task)
+{
+ task->tfRegister[IDE_NSECTOR_OFFSET] = drive->mult_req;
+ task->tfRegister[IDE_COMMAND_OFFSET] = WIN_SETMULT;
+
+ task->handler = &set_multmode_intr;
+}
+
+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.command_type = IDE_DRIVE_TASK_NO_DATA;
+
+ if (s->b.set_geometry) {
+ s->b.set_geometry = 0;
+ ide_init_specify_cmd(drive, &args);
+ } else if (s->b.recalibrate) {
+ s->b.recalibrate = 0;
+ ide_init_restore_cmd(drive, &args);
+ } else if (s->b.set_multmode) {
+ s->b.set_multmode = 0;
+ if (drive->mult_req > drive->id->max_multsect)
+ drive->mult_req = drive->id->max_multsect;
+ ide_init_setmult_cmd(drive, &args);
+ } 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;
+ }
+
+ 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 WIN_SPECIFY, WIN_RESTORE, and WIN_SETMULT
+ * 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 (s->b.set_tune) {
+ s->b.set_tune = 0;
+ if (HWIF(drive)->tuneproc != NULL)
+ HWIF(drive)->tuneproc(drive, drive->tune_req);
+ return ide_stopped;
+ } else {
+ 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->flags & REQ_DRIVE_TASKFILE) == 0) {
+ hwif->sg_nents = blk_rq_map_sg(drive->queue, rq, sg);
+ } else {
+ sg_init_one(sg, rq->buffer, rq->nr_sectors * SECTOR_SIZE);
+ hwif->sg_nents = 1;
+ }
+}
+
+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 = hwif->cursg_ofs = 0;
+}
+
+EXPORT_SYMBOL_GPL(ide_init_sg_cmd);
+
+/**
+ * execute_drive_command - issue special drive command
+ * @drive: the drive to issue th 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);
+ if (rq->flags & REQ_DRIVE_TASKFILE) {
+ ide_task_t *args = rq->special;
+
+ if (!args)
+ goto done;
+
+ hwif->data_phase = args->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;
+ }
+
+ if (args->tf_out_flags.all != 0)
+ return flagged_taskfile(drive, args);
+ return do_rw_taskfile(drive, args);
+ } else if (rq->flags & REQ_DRIVE_TASK) {
+ u8 *args = rq->buffer;
+ u8 sel;
+
+ if (!args)
+ goto done;
+#ifdef DEBUG
+ printk("%s: DRIVE_TASK_CMD ", drive->name);
+ printk("cmd=0x%02x ", args[0]);
+ printk("fr=0x%02x ", args[1]);
+ printk("ns=0x%02x ", args[2]);
+ printk("sc=0x%02x ", args[3]);
+ printk("lcyl=0x%02x ", args[4]);
+ printk("hcyl=0x%02x ", args[5]);
+ printk("sel=0x%02x\n", args[6]);
+#endif
+ hwif->OUTB(args[1], IDE_FEATURE_REG);
+ hwif->OUTB(args[3], IDE_SECTOR_REG);
+ hwif->OUTB(args[4], IDE_LCYL_REG);
+ hwif->OUTB(args[5], IDE_HCYL_REG);
+ sel = (args[6] & ~0x10);
+ if (drive->select.b.unit)
+ sel |= 0x10;
+ hwif->OUTB(sel, IDE_SELECT_REG);
+ ide_cmd(drive, args[0], args[2], &drive_cmd_intr);
+ return ide_started;
+ } else if (rq->flags & REQ_DRIVE_CMD) {
+ u8 *args = rq->buffer;
+
+ if (!args)
+ goto done;
+#ifdef DEBUG
+ printk("%s: DRIVE_CMD ", drive->name);
+ printk("cmd=0x%02x ", args[0]);
+ printk("sc=0x%02x ", args[1]);
+ printk("fr=0x%02x ", args[2]);
+ printk("xx=0x%02x\n", args[3]);
+#endif
+ if (args[0] == WIN_SMART) {
+ hwif->OUTB(0x4f, IDE_LCYL_REG);
+ hwif->OUTB(0xc2, IDE_HCYL_REG);
+ hwif->OUTB(args[2],IDE_FEATURE_REG);
+ hwif->OUTB(args[1],IDE_SECTOR_REG);
+ ide_cmd(drive, args[0], args[3], &drive_cmd_intr);
+ return ide_started;
+ }
+ hwif->OUTB(args[2],IDE_FEATURE_REG);
+ ide_cmd(drive, args[0], args[1], &drive_cmd_intr);
+ return ide_started;
+ }
+
+done:
+ /*
+ * 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->INB(IDE_STATUS_REG),
+ hwif->INB(IDE_ERROR_REG));
+ return ide_stopped;
+}
+
+/**
+ * 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. It also does
+ * the final remapping for weird stuff like EZDrive. Once
+ * device mapper can work sector level the EZDrive stuff can go away
+ *
+ * FIXME: this function needs a rename
+ */
+
+static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq)
+{
+ ide_startstop_t startstop;
+ sector_t block;
+
+ BUG_ON(!(rq->flags & REQ_STARTED));
+
+#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)) {
+ goto kill_rq;
+ }
+
+ block = rq->sector;
+ if (blk_fs_request(rq) &&
+ (drive->media == ide_disk || drive->media == ide_floppy)) {
+ block += drive->sect0;
+ }
+ /* Yecch - this will shift the entire interval,
+ possibly killing some innocent following sector */
+ if (block == 0 && drive->remap_0_to_1 == 1)
+ block = 1; /* redirect MBR access to EZ-Drive partn table */
+
+ if (blk_pm_suspend_request(rq) &&
+ rq->pm->pm_step == ide_pm_state_start_suspend)
+ /* Mark drive blocked when starting the suspend sequence. */
+ drive->blocked = 1;
+ else if (blk_pm_resume_request(rq) &&
+ rq->pm->pm_step == ide_pm_state_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.
+ */
+ int rc;
+#ifdef DEBUG_PM
+ printk("%s: Wakeup request inited, waiting for !BSY...\n", drive->name);
+#endif
+ rc = ide_wait_not_busy(HWIF(drive), 35000);
+ if (rc)
+ printk(KERN_WARNING "%s: bus not ready on wakeup\n", drive->name);
+ SELECT_DRIVE(drive);
+ HWIF(drive)->OUTB(8, HWIF(drive)->io_ports[IDE_CONTROL_OFFSET]);
+ rc = ide_wait_not_busy(HWIF(drive), 10000);
+ if (rc)
+ printk(KERN_WARNING "%s: drive not ready on wakeup\n", drive->name);
+ }
+
+ SELECT_DRIVE(drive);
+ if (ide_wait_stat(&startstop, drive, drive->ready_stat, BUSY_STAT|DRQ_STAT, WAIT_READY)) {
+ printk(KERN_ERR "%s: drive not ready for command\n", drive->name);
+ return startstop;
+ }
+ if (!drive->special.all) {
+ ide_driver_t *drv;
+
+ if (rq->flags & (REQ_DRIVE_CMD | REQ_DRIVE_TASK))
+ return execute_drive_cmd(drive, rq);
+ else if (rq->flags & REQ_DRIVE_TASKFILE)
+ return execute_drive_cmd(drive, rq);
+ else if (blk_pm_request(rq)) {
+#ifdef DEBUG_PM
+ printk("%s: start_power_step(step: %d)\n",
+ drive->name, rq->pm->pm_step);
+#endif
+ startstop = ide_start_power_step(drive, rq);
+ if (startstop == ide_stopped &&
+ rq->pm->pm_step == ide_pm_state_completed)
+ ide_complete_pm_request(drive, rq);
+ return startstop;
+ }
+
+ drv = *(ide_driver_t **)rq->rq_disk->private_data;
+ return drv->do_request(drive, rq, block);
+ }
+ 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->sleeping = 1;
+}
+
+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 {
+ if ((!drive->sleeping || time_after_eq(jiffies, drive->sleep))
+ && !elv_queue_empty(drive->queue)) {
+ if (!best
+ || (drive->sleeping && (!best->sleeping || time_before(drive->sleep, best->sleep)))
+ || (!best->sleeping && time_before(WAKEUP(drive), WAKEUP(best))))
+ {
+ if (!blk_queue_plugged(drive->queue))
+ best = drive;
+ }
+ }
+ } while ((drive = drive->next) != hwgroup->drive);
+ if (best && best->nice1 && !best->sleeping && 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->sleeping
+ && 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;
+
+ /* for atari only: POSSIBLY BROKEN HERE(?) */
+ ide_get_lock(ide_intr, hwgroup);
+
+ /* caller must own ide_lock */
+ BUG_ON(!irqs_disabled());
+
+ while (!hwgroup->busy) {
+ hwgroup->busy = 1;
+ 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->sleeping && (!sleeping || 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;
+ 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;
+ }
+ hwif = HWIF(drive);
+ if (hwgroup->hwif->sharing_irq &&
+ hwif != hwgroup->hwif &&
+ hwif->io_ports[IDE_CONTROL_OFFSET]) {
+ /* set nIEN for previous hwif */
+ SELECT_INTERRUPT(drive);
+ }
+ hwgroup->hwif = hwif;
+ hwgroup->drive = drive;
+ drive->sleeping = 0;
+ 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.
+ */
+ if (drive->blocked && !blk_pm_request(rq) && !(rq->flags & REQ_PREEMPT)) {
+ /* 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();
+ /* 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(request_queue_t *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(drive)->ide_dma_end(drive);
+ ret = ide_error(drive, "dma timeout error",
+ hwif->INB(IDE_STATUS_REG));
+ } else {
+ printk(KERN_WARNING "%s: DMA timeout retry\n", drive->name);
+ (void) hwif->ide_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->retry_pio++;
+ drive->state = DMA_PIO_RETRY;
+ (void) hwif->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;
+ 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) {
+ /*
+ * 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;
+ 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);
+#if DISABLE_IRQ_NOSYNC
+ disable_irq_nosync(hwif->irq);
+#else
+ /* disable_irq_nosync ?? */
+ disable_irq(hwif->irq);
+#endif /* DISABLE_IRQ_NOSYNC */
+ /* 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)
+ (void) hwgroup->hwif->ide_dma_lostirq(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->INB(IDE_STATUS_REG));
+ }
+ 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->INB(hwif->io_ports[IDE_STATUS_OFFSET]);
+ if (!OK_STAT(stat, READY_STAT, 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, struct pt_regs *regs)
+{
+ 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->pci_dev && !hwif->pci_dev->vendor)
+#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->INB(hwif->io_ports[IDE_STATUS_OFFSET]);
+#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;
+ del_timer(&hwgroup->timer);
+ spin_unlock(&ide_lock);
+
+ if (drive->unmask)
+ local_irq_enable();
+ /* 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_init_drive_cmd - initialize a drive command request
+ * @rq: request object
+ *
+ * Initialize a request before we fill it in and send it down to
+ * ide_do_drive_cmd. Commands must be set up by this function. Right
+ * now it doesn't do a lot, but if that changes abusers will have a
+ * nasty suprise.
+ */
+
+void ide_init_drive_cmd (struct request *rq)
+{
+ memset(rq, 0, sizeof(*rq));
+ rq->flags = REQ_DRIVE_CMD;
+ rq->ref_count = 1;
+}
+
+EXPORT_SYMBOL(ide_init_drive_cmd);
+
+/**
+ * ide_do_drive_cmd - issue IDE special command
+ * @drive: device to issue command
+ * @rq: request to issue
+ * @action: action for processing
+ *
+ * This function issues a special IDE device request
+ * onto the request queue.
+ *
+ * If action is ide_wait, then the rq is queued at the end of the
+ * request queue, and the function sleeps until it has been processed.
+ * This is for use when invoked from an ioctl handler.
+ *
+ * If action is ide_preempt, then 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.
+ *
+ * If action is ide_next, then the rq is queued immediately after
+ * the currently-being-processed-request (if any), and the function
+ * returns without waiting for the new rq to be completed. As above,
+ * This is VERY DANGEROUS, and is intended for careful use by the
+ * ATAPI tape/cdrom driver code.
+ *
+ * If action is ide_end, then the rq is queued at the end of the
+ * request queue, and the function returns immediately without waiting
+ * for the new rq to be completed. This is again intended for careful
+ * use by the ATAPI tape/cdrom driver code.
+ */
+
+int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t action)
+{
+ unsigned long flags;
+ ide_hwgroup_t *hwgroup = HWGROUP(drive);
+ DECLARE_COMPLETION(wait);
+ int where = ELEVATOR_INSERT_BACK, err;
+ int must_wait = (action == ide_wait || action == ide_head_wait);
+
+ rq->errors = 0;
+ rq->rq_status = RQ_ACTIVE;
+
+ /*
+ * we need to hold an extra reference to request for safe inspection
+ * after completion
+ */
+ if (must_wait) {
+ rq->ref_count++;
+ rq->waiting = &wait;
+ rq->end_io = blk_end_sync_rq;
+ }
+
+ spin_lock_irqsave(&ide_lock, flags);
+ if (action == ide_preempt)
+ hwgroup->rq = NULL;
+ if (action == ide_preempt || action == ide_head_wait) {
+ where = ELEVATOR_INSERT_FRONT;
+ rq->flags |= REQ_PREEMPT;
+ }
+ __elv_add_request(drive->queue, rq, where, 0);
+ ide_do_request(hwgroup, IDE_NO_IRQ);
+ spin_unlock_irqrestore(&ide_lock, flags);
+
+ err = 0;
+ if (must_wait) {
+ wait_for_completion(&wait);
+ rq->waiting = NULL;
+ if (rq->errors)
+ err = -EIO;
+
+ blk_put_request(rq);
+ }
+
+ return err;
+}
+
+EXPORT_SYMBOL(ide_do_drive_cmd);
diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c
new file mode 100644
index 000000000000..53024942a7eb
--- /dev/null
+++ b/drivers/ide/ide-iops.c
@@ -0,0 +1,1285 @@
+/*
+ * linux/drivers/ide/ide-iops.c Version 0.37 Mar 05, 2003
+ *
+ * Copyright (C) 2000-2002 Andre Hedrick <andre@linux-ide.org>
+ * Copyright (C) 2003 Red Hat <alan@redhat.com>
+ *
+ */
+
+#include <linux/config.h>
+#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/hdreg.h>
+#include <linux/ide.h>
+#include <linux/bitops.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 u16 ide_inw (unsigned long port)
+{
+ return (u16) inw(port);
+}
+
+static void ide_insw (unsigned long port, void *addr, u32 count)
+{
+ insw(port, addr, count);
+}
+
+static u32 ide_inl (unsigned long port)
+{
+ return (u32) inl(port);
+}
+
+static void ide_insl (unsigned long port, void *addr, u32 count)
+{
+ insl(port, addr, count);
+}
+
+static void ide_outb (u8 val, unsigned long port)
+{
+ outb(val, port);
+}
+
+static void ide_outbsync (ide_drive_t *drive, u8 addr, unsigned long port)
+{
+ outb(addr, port);
+}
+
+static void ide_outw (u16 val, unsigned long port)
+{
+ outw(val, port);
+}
+
+static void ide_outsw (unsigned long port, void *addr, u32 count)
+{
+ outsw(port, addr, count);
+}
+
+static void ide_outl (u32 val, unsigned long port)
+{
+ outl(val, port);
+}
+
+static void ide_outsl (unsigned long port, void *addr, u32 count)
+{
+ outsl(port, addr, count);
+}
+
+void default_hwif_iops (ide_hwif_t *hwif)
+{
+ hwif->OUTB = ide_outb;
+ hwif->OUTBSYNC = ide_outbsync;
+ hwif->OUTW = ide_outw;
+ hwif->OUTL = ide_outl;
+ hwif->OUTSW = ide_outsw;
+ hwif->OUTSL = ide_outsl;
+ hwif->INB = ide_inb;
+ hwif->INW = ide_inw;
+ hwif->INL = ide_inl;
+ hwif->INSW = ide_insw;
+ hwif->INSL = ide_insl;
+}
+
+EXPORT_SYMBOL(default_hwif_iops);
+
+/*
+ * MMIO operations, typically used for SATA controllers
+ */
+
+static u8 ide_mm_inb (unsigned long port)
+{
+ return (u8) readb((void __iomem *) port);
+}
+
+static u16 ide_mm_inw (unsigned long port)
+{
+ return (u16) readw((void __iomem *) port);
+}
+
+static void ide_mm_insw (unsigned long port, void *addr, u32 count)
+{
+ __ide_mm_insw((void __iomem *) port, addr, count);
+}
+
+static u32 ide_mm_inl (unsigned long port)
+{
+ return (u32) readl((void __iomem *) port);
+}
+
+static void ide_mm_insl (unsigned long port, void *addr, u32 count)
+{
+ __ide_mm_insl((void __iomem *) port, addr, count);
+}
+
+static void ide_mm_outb (u8 value, unsigned long port)
+{
+ writeb(value, (void __iomem *) port);
+}
+
+static void ide_mm_outbsync (ide_drive_t *drive, u8 value, unsigned long port)
+{
+ writeb(value, (void __iomem *) port);
+}
+
+static void ide_mm_outw (u16 value, unsigned long port)
+{
+ writew(value, (void __iomem *) port);
+}
+
+static void ide_mm_outsw (unsigned long port, void *addr, u32 count)
+{
+ __ide_mm_outsw((void __iomem *) port, addr, count);
+}
+
+static void ide_mm_outl (u32 value, unsigned long port)
+{
+ writel(value, (void __iomem *) port);
+}
+
+static void ide_mm_outsl (unsigned long port, void *addr, u32 count)
+{
+ __ide_mm_outsl((void __iomem *) port, addr, count);
+}
+
+void default_hwif_mmiops (ide_hwif_t *hwif)
+{
+ hwif->OUTB = ide_mm_outb;
+ /* Most systems will need to override OUTBSYNC, alas however
+ this one is controller specific! */
+ hwif->OUTBSYNC = ide_mm_outbsync;
+ hwif->OUTW = ide_mm_outw;
+ hwif->OUTL = ide_mm_outl;
+ hwif->OUTSW = ide_mm_outsw;
+ hwif->OUTSL = ide_mm_outsl;
+ hwif->INB = ide_mm_inb;
+ hwif->INW = ide_mm_inw;
+ hwif->INL = ide_mm_inl;
+ hwif->INSW = ide_mm_insw;
+ hwif->INSL = ide_mm_insl;
+}
+
+EXPORT_SYMBOL(default_hwif_mmiops);
+
+u32 ide_read_24 (ide_drive_t *drive)
+{
+ u8 hcyl = HWIF(drive)->INB(IDE_HCYL_REG);
+ u8 lcyl = HWIF(drive)->INB(IDE_LCYL_REG);
+ u8 sect = HWIF(drive)->INB(IDE_SECTOR_REG);
+ return (hcyl<<16)|(lcyl<<8)|sect;
+}
+
+void SELECT_DRIVE (ide_drive_t *drive)
+{
+ if (HWIF(drive)->selectproc)
+ HWIF(drive)->selectproc(drive);
+ HWIF(drive)->OUTB(drive->select.all, IDE_SELECT_REG);
+}
+
+EXPORT_SYMBOL(SELECT_DRIVE);
+
+void SELECT_INTERRUPT (ide_drive_t *drive)
+{
+ if (HWIF(drive)->intrproc)
+ HWIF(drive)->intrproc(drive);
+ else
+ HWIF(drive)->OUTB(drive->ctl|2, IDE_CONTROL_REG);
+}
+
+void SELECT_MASK (ide_drive_t *drive, int mask)
+{
+ if (HWIF(drive)->maskproc)
+ HWIF(drive)->maskproc(drive, mask);
+}
+
+void QUIRK_LIST (ide_drive_t *drive)
+{
+ if (HWIF(drive)->quirkproc)
+ drive->quirk_list = HWIF(drive)->quirkproc(drive);
+}
+
+/*
+ * 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(ide_drive_t *drive, unsigned long port)
+{
+ (void) HWIF(drive)->INB(port);
+ (void) HWIF(drive)->INB(port);
+ (void) HWIF(drive)->INB(port);
+}
+
+/*
+ * This is used for most PIO data transfers *from* the IDE interface
+ */
+static void ata_input_data(ide_drive_t *drive, void *buffer, u32 wcount)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ u8 io_32bit = drive->io_32bit;
+
+ if (io_32bit) {
+ if (io_32bit & 2) {
+ unsigned long flags;
+ local_irq_save(flags);
+ ata_vlb_sync(drive, IDE_NSECTOR_REG);
+ hwif->INSL(IDE_DATA_REG, buffer, wcount);
+ local_irq_restore(flags);
+ } else
+ hwif->INSL(IDE_DATA_REG, buffer, wcount);
+ } else {
+ hwif->INSW(IDE_DATA_REG, buffer, wcount<<1);
+ }
+}
+
+/*
+ * This is used for most PIO data transfers *to* the IDE interface
+ */
+static void ata_output_data(ide_drive_t *drive, void *buffer, u32 wcount)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ u8 io_32bit = drive->io_32bit;
+
+ if (io_32bit) {
+ if (io_32bit & 2) {
+ unsigned long flags;
+ local_irq_save(flags);
+ ata_vlb_sync(drive, IDE_NSECTOR_REG);
+ hwif->OUTSL(IDE_DATA_REG, buffer, wcount);
+ local_irq_restore(flags);
+ } else
+ hwif->OUTSL(IDE_DATA_REG, buffer, wcount);
+ } else {
+ hwif->OUTSW(IDE_DATA_REG, buffer, wcount<<1);
+ }
+}
+
+/*
+ * The following routines are mainly used by the ATAPI drivers.
+ *
+ * These routines will round up any request for an odd number of bytes,
+ * so if an odd bytecount is specified, be sure that there's at least one
+ * extra byte allocated for the buffer.
+ */
+
+static void atapi_input_bytes(ide_drive_t *drive, void *buffer, u32 bytecount)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+
+ ++bytecount;
+#if defined(CONFIG_ATARI) || defined(CONFIG_Q40)
+ if (MACH_IS_ATARI || MACH_IS_Q40) {
+ /* Atari has a byte-swapped IDE interface */
+ insw_swapw(IDE_DATA_REG, buffer, bytecount / 2);
+ return;
+ }
+#endif /* CONFIG_ATARI || CONFIG_Q40 */
+ hwif->ata_input_data(drive, buffer, bytecount / 4);
+ if ((bytecount & 0x03) >= 2)
+ hwif->INSW(IDE_DATA_REG, ((u8 *)buffer)+(bytecount & ~0x03), 1);
+}
+
+static void atapi_output_bytes(ide_drive_t *drive, void *buffer, u32 bytecount)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+
+ ++bytecount;
+#if defined(CONFIG_ATARI) || defined(CONFIG_Q40)
+ if (MACH_IS_ATARI || MACH_IS_Q40) {
+ /* Atari has a byte-swapped IDE interface */
+ outsw_swapw(IDE_DATA_REG, buffer, bytecount / 2);
+ return;
+ }
+#endif /* CONFIG_ATARI || CONFIG_Q40 */
+ hwif->ata_output_data(drive, buffer, bytecount / 4);
+ if ((bytecount & 0x03) >= 2)
+ hwif->OUTSW(IDE_DATA_REG, ((u8*)buffer)+(bytecount & ~0x03), 1);
+}
+
+void default_hwif_transport(ide_hwif_t *hwif)
+{
+ hwif->ata_input_data = ata_input_data;
+ hwif->ata_output_data = ata_output_data;
+ hwif->atapi_input_bytes = atapi_input_bytes;
+ hwif->atapi_output_bytes = atapi_output_bytes;
+}
+
+EXPORT_SYMBOL(default_hwif_transport);
+
+/*
+ * Beginning of Taskfile OPCODE Library and feature sets.
+ */
+void ide_fix_driveid (struct hd_driveid *id)
+{
+#ifndef __LITTLE_ENDIAN
+# ifdef __BIG_ENDIAN
+ int i;
+ u16 *stringcast;
+
+ id->config = __le16_to_cpu(id->config);
+ id->cyls = __le16_to_cpu(id->cyls);
+ id->reserved2 = __le16_to_cpu(id->reserved2);
+ id->heads = __le16_to_cpu(id->heads);
+ id->track_bytes = __le16_to_cpu(id->track_bytes);
+ id->sector_bytes = __le16_to_cpu(id->sector_bytes);
+ id->sectors = __le16_to_cpu(id->sectors);
+ id->vendor0 = __le16_to_cpu(id->vendor0);
+ id->vendor1 = __le16_to_cpu(id->vendor1);
+ id->vendor2 = __le16_to_cpu(id->vendor2);
+ stringcast = (u16 *)&id->serial_no[0];
+ for (i = 0; i < (20/2); i++)
+ stringcast[i] = __le16_to_cpu(stringcast[i]);
+ id->buf_type = __le16_to_cpu(id->buf_type);
+ id->buf_size = __le16_to_cpu(id->buf_size);
+ id->ecc_bytes = __le16_to_cpu(id->ecc_bytes);
+ stringcast = (u16 *)&id->fw_rev[0];
+ for (i = 0; i < (8/2); i++)
+ stringcast[i] = __le16_to_cpu(stringcast[i]);
+ stringcast = (u16 *)&id->model[0];
+ for (i = 0; i < (40/2); i++)
+ stringcast[i] = __le16_to_cpu(stringcast[i]);
+ id->dword_io = __le16_to_cpu(id->dword_io);
+ id->reserved50 = __le16_to_cpu(id->reserved50);
+ id->field_valid = __le16_to_cpu(id->field_valid);
+ id->cur_cyls = __le16_to_cpu(id->cur_cyls);
+ id->cur_heads = __le16_to_cpu(id->cur_heads);
+ id->cur_sectors = __le16_to_cpu(id->cur_sectors);
+ id->cur_capacity0 = __le16_to_cpu(id->cur_capacity0);
+ id->cur_capacity1 = __le16_to_cpu(id->cur_capacity1);
+ id->lba_capacity = __le32_to_cpu(id->lba_capacity);
+ id->dma_1word = __le16_to_cpu(id->dma_1word);
+ id->dma_mword = __le16_to_cpu(id->dma_mword);
+ id->eide_pio_modes = __le16_to_cpu(id->eide_pio_modes);
+ id->eide_dma_min = __le16_to_cpu(id->eide_dma_min);
+ id->eide_dma_time = __le16_to_cpu(id->eide_dma_time);
+ id->eide_pio = __le16_to_cpu(id->eide_pio);
+ id->eide_pio_iordy = __le16_to_cpu(id->eide_pio_iordy);
+ for (i = 0; i < 2; ++i)
+ id->words69_70[i] = __le16_to_cpu(id->words69_70[i]);
+ for (i = 0; i < 4; ++i)
+ id->words71_74[i] = __le16_to_cpu(id->words71_74[i]);
+ id->queue_depth = __le16_to_cpu(id->queue_depth);
+ for (i = 0; i < 4; ++i)
+ id->words76_79[i] = __le16_to_cpu(id->words76_79[i]);
+ id->major_rev_num = __le16_to_cpu(id->major_rev_num);
+ id->minor_rev_num = __le16_to_cpu(id->minor_rev_num);
+ id->command_set_1 = __le16_to_cpu(id->command_set_1);
+ id->command_set_2 = __le16_to_cpu(id->command_set_2);
+ id->cfsse = __le16_to_cpu(id->cfsse);
+ id->cfs_enable_1 = __le16_to_cpu(id->cfs_enable_1);
+ id->cfs_enable_2 = __le16_to_cpu(id->cfs_enable_2);
+ id->csf_default = __le16_to_cpu(id->csf_default);
+ id->dma_ultra = __le16_to_cpu(id->dma_ultra);
+ id->trseuc = __le16_to_cpu(id->trseuc);
+ id->trsEuc = __le16_to_cpu(id->trsEuc);
+ id->CurAPMvalues = __le16_to_cpu(id->CurAPMvalues);
+ id->mprc = __le16_to_cpu(id->mprc);
+ id->hw_config = __le16_to_cpu(id->hw_config);
+ id->acoustic = __le16_to_cpu(id->acoustic);
+ id->msrqs = __le16_to_cpu(id->msrqs);
+ id->sxfert = __le16_to_cpu(id->sxfert);
+ id->sal = __le16_to_cpu(id->sal);
+ id->spg = __le32_to_cpu(id->spg);
+ id->lba_capacity_2 = __le64_to_cpu(id->lba_capacity_2);
+ for (i = 0; i < 22; i++)
+ id->words104_125[i] = __le16_to_cpu(id->words104_125[i]);
+ id->last_lun = __le16_to_cpu(id->last_lun);
+ id->word127 = __le16_to_cpu(id->word127);
+ id->dlf = __le16_to_cpu(id->dlf);
+ id->csfo = __le16_to_cpu(id->csfo);
+ for (i = 0; i < 26; i++)
+ id->words130_155[i] = __le16_to_cpu(id->words130_155[i]);
+ id->word156 = __le16_to_cpu(id->word156);
+ for (i = 0; i < 3; i++)
+ id->words157_159[i] = __le16_to_cpu(id->words157_159[i]);
+ id->cfa_power = __le16_to_cpu(id->cfa_power);
+ for (i = 0; i < 14; i++)
+ id->words161_175[i] = __le16_to_cpu(id->words161_175[i]);
+ for (i = 0; i < 31; i++)
+ id->words176_205[i] = __le16_to_cpu(id->words176_205[i]);
+ for (i = 0; i < 48; i++)
+ id->words206_254[i] = __le16_to_cpu(id->words206_254[i]);
+ id->integrity_word = __le16_to_cpu(id->integrity_word);
+# else
+# error "Please fix <asm/byteorder.h>"
+# endif
+#endif
+}
+
+/* FIXME: exported for use by the USB storage (isd200.c) code only */
+EXPORT_SYMBOL(ide_fix_driveid);
+
+void ide_fixstring (u8 *s, const int bytecount, const int byteswap)
+{
+ u8 *p = s, *end = &s[bytecount & ~1]; /* bytecount must be even */
+
+ if (byteswap) {
+ /* convert from big-endian to host byte order */
+ for (p = end ; p != s;) {
+ unsigned short *pp = (unsigned short *) (p -= 2);
+ *pp = ntohs(*pp);
+ }
+ }
+ /* strip leading blanks */
+ 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->ide_dma_test_irq(drive);
+
+#if 0
+ /* need to guarantee 400ns since last command was issued */
+ udelay(1);
+#endif
+
+#ifdef CONFIG_IDEPCI_SHARE_IRQ
+ /*
+ * 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 (IDE_CONTROL_REG)
+ stat = hwif->INB(IDE_ALTSTATUS_REG);
+ else
+#endif /* CONFIG_IDEPCI_SHARE_IRQ */
+ /* Note: this may clear a pending IRQ!! */
+ stat = hwif->INB(IDE_STATUS_REG);
+
+ if (stat & BUSY_STAT)
+ /* drive busy: definitely not interrupting */
+ return 0;
+
+ /* drive ready: *might* be interrupting */
+ return 1;
+}
+
+EXPORT_SYMBOL(drive_is_ready);
+
+/*
+ * Global for All, and taken from ide-pmac.c. Can be called
+ * with spinlock held & IRQs disabled, so don't schedule !
+ */
+int wait_for_ready (ide_drive_t *drive, int timeout)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ u8 stat = 0;
+
+ while(--timeout) {
+ stat = hwif->INB(IDE_STATUS_REG);
+ if (!(stat & BUSY_STAT)) {
+ if (drive->ready_stat == 0)
+ break;
+ else if ((stat & drive->ready_stat)||(stat & ERR_STAT))
+ break;
+ }
+ mdelay(1);
+ }
+ if ((stat & ERR_STAT) || timeout <= 0) {
+ if (stat & ERR_STAT) {
+ printk(KERN_ERR "%s: wait_for_ready, "
+ "error status: %x\n", drive->name, stat);
+ }
+ return 1;
+ }
+ return 0;
+}
+
+EXPORT_SYMBOL(wait_for_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 1 after invoking ide_error() -- caller should just return.
+ *
+ * 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.
+ */
+int ide_wait_stat (ide_startstop_t *startstop, ide_drive_t *drive, u8 good, u8 bad, unsigned long timeout)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ u8 stat;
+ int i;
+ unsigned long flags;
+
+ /* bail early if we've exceeded max_failures */
+ if (drive->max_failures && (drive->failures > drive->max_failures)) {
+ *startstop = ide_stopped;
+ return 1;
+ }
+
+ udelay(1); /* spec allows drive 400ns to assert "BUSY" */
+ if ((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) {
+ local_irq_set(flags);
+ timeout += jiffies;
+ while ((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) {
+ 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 = hwif->INB(IDE_STATUS_REG);
+ if (!(stat & BUSY_STAT))
+ break;
+
+ local_irq_restore(flags);
+ *startstop = ide_error(drive, "status timeout", stat);
+ return 1;
+ }
+ }
+ 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);
+ if (OK_STAT((stat = hwif->INB(IDE_STATUS_REG)), good, bad))
+ return 0;
+ }
+ *startstop = ide_error(drive, "status error", stat);
+ return 1;
+}
+
+EXPORT_SYMBOL(ide_wait_stat);
+
+/*
+ * 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)
+{
+#if 0
+ if (!HWIF(drive)->udma_four)
+ return 0;
+
+ if (drive->id->major_rev_num) {
+ int hssbd = 0;
+ int i;
+ /*
+ * Determine highest Supported SPEC
+ */
+ for (i=1; i<=15; i++)
+ if (drive->id->major_rev_num & (1<<i))
+ hssbd++;
+
+ switch (hssbd) {
+ case 7:
+ case 6:
+ case 5:
+ /* ATA-4 and older do not support above Ultra 33 */
+ default:
+ return 0;
+ }
+ }
+
+ return ((u8) (
+#ifndef CONFIG_IDEDMA_IVB
+ (drive->id->hw_config & 0x4000) &&
+#endif /* CONFIG_IDEDMA_IVB */
+ (drive->id->hw_config & 0x6000)) ? 1 : 0);
+
+#else
+
+ return ((u8) ((HWIF(drive)->udma_four) &&
+#ifndef CONFIG_IDEDMA_IVB
+ (drive->id->hw_config & 0x4000) &&
+#endif /* CONFIG_IDEDMA_IVB */
+ (drive->id->hw_config & 0x6000)) ? 1 : 0);
+#endif
+}
+
+EXPORT_SYMBOL(eighty_ninty_three);
+
+int ide_ata66_check (ide_drive_t *drive, ide_task_t *args)
+{
+ if ((args->tfRegister[IDE_COMMAND_OFFSET] == WIN_SETFEATURES) &&
+ (args->tfRegister[IDE_SECTOR_OFFSET] > XFER_UDMA_2) &&
+ (args->tfRegister[IDE_FEATURE_OFFSET] == SETFEATURES_XFER)) {
+#ifndef CONFIG_IDEDMA_IVB
+ if ((drive->id->hw_config & 0x6000) == 0) {
+#else /* !CONFIG_IDEDMA_IVB */
+ if (((drive->id->hw_config & 0x2000) == 0) ||
+ ((drive->id->hw_config & 0x4000) == 0)) {
+#endif /* CONFIG_IDEDMA_IVB */
+ printk("%s: Speed warnings UDMA 3/4/5 is not "
+ "functional.\n", drive->name);
+ return 1;
+ }
+ if (!HWIF(drive)->udma_four) {
+ printk("%s: Speed warnings UDMA 3/4/5 is not "
+ "functional.\n",
+ HWIF(drive)->name);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/*
+ * Backside of HDIO_DRIVE_CMD call of SETFEATURES_XFER.
+ * 1 : Safe to update drive->id DMA registers.
+ * 0 : OOPs not allowed.
+ */
+int set_transfer (ide_drive_t *drive, ide_task_t *args)
+{
+ if ((args->tfRegister[IDE_COMMAND_OFFSET] == WIN_SETFEATURES) &&
+ (args->tfRegister[IDE_SECTOR_OFFSET] >= XFER_SW_DMA_0) &&
+ (args->tfRegister[IDE_FEATURE_OFFSET] == SETFEATURES_XFER) &&
+ (drive->id->dma_ultra ||
+ drive->id->dma_mword ||
+ drive->id->dma_1word))
+ return 1;
+
+ return 0;
+}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+static u8 ide_auto_reduce_xfer (ide_drive_t *drive)
+{
+ if (!drive->crc_count)
+ return drive->current_speed;
+ drive->crc_count = 0;
+
+ switch(drive->current_speed) {
+ case XFER_UDMA_7: return XFER_UDMA_6;
+ case XFER_UDMA_6: return XFER_UDMA_5;
+ case XFER_UDMA_5: return XFER_UDMA_4;
+ case XFER_UDMA_4: return XFER_UDMA_3;
+ case XFER_UDMA_3: return XFER_UDMA_2;
+ case XFER_UDMA_2: return XFER_UDMA_1;
+ case XFER_UDMA_1: return XFER_UDMA_0;
+ /*
+ * OOPS we do not goto non Ultra DMA modes
+ * without iCRC's available we force
+ * the system to PIO and make the user
+ * invoke the ATA-1 ATA-2 DMA modes.
+ */
+ case XFER_UDMA_0:
+ default: return XFER_PIO_4;
+ }
+}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
+/*
+ * Update the
+ */
+int ide_driveid_update (ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct hd_driveid *id;
+#if 0
+ id = kmalloc(SECTOR_WORDS*4, GFP_ATOMIC);
+ if (!id)
+ return 0;
+
+ taskfile_lib_get_identify(drive, (char *)&id);
+
+ ide_fix_driveid(id);
+ if (id) {
+ drive->id->dma_ultra = id->dma_ultra;
+ drive->id->dma_mword = id->dma_mword;
+ drive->id->dma_1word = id->dma_1word;
+ /* anything more ? */
+ kfree(id);
+ }
+ return 1;
+#else
+ /*
+ * Re-read drive->id for possible DMA mode
+ * change (copied from ide-probe.c)
+ */
+ unsigned long timeout, flags;
+
+ SELECT_MASK(drive, 1);
+ if (IDE_CONTROL_REG)
+ hwif->OUTB(drive->ctl,IDE_CONTROL_REG);
+ msleep(50);
+ hwif->OUTB(WIN_IDENTIFY, IDE_COMMAND_REG);
+ timeout = jiffies + WAIT_WORSTCASE;
+ do {
+ if (time_after(jiffies, timeout)) {
+ SELECT_MASK(drive, 0);
+ return 0; /* drive timed-out */
+ }
+ msleep(50); /* give drive a breather */
+ } while (hwif->INB(IDE_ALTSTATUS_REG) & BUSY_STAT);
+ msleep(50); /* wait for IRQ and DRQ_STAT */
+ if (!OK_STAT(hwif->INB(IDE_STATUS_REG),DRQ_STAT,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_WORDS*4, GFP_ATOMIC);
+ if (!id) {
+ local_irq_restore(flags);
+ return 0;
+ }
+ ata_input_data(drive, id, SECTOR_WORDS);
+ (void) hwif->INB(IDE_STATUS_REG); /* clear drive IRQ */
+ local_irq_enable();
+ local_irq_restore(flags);
+ ide_fix_driveid(id);
+ if (id) {
+ drive->id->dma_ultra = id->dma_ultra;
+ drive->id->dma_mword = id->dma_mword;
+ drive->id->dma_1word = id->dma_1word;
+ /* anything more ? */
+ kfree(id);
+ }
+
+ return 1;
+#endif
+}
+
+/*
+ * Similar to ide_wait_stat(), except it never calls ide_error internally.
+ * This is a kludge to handle the new ide_config_drive_speed() function,
+ * and should not otherwise be used anywhere. Eventually, the tuneproc's
+ * should be updated to return ide_startstop_t, in which case we can get
+ * rid of this abomination again. :) -ml
+ *
+ * It is gone..........
+ *
+ * const char *msg == consider adding for verbose errors.
+ */
+int ide_config_drive_speed (ide_drive_t *drive, u8 speed)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ int i, error = 1;
+ u8 stat;
+
+// while (HWGROUP(drive)->busy)
+// msleep(50);
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+ if (hwif->ide_dma_check) /* check if host supports DMA */
+ hwif->ide_dma_host_off(drive);
+#endif
+
+ /*
+ * 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, 0);
+ udelay(1);
+ if (IDE_CONTROL_REG)
+ hwif->OUTB(drive->ctl | 2, IDE_CONTROL_REG);
+ hwif->OUTB(speed, IDE_NSECTOR_REG);
+ hwif->OUTB(SETFEATURES_XFER, IDE_FEATURE_REG);
+ hwif->OUTB(WIN_SETFEATURES, IDE_COMMAND_REG);
+ if ((IDE_CONTROL_REG) && (drive->quirk_list == 2))
+ hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
+ udelay(1);
+ /*
+ * Wait for drive to become non-BUSY
+ */
+ if ((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) {
+ unsigned long flags, timeout;
+ local_irq_set(flags);
+ timeout = jiffies + WAIT_CMD;
+ while ((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) {
+ if (time_after(jiffies, timeout))
+ break;
+ }
+ 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);
+ if (OK_STAT((stat = hwif->INB(IDE_STATUS_REG)), DRIVE_READY, BUSY_STAT|DRQ_STAT|ERR_STAT)) {
+ error = 0;
+ break;
+ }
+ }
+
+ SELECT_MASK(drive, 0);
+
+ enable_irq(hwif->irq);
+
+ if (error) {
+ (void) ide_dump_status(drive, "set_drive_speed_status", stat);
+ return error;
+ }
+
+ drive->id->dma_ultra &= ~0xFF00;
+ drive->id->dma_mword &= ~0x0F00;
+ drive->id->dma_1word &= ~0x0F00;
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+ if (speed >= XFER_SW_DMA_0)
+ hwif->ide_dma_host_on(drive);
+ else if (hwif->ide_dma_check) /* check if host supports DMA */
+ hwif->ide_dma_off_quietly(drive);
+#endif
+
+ switch(speed) {
+ case XFER_UDMA_7: drive->id->dma_ultra |= 0x8080; break;
+ case XFER_UDMA_6: drive->id->dma_ultra |= 0x4040; break;
+ case XFER_UDMA_5: drive->id->dma_ultra |= 0x2020; break;
+ case XFER_UDMA_4: drive->id->dma_ultra |= 0x1010; break;
+ case XFER_UDMA_3: drive->id->dma_ultra |= 0x0808; break;
+ case XFER_UDMA_2: drive->id->dma_ultra |= 0x0404; break;
+ case XFER_UDMA_1: drive->id->dma_ultra |= 0x0202; break;
+ case XFER_UDMA_0: drive->id->dma_ultra |= 0x0101; break;
+ case XFER_MW_DMA_2: drive->id->dma_mword |= 0x0404; break;
+ case XFER_MW_DMA_1: drive->id->dma_mword |= 0x0202; break;
+ case XFER_MW_DMA_0: drive->id->dma_mword |= 0x0101; break;
+ case XFER_SW_DMA_2: drive->id->dma_1word |= 0x0404; break;
+ case XFER_SW_DMA_1: drive->id->dma_1word |= 0x0202; break;
+ case XFER_SW_DMA_0: drive->id->dma_1word |= 0x0101; break;
+ default: break;
+ }
+ if (!drive->init_speed)
+ drive->init_speed = speed;
+ drive->current_speed = speed;
+ return error;
+}
+
+EXPORT_SYMBOL(ide_config_drive_speed);
+
+
+/*
+ * 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);
+
+ if (hwgroup->handler != NULL) {
+ printk(KERN_CRIT "%s: ide_set_handler: handler not null; "
+ "old=%p, new=%p\n",
+ drive->name, hwgroup->handler, handler);
+ }
+ hwgroup->handler = handler;
+ hwgroup->expiry = expiry;
+ hwgroup->timer.expires = jiffies + timeout;
+ 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, task_ioreg_t cmd, ide_handler_t *handler, unsigned timeout, ide_expiry_t *expiry)
+{
+ unsigned long flags;
+ ide_hwgroup_t *hwgroup = HWGROUP(drive);
+ ide_hwif_t *hwif = HWIF(drive);
+
+ spin_lock_irqsave(&ide_lock, flags);
+
+ if(hwgroup->handler)
+ BUG();
+ hwgroup->handler = handler;
+ hwgroup->expiry = expiry;
+ hwgroup->timer.expires = jiffies + timeout;
+ add_timer(&hwgroup->timer);
+ hwif->OUTBSYNC(drive, cmd, IDE_COMMAND_REG);
+ /* 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);
+
+
+/* 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_hwgroup_t *hwgroup = HWGROUP(drive);
+ ide_hwif_t *hwif = HWIF(drive);
+ u8 stat;
+
+ SELECT_DRIVE(drive);
+ udelay (10);
+
+ if (OK_STAT(stat = hwif->INB(IDE_STATUS_REG), 0, BUSY_STAT)) {
+ printk("%s: ATAPI reset complete\n", drive->name);
+ } else {
+ if (time_before(jiffies, hwgroup->poll_timeout)) {
+ if (HWGROUP(drive)->handler != NULL)
+ BUG();
+ 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;
+ return ide_stopped;
+}
+
+/*
+ * 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);
+ u8 tmp;
+
+ if (hwif->reset_poll != NULL) {
+ if (hwif->reset_poll(drive)) {
+ printk(KERN_ERR "%s: host reset_poll failure for %s.\n",
+ hwif->name, drive->name);
+ return ide_stopped;
+ }
+ }
+
+ if (!OK_STAT(tmp = hwif->INB(IDE_STATUS_REG), 0, BUSY_STAT)) {
+ if (time_before(jiffies, hwgroup->poll_timeout)) {
+ if (HWGROUP(drive)->handler != NULL)
+ BUG();
+ 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++;
+ } else {
+ printk("%s: reset: ", hwif->name);
+ if ((tmp = hwif->INB(IDE_ERROR_REG)) == 1) {
+ printk("success\n");
+ drive->failures = 0;
+ } else {
+ drive->failures++;
+ printk("master: ");
+ switch (tmp & 0x7f) {
+ case 1: printk("passed");
+ break;
+ case 2: printk("formatter device error");
+ break;
+ case 3: printk("sector buffer error");
+ break;
+ case 4: printk("ECC circuitry error");
+ break;
+ case 5: printk("controlling MPU error");
+ break;
+ default:printk("error (0x%02x?)", tmp);
+ }
+ if (tmp & 0x80)
+ printk("; slave: failed");
+ printk("\n");
+ }
+ }
+ hwgroup->polling = 0; /* done polling */
+ return ide_stopped;
+}
+
+static void check_dma_crc(ide_drive_t *drive)
+{
+#ifdef CONFIG_BLK_DEV_IDEDMA
+ if (drive->crc_count) {
+ (void) HWIF(drive)->ide_dma_off_quietly(drive);
+ ide_set_xfer_rate(drive, ide_auto_reduce_xfer(drive));
+ if (drive->current_speed >= XFER_SW_DMA_0)
+ (void) HWIF(drive)->ide_dma_on(drive);
+ } else
+ (void)__ide_dma_off(drive);
+#endif
+}
+
+static void ide_disk_pre_reset(ide_drive_t *drive)
+{
+ int legacy = (drive->id->cfs_enable_2 & 0x0400) ? 0 : 1;
+
+ drive->special.all = 0;
+ drive->special.b.set_geometry = legacy;
+ drive->special.b.recalibrate = legacy;
+ if (OK_TO_RESET_CONTROLLER)
+ drive->mult_count = 0;
+ if (!drive->keep_settings && !drive->using_dma)
+ 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)
+{
+ if (drive->media == ide_disk)
+ ide_disk_pre_reset(drive);
+ else
+ drive->post_reset = 1;
+
+ if (!drive->keep_settings) {
+ if (drive->using_dma) {
+ check_dma_crc(drive);
+ } else {
+ drive->unmask = 0;
+ drive->io_32bit = 0;
+ }
+ return;
+ }
+ if (drive->using_dma)
+ check_dma_crc(drive);
+
+ if (HWIF(drive)->pre_reset != NULL)
+ HWIF(drive)->pre_reset(drive);
+
+}
+
+/*
+ * 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;
+ ide_hwif_t *hwif;
+ ide_hwgroup_t *hwgroup;
+
+ spin_lock_irqsave(&ide_lock, flags);
+ hwif = HWIF(drive);
+ hwgroup = HWGROUP(drive);
+
+ /* We must not reset with running handlers */
+ if(hwgroup->handler != NULL)
+ BUG();
+
+ /* 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);
+ hwif->OUTB(WIN_SRST, IDE_COMMAND_REG);
+ 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;
+ }
+
+ /*
+ * 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 OK_TO_RESET_CONTROLLER
+ if (!IDE_CONTROL_REG) {
+ spin_unlock_irqrestore(&ide_lock, flags);
+ 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.
+ */
+ /* set SRST and nIEN */
+ hwif->OUTBSYNC(drive, drive->ctl|6,IDE_CONTROL_REG);
+ /* more than enough time */
+ udelay(10);
+ if (drive->quirk_list == 2) {
+ /* clear SRST and nIEN */
+ hwif->OUTBSYNC(drive, drive->ctl, IDE_CONTROL_REG);
+ } else {
+ /* clear SRST, leave nIEN */
+ hwif->OUTBSYNC(drive, drive->ctl|2, IDE_CONTROL_REG);
+ }
+ /* 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
+ */
+ if (hwif->resetproc != NULL) {
+ hwif->resetproc(drive);
+ }
+
+#endif /* OK_TO_RESET_CONTROLLER */
+
+ 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 probe_hwif().
+ */
+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->INB(hwif->io_ports[IDE_STATUS_OFFSET]);
+ if ((stat & BUSY_STAT) == 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;
+ }
+ 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 000000000000..6806d407e9c1
--- /dev/null
+++ b/drivers/ide/ide-lib.c
@@ -0,0 +1,622 @@
+#include <linux/config.h>
+#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/hdreg.h>
+#include <linux/ide.h>
+#include <linux/bitops.h>
+
+#include <asm/byteorder.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+/*
+ * IDE library routines. These are plug in code that most
+ * drivers can use but occasionally may be weird enough
+ * to want to do their own thing with
+ *
+ * Add common non I/O op stuff here. Make sure it has proper
+ * kernel-doc function headers or your patch will be rejected
+ */
+
+
+/**
+ * ide_xfer_verbose - return IDE mode names
+ * @xfer_rate: rate to name
+ *
+ * Returns a constant string giving the name of the mode
+ * requested.
+ */
+
+char *ide_xfer_verbose (u8 xfer_rate)
+{
+ switch(xfer_rate) {
+ case XFER_UDMA_7: return("UDMA 7");
+ case XFER_UDMA_6: return("UDMA 6");
+ case XFER_UDMA_5: return("UDMA 5");
+ case XFER_UDMA_4: return("UDMA 4");
+ case XFER_UDMA_3: return("UDMA 3");
+ case XFER_UDMA_2: return("UDMA 2");
+ case XFER_UDMA_1: return("UDMA 1");
+ case XFER_UDMA_0: return("UDMA 0");
+ case XFER_MW_DMA_2: return("MW DMA 2");
+ case XFER_MW_DMA_1: return("MW DMA 1");
+ case XFER_MW_DMA_0: return("MW DMA 0");
+ case XFER_SW_DMA_2: return("SW DMA 2");
+ case XFER_SW_DMA_1: return("SW DMA 1");
+ case XFER_SW_DMA_0: return("SW DMA 0");
+ case XFER_PIO_4: return("PIO 4");
+ case XFER_PIO_3: return("PIO 3");
+ case XFER_PIO_2: return("PIO 2");
+ case XFER_PIO_1: return("PIO 1");
+ case XFER_PIO_0: return("PIO 0");
+ case XFER_PIO_SLOW: return("PIO SLOW");
+ default: return("XFER ERROR");
+ }
+}
+
+EXPORT_SYMBOL(ide_xfer_verbose);
+
+/**
+ * ide_dma_speed - compute DMA speed
+ * @drive: drive
+ * @mode; intended mode
+ *
+ * Checks the drive capabilities and returns the speed to use
+ * for the transfer. Returns -1 if the requested mode is unknown
+ * (eg PIO)
+ */
+
+u8 ide_dma_speed(ide_drive_t *drive, u8 mode)
+{
+ struct hd_driveid *id = drive->id;
+ ide_hwif_t *hwif = HWIF(drive);
+ u8 speed = 0;
+
+ if (drive->media != ide_disk && hwif->atapi_dma == 0)
+ return 0;
+
+ switch(mode) {
+ case 0x04:
+ if ((id->dma_ultra & 0x0040) &&
+ (id->dma_ultra & hwif->ultra_mask))
+ { speed = XFER_UDMA_6; break; }
+ case 0x03:
+ if ((id->dma_ultra & 0x0020) &&
+ (id->dma_ultra & hwif->ultra_mask))
+ { speed = XFER_UDMA_5; break; }
+ case 0x02:
+ if ((id->dma_ultra & 0x0010) &&
+ (id->dma_ultra & hwif->ultra_mask))
+ { speed = XFER_UDMA_4; break; }
+ if ((id->dma_ultra & 0x0008) &&
+ (id->dma_ultra & hwif->ultra_mask))
+ { speed = XFER_UDMA_3; break; }
+ case 0x01:
+ if ((id->dma_ultra & 0x0004) &&
+ (id->dma_ultra & hwif->ultra_mask))
+ { speed = XFER_UDMA_2; break; }
+ if ((id->dma_ultra & 0x0002) &&
+ (id->dma_ultra & hwif->ultra_mask))
+ { speed = XFER_UDMA_1; break; }
+ if ((id->dma_ultra & 0x0001) &&
+ (id->dma_ultra & hwif->ultra_mask))
+ { speed = XFER_UDMA_0; break; }
+ case 0x00:
+ if ((id->dma_mword & 0x0004) &&
+ (id->dma_mword & hwif->mwdma_mask))
+ { speed = XFER_MW_DMA_2; break; }
+ if ((id->dma_mword & 0x0002) &&
+ (id->dma_mword & hwif->mwdma_mask))
+ { speed = XFER_MW_DMA_1; break; }
+ if ((id->dma_mword & 0x0001) &&
+ (id->dma_mword & hwif->mwdma_mask))
+ { speed = XFER_MW_DMA_0; break; }
+ if ((id->dma_1word & 0x0004) &&
+ (id->dma_1word & hwif->swdma_mask))
+ { speed = XFER_SW_DMA_2; break; }
+ if ((id->dma_1word & 0x0002) &&
+ (id->dma_1word & hwif->swdma_mask))
+ { speed = XFER_SW_DMA_1; break; }
+ if ((id->dma_1word & 0x0001) &&
+ (id->dma_1word & hwif->swdma_mask))
+ { speed = XFER_SW_DMA_0; break; }
+ }
+
+// printk("%s: %s: mode 0x%02x, speed 0x%02x\n",
+// __FUNCTION__, drive->name, mode, speed);
+
+ return speed;
+}
+
+EXPORT_SYMBOL(ide_dma_speed);
+
+
+/**
+ * ide_rate_filter - return best speed for mode
+ * @mode: modes available
+ * @speed: desired speed
+ *
+ * Given the available DMA/UDMA mode this function returns
+ * the best available speed at or below the speed requested.
+ */
+
+u8 ide_rate_filter (u8 mode, u8 speed)
+{
+#ifdef CONFIG_BLK_DEV_IDEDMA
+ static u8 speed_max[] = {
+ XFER_MW_DMA_2, XFER_UDMA_2, XFER_UDMA_4,
+ XFER_UDMA_5, XFER_UDMA_6
+ };
+
+// printk("%s: mode 0x%02x, speed 0x%02x\n", __FUNCTION__, mode, speed);
+
+ /* So that we remember to update this if new modes appear */
+ if (mode > 4)
+ BUG();
+ return min(speed, speed_max[mode]);
+#else /* !CONFIG_BLK_DEV_IDEDMA */
+ return min(speed, (u8)XFER_PIO_4);
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+}
+
+EXPORT_SYMBOL(ide_rate_filter);
+
+int ide_dma_enable (ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct hd_driveid *id = drive->id;
+
+ return ((int) ((((id->dma_ultra >> 8) & hwif->ultra_mask) ||
+ ((id->dma_mword >> 8) & hwif->mwdma_mask) ||
+ ((id->dma_1word >> 8) & hwif->swdma_mask)) ? 1 : 0));
+}
+
+EXPORT_SYMBOL(ide_dma_enable);
+
+/*
+ * Standard (generic) timings for PIO modes, from ATA2 specification.
+ * These timings are for access to the IDE data port register *only*.
+ * Some drives may specify a mode, while also specifying a different
+ * value for cycle_time (from drive identification data).
+ */
+const ide_pio_timings_t ide_pio_timings[6] = {
+ { 70, 165, 600 }, /* PIO Mode 0 */
+ { 50, 125, 383 }, /* PIO Mode 1 */
+ { 30, 100, 240 }, /* PIO Mode 2 */
+ { 30, 80, 180 }, /* PIO Mode 3 with IORDY */
+ { 25, 70, 120 }, /* PIO Mode 4 with IORDY */
+ { 20, 50, 100 } /* PIO Mode 5 with IORDY (nonstandard) */
+};
+
+EXPORT_SYMBOL_GPL(ide_pio_timings);
+
+/*
+ * Shared data/functions for determining best PIO mode for an IDE drive.
+ * Most of this stuff originally lived in cmd640.c, and changes to the
+ * ide_pio_blacklist[] table should be made with EXTREME CAUTION to avoid
+ * breaking the fragile cmd640.c support.
+ */
+
+/*
+ * Black list. Some drives incorrectly report their maximal PIO mode,
+ * at least in respect to CMD640. Here we keep info on some known drives.
+ */
+static struct ide_pio_info {
+ const char *name;
+ int pio;
+} ide_pio_blacklist [] = {
+/* { "Conner Peripherals 1275MB - CFS1275A", 4 }, */
+ { "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 AC21000", 4 }, */
+ { "WDC AC31000", 3 },
+ { "WDC AC31200", 3 },
+/* { "WDC AC31600", 4 }, */
+
+ { "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 },
+
+/* { "ST51080A", 4 },
+ * { "ST51270A", 4 },
+ * { "ST31220A", 4 },
+ * { "ST31640A", 4 },
+ * { "ST32140A", 4 },
+ * { "ST3780A", 4 },
+ */
+ { "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 Seagates 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[].
+ */
+
+static 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;
+}
+
+/**
+ * ide_get_best_pio_mode - get PIO mode from drive
+ * @driver: drive to consider
+ * @mode_wanted: preferred mode
+ * @max_mode: highest allowed
+ * @d: pio data
+ *
+ * This routine returns the recommended PIO settings for a given drive,
+ * based on the drive->id information and the ide_pio_blacklist[].
+ * This is used by most chipset support modules when "auto-tuning".
+ *
+ * Drive PIO mode auto selection
+ */
+
+u8 ide_get_best_pio_mode (ide_drive_t *drive, u8 mode_wanted, u8 max_mode, ide_pio_data_t *d)
+{
+ int pio_mode;
+ int cycle_time = 0;
+ int use_iordy = 0;
+ struct hd_driveid* id = drive->id;
+ int overridden = 0;
+ int blacklisted = 0;
+
+ if (mode_wanted != 255) {
+ pio_mode = mode_wanted;
+ } else if (!drive->id) {
+ pio_mode = 0;
+ } else if ((pio_mode = ide_scan_pio_blacklist(id->model)) != -1) {
+ overridden = 1;
+ blacklisted = 1;
+ use_iordy = (pio_mode > 2);
+ } else {
+ pio_mode = id->tPIO;
+ if (pio_mode > 2) { /* 2 is maximum allowed tPIO value */
+ pio_mode = 2;
+ overridden = 1;
+ }
+ if (id->field_valid & 2) { /* drive implements ATA2? */
+ if (id->capability & 8) { /* drive supports use_iordy? */
+ use_iordy = 1;
+ cycle_time = id->eide_pio_iordy;
+ if (id->eide_pio_modes & 7) {
+ overridden = 0;
+ if (id->eide_pio_modes & 4)
+ pio_mode = 5;
+ else if (id->eide_pio_modes & 2)
+ pio_mode = 4;
+ else
+ pio_mode = 3;
+ }
+ } else {
+ cycle_time = id->eide_pio;
+ }
+ }
+
+#if 0
+ if (drive->id->major_rev_num & 0x0004) printk("ATA-2 ");
+#endif
+
+ /*
+ * Conservative "downgrade" for all pre-ATA2 drives
+ */
+ if (pio_mode && pio_mode < 4) {
+ pio_mode--;
+ overridden = 1;
+#if 0
+ use_iordy = (pio_mode > 2);
+#endif
+ if (cycle_time && cycle_time < ide_pio_timings[pio_mode].cycle_time)
+ cycle_time = 0; /* use standard timing */
+ }
+ }
+ if (pio_mode > max_mode) {
+ pio_mode = max_mode;
+ cycle_time = 0;
+ }
+ if (d) {
+ d->pio_mode = pio_mode;
+ d->cycle_time = cycle_time ? cycle_time : ide_pio_timings[pio_mode].cycle_time;
+ d->use_iordy = use_iordy;
+ d->overridden = overridden;
+ d->blacklisted = blacklisted;
+ }
+ return pio_mode;
+}
+
+EXPORT_SYMBOL_GPL(ide_get_best_pio_mode);
+
+/**
+ * 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 (on && drive->media == ide_disk) {
+ if (!PCI_DMA_BUS_IS_PHYS)
+ addr = BLK_BOUNCE_ANY;
+ else if (HWIF(drive)->pci_dev)
+ addr = HWIF(drive)->pci_dev->dma_mask;
+ }
+
+ if (drive->queue)
+ blk_queue_bounce_limit(drive->queue, addr);
+}
+
+/**
+ * ide_set_xfer_rate - set transfer rate
+ * @drive: drive to set
+ * @speed: 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 speedproc() does not. High level drivers should never
+ * invoke speedproc() directly.
+ */
+
+int ide_set_xfer_rate(ide_drive_t *drive, u8 rate)
+{
+#ifndef CONFIG_BLK_DEV_IDEDMA
+ rate = min(rate, (u8) XFER_PIO_4);
+#endif
+ if(HWIF(drive)->speedproc)
+ return HWIF(drive)->speedproc(drive, rate);
+ else
+ return -1;
+}
+
+EXPORT_SYMBOL_GPL(ide_set_xfer_rate);
+
+static void ide_dump_opcode(ide_drive_t *drive)
+{
+ struct request *rq;
+ u8 opcode = 0;
+ int found = 0;
+
+ spin_lock(&ide_lock);
+ rq = NULL;
+ if (HWGROUP(drive))
+ rq = HWGROUP(drive)->rq;
+ spin_unlock(&ide_lock);
+ if (!rq)
+ return;
+ if (rq->flags & (REQ_DRIVE_CMD | REQ_DRIVE_TASK)) {
+ char *args = rq->buffer;
+ if (args) {
+ opcode = args[0];
+ found = 1;
+ }
+ } else if (rq->flags & REQ_DRIVE_TASKFILE) {
+ ide_task_t *args = rq->special;
+ if (args) {
+ task_struct_t *tf = (task_struct_t *) args->tfRegister;
+ opcode = tf->command;
+ found = 1;
+ }
+ }
+
+ printk("ide: failed opcode was: ");
+ if (!found)
+ printk("unknown\n");
+ else
+ printk("0x%02x\n", opcode);
+}
+
+static u8 ide_dump_ata_status(ide_drive_t *drive, const char *msg, u8 stat)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ unsigned long flags;
+ u8 err = 0;
+
+ local_irq_set(flags);
+ printk("%s: %s: status=0x%02x", drive->name, msg, stat);
+ printk(" { ");
+ if (stat & BUSY_STAT)
+ printk("Busy ");
+ else {
+ if (stat & READY_STAT) printk("DriveReady ");
+ if (stat & WRERR_STAT) printk("DeviceFault ");
+ if (stat & SEEK_STAT) printk("SeekComplete ");
+ if (stat & DRQ_STAT) printk("DataRequest ");
+ if (stat & ECC_STAT) printk("CorrectedError ");
+ if (stat & INDEX_STAT) printk("Index ");
+ if (stat & ERR_STAT) printk("Error ");
+ }
+ printk("}");
+ printk("\n");
+ if ((stat & (BUSY_STAT|ERR_STAT)) == ERR_STAT) {
+ err = hwif->INB(IDE_ERROR_REG);
+ printk("%s: %s: error=0x%02x", drive->name, msg, err);
+ printk(" { ");
+ if (err & ABRT_ERR) printk("DriveStatusError ");
+ if (err & ICRC_ERR)
+ printk("Bad%s ", (err & ABRT_ERR) ? "CRC" : "Sector");
+ if (err & ECC_ERR) printk("UncorrectableError ");
+ if (err & ID_ERR) printk("SectorIdNotFound ");
+ if (err & TRK0_ERR) printk("TrackZeroNotFound ");
+ if (err & MARK_ERR) printk("AddrMarkNotFound ");
+ printk("}");
+ if ((err & (BBD_ERR | ABRT_ERR)) == BBD_ERR ||
+ (err & (ECC_ERR|ID_ERR|MARK_ERR))) {
+ if (drive->addressing == 1) {
+ __u64 sectors = 0;
+ u32 low = 0, high = 0;
+ low = ide_read_24(drive);
+ hwif->OUTB(drive->ctl|0x80, IDE_CONTROL_REG);
+ high = ide_read_24(drive);
+ sectors = ((__u64)high << 24) | low;
+ printk(", LBAsect=%llu, high=%d, low=%d",
+ (unsigned long long) sectors,
+ high, low);
+ } else {
+ u8 cur = hwif->INB(IDE_SELECT_REG);
+ if (cur & 0x40) { /* using LBA? */
+ printk(", LBAsect=%ld", (unsigned long)
+ ((cur&0xf)<<24)
+ |(hwif->INB(IDE_HCYL_REG)<<16)
+ |(hwif->INB(IDE_LCYL_REG)<<8)
+ | hwif->INB(IDE_SECTOR_REG));
+ } else {
+ printk(", CHS=%d/%d/%d",
+ (hwif->INB(IDE_HCYL_REG)<<8) +
+ hwif->INB(IDE_LCYL_REG),
+ cur & 0xf,
+ hwif->INB(IDE_SECTOR_REG));
+ }
+ }
+ if (HWGROUP(drive) && HWGROUP(drive)->rq)
+ printk(", sector=%llu",
+ (unsigned long long)HWGROUP(drive)->rq->sector);
+ }
+ }
+ printk("\n");
+ ide_dump_opcode(drive);
+ local_irq_restore(flags);
+ return err;
+}
+
+/**
+ * ide_dump_atapi_status - print human readable atapi status
+ * @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).
+ */
+
+static u8 ide_dump_atapi_status(ide_drive_t *drive, const char *msg, u8 stat)
+{
+ unsigned long flags;
+
+ atapi_status_t status;
+ atapi_error_t error;
+
+ status.all = stat;
+ error.all = 0;
+ local_irq_set(flags);
+ printk("%s: %s: status=0x%02x { ", drive->name, msg, stat);
+ if (status.b.bsy)
+ printk("Busy ");
+ else {
+ if (status.b.drdy) printk("DriveReady ");
+ if (status.b.df) printk("DeviceFault ");
+ if (status.b.dsc) printk("SeekComplete ");
+ if (status.b.drq) printk("DataRequest ");
+ if (status.b.corr) printk("CorrectedError ");
+ if (status.b.idx) printk("Index ");
+ if (status.b.check) printk("Error ");
+ }
+ printk("}\n");
+ if (status.b.check && !status.b.bsy) {
+ error.all = HWIF(drive)->INB(IDE_ERROR_REG);
+ printk("%s: %s: error=0x%02x { ", drive->name, msg, error.all);
+ if (error.b.ili) printk("IllegalLengthIndication ");
+ if (error.b.eom) printk("EndOfMedia ");
+ if (error.b.abrt) printk("AbortedCommand ");
+ if (error.b.mcr) printk("MediaChangeRequested ");
+ if (error.b.sense_key) printk("LastFailedSense=0x%02x ",
+ error.b.sense_key);
+ printk("}\n");
+ }
+ ide_dump_opcode(drive);
+ local_irq_restore(flags);
+ return error.all;
+}
+
+/**
+ * ide_dump_status - translate ATA/ATAPI error
+ * @drive: drive the error occured on
+ * @msg: information string
+ * @stat: status byte
+ *
+ * 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)
+{
+ if (drive->media == ide_disk)
+ return ide_dump_ata_status(drive, msg, stat);
+ return ide_dump_atapi_status(drive, msg, stat);
+}
+
+EXPORT_SYMBOL(ide_dump_status);
diff --git a/drivers/ide/ide-pnp.c b/drivers/ide/ide-pnp.c
new file mode 100644
index 000000000000..df7d1504f84e
--- /dev/null
+++ b/drivers/ide/ide-pnp.c
@@ -0,0 +1,75 @@
+/*
+ * linux/drivers/ide/ide-pnp.c
+ *
+ * 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>
+
+/* 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)
+{
+ hw_regs_t hw;
+ ide_hwif_t *hwif;
+ int index;
+
+ if (!(pnp_port_valid(dev, 0) && pnp_port_valid(dev, 1) && pnp_irq_valid(dev, 0)))
+ return -1;
+
+ memset(&hw, 0, sizeof(hw));
+ ide_std_init_ports(&hw, pnp_port_start(dev, 0),
+ pnp_port_start(dev, 1));
+ hw.irq = pnp_irq(dev, 0);
+ hw.dma = NO_DMA;
+
+ index = ide_register_hw(&hw, &hwif);
+
+ if (index != -1) {
+ printk(KERN_INFO "ide%d: generic PnP IDE interface\n", index);
+ pnp_set_drvdata(dev,hwif);
+ return 0;
+ }
+
+ return -1;
+}
+
+static void idepnp_remove(struct pnp_dev * dev)
+{
+ ide_hwif_t *hwif = pnp_get_drvdata(dev);
+ if (hwif) {
+ ide_unregister(hwif->index);
+ } else
+ printk(KERN_ERR "idepnp: Unable to remove device, please report.\n");
+}
+
+static struct pnp_driver idepnp_driver = {
+ .name = "ide",
+ .id_table = idepnp_devices,
+ .probe = idepnp_probe,
+ .remove = idepnp_remove,
+};
+
+void __init pnpide_init(void)
+{
+ pnp_register_driver(&idepnp_driver);
+}
diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c
new file mode 100644
index 000000000000..554473a95cf7
--- /dev/null
+++ b/drivers/ide/ide-probe.c
@@ -0,0 +1,1421 @@
+/*
+ * linux/drivers/ide/ide-probe.c Version 1.11 Mar 05, 2003
+ *
+ * Copyright (C) 1994-1998 Linus Torvalds & authors (see below)
+ */
+
+/*
+ * 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.
+ *
+ * Version 1.00 move drive probing code from ide.c to ide-probe.c
+ * Version 1.01 fix compilation problem for m68k
+ * Version 1.02 increase WAIT_PIDENTIFY to avoid CD-ROM locking at boot
+ * by Andrea Arcangeli
+ * Version 1.03 fix for (hwif->chipset == ide_4drives)
+ * Version 1.04 fixed buggy treatments of known flash memory cards
+ *
+ * Version 1.05 fix for (hwif->chipset == ide_pdc4030)
+ * added ide6/7/8/9
+ * allowed for secondary flash card to be detectable
+ * with new flag : drive->ata_flash : 1;
+ * Version 1.06 stream line request queue and prep for cascade project.
+ * Version 1.07 max_sect <= 255; slower disks would get behind and
+ * then fall over when they get to 256. Paul G.
+ * Version 1.10 Update set for new IDE. drive->id is now always
+ * valid after probe time even with noprobe
+ */
+
+#undef REALLY_SLOW_IO /* most systems can safely undef this */
+
+#include <linux/config.h>
+#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 <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)
+{
+ drive->id->cyls = drive->cyl;
+ drive->id->heads = drive->head;
+ drive->id->sectors = drive->sect;
+ drive->id->cur_cyls = drive->cyl;
+ drive->id->cur_heads = drive->head;
+ drive->id->cur_sectors = drive->sect;
+}
+
+static void ide_disk_init_chs(ide_drive_t *drive)
+{
+ struct hd_driveid *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->cyls;
+ drive->head = drive->bios_head = id->heads;
+ drive->sect = drive->bios_sect = id->sectors;
+ }
+
+ /* Handle logical geometry translation by the drive */
+ if ((id->field_valid & 1) && id->cur_cyls &&
+ id->cur_heads && (id->cur_heads <= 16) && id->cur_sectors) {
+ drive->cyl = id->cur_cyls;
+ drive->head = id->cur_heads;
+ drive->sect = id->cur_sectors;
+ }
+
+ /* Use physical geometry if what we have still makes no sense */
+ if (drive->head > 16 && id->heads && id->heads <= 16) {
+ drive->cyl = id->cyls;
+ drive->head = id->heads;
+ drive->sect = id->sectors;
+ }
+}
+
+static void ide_disk_init_mult_count(ide_drive_t *drive)
+{
+ struct hd_driveid *id = drive->id;
+
+ drive->mult_count = 0;
+ if (id->max_multsect) {
+#ifdef CONFIG_IDEDISK_MULTI_MODE
+ id->multsect = ((id->max_multsect/2) > 1) ? id->max_multsect : 0;
+ id->multsect_valid = id->multsect ? 1 : 0;
+ drive->mult_req = id->multsect_valid ? id->max_multsect : INITIAL_MULT_COUNT;
+ drive->special.b.set_multmode = drive->mult_req ? 1 : 0;
+#else /* original, pre IDE-NFG, per request of AC */
+ drive->mult_req = INITIAL_MULT_COUNT;
+ if (drive->mult_req > id->max_multsect)
+ drive->mult_req = id->max_multsect;
+ if (drive->mult_req || ((id->multsect_valid & 1) && id->multsect))
+ drive->special.b.set_multmode = 1;
+#endif
+ }
+}
+
+/**
+ * drive_is_flashcard - check for compact flash
+ * @drive: drive to check
+ *
+ * CompactFlash cards and their brethern pretend to be removable
+ * hard disks, except:
+ * (1) they never have a slave unit, and
+ * (2) they don't have doorlock mechanisms.
+ * This test catches them, and is invoked elsewhere when setting
+ * appropriate config bits.
+ *
+ * FIXME: This treatment is probably applicable for *all* PCMCIA (PC CARD)
+ * devices, so in linux 2.3.x we should change this to just treat all
+ * PCMCIA drives this way, and get rid of the model-name tests below
+ * (too big of an interface change for 2.4.x).
+ * At that time, we might also consider parameterizing the timeouts and
+ * retries, since these are MUCH faster than mechanical drives. -M.Lord
+ */
+
+static inline int drive_is_flashcard (ide_drive_t *drive)
+{
+ struct hd_driveid *id = drive->id;
+
+ if (drive->removable) {
+ if (id->config == 0x848a) return 1; /* CompactFlash */
+ if (!strncmp(id->model, "KODAK ATA_FLASH", 15) /* Kodak */
+ || !strncmp(id->model, "Hitachi CV", 10) /* Hitachi */
+ || !strncmp(id->model, "SunDisk SDCFB", 13) /* old SanDisk */
+ || !strncmp(id->model, "SanDisk SDCFB", 13) /* SanDisk */
+ || !strncmp(id->model, "HAGIWARA HPC", 12) /* Hagiwara */
+ || !strncmp(id->model, "LEXAR ATA_FLASH", 15) /* Lexar */
+ || !strncmp(id->model, "ATA_FLASH", 9)) /* Simple Tech */
+ {
+ return 1; /* yes, it is a flash memory card */
+ }
+ }
+ return 0; /* no, it is not a flash memory card */
+}
+
+/**
+ * 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);
+ int bswap = 1;
+ struct hd_driveid *id;
+
+ id = drive->id;
+ /* read 512 bytes of id info */
+ hwif->ata_input_data(drive, id, SECTOR_WORDS);
+
+ drive->id_read = 1;
+ local_irq_enable();
+ ide_fix_driveid(id);
+
+#if defined (CONFIG_SCSI_EATA_DMA) || defined (CONFIG_SCSI_EATA_PIO) || defined (CONFIG_SCSI_EATA)
+ /*
+ * EATA SCSI controllers do a hardware ATA emulation:
+ * Ignore them if there is a driver for them available.
+ */
+ if ((id->model[0] == 'P' && id->model[1] == 'M') ||
+ (id->model[0] == 'S' && id->model[1] == 'K')) {
+ printk("%s: EATA SCSI HBA %.10s\n", drive->name, id->model);
+ goto err_misc;
+ }
+#endif /* CONFIG_SCSI_EATA_DMA || CONFIG_SCSI_EATA_PIO */
+
+ /*
+ * WIN_IDENTIFY returns little-endian info,
+ * WIN_PIDENTIFY *usually* returns little-endian info.
+ */
+ if (cmd == WIN_PIDENTIFY) {
+ if ((id->model[0] == 'N' && id->model[1] == 'E') /* NEC */
+ || (id->model[0] == 'F' && id->model[1] == 'X') /* Mitsumi */
+ || (id->model[0] == 'P' && id->model[1] == 'i'))/* Pioneer */
+ /* Vertos drives may still be weird */
+ bswap ^= 1;
+ }
+ ide_fixstring(id->model, sizeof(id->model), bswap);
+ ide_fixstring(id->fw_rev, sizeof(id->fw_rev), bswap);
+ ide_fixstring(id->serial_no, sizeof(id->serial_no), bswap);
+
+ if (strstr(id->model, "E X A B Y T E N E S T"))
+ goto err_misc;
+
+ /* we depend on this a lot! */
+ id->model[sizeof(id->model)-1] = '\0';
+ printk("%s: %s, ", drive->name, id->model);
+ drive->present = 1;
+ drive->dead = 0;
+
+ /*
+ * Check for an ATAPI device
+ */
+ if (cmd == WIN_PIDENTIFY) {
+ u8 type = (id->config >> 8) & 0x1f;
+ printk("ATAPI ");
+ switch (type) {
+ case ide_floppy:
+ if (!strstr(id->model, "CD-ROM")) {
+ if (!strstr(id->model, "oppy") &&
+ !strstr(id->model, "poyp") &&
+ !strstr(id->model, "ZIP"))
+ printk("cdrom or floppy?, assuming ");
+ if (drive->media != ide_cdrom) {
+ printk ("FLOPPY");
+ drive->removable = 1;
+ break;
+ }
+ }
+ /* Early cdrom models used zero */
+ type = ide_cdrom;
+ case ide_cdrom:
+ drive->removable = 1;
+#ifdef CONFIG_PPC
+ /* kludge for Apple PowerBook internal zip */
+ if (!strstr(id->model, "CD-ROM") &&
+ strstr(id->model, "ZIP")) {
+ printk ("FLOPPY");
+ type = ide_floppy;
+ break;
+ }
+#endif
+ printk ("CD/DVD-ROM");
+ break;
+ case ide_tape:
+ printk ("TAPE");
+ break;
+ case ide_optical:
+ printk ("OPTICAL");
+ drive->removable = 1;
+ break;
+ default:
+ printk("UNKNOWN (type %d)", type);
+ break;
+ }
+ printk (" drive\n");
+ drive->media = type;
+ /* an ATAPI device ignores DRDY */
+ drive->ready_stat = 0;
+ return;
+ }
+
+ /*
+ * Not an ATAPI device: looks like a "regular" hard disk
+ */
+ if (id->config & (1<<7))
+ drive->removable = 1;
+
+ if (drive_is_flashcard(drive))
+ drive->is_flash = 1;
+ drive->media = ide_disk;
+ printk("%s DISK drive\n", (drive->is_flash) ? "CFA" : "ATA" );
+ QUIRK_LIST(drive);
+ return;
+
+err_misc:
+ kfree(id);
+ drive->present = 0;
+ 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);
+ int rc;
+ unsigned long hd_status;
+ unsigned long timeout;
+ u8 s = 0, a = 0;
+
+ /* take a deep breath */
+ msleep(50);
+
+ if (IDE_CONTROL_REG) {
+ a = hwif->INB(IDE_ALTSTATUS_REG);
+ s = hwif->INB(IDE_STATUS_REG);
+ if ((a ^ s) & ~INDEX_STAT) {
+ printk(KERN_INFO "%s: probing with STATUS(0x%02x) instead of "
+ "ALTSTATUS(0x%02x)\n", drive->name, s, a);
+ /* ancient Seagate drives, broken interfaces */
+ hd_status = IDE_STATUS_REG;
+ } else {
+ /* use non-intrusive polling */
+ hd_status = IDE_ALTSTATUS_REG;
+ }
+ } else
+ hd_status = IDE_STATUS_REG;
+
+ /* set features register for atapi
+ * identify command to be sure of reply
+ */
+ if ((cmd == WIN_PIDENTIFY))
+ /* disable dma & overlap */
+ hwif->OUTB(0, IDE_FEATURE_REG);
+
+ /* ask drive for ID */
+ hwif->OUTB(cmd, IDE_COMMAND_REG);
+
+ timeout = ((cmd == WIN_IDENTIFY) ? WAIT_WORSTCASE : WAIT_PIDENTIFY) / 2;
+ timeout += jiffies;
+ do {
+ if (time_after(jiffies, timeout)) {
+ /* drive timed-out */
+ return 1;
+ }
+ /* give drive a breather */
+ msleep(50);
+ } while ((hwif->INB(hd_status)) & BUSY_STAT);
+
+ /* wait for IRQ and DRQ_STAT */
+ msleep(50);
+ if (OK_STAT((hwif->INB(IDE_STATUS_REG)), DRQ_STAT, 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) hwif->INB(IDE_STATUS_REG);
+ 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);
+ 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 (IDE_CONTROL_REG) {
+ u8 ctl = drive->ctl | 2;
+ if (!hwif->irq) {
+ autoprobe = 1;
+ cookie = probe_irq_on();
+ /* enable device irq */
+ ctl &= ~2;
+ }
+ hwif->OUTB(ctl, IDE_CONTROL_REG);
+ }
+
+ retval = actual_try_to_identify(drive, cmd);
+
+ if (autoprobe) {
+ int irq;
+ /* mask device irq */
+ hwif->OUTB(drive->ctl|2, IDE_CONTROL_REG);
+ /* clear drive IRQ */
+ (void) hwif->INB(IDE_STATUS_REG);
+ 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("%s: IRQ probe failed (0x%lx)\n",
+ drive->name, cookie);
+ }
+ }
+ }
+ return retval;
+}
+
+
+/**
+ * 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)
+{
+ int rc;
+ ide_hwif_t *hwif = HWIF(drive);
+
+ if (drive->present) {
+ /* avoid waiting for inappropriate probes */
+ if ((drive->media != ide_disk) && (cmd == WIN_IDENTIFY))
+ return 4;
+ }
+#ifdef DEBUG
+ printk("probing for %s: present=%d, media=%d, probetype=%s\n",
+ drive->name, drive->present, drive->media,
+ (cmd == WIN_IDENTIFY) ? "ATA" : "ATAPI");
+#endif
+
+ /* needed for some systems
+ * (e.g. crw9624 as drive0 with disk as slave)
+ */
+ msleep(50);
+ SELECT_DRIVE(drive);
+ msleep(50);
+ if (hwif->INB(IDE_SELECT_REG) != drive->select.all && !drive->present) {
+ if (drive->select.b.unit != 0) {
+ /* exit with drive0 selected */
+ SELECT_DRIVE(&hwif->drives[0]);
+ /* allow BUSY_STAT to assert & clear */
+ msleep(50);
+ }
+ /* no i/f present: mmm.. this should be a 4 -ml */
+ return 3;
+ }
+
+ if (OK_STAT((hwif->INB(IDE_STATUS_REG)), READY_STAT, BUSY_STAT) ||
+ drive->present || cmd == WIN_PIDENTIFY) {
+ /* send cmd and wait */
+ if ((rc = try_to_identify(drive, cmd))) {
+ /* failed: try again */
+ rc = try_to_identify(drive,cmd);
+ }
+ if (hwif->INB(IDE_STATUS_REG) == (BUSY_STAT|READY_STAT))
+ return 4;
+
+ if ((rc == 1 && cmd == WIN_PIDENTIFY) &&
+ ((drive->autotune == IDE_TUNE_DEFAULT) ||
+ (drive->autotune == IDE_TUNE_AUTO))) {
+ unsigned long timeout;
+ printk("%s: no response (status = 0x%02x), "
+ "resetting drive\n", drive->name,
+ hwif->INB(IDE_STATUS_REG));
+ msleep(50);
+ hwif->OUTB(drive->select.all, IDE_SELECT_REG);
+ msleep(50);
+ hwif->OUTB(WIN_SRST, IDE_COMMAND_REG);
+ timeout = jiffies;
+ while (((hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) &&
+ time_before(jiffies, timeout + WAIT_WORSTCASE))
+ msleep(50);
+ rc = try_to_identify(drive, cmd);
+ }
+ if (rc == 1)
+ printk("%s: no response (status = 0x%02x)\n",
+ drive->name, hwif->INB(IDE_STATUS_REG));
+ /* ensure drive irq is clear */
+ (void) hwif->INB(IDE_STATUS_REG);
+ } else {
+ /* not present or maybe ATAPI */
+ rc = 3;
+ }
+ if (drive->select.b.unit != 0) {
+ /* exit with drive0 selected */
+ SELECT_DRIVE(&hwif->drives[0]);
+ msleep(50);
+ /* ensure drive irq is clear */
+ (void) hwif->INB(IDE_STATUS_REG);
+ }
+ return rc;
+}
+
+/*
+ *
+ */
+static void enable_nest (ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ unsigned long timeout;
+
+ printk("%s: enabling %s -- ", hwif->name, drive->id->model);
+ SELECT_DRIVE(drive);
+ msleep(50);
+ hwif->OUTB(EXABYTE_ENABLE_NEST, IDE_COMMAND_REG);
+ timeout = jiffies + WAIT_WORSTCASE;
+ do {
+ if (time_after(jiffies, timeout)) {
+ printk("failed (timeout)\n");
+ return;
+ }
+ msleep(50);
+ } while ((hwif->INB(IDE_STATUS_REG)) & BUSY_STAT);
+
+ msleep(50);
+
+ if (!OK_STAT((hwif->INB(IDE_STATUS_REG)), 0, BAD_STAT)) {
+ printk("failed (status = 0x%02x)\n", hwif->INB(IDE_STATUS_REG));
+ } else {
+ printk("success\n");
+ }
+
+ /* if !(success||timed-out) */
+ if (do_probe(drive, WIN_IDENTIFY) >= 2) {
+ /* look for ATAPI device */
+ (void) do_probe(drive, WIN_PIDENTIFY);
+ }
+}
+
+/**
+ * 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: drive->present might
+ * still be 0)
+ */
+
+static inline u8 probe_for_drive (ide_drive_t *drive)
+{
+ /*
+ * 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->id = kmalloc(SECTOR_WORDS *4, GFP_KERNEL);
+ drive->id_read = 0;
+ if(drive->id == NULL)
+ {
+ printk(KERN_ERR "ide: out of memory for id data.\n");
+ return 0;
+ }
+ memset(drive->id, 0, SECTOR_WORDS * 4);
+ strcpy(drive->id->model, "UNKNOWN");
+
+ /* skip probing? */
+ if (!drive->noprobe)
+ {
+ /* if !(success||timed-out) */
+ if (do_probe(drive, WIN_IDENTIFY) >= 2) {
+ /* look for ATAPI device */
+ (void) do_probe(drive, WIN_PIDENTIFY);
+ }
+ if (strstr(drive->id->model, "E X A B Y T E N E S T"))
+ enable_nest(drive);
+ if (!drive->present)
+ /* drive not found */
+ return 0;
+
+ /* identification failed? */
+ if (!drive->id_read) {
+ 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->present = 0;
+ }
+ }
+ /* drive was found */
+ }
+ if(!drive->present)
+ return 0;
+ /* The drive wasn't being helpful. Add generic info only */
+ if (drive->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->present;
+}
+
+static void hwif_release_dev (struct device *dev)
+{
+ ide_hwif_t *hwif = container_of(dev, ide_hwif_t, gendev);
+
+ up(&hwif->gendev_rel_sem);
+}
+
+static void hwif_register (ide_hwif_t *hwif)
+{
+ /* 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->pci_dev)
+ hwif->gendev.parent = &hwif->pci_dev->dev;
+ else
+ /* Would like to do = &device_legacy */
+ hwif->gendev.parent = NULL;
+ }
+ hwif->gendev.release = hwif_release_dev;
+ device_register(&hwif->gendev);
+}
+
+static int wait_hwif_ready(ide_hwif_t *hwif)
+{
+ int 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 */
+ SELECT_DRIVE(&hwif->drives[0]);
+ hwif->OUTB(8, hwif->io_ports[IDE_CONTROL_OFFSET]);
+ mdelay(2);
+ rc = ide_wait_not_busy(hwif, 10000);
+ if (rc)
+ return rc;
+ SELECT_DRIVE(&hwif->drives[1]);
+ hwif->OUTB(8, hwif->io_ports[IDE_CONTROL_OFFSET]);
+ mdelay(2);
+ rc = ide_wait_not_busy(hwif, 10000);
+
+ /* Exit function with master reselected (let's be sane) */
+ SELECT_DRIVE(&hwif->drives[0]);
+
+ return rc;
+}
+
+/**
+ * ide_undecoded_slave - look for bad CF adapters
+ * @hwif: interface
+ *
+ * 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_hwif_t *hwif)
+{
+ ide_drive_t *drive0 = &hwif->drives[0];
+ ide_drive_t *drive1 = &hwif->drives[1];
+
+ if (drive0->present == 0 || drive1->present == 0)
+ return;
+
+ /* If the models don't match they are not the same product */
+ if (strcmp(drive0->id->model, drive1->id->model))
+ return;
+
+ /* Serial numbers do not match */
+ if (strncmp(drive0->id->serial_no, drive1->id->serial_no, 20))
+ return;
+
+ /* No serial number, thankfully very rare for CF */
+ if (drive0->id->serial_no[0] == 0)
+ return;
+
+ /* Appears to be an IDE flash adapter with decode bugs */
+ printk(KERN_WARNING "ide-probe: ignoring undecoded slave\n");
+
+ drive1->present = 0;
+}
+
+EXPORT_SYMBOL_GPL(ide_undecoded_slave);
+
+/*
+ * This routine only knows how to look for drive units 0 and 1
+ * on an interface, so any setting of MAX_DRIVES > 2 won't work here.
+ */
+static void probe_hwif(ide_hwif_t *hwif)
+{
+ unsigned int unit;
+ unsigned long flags;
+ unsigned int irqd;
+
+ if (hwif->noprobe)
+ return;
+
+ if ((hwif->chipset != ide_4drives || !hwif->mate || !hwif->mate->present) &&
+ (ide_hwif_request_regions(hwif))) {
+ u16 msgout = 0;
+ for (unit = 0; unit < MAX_DRIVES; ++unit) {
+ ide_drive_t *drive = &hwif->drives[unit];
+ if (drive->present) {
+ drive->present = 0;
+ printk(KERN_ERR "%s: ERROR, PORTS ALREADY IN USE\n",
+ drive->name);
+ msgout = 1;
+ }
+ }
+ if (!msgout)
+ printk(KERN_ERR "%s: ports already in use, skipping probe\n",
+ hwif->name);
+ return;
+ }
+
+ /*
+ * 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);
+
+ /* 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-busy should not harm any existing configuration
+ * (at least things won't be worse than what current code does, that
+ * is blindly go & talk to the drive) and fix some issues like the
+ * above.
+ *
+ * BenH.
+ */
+ if (wait_hwif_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];
+ drive->dn = (hwif->channel ? 2 : 0) + unit;
+ (void) probe_for_drive(drive);
+ if (drive->present && !hwif->present) {
+ hwif->present = 1;
+ if (hwif->chipset != ide_4drives ||
+ !hwif->mate ||
+ !hwif->mate->present) {
+ hwif_register(hwif);
+ }
+ }
+ }
+ if (hwif->io_ports[IDE_CONTROL_OFFSET] && hwif->reset) {
+ unsigned long timeout = jiffies + WAIT_WORSTCASE;
+ u8 stat;
+
+ printk(KERN_WARNING "%s: reset\n", hwif->name);
+ hwif->OUTB(12, hwif->io_ports[IDE_CONTROL_OFFSET]);
+ udelay(10);
+ hwif->OUTB(8, hwif->io_ports[IDE_CONTROL_OFFSET]);
+ do {
+ msleep(50);
+ stat = hwif->INB(hwif->io_ports[IDE_STATUS_OFFSET]);
+ } while ((stat & BUSY_STAT) && time_after(timeout, jiffies));
+
+ }
+ local_irq_restore(flags);
+ /*
+ * Use cached IRQ number. It might be (and is...) changed by probe
+ * code above
+ */
+ if (irqd)
+ enable_irq(irqd);
+
+ if (!hwif->present) {
+ ide_hwif_release_regions(hwif);
+ return;
+ }
+
+ for (unit = 0; unit < MAX_DRIVES; ++unit) {
+ ide_drive_t *drive = &hwif->drives[unit];
+
+ if (drive->present) {
+ if (hwif->tuneproc != NULL &&
+ drive->autotune == IDE_TUNE_AUTO)
+ /* auto-tune PIO mode */
+ hwif->tuneproc(drive, 255);
+
+ if (drive->autotune != IDE_TUNE_DEFAULT &&
+ drive->autotune != IDE_TUNE_AUTO)
+ continue;
+
+ drive->nice1 = 1;
+
+ /*
+ * MAJOR HACK BARF :-/
+ *
+ * FIXME: chipsets own this cruft!
+ */
+ /*
+ * Move here to prevent module loading clashing.
+ */
+ // drive->autodma = hwif->autodma;
+ if (hwif->ide_dma_check) {
+ /*
+ * Force DMAing for the beginning of the check.
+ * Some chipsets appear to do interesting
+ * things, if not checked and cleared.
+ * PARANOIA!!!
+ */
+ hwif->ide_dma_off_quietly(drive);
+#ifdef CONFIG_IDEDMA_ONLYDISK
+ if (drive->media == ide_disk)
+#endif
+ hwif->ide_dma_check(drive);
+ }
+ }
+ }
+}
+
+static int hwif_init(ide_hwif_t *hwif);
+
+int probe_hwif_init_with_fixup(ide_hwif_t *hwif, void (*fixup)(ide_hwif_t *hwif))
+{
+ probe_hwif(hwif);
+
+ if (fixup)
+ fixup(hwif);
+
+ if (!hwif_init(hwif)) {
+ printk(KERN_INFO "%s: failed to initialize IDE interface\n",
+ hwif->name);
+ return -1;
+ }
+
+ if (hwif->present) {
+ u16 unit = 0;
+ for (unit = 0; unit < MAX_DRIVES; ++unit) {
+ ide_drive_t *drive = &hwif->drives[unit];
+ /* For now don't attach absent drives, we may
+ want them on default or a new "empty" class
+ for hotplug reprobing ? */
+ if (drive->present) {
+ ata_attach(drive);
+ }
+ }
+ }
+ return 0;
+}
+
+int probe_hwif_init(ide_hwif_t *hwif)
+{
+ return probe_hwif_init_with_fixup(hwif, NULL);
+}
+
+EXPORT_SYMBOL(probe_hwif_init);
+
+#if MAX_HWIFS > 1
+/*
+ * 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("%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;
+}
+#endif /* MAX_HWIFS > 1 */
+
+/*
+ * init request queue
+ */
+static int ide_init_queue(ide_drive_t *drive)
+{
+ request_queue_t *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(do_ide_request, &ide_lock);
+ if (!q)
+ return 1;
+
+ q->queuedata = drive;
+ blk_queue_segment_boundary(q, 0xffff);
+
+ if (!hwif->rqsize) {
+ if (hwif->no_lba48 || hwif->no_lba48_dma)
+ hwif->rqsize = 256;
+ else
+ hwif->rqsize = 65536;
+ }
+ 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);
+
+ /* enable led activity for disk drives only */
+ if (drive->media == ide_disk && hwif->led_act)
+ blk_queue_activity_fn(q, hwif->led_act, drive);
+
+ return 0;
+}
+
+/*
+ * 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.
+ *
+ * The SA_INTERRUPT in sa_flags means ide_intr() is always entered with
+ * interrupts completely disabled. This can be bad for interrupt latency,
+ * but anything else has led to problems on some machines. We re-enable
+ * interrupts as much as we can safely do in most places.
+ */
+static int init_irq (ide_hwif_t *hwif)
+{
+ unsigned int index;
+ ide_hwgroup_t *hwgroup;
+ ide_hwif_t *match = NULL;
+
+
+ BUG_ON(in_interrupt());
+ BUG_ON(irqs_disabled());
+ down(&ide_cfg_sem);
+ hwif->hwgroup = NULL;
+#if MAX_HWIFS > 1
+ /*
+ * Group up with any other hwifs that share our irq(s).
+ */
+ for (index = 0; index < MAX_HWIFS; index++) {
+ ide_hwif_t *h = &ide_hwifs[index];
+ if (h->hwgroup) { /* scan only initialized hwif's */
+ 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);
+ }
+ }
+ }
+#endif /* MAX_HWIFS > 1 */
+ /*
+ * 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;
+ spin_unlock_irq(&ide_lock);
+ } else {
+ hwgroup = kmalloc(sizeof(ide_hwgroup_t),GFP_KERNEL);
+ if (!hwgroup)
+ goto out_up;
+
+ hwif->hwgroup = hwgroup;
+
+ memset(hwgroup, 0, sizeof(ide_hwgroup_t));
+ hwgroup->hwif = hwif->next = hwif;
+ hwgroup->rq = NULL;
+ hwgroup->handler = NULL;
+ hwgroup->drive = NULL;
+ hwgroup->busy = 0;
+ init_timer(&hwgroup->timer);
+ hwgroup->timer.function = &ide_timer_expiry;
+ hwgroup->timer.data = (unsigned long) hwgroup;
+ }
+
+ /*
+ * Allocate the irq, if not already obtained for another hwif
+ */
+ if (!match || match->irq != hwif->irq) {
+ int sa = SA_INTERRUPT;
+#if defined(__mc68000__) || defined(CONFIG_APUS)
+ sa = SA_SHIRQ;
+#endif /* __mc68000__ || CONFIG_APUS */
+
+ if (IDE_CHIPSET_IS_PCI(hwif->chipset)) {
+ sa = SA_SHIRQ;
+#ifndef CONFIG_IDEPCI_SHARE_IRQ
+ sa |= SA_INTERRUPT;
+#endif /* CONFIG_IDEPCI_SHARE_IRQ */
+ }
+
+ if (hwif->io_ports[IDE_CONTROL_OFFSET])
+ /* clear nIEN */
+ hwif->OUTB(0x08, hwif->io_ports[IDE_CONTROL_OFFSET]);
+
+ if (request_irq(hwif->irq,&ide_intr,sa,hwif->name,hwgroup))
+ goto out_unlink;
+ }
+
+ /*
+ * For any present drive:
+ * - allocate the block device queue
+ * - link drive into the hwgroup
+ */
+ for (index = 0; index < MAX_DRIVES; ++index) {
+ ide_drive_t *drive = &hwif->drives[index];
+ if (!drive->present)
+ continue;
+ if (ide_init_queue(drive)) {
+ printk(KERN_ERR "ide: failed to init %s\n",drive->name);
+ continue;
+ }
+ 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);
+ }
+
+#if !defined(__mc68000__) && !defined(CONFIG_APUS) && !defined(__sparc__)
+ printk("%s at 0x%03lx-0x%03lx,0x%03lx on irq %d", hwif->name,
+ hwif->io_ports[IDE_DATA_OFFSET],
+ hwif->io_ports[IDE_DATA_OFFSET]+7,
+ hwif->io_ports[IDE_CONTROL_OFFSET], hwif->irq);
+#elif defined(__sparc__)
+ printk("%s at 0x%03lx-0x%03lx,0x%03lx on irq %s", hwif->name,
+ hwif->io_ports[IDE_DATA_OFFSET],
+ hwif->io_ports[IDE_DATA_OFFSET]+7,
+ hwif->io_ports[IDE_CONTROL_OFFSET], __irq_itoa(hwif->irq));
+#else
+ printk("%s at 0x%08lx on irq %d", hwif->name,
+ hwif->io_ports[IDE_DATA_OFFSET], hwif->irq);
+#endif /* __mc68000__ && CONFIG_APUS */
+ if (match)
+ printk(" (%sed with %s)",
+ hwif->sharing_irq ? "shar" : "serializ", match->name);
+ printk("\n");
+ up(&ide_cfg_sem);
+ return 0;
+out_unlink:
+ spin_lock_irq(&ide_lock);
+ if (hwif->next == hwif) {
+ BUG_ON(match);
+ BUG_ON(hwgroup->hwif != hwif);
+ kfree(hwgroup);
+ } else {
+ ide_hwif_t *g;
+ g = hwgroup->hwif;
+ while (g->next != hwif)
+ g = g->next;
+ g->next = hwif->next;
+ if (hwgroup->hwif == hwif) {
+ /* Impossible. */
+ printk(KERN_ERR "Duh. Uninitialized hwif listed as active hwif.\n");
+ hwgroup->hwif = g;
+ }
+ BUG_ON(hwgroup->hwif == hwif);
+ }
+ spin_unlock_irq(&ide_lock);
+out_up:
+ up(&ide_cfg_sem);
+ 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->present)
+ return NULL;
+
+ if (drive->media == ide_disk)
+ request_module("ide-disk");
+ if (drive->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 &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->select.all >> 4) & 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 drive_release_dev (struct device *dev)
+{
+ ide_drive_t *drive = container_of(dev, ide_drive_t, gendev);
+
+ up(&drive->gendev_rel_sem);
+}
+
+/*
+ * init_gendisk() (as opposed to ide_geninit) is called for each major device,
+ * after probing for drives, to allocate partition tables and other data
+ * structures needed for the routines in genhd.c. ide_geninit() gets called
+ * somewhat later, during the partition check.
+ */
+static void init_gendisk (ide_hwif_t *hwif)
+{
+ unsigned int unit;
+
+ for (unit = 0; unit < MAX_DRIVES; ++unit) {
+ ide_drive_t * drive = &hwif->drives[unit];
+ ide_add_generic_settings(drive);
+ snprintf(drive->gendev.bus_id,BUS_ID_SIZE,"%u.%u",
+ hwif->index,unit);
+ drive->gendev.parent = &hwif->gendev;
+ drive->gendev.bus = &ide_bus_type;
+ drive->gendev.driver_data = drive;
+ drive->gendev.release = drive_release_dev;
+ if (drive->present) {
+ device_register(&drive->gendev);
+ sprintf(drive->devfs_name, "ide/host%d/bus%d/target%d/lun%d",
+ (hwif->channel && hwif->mate) ?
+ hwif->mate->index : hwif->index,
+ hwif->channel, unit, drive->lun);
+ }
+ }
+ blk_register_region(MKDEV(hwif->major, 0), MAX_DRIVES << PARTN_BITS,
+ THIS_MODULE, ata_probe, ata_lock, hwif);
+}
+
+static int hwif_init(ide_hwif_t *hwif)
+{
+ int old_irq;
+
+ /* Return success if no device is connected */
+ if (!hwif->present)
+ return 1;
+
+ if (!hwif->irq) {
+ if (!(hwif->irq = ide_default_irq(hwif->io_ports[IDE_DATA_OFFSET])))
+ {
+ printk("%s: DISABLED, NO IRQ\n", hwif->name);
+ return (hwif->present = 0);
+ }
+ }
+#ifdef CONFIG_BLK_DEV_HD
+ if (hwif->irq == HD_IRQ && hwif->io_ports[IDE_DATA_OFFSET] != HD_DATA) {
+ printk("%s: CANNOT SHARE IRQ WITH OLD "
+ "HARDDISK DRIVER (hd.c)\n", hwif->name);
+ return (hwif->present = 0);
+ }
+#endif /* CONFIG_BLK_DEV_HD */
+
+ /* we set it back to 1 if all is ok below */
+ hwif->present = 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;
+ }
+
+ 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.
+ */
+ if (!(hwif->irq = ide_default_irq(hwif->io_ports[IDE_DATA_OFFSET]))) {
+ printk("%s: Disabled unable to get IRQ %d.\n",
+ hwif->name, old_irq);
+ goto out;
+ }
+ if (init_irq(hwif)) {
+ printk("%s: probed IRQ %d and default IRQ %d failed.\n",
+ hwif->name, old_irq, hwif->irq);
+ goto out;
+ }
+ printk("%s: probed IRQ %d failed, using default.\n",
+ hwif->name, hwif->irq);
+
+done:
+ init_gendisk(hwif);
+ hwif->present = 1; /* success */
+ return 1;
+
+out:
+ unregister_blkdev(hwif->major, hwif->name);
+ return 0;
+}
+
+int ideprobe_init (void)
+{
+ unsigned int index;
+ int probe[MAX_HWIFS];
+
+ memset(probe, 0, MAX_HWIFS * sizeof(int));
+ for (index = 0; index < MAX_HWIFS; ++index)
+ probe[index] = !ide_hwifs[index].present;
+
+ for (index = 0; index < MAX_HWIFS; ++index)
+ if (probe[index])
+ probe_hwif(&ide_hwifs[index]);
+ for (index = 0; index < MAX_HWIFS; ++index)
+ if (probe[index])
+ hwif_init(&ide_hwifs[index]);
+ for (index = 0; index < MAX_HWIFS; ++index) {
+ if (probe[index]) {
+ ide_hwif_t *hwif = &ide_hwifs[index];
+ int unit;
+ if (!hwif->present)
+ continue;
+ if (hwif->chipset == ide_unknown || hwif->chipset == ide_forced)
+ hwif->chipset = ide_generic;
+ for (unit = 0; unit < MAX_DRIVES; ++unit)
+ if (hwif->drives[unit].present)
+ ata_attach(&hwif->drives[unit]);
+ }
+ }
+ return 0;
+}
+
+EXPORT_SYMBOL_GPL(ideprobe_init);
diff --git a/drivers/ide/ide-proc.c b/drivers/ide/ide-proc.c
new file mode 100644
index 000000000000..bdff5ac58053
--- /dev/null
+++ b/drivers/ide/ide-proc.c
@@ -0,0 +1,521 @@
+/*
+ * linux/drivers/ide/ide-proc.c Version 1.05 Mar 05, 2003
+ *
+ * Copyright (C) 1997-1998 Mark Lord
+ * Copyright (C) 2003 Red Hat <alan@redhat.com>
+ */
+
+/*
+ * 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
+ *
+ * Also useful, "cat /proc/ide0/hda/[identify, smart_values,
+ * smart_thresholds, capabilities]" will issue an IDENTIFY /
+ * PACKET_IDENTIFY / SMART_READ_VALUES / SMART_READ_THRESHOLDS /
+ * SENSE CAPABILITIES command to /dev/hda, and then dump out the
+ * returned data as 256 16-bit words. The "hdparm" utility will
+ * be updated someday soon to use this mechanism.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <asm/uaccess.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+#include <linux/mm.h>
+#include <linux/pci.h>
+#include <linux/ctype.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/seq_file.h>
+
+#include <asm/io.h>
+
+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;
+
+ /*
+ * Neither ide_unknown nor ide_forced should be set at this point.
+ */
+ 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;
+ 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 && hwif->mate->present)
+ 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) {
+ unsigned short *val = (unsigned short *) page;
+
+ err = taskfile_lib_get_identify(drive, page);
+ if (!err) {
+ char *out = ((char *)page) + (SECTOR_WORDS * 4);
+ page = out;
+ do {
+ out += sprintf(out, "%04x%c",
+ le16_to_cpu(*val), (++i & 7) ? ' ' : '\n');
+ val += 1;
+ } while (i < (SECTOR_WORDS * 2));
+ len = out - page;
+ }
+ }
+ PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+}
+
+static void proc_ide_settings_warn(void)
+{
+ static int warned = 0;
+
+ 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)
+{
+ ide_drive_t *drive = (ide_drive_t *) data;
+ ide_settings_t *setting = (ide_settings_t *) drive->settings;
+ char *out = page;
+ int len, rc, mul_factor, div_factor;
+
+ proc_ide_settings_warn();
+
+ down(&ide_setting_sem);
+ 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(setting) {
+ mul_factor = setting->mul_factor;
+ div_factor = setting->div_factor;
+ out += sprintf(out, "%-24s", setting->name);
+ if ((rc = ide_read_setting(drive, setting)) >= 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);
+ if (setting->rw & SETTING_READ)
+ out += sprintf(out, "r");
+ if (setting->rw & SETTING_WRITE)
+ out += sprintf(out, "w");
+ out += sprintf(out, "\n");
+ setting = setting->next;
+ }
+ len = out - page;
+ up(&ide_setting_sem);
+ 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;
+ unsigned long n;
+ ide_settings_t *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;
+ }
+
+ down(&ide_setting_sem);
+ setting = ide_find_setting_by_name(drive, name);
+ if (!setting)
+ {
+ up(&ide_setting_sem);
+ goto parse_error;
+ }
+ if (for_real)
+ ide_write_setting(drive, setting, val * setting->div_factor / setting->mul_factor);
+ up(&ide_setting_sem);
+ }
+ } 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;
+ struct hd_driveid *id = drive->id;
+ int len;
+
+ len = sprintf(page, "%.40s\n",
+ (id && id->model[0]) ? (char *)id->model : "(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;
+ ide_driver_t *driver = drive->driver;
+ int len;
+
+ if (driver) {
+ len = sprintf(page, "%s version %s\n",
+ driver->name, driver->version);
+ } else
+ len = sprintf(page, "ide-default version 0.9.newide\n");
+ PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+}
+
+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;
+ 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 }
+};
+
+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->nlink = 1;
+ ent->data = data;
+ ent->read_proc = p->read_proc;
+ ent->write_proc = p->write_proc;
+ p++;
+ }
+}
+
+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++;
+ }
+}
+
+static void create_proc_ide_drives(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->present)
+ continue;
+ if (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;
+ }
+}
+
+static void destroy_proc_ide_device(ide_hwif_t *hwif, 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, hwif->proc);
+ drive->proc = NULL;
+ }
+}
+
+static void destroy_proc_ide_drives(ide_hwif_t *hwif)
+{
+ int d;
+
+ for (d = 0; d < MAX_DRIVES; d++) {
+ ide_drive_t *drive = &hwif->drives[d];
+ if (drive->proc)
+ destroy_proc_ide_device(hwif, drive);
+ }
+}
+
+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 create_proc_ide_interfaces(void)
+{
+ int h;
+
+ for (h = 0; h < MAX_HWIFS; h++) {
+ ide_hwif_t *hwif = &ide_hwifs[h];
+
+ if (!hwif->present)
+ continue;
+ 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);
+ }
+ create_proc_ide_drives(hwif);
+ }
+}
+
+EXPORT_SYMBOL(create_proc_ide_interfaces);
+
+#ifdef CONFIG_BLK_DEV_IDEPCI
+void ide_pci_create_host_proc(const char *name, get_info_t *get_info)
+{
+ create_proc_info_entry(name, 0, proc_ide_root, get_info);
+}
+
+EXPORT_SYMBOL_GPL(ide_pci_create_host_proc);
+#endif
+
+void destroy_proc_ide_interface(ide_hwif_t *hwif)
+{
+ if (hwif->proc) {
+ destroy_proc_ide_drives(hwif);
+ ide_remove_proc_entries(hwif->proc, hwif_entries);
+ remove_proc_entry(hwif->name, proc_ide_root);
+ hwif->proc = NULL;
+ }
+}
+
+extern struct seq_operations ide_drivers_op;
+static int ide_drivers_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &ide_drivers_op);
+}
+static struct file_operations ide_drivers_operations = {
+ .open = ide_drivers_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+void proc_ide_create(void)
+{
+ struct proc_dir_entry *entry;
+
+ if (!proc_ide_root)
+ return;
+
+ create_proc_ide_interfaces();
+
+ entry = create_proc_entry("drivers", 0, proc_ide_root);
+ if (entry)
+ entry->proc_fops = &ide_drivers_operations;
+}
+
+void proc_ide_destroy(void)
+{
+ remove_proc_entry("ide/drivers", proc_ide_root);
+ remove_proc_entry("ide", NULL);
+}
diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c
new file mode 100644
index 000000000000..482544854985
--- /dev/null
+++ b/drivers/ide/ide-tape.c
@@ -0,0 +1,4937 @@
+/*
+ * linux/drivers/ide/ide-tape.c Version 1.19 Nov, 2003
+ *
+ * Copyright (C) 1995 - 1999 Gadi Oxman <gadio@netvision.net.il>
+ *
+ * $Header$
+ *
+ * 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).
+ */
+
+/*
+ * IDE ATAPI streaming tape driver.
+ *
+ * This driver is a part of the Linux ide driver and works in co-operation
+ * with linux/drivers/block/ide.c.
+ *
+ * The driver, in co-operation with ide.c, basically traverses the
+ * request-list for the block device interface. The character device
+ * interface, on the other hand, creates new requests, adds them
+ * to the request-list of the block device, and waits for their completion.
+ *
+ * Pipelined operation mode is now supported on both reads and writes.
+ *
+ * The block device major and minor numbers are determined from the
+ * tape's relative position in the ide interfaces, as explained in ide.c.
+ *
+ * The character device interface consists of the following devices:
+ *
+ * ht0 major 37, minor 0 first IDE tape, rewind on close.
+ * ht1 major 37, minor 1 second IDE tape, rewind on close.
+ * ...
+ * nht0 major 37, minor 128 first IDE tape, no rewind on close.
+ * nht1 major 37, minor 129 second IDE tape, no rewind on close.
+ * ...
+ *
+ * Run linux/scripts/MAKEDEV.ide to create the above entries.
+ *
+ * The general magnetic tape commands compatible interface, as defined by
+ * include/linux/mtio.h, is accessible through the character device.
+ *
+ * General ide driver configuration options, such as the interrupt-unmask
+ * flag, can be configured by issuing an ioctl to the block device interface,
+ * as any other ide device.
+ *
+ * Our own ide-tape ioctl's can be issued to either the block device or
+ * the character device interface.
+ *
+ * Maximal throughput with minimal bus load will usually be achieved in the
+ * following scenario:
+ *
+ * 1. ide-tape is operating in the pipelined operation mode.
+ * 2. No buffering is performed by the user backup program.
+ *
+ * Testing was done with a 2 GB CONNER CTMA 4000 IDE ATAPI Streaming Tape Drive.
+ *
+ * Ver 0.1 Nov 1 95 Pre-working code :-)
+ * Ver 0.2 Nov 23 95 A short backup (few megabytes) and restore procedure
+ * was successful ! (Using tar cvf ... on the block
+ * device interface).
+ * A longer backup resulted in major swapping, bad
+ * overall Linux performance and eventually failed as
+ * we received non serial read-ahead requests from the
+ * buffer cache.
+ * Ver 0.3 Nov 28 95 Long backups are now possible, thanks to the
+ * character device interface. Linux's responsiveness
+ * and performance doesn't seem to be much affected
+ * from the background backup procedure.
+ * Some general mtio.h magnetic tape operations are
+ * now supported by our character device. As a result,
+ * popular tape utilities are starting to work with
+ * ide tapes :-)
+ * The following configurations were tested:
+ * 1. An IDE ATAPI TAPE shares the same interface
+ * and irq with an IDE ATAPI CDROM.
+ * 2. An IDE ATAPI TAPE shares the same interface
+ * and irq with a normal IDE disk.
+ * Both configurations seemed to work just fine !
+ * However, to be on the safe side, it is meanwhile
+ * recommended to give the IDE TAPE its own interface
+ * and irq.
+ * The one thing which needs to be done here is to
+ * add a "request postpone" feature to ide.c,
+ * so that we won't have to wait for the tape to finish
+ * performing a long media access (DSC) request (such
+ * as a rewind) before we can access the other device
+ * on the same interface. This effect doesn't disturb
+ * normal operation most of the time because read/write
+ * requests are relatively fast, and once we are
+ * performing one tape r/w request, a lot of requests
+ * from the other device can be queued and ide.c will
+ * service all of them after this single tape request.
+ * Ver 1.0 Dec 11 95 Integrated into Linux 1.3.46 development tree.
+ * On each read / write request, we now ask the drive
+ * if we can transfer a constant number of bytes
+ * (a parameter of the drive) only to its buffers,
+ * without causing actual media access. If we can't,
+ * we just wait until we can by polling the DSC bit.
+ * This ensures that while we are not transferring
+ * more bytes than the constant referred to above, the
+ * interrupt latency will not become too high and
+ * we won't cause an interrupt timeout, as happened
+ * occasionally in the previous version.
+ * While polling for DSC, the current request is
+ * postponed and ide.c is free to handle requests from
+ * the other device. This is handled transparently to
+ * ide.c. The hwgroup locking method which was used
+ * in the previous version was removed.
+ * Use of new general features which are provided by
+ * ide.c for use with atapi devices.
+ * (Programming done by Mark Lord)
+ * Few potential bug fixes (Again, suggested by Mark)
+ * Single character device data transfers are now
+ * not limited in size, as they were before.
+ * We are asking the tape about its recommended
+ * transfer unit and send a larger data transfer
+ * as several transfers of the above size.
+ * For best results, use an integral number of this
+ * basic unit (which is shown during driver
+ * initialization). I will soon add an ioctl to get
+ * this important parameter.
+ * Our data transfer buffer is allocated on startup,
+ * rather than before each data transfer. This should
+ * ensure that we will indeed have a data buffer.
+ * Ver 1.1 Dec 14 95 Fixed random problems which occurred when the tape
+ * shared an interface with another device.
+ * (poll_for_dsc was a complete mess).
+ * Removed some old (non-active) code which had
+ * to do with supporting buffer cache originated
+ * requests.
+ * The block device interface can now be opened, so
+ * that general ide driver features like the unmask
+ * interrupts flag can be selected with an ioctl.
+ * This is the only use of the block device interface.
+ * New fast pipelined operation mode (currently only on
+ * writes). When using the pipelined mode, the
+ * throughput can potentially reach the maximum
+ * tape supported throughput, regardless of the
+ * user backup program. On my tape drive, it sometimes
+ * boosted performance by a factor of 2. Pipelined
+ * mode is enabled by default, but since it has a few
+ * downfalls as well, you may want to disable it.
+ * A short explanation of the pipelined operation mode
+ * is available below.
+ * Ver 1.2 Jan 1 96 Eliminated pipelined mode race condition.
+ * Added pipeline read mode. As a result, restores
+ * are now as fast as backups.
+ * Optimized shared interface behavior. The new behavior
+ * typically results in better IDE bus efficiency and
+ * higher tape throughput.
+ * Pre-calculation of the expected read/write request
+ * service time, based on the tape's parameters. In
+ * the pipelined operation mode, this allows us to
+ * adjust our polling frequency to a much lower value,
+ * and thus to dramatically reduce our load on Linux,
+ * without any decrease in performance.
+ * Implemented additional mtio.h operations.
+ * The recommended user block size is returned by
+ * the MTIOCGET ioctl.
+ * Additional minor changes.
+ * Ver 1.3 Feb 9 96 Fixed pipelined read mode bug which prevented the
+ * use of some block sizes during a restore procedure.
+ * The character device interface will now present a
+ * continuous view of the media - any mix of block sizes
+ * during a backup/restore procedure is supported. The
+ * driver will buffer the requests internally and
+ * convert them to the tape's recommended transfer
+ * unit, making performance almost independent of the
+ * chosen user block size.
+ * Some improvements in error recovery.
+ * By cooperating with ide-dma.c, bus mastering DMA can
+ * now sometimes be used with IDE tape drives as well.
+ * Bus mastering DMA has the potential to dramatically
+ * reduce the CPU's overhead when accessing the device,
+ * and can be enabled by using hdparm -d1 on the tape's
+ * block device interface. For more info, read the
+ * comments in ide-dma.c.
+ * Ver 1.4 Mar 13 96 Fixed serialize support.
+ * Ver 1.5 Apr 12 96 Fixed shared interface operation, broken in 1.3.85.
+ * Fixed pipelined read mode inefficiency.
+ * Fixed nasty null dereferencing bug.
+ * Ver 1.6 Aug 16 96 Fixed FPU usage in the driver.
+ * Fixed end of media bug.
+ * Ver 1.7 Sep 10 96 Minor changes for the CONNER CTT8000-A model.
+ * Ver 1.8 Sep 26 96 Attempt to find a better balance between good
+ * interactive response and high system throughput.
+ * Ver 1.9 Nov 5 96 Automatically cross encountered filemarks rather
+ * than requiring an explicit FSF command.
+ * Abort pending requests at end of media.
+ * MTTELL was sometimes returning incorrect results.
+ * Return the real block size in the MTIOCGET ioctl.
+ * Some error recovery bug fixes.
+ * Ver 1.10 Nov 5 96 Major reorganization.
+ * Reduced CPU overhead a bit by eliminating internal
+ * bounce buffers.
+ * Added module support.
+ * Added multiple tape drives support.
+ * Added partition support.
+ * Rewrote DSC handling.
+ * Some portability fixes.
+ * Removed ide-tape.h.
+ * Additional minor changes.
+ * Ver 1.11 Dec 2 96 Bug fix in previous DSC timeout handling.
+ * Use ide_stall_queue() for DSC overlap.
+ * Use the maximum speed rather than the current speed
+ * to compute the request service time.
+ * Ver 1.12 Dec 7 97 Fix random memory overwriting and/or last block data
+ * corruption, which could occur if the total number
+ * of bytes written to the tape was not an integral
+ * number of tape blocks.
+ * Add support for INTERRUPT DRQ devices.
+ * Ver 1.13 Jan 2 98 Add "speed == 0" work-around for HP COLORADO 5GB
+ * Ver 1.14 Dec 30 98 Partial fixes for the Sony/AIWA tape drives.
+ * Replace cli()/sti() with hwgroup spinlocks.
+ * Ver 1.15 Mar 25 99 Fix SMP race condition by replacing hwgroup
+ * spinlock with private per-tape spinlock.
+ * Ver 1.16 Sep 1 99 Add OnStream tape support.
+ * Abort read pipeline on EOD.
+ * Wait for the tape to become ready in case it returns
+ * "in the process of becoming ready" on open().
+ * Fix zero padding of the last written block in
+ * case the tape block size is larger than PAGE_SIZE.
+ * Decrease the default disconnection time to tn.
+ * Ver 1.16e Oct 3 99 Minor fixes.
+ * Ver 1.16e1 Oct 13 99 Patches by Arnold Niessen,
+ * niessen@iae.nl / arnold.niessen@philips.com
+ * GO-1) Undefined code in idetape_read_position
+ * according to Gadi's email
+ * AJN-1) Minor fix asc == 11 should be asc == 0x11
+ * in idetape_issue_packet_command (did effect
+ * debugging output only)
+ * AJN-2) Added more debugging output, and
+ * added ide-tape: where missing. I would also
+ * like to add tape->name where possible
+ * AJN-3) Added different debug_level's
+ * via /proc/ide/hdc/settings
+ * "debug_level" determines amount of debugging output;
+ * can be changed using /proc/ide/hdx/settings
+ * 0 : almost no debugging output
+ * 1 : 0+output errors only
+ * 2 : 1+output all sensekey/asc
+ * 3 : 2+follow all chrdev related procedures
+ * 4 : 3+follow all procedures
+ * 5 : 4+include pc_stack rq_stack info
+ * 6 : 5+USE_COUNT updates
+ * AJN-4) Fixed timeout for retension in idetape_queue_pc_tail
+ * from 5 to 10 minutes
+ * AJN-5) Changed maximum number of blocks to skip when
+ * reading tapes with multiple consecutive write
+ * errors from 100 to 1000 in idetape_get_logical_blk
+ * Proposed changes to code:
+ * 1) output "logical_blk_num" via /proc
+ * 2) output "current_operation" via /proc
+ * 3) Either solve or document the fact that `mt rewind' is
+ * required after reading from /dev/nhtx to be
+ * able to rmmod the idetape module;
+ * Also, sometimes an application finishes but the
+ * device remains `busy' for some time. Same cause ?
+ * Proposed changes to release-notes:
+ * 4) write a simple `quickstart' section in the
+ * release notes; I volunteer if you don't want to
+ * 5) include a pointer to video4linux in the doc
+ * to stimulate video applications
+ * 6) release notes lines 331 and 362: explain what happens
+ * if the application data rate is higher than 1100 KB/s;
+ * similar approach to lower-than-500 kB/s ?
+ * 7) 6.6 Comparison; wouldn't it be better to allow different
+ * strategies for read and write ?
+ * Wouldn't it be better to control the tape buffer
+ * contents instead of the bandwidth ?
+ * 8) line 536: replace will by would (if I understand
+ * this section correctly, a hypothetical and unwanted situation
+ * is being described)
+ * Ver 1.16f Dec 15 99 Change place of the secondary OnStream header frames.
+ * Ver 1.17 Nov 2000 / Jan 2001 Marcel Mol, marcel@mesa.nl
+ * - Add idetape_onstream_mode_sense_tape_parameter_page
+ * function to get tape capacity in frames: tape->capacity.
+ * - Add support for DI-50 drives( or any DI- drive).
+ * - 'workaround' for read error/blank block around block 3000.
+ * - Implement Early warning for end of media for Onstream.
+ * - Cosmetic code changes for readability.
+ * - Idetape_position_tape should not use SKIP bit during
+ * Onstream read recovery.
+ * - Add capacity, logical_blk_num and first/last_frame_position
+ * to /proc/ide/hd?/settings.
+ * - Module use count was gone in the Linux 2.4 driver.
+ * Ver 1.17a Apr 2001 Willem Riede osst@riede.org
+ * - Get drive's actual block size from mode sense block descriptor
+ * - Limit size of pipeline
+ * Ver 1.17b Oct 2002 Alan Stern <stern@rowland.harvard.edu>
+ * Changed IDETAPE_MIN_PIPELINE_STAGES to 1 and actually used
+ * it in the code!
+ * Actually removed aborted stages in idetape_abort_pipeline
+ * instead of just changing the command code.
+ * Made the transfer byte count for Request Sense equal to the
+ * actual length of the data transfer.
+ * Changed handling of partial data transfers: they do not
+ * cause DMA errors.
+ * Moved initiation of DMA transfers to the correct place.
+ * Removed reference to unallocated memory.
+ * Made __idetape_discard_read_pipeline return the number of
+ * sectors skipped, not the number of stages.
+ * Replaced errant kfree() calls with __idetape_kfree_stage().
+ * Fixed off-by-one error in testing the pipeline length.
+ * Fixed handling of filemarks in the read pipeline.
+ * Small code optimization for MTBSF and MTBSFM ioctls.
+ * Don't try to unlock the door during device close if is
+ * already unlocked!
+ * Cosmetic fixes to miscellaneous debugging output messages.
+ * Set the minimum /proc/ide/hd?/settings values for "pipeline",
+ * "pipeline_min", and "pipeline_max" to 1.
+ *
+ * Here are some words from the first releases of hd.c, which are quoted
+ * in ide.c and apply here as well:
+ *
+ * | Special care is recommended. Have Fun!
+ *
+ */
+
+/*
+ * An overview of the pipelined operation mode.
+ *
+ * In the pipelined write mode, we will usually just add requests to our
+ * pipeline and return immediately, before we even start to service them. The
+ * user program will then have enough time to prepare the next request while
+ * we are still busy servicing previous requests. In the pipelined read mode,
+ * the situation is similar - we add read-ahead requests into the pipeline,
+ * before the user even requested them.
+ *
+ * The pipeline can be viewed as a "safety net" which will be activated when
+ * the system load is high and prevents the user backup program from keeping up
+ * with the current tape speed. At this point, the pipeline will get
+ * shorter and shorter but the tape will still be streaming at the same speed.
+ * Assuming we have enough pipeline stages, the system load will hopefully
+ * decrease before the pipeline is completely empty, and the backup program
+ * will be able to "catch up" and refill the pipeline again.
+ *
+ * When using the pipelined mode, it would be best to disable any type of
+ * buffering done by the user program, as ide-tape already provides all the
+ * benefits in the kernel, where it can be done in a more efficient way.
+ * As we will usually not block the user program on a request, the most
+ * efficient user code will then be a simple read-write-read-... cycle.
+ * Any additional logic will usually just slow down the backup process.
+ *
+ * Using the pipelined mode, I get a constant over 400 KBps throughput,
+ * which seems to be the maximum throughput supported by my tape.
+ *
+ * However, there are some downfalls:
+ *
+ * 1. We use memory (for data buffers) in proportional to the number
+ * of pipeline stages (each stage is about 26 KB with my tape).
+ * 2. In the pipelined write mode, we cheat and postpone error codes
+ * to the user task. In read mode, the actual tape position
+ * will be a bit further than the last requested block.
+ *
+ * Concerning (1):
+ *
+ * 1. We allocate stages dynamically only when we need them. When
+ * we don't need them, we don't consume additional memory. In
+ * case we can't allocate stages, we just manage without them
+ * (at the expense of decreased throughput) so when Linux is
+ * tight in memory, we will not pose additional difficulties.
+ *
+ * 2. The maximum number of stages (which is, in fact, the maximum
+ * amount of memory) which we allocate is limited by the compile
+ * time parameter IDETAPE_MAX_PIPELINE_STAGES.
+ *
+ * 3. The maximum number of stages is a controlled parameter - We
+ * don't start from the user defined maximum number of stages
+ * but from the lower IDETAPE_MIN_PIPELINE_STAGES (again, we
+ * will not even allocate this amount of stages if the user
+ * program can't handle the speed). We then implement a feedback
+ * loop which checks if the pipeline is empty, and if it is, we
+ * increase the maximum number of stages as necessary until we
+ * reach the optimum value which just manages to keep the tape
+ * busy with minimum allocated memory or until we reach
+ * IDETAPE_MAX_PIPELINE_STAGES.
+ *
+ * Concerning (2):
+ *
+ * In pipelined write mode, ide-tape can not return accurate error codes
+ * to the user program since we usually just add the request to the
+ * pipeline without waiting for it to be serviced. In case an error
+ * occurs, I will report it on the next user request.
+ *
+ * In the pipelined read mode, subsequent read requests or forward
+ * filemark spacing will perform correctly, as we preserve all blocks
+ * and filemarks which we encountered during our excess read-ahead.
+ *
+ * For accurate tape positioning and error reporting, disabling
+ * pipelined mode might be the best option.
+ *
+ * You can enable/disable/tune the pipelined operation mode by adjusting
+ * the compile time parameters below.
+ */
+
+/*
+ * Possible improvements.
+ *
+ * 1. Support for the ATAPI overlap protocol.
+ *
+ * In order to maximize bus throughput, we currently use the DSC
+ * overlap method which enables ide.c to service requests from the
+ * other device while the tape is busy executing a command. The
+ * DSC overlap method involves polling the tape's status register
+ * for the DSC bit, and servicing the other device while the tape
+ * isn't ready.
+ *
+ * In the current QIC development standard (December 1995),
+ * it is recommended that new tape drives will *in addition*
+ * implement the ATAPI overlap protocol, which is used for the
+ * same purpose - efficient use of the IDE bus, but is interrupt
+ * driven and thus has much less CPU overhead.
+ *
+ * ATAPI overlap is likely to be supported in most new ATAPI
+ * devices, including new ATAPI cdroms, and thus provides us
+ * a method by which we can achieve higher throughput when
+ * sharing a (fast) ATA-2 disk with any (slow) new ATAPI device.
+ */
+
+#define IDETAPE_VERSION "1.19"
+
+#include <linux/config.h>
+#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/major.h>
+#include <linux/devfs_fs_kernel.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 <asm/byteorder.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/unaligned.h>
+
+/*
+ * partition
+ */
+typedef struct os_partition_s {
+ __u8 partition_num;
+ __u8 par_desc_ver;
+ __u16 wrt_pass_cntr;
+ __u32 first_frame_addr;
+ __u32 last_frame_addr;
+ __u32 eod_frame_addr;
+} os_partition_t;
+
+/*
+ * DAT entry
+ */
+typedef struct os_dat_entry_s {
+ __u32 blk_sz;
+ __u16 blk_cnt;
+ __u8 flags;
+ __u8 reserved;
+} os_dat_entry_t;
+
+/*
+ * DAT
+ */
+#define OS_DAT_FLAGS_DATA (0xc)
+#define OS_DAT_FLAGS_MARK (0x1)
+
+typedef struct os_dat_s {
+ __u8 dat_sz;
+ __u8 reserved1;
+ __u8 entry_cnt;
+ __u8 reserved3;
+ os_dat_entry_t dat_list[16];
+} os_dat_t;
+
+#include <linux/mtio.h>
+
+/**************************** Tunable parameters *****************************/
+
+
+/*
+ * Pipelined mode parameters.
+ *
+ * We try to use the minimum number of stages which is enough to
+ * keep the tape constantly streaming. To accomplish that, we implement
+ * a feedback loop around the maximum number of stages:
+ *
+ * We start from MIN maximum stages (we will not even use MIN stages
+ * if we don't need them), increment it by RATE*(MAX-MIN)
+ * whenever we sense that the pipeline is empty, until we reach
+ * the optimum value or until we reach MAX.
+ *
+ * Setting the following parameter to 0 is illegal: the pipelined mode
+ * cannot be disabled (calculate_speeds() divides by tape->max_stages.)
+ */
+#define IDETAPE_MIN_PIPELINE_STAGES 1
+#define IDETAPE_MAX_PIPELINE_STAGES 400
+#define IDETAPE_INCREASE_STAGES_RATE 20
+
+/*
+ * The following are used to debug the driver:
+ *
+ * Setting IDETAPE_DEBUG_INFO to 1 will report device capabilities.
+ * Setting IDETAPE_DEBUG_LOG to 1 will log driver flow control.
+ * Setting IDETAPE_DEBUG_BUGS to 1 will enable self-sanity checks in
+ * some places.
+ *
+ * Setting them to 0 will restore normal operation mode:
+ *
+ * 1. Disable logging normal successful operations.
+ * 2. Disable self-sanity checks.
+ * 3. Errors will still be logged, of course.
+ *
+ * All the #if DEBUG code will be removed some day, when the driver
+ * is verified to be stable enough. This will make it much more
+ * esthetic.
+ */
+#define IDETAPE_DEBUG_INFO 0
+#define IDETAPE_DEBUG_LOG 0
+#define IDETAPE_DEBUG_BUGS 1
+
+/*
+ * 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
+
+/*
+ * With each packet command, we allocate a buffer of
+ * IDETAPE_PC_BUFFER_SIZE bytes. This is used for several packet
+ * commands (Not for READ/WRITE commands).
+ */
+#define IDETAPE_PC_BUFFER_SIZE 256
+
+/*
+ * In various places in the driver, we need to allocate storage
+ * for packet commands and requests, which will remain valid while
+ * we leave the driver to wait for an interrupt or a timeout event.
+ */
+#define IDETAPE_PC_STACK (10 + IDETAPE_MAX_PC_RETRIES)
+
+/*
+ * Some drives (for example, Seagate STT3401A Travan) require a very long
+ * timeout, because they don't return an interrupt or clear their busy bit
+ * until after the command completes (even retension commands).
+ */
+#define IDETAPE_WAIT_CMD (900*HZ)
+
+/*
+ * 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 sytem
+ * 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 will service requests from
+ * the other device on the same interface meanwhile.
+ *
+ * 2. After the successful initialization of a "media access
+ * packet command", which is a command which can take a long
+ * time to complete (it can be several seconds or 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 (one second), and if we don't receive DSC
+ * after IDETAPE_DSC_MA_THRESHOLD (5 minutes), we switch it to a
+ * lower frequency - IDETAPE_DSC_MA_SLOW (1 minute).
+ *
+ * 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 ***********************/
+
+/*
+ * Debugging/Performance analysis
+ *
+ * I/O trace support
+ */
+#define USE_IOTRACE 0
+#if USE_IOTRACE
+#include <linux/io_trace.h>
+#define IO_IDETAPE_FIFO 500
+#endif
+
+/*
+ * Read/Write error simulation
+ */
+#define SIMULATE_ERRORS 0
+
+/*
+ * For general magnetic tape device compatibility.
+ */
+typedef enum {
+ idetape_direction_none,
+ idetape_direction_read,
+ idetape_direction_write
+} idetape_chrdev_direction_t;
+
+struct idetape_bh {
+ unsigned short b_size;
+ atomic_t b_count;
+ struct idetape_bh *b_reqnext;
+ char *b_data;
+};
+
+/*
+ * Our view of a packet command.
+ */
+typedef struct idetape_packet_command_s {
+ u8 c[12]; /* Actual packet bytes */
+ int retries; /* On each retry, we increment retries */
+ int error; /* Error code */
+ int request_transfer; /* Bytes to transfer */
+ int actually_transferred; /* Bytes actually transferred */
+ int buffer_size; /* Size of our data buffer */
+ struct idetape_bh *bh;
+ char *b_data;
+ int b_count;
+ u8 *buffer; /* Data buffer */
+ u8 *current_position; /* Pointer into the above buffer */
+ ide_startstop_t (*callback) (ide_drive_t *); /* Called when this packet command is completed */
+ u8 pc_buffer[IDETAPE_PC_BUFFER_SIZE]; /* Temporary buffer */
+ unsigned long flags; /* Status/Action bit flags: long for set_bit */
+} idetape_pc_t;
+
+/*
+ * Packet command flag bits.
+ */
+/* Set when an error is considered normal - We won't retry */
+#define PC_ABORT 0
+/* 1 When polling for DSC on a media access command */
+#define PC_WAIT_FOR_DSC 1
+/* 1 when we prefer to use DMA if possible */
+#define PC_DMA_RECOMMENDED 2
+/* 1 while DMA in progress */
+#define PC_DMA_IN_PROGRESS 3
+/* 1 when encountered problem during DMA */
+#define PC_DMA_ERROR 4
+/* Data direction */
+#define PC_WRITING 5
+
+/*
+ * Capabilities and Mechanical Status Page
+ */
+typedef struct {
+ unsigned page_code :6; /* Page code - Should be 0x2a */
+ __u8 reserved0_6 :1;
+ __u8 ps :1; /* parameters saveable */
+ __u8 page_length; /* Page Length - Should be 0x12 */
+ __u8 reserved2, reserved3;
+ unsigned ro :1; /* Read Only Mode */
+ unsigned reserved4_1234 :4;
+ unsigned sprev :1; /* Supports SPACE in the reverse direction */
+ unsigned reserved4_67 :2;
+ unsigned reserved5_012 :3;
+ unsigned efmt :1; /* Supports ERASE command initiated formatting */
+ unsigned reserved5_4 :1;
+ unsigned qfa :1; /* Supports the QFA two partition formats */
+ unsigned reserved5_67 :2;
+ unsigned lock :1; /* Supports locking the volume */
+ unsigned locked :1; /* The volume is locked */
+ unsigned prevent :1; /* The device defaults in the prevent state after power up */
+ unsigned eject :1; /* The device can eject the volume */
+ __u8 disconnect :1; /* The device can break request > ctl */
+ __u8 reserved6_5 :1;
+ unsigned ecc :1; /* Supports error correction */
+ unsigned cmprs :1; /* Supports data compression */
+ unsigned reserved7_0 :1;
+ unsigned blk512 :1; /* Supports 512 bytes block size */
+ unsigned blk1024 :1; /* Supports 1024 bytes block size */
+ unsigned reserved7_3_6 :4;
+ unsigned blk32768 :1; /* slowb - the device restricts the byte count for PIO */
+ /* transfers for slow buffer memory ??? */
+ /* Also 32768 block size in some cases */
+ __u16 max_speed; /* Maximum speed supported in KBps */
+ __u8 reserved10, reserved11;
+ __u16 ctl; /* Continuous Transfer Limit in blocks */
+ __u16 speed; /* Current Speed, in KBps */
+ __u16 buffer_size; /* Buffer Size, in 512 bytes */
+ __u8 reserved18, reserved19;
+} idetape_capabilities_page_t;
+
+/*
+ * Block Size Page
+ */
+typedef struct {
+ unsigned page_code :6; /* Page code - Should be 0x30 */
+ unsigned reserved1_6 :1;
+ unsigned ps :1;
+ __u8 page_length; /* Page Length - Should be 2 */
+ __u8 reserved2;
+ unsigned play32 :1;
+ unsigned play32_5 :1;
+ unsigned reserved2_23 :2;
+ unsigned record32 :1;
+ unsigned record32_5 :1;
+ unsigned reserved2_6 :1;
+ unsigned one :1;
+} idetape_block_size_page_t;
+
+/*
+ * A pipeline stage.
+ */
+typedef struct idetape_stage_s {
+ struct request rq; /* The corresponding request */
+ struct idetape_bh *bh; /* The data buffers */
+ struct idetape_stage_s *next; /* Pointer to the next stage */
+} idetape_stage_t;
+
+/*
+ * REQUEST SENSE packet command result - Data Format.
+ */
+typedef struct {
+ unsigned error_code :7; /* Current of deferred errors */
+ unsigned valid :1; /* The information field conforms to QIC-157C */
+ __u8 reserved1 :8; /* Segment Number - Reserved */
+ unsigned sense_key :4; /* Sense Key */
+ unsigned reserved2_4 :1; /* Reserved */
+ unsigned ili :1; /* Incorrect Length Indicator */
+ unsigned eom :1; /* End Of Medium */
+ unsigned filemark :1; /* Filemark */
+ __u32 information __attribute__ ((packed));
+ __u8 asl; /* Additional sense length (n-7) */
+ __u32 command_specific; /* Additional command specific information */
+ __u8 asc; /* Additional Sense Code */
+ __u8 ascq; /* Additional Sense Code Qualifier */
+ __u8 replaceable_unit_code; /* Field Replaceable Unit Code */
+ unsigned sk_specific1 :7; /* Sense Key Specific */
+ unsigned sksv :1; /* Sense Key Specific information is valid */
+ __u8 sk_specific2; /* Sense Key Specific */
+ __u8 sk_specific3; /* Sense Key Specific */
+ __u8 pad[2]; /* Padding to 20 bytes */
+} idetape_request_sense_result_t;
+
+
+/*
+ * 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 a variable
+ * of type idetape_tape_t, defined below.
+ */
+typedef struct ide_tape_obj {
+ ide_drive_t *drive;
+ ide_driver_t *driver;
+ struct gendisk *disk;
+ struct kref kref;
+
+ /*
+ * Since a typical character device operation requires more
+ * than one packet command, we provide here enough memory
+ * for the maximum of interconnected packet commands.
+ * The packet commands are stored in the circular array pc_stack.
+ * pc_stack_index points to the last used entry, and warps around
+ * to the start when we get to the last array entry.
+ *
+ * pc points to the current processed packet command.
+ *
+ * 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.
+ */
+ /* Current packet command */
+ idetape_pc_t *pc;
+ /* Last failed packet command */
+ idetape_pc_t *failed_pc;
+ /* Packet command stack */
+ idetape_pc_t pc_stack[IDETAPE_PC_STACK];
+ /* Next free packet command storage space */
+ int pc_stack_index;
+ struct request rq_stack[IDETAPE_PC_STACK];
+ /* We implement a circular array */
+ int rq_stack_index;
+
+ /*
+ * 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. Additional requests can be
+ * queued in our internal pipeline, but they will be visible
+ * to ide.c only one at a time.
+ */
+ 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_frequency;
+ /* The current polling frequency */
+ unsigned long dsc_polling_frequency;
+ /* Maximum waiting time */
+ unsigned long dsc_timeout;
+
+ /*
+ * Read position information
+ */
+ u8 partition;
+ /* Current block */
+ unsigned int first_frame_position;
+ unsigned int last_frame_position;
+ unsigned int blocks_in_buffer;
+
+ /*
+ * 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 */
+ idetape_chrdev_direction_t chrdev_direction;
+
+ /*
+ * Device information
+ */
+ /* Usually 512 or 1024 bytes */
+ unsigned short tape_block_size;
+ int user_bs_factor;
+ /* Copy of the tape's Capabilities and Mechanical Page */
+ idetape_capabilities_page_t capabilities;
+
+ /*
+ * 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. In the pipelined operation
+ * mode, we use our internal pipeline structure to hold
+ * more data requests.
+ *
+ * The data buffer size is chosen based on the tape's
+ * recommendation.
+ */
+ /* Pointer to the request which is waiting in the device request queue */
+ struct request *active_data_request;
+ /* Data buffer size (chosen based on the tape's recommendation */
+ int stage_size;
+ idetape_stage_t *merge_stage;
+ int merge_stage_size;
+ struct idetape_bh *bh;
+ char *b_data;
+ int b_count;
+
+ /*
+ * Pipeline parameters.
+ *
+ * To accomplish non-pipelined mode, we simply set the following
+ * variables to zero (or NULL, where appropriate).
+ */
+ /* Number of currently used stages */
+ int nr_stages;
+ /* Number of pending stages */
+ int nr_pending_stages;
+ /* We will not allocate more than this number of stages */
+ int max_stages, min_pipeline, max_pipeline;
+ /* The first stage which will be removed from the pipeline */
+ idetape_stage_t *first_stage;
+ /* The currently active stage */
+ idetape_stage_t *active_stage;
+ /* Will be serviced after the currently active request */
+ idetape_stage_t *next_stage;
+ /* New requests will be added to the pipeline here */
+ idetape_stage_t *last_stage;
+ /* Optional free stage which we can use */
+ idetape_stage_t *cache_stage;
+ int pages_per_stage;
+ /* Wasted space in each stage */
+ int excess_bh_size;
+
+ /* Status/Action flags: long for set_bit */
+ unsigned long flags;
+ /* protects the ide-tape queue */
+ spinlock_t spinlock;
+
+ /*
+ * Measures average tape speed
+ */
+ unsigned long avg_time;
+ int avg_size;
+ int avg_speed;
+
+ /* last sense information */
+ idetape_request_sense_result_t sense;
+
+ char vendor_id[10];
+ char product_id[18];
+ char firmware_revision[6];
+ int firmware_revision_num;
+
+ /* 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;
+
+ /*
+ * Limit the number of times a request can
+ * be postponed, to avoid an infinite postpone
+ * deadlock.
+ */
+ /* request postpone count limit */
+ int postpone_cnt;
+
+ /*
+ * Measures number of frames:
+ *
+ * 1. written/read to/from the driver pipeline (pipeline_head).
+ * 2. written/read to/from the tape buffers (idetape_bh).
+ * 3. written/read by the tape to/from the media (tape_head).
+ */
+ int pipeline_head;
+ int buffer_head;
+ int tape_head;
+ int last_tape_head;
+
+ /*
+ * Speed control at the tape buffers input/output
+ */
+ unsigned long insert_time;
+ int insert_size;
+ int insert_speed;
+ int max_insert_speed;
+ int measure_insert_time;
+
+ /*
+ * Measure tape still time, in milliseconds
+ */
+ unsigned long tape_still_time_begin;
+ int tape_still_time;
+
+ /*
+ * Speed regulation negative feedback loop
+ */
+ int speed_control;
+ int pipeline_head_speed;
+ int controlled_pipeline_head_speed;
+ int uncontrolled_pipeline_head_speed;
+ int controlled_last_pipeline_head;
+ int uncontrolled_last_pipeline_head;
+ unsigned long uncontrolled_pipeline_head_time;
+ unsigned long controlled_pipeline_head_time;
+ int controlled_previous_pipeline_head;
+ int uncontrolled_previous_pipeline_head;
+ unsigned long controlled_previous_head_time;
+ unsigned long uncontrolled_previous_head_time;
+ int restart_speed_control_req;
+
+ /*
+ * Debug_level determines amount of debugging output;
+ * can be changed using /proc/ide/hdx/settings
+ * 0 : almost no debugging output
+ * 1 : 0+output errors only
+ * 2 : 1+output all sensekey/asc
+ * 3 : 2+follow all chrdev related procedures
+ * 4 : 3+follow all procedures
+ * 5 : 4+include pc_stack rq_stack info
+ * 6 : 5+USE_COUNT updates
+ */
+ int debug_level;
+} idetape_tape_t;
+
+static DECLARE_MUTEX(idetape_ref_sem);
+
+#define to_ide_tape(obj) container_of(obj, struct ide_tape_obj, kref)
+
+#define ide_tape_g(disk) \
+ container_of((disk)->private_data, struct ide_tape_obj, driver)
+
+static struct ide_tape_obj *ide_tape_get(struct gendisk *disk)
+{
+ struct ide_tape_obj *tape = NULL;
+
+ down(&idetape_ref_sem);
+ tape = ide_tape_g(disk);
+ if (tape)
+ kref_get(&tape->kref);
+ up(&idetape_ref_sem);
+ return tape;
+}
+
+static void ide_tape_release(struct kref *);
+
+static void ide_tape_put(struct ide_tape_obj *tape)
+{
+ down(&idetape_ref_sem);
+ kref_put(&tape->kref, ide_tape_release);
+ up(&idetape_ref_sem);
+}
+
+/*
+ * Tape door status
+ */
+#define DOOR_UNLOCKED 0
+#define DOOR_LOCKED 1
+#define DOOR_EXPLICITLY_LOCKED 2
+
+/*
+ * Tape flag bits values.
+ */
+#define IDETAPE_IGNORE_DSC 0
+#define IDETAPE_ADDRESS_VALID 1 /* 0 When the tape position is unknown */
+#define IDETAPE_BUSY 2 /* Device already opened */
+#define IDETAPE_PIPELINE_ERROR 3 /* Error detected in a pipeline stage */
+#define IDETAPE_DETECT_BS 4 /* Attempt to auto-detect the current user block size */
+#define IDETAPE_FILEMARK 5 /* Currently on a filemark */
+#define IDETAPE_DRQ_INTERRUPT 6 /* DRQ interrupt device */
+#define IDETAPE_READ_ERROR 7
+#define IDETAPE_PIPELINE_ACTIVE 8 /* pipeline active */
+/* 0 = no tape is loaded, so we don't rewind after ejecting */
+#define IDETAPE_MEDIUM_PRESENT 9
+
+/*
+ * Supported ATAPI tape drives packet commands
+ */
+#define IDETAPE_TEST_UNIT_READY_CMD 0x00
+#define IDETAPE_REWIND_CMD 0x01
+#define IDETAPE_REQUEST_SENSE_CMD 0x03
+#define IDETAPE_READ_CMD 0x08
+#define IDETAPE_WRITE_CMD 0x0a
+#define IDETAPE_WRITE_FILEMARK_CMD 0x10
+#define IDETAPE_SPACE_CMD 0x11
+#define IDETAPE_INQUIRY_CMD 0x12
+#define IDETAPE_ERASE_CMD 0x19
+#define IDETAPE_MODE_SENSE_CMD 0x1a
+#define IDETAPE_MODE_SELECT_CMD 0x15
+#define IDETAPE_LOAD_UNLOAD_CMD 0x1b
+#define IDETAPE_PREVENT_CMD 0x1e
+#define IDETAPE_LOCATE_CMD 0x2b
+#define IDETAPE_READ_POSITION_CMD 0x34
+#define IDETAPE_READ_BUFFER_CMD 0x3c
+#define IDETAPE_SET_SPEED_CMD 0xbb
+
+/*
+ * Some defines for the READ BUFFER command
+ */
+#define IDETAPE_RETRIEVE_FAULTY_BLOCK 6
+
+/*
+ * 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
+
+/*
+ * Special requests for our block device strategy routine.
+ *
+ * In order to service a character device command, we add special
+ * requests to the tail of our block device request queue and wait
+ * for their completion.
+ */
+
+enum {
+ REQ_IDETAPE_PC1 = (1 << 0), /* packet command (first stage) */
+ REQ_IDETAPE_PC2 = (1 << 1), /* packet command (second stage) */
+ REQ_IDETAPE_READ = (1 << 2),
+ REQ_IDETAPE_WRITE = (1 << 3),
+ REQ_IDETAPE_READ_BUFFER = (1 << 4),
+};
+
+/*
+ * Error codes which are 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
+
+/*
+ * The following is used to format the general configuration word of
+ * the ATAPI IDENTIFY DEVICE command.
+ */
+struct idetape_id_gcw {
+ unsigned packet_size :2; /* Packet Size */
+ unsigned reserved234 :3; /* Reserved */
+ unsigned drq_type :2; /* Command packet DRQ type */
+ unsigned removable :1; /* Removable media */
+ unsigned device_type :5; /* Device type */
+ unsigned reserved13 :1; /* Reserved */
+ unsigned protocol :2; /* Protocol type */
+};
+
+/*
+ * INQUIRY packet command - Data Format (From Table 6-8 of QIC-157C)
+ */
+typedef struct {
+ unsigned device_type :5; /* Peripheral Device Type */
+ unsigned reserved0_765 :3; /* Peripheral Qualifier - Reserved */
+ unsigned reserved1_6t0 :7; /* Reserved */
+ unsigned rmb :1; /* Removable Medium Bit */
+ unsigned ansi_version :3; /* ANSI Version */
+ unsigned ecma_version :3; /* ECMA Version */
+ unsigned iso_version :2; /* ISO Version */
+ unsigned response_format :4; /* Response Data Format */
+ unsigned reserved3_45 :2; /* Reserved */
+ unsigned reserved3_6 :1; /* TrmIOP - Reserved */
+ unsigned reserved3_7 :1; /* AENC - Reserved */
+ __u8 additional_length; /* Additional Length (total_length-4) */
+ __u8 rsv5, rsv6, rsv7; /* Reserved */
+ __u8 vendor_id[8]; /* Vendor Identification */
+ __u8 product_id[16]; /* Product Identification */
+ __u8 revision_level[4]; /* Revision Level */
+ __u8 vendor_specific[20]; /* Vendor Specific - Optional */
+ __u8 reserved56t95[40]; /* Reserved - Optional */
+ /* Additional information may be returned */
+} idetape_inquiry_result_t;
+
+/*
+ * READ POSITION packet command - Data Format (From Table 6-57)
+ */
+typedef struct {
+ unsigned reserved0_10 :2; /* Reserved */
+ unsigned bpu :1; /* Block Position Unknown */
+ unsigned reserved0_543 :3; /* Reserved */
+ unsigned eop :1; /* End Of Partition */
+ unsigned bop :1; /* Beginning Of Partition */
+ u8 partition; /* Partition Number */
+ u8 reserved2, reserved3; /* Reserved */
+ u32 first_block; /* First Block Location */
+ u32 last_block; /* Last Block Location (Optional) */
+ u8 reserved12; /* Reserved */
+ u8 blocks_in_buffer[3]; /* Blocks In Buffer - (Optional) */
+ u32 bytes_in_buffer; /* Bytes In Buffer (Optional) */
+} idetape_read_position_result_t;
+
+/*
+ * Follows structures which are related to the SELECT SENSE / MODE SENSE
+ * packet commands. Those packet commands are still not supported
+ * by ide-tape.
+ */
+#define IDETAPE_BLOCK_DESCRIPTOR 0
+#define IDETAPE_CAPABILITIES_PAGE 0x2a
+#define IDETAPE_PARAMTR_PAGE 0x2b /* Onstream DI-x0 only */
+#define IDETAPE_BLOCK_SIZE_PAGE 0x30
+#define IDETAPE_BUFFER_FILLING_PAGE 0x33
+
+/*
+ * Mode Parameter Header for the MODE SENSE packet command
+ */
+typedef struct {
+ __u8 mode_data_length; /* Length of the following data transfer */
+ __u8 medium_type; /* Medium Type */
+ __u8 dsp; /* Device Specific Parameter */
+ __u8 bdl; /* Block Descriptor Length */
+#if 0
+ /* data transfer page */
+ __u8 page_code :6;
+ __u8 reserved0_6 :1;
+ __u8 ps :1; /* parameters saveable */
+ __u8 page_length; /* page Length == 0x02 */
+ __u8 reserved2;
+ __u8 read32k :1; /* 32k blk size (data only) */
+ __u8 read32k5 :1; /* 32.5k blk size (data&AUX) */
+ __u8 reserved3_23 :2;
+ __u8 write32k :1; /* 32k blk size (data only) */
+ __u8 write32k5 :1; /* 32.5k blk size (data&AUX) */
+ __u8 reserved3_6 :1;
+ __u8 streaming :1; /* streaming mode enable */
+#endif
+} idetape_mode_parameter_header_t;
+
+/*
+ * Mode Parameter Block Descriptor the MODE SENSE packet command
+ *
+ * Support for block descriptors is optional.
+ */
+typedef struct {
+ __u8 density_code; /* Medium density code */
+ __u8 blocks[3]; /* Number of blocks */
+ __u8 reserved4; /* Reserved */
+ __u8 length[3]; /* Block Length */
+} idetape_parameter_block_descriptor_t;
+
+/*
+ * The Data Compression Page, as returned by the MODE SENSE packet command.
+ */
+typedef struct {
+ unsigned page_code :6; /* Page Code - Should be 0xf */
+ unsigned reserved0 :1; /* Reserved */
+ unsigned ps :1;
+ __u8 page_length; /* Page Length - Should be 14 */
+ unsigned reserved2 :6; /* Reserved */
+ unsigned dcc :1; /* Data Compression Capable */
+ unsigned dce :1; /* Data Compression Enable */
+ unsigned reserved3 :5; /* Reserved */
+ unsigned red :2; /* Report Exception on Decompression */
+ unsigned dde :1; /* Data Decompression Enable */
+ __u32 ca; /* Compression Algorithm */
+ __u32 da; /* Decompression Algorithm */
+ __u8 reserved[4]; /* Reserved */
+} idetape_data_compression_page_t;
+
+/*
+ * The Medium Partition Page, as returned by the MODE SENSE packet command.
+ */
+typedef struct {
+ unsigned page_code :6; /* Page Code - Should be 0x11 */
+ unsigned reserved1_6 :1; /* Reserved */
+ unsigned ps :1;
+ __u8 page_length; /* Page Length - Should be 6 */
+ __u8 map; /* Maximum Additional Partitions - Should be 0 */
+ __u8 apd; /* Additional Partitions Defined - Should be 0 */
+ unsigned reserved4_012 :3; /* Reserved */
+ unsigned psum :2; /* Should be 0 */
+ unsigned idp :1; /* Should be 0 */
+ unsigned sdp :1; /* Should be 0 */
+ unsigned fdp :1; /* Fixed Data Partitions */
+ __u8 mfr; /* Medium Format Recognition */
+ __u8 reserved[2]; /* Reserved */
+} idetape_medium_partition_page_t;
+
+/*
+ * Run time configurable parameters.
+ */
+typedef struct {
+ int dsc_rw_frequency;
+ int dsc_media_access_frequency;
+ int nr_stages;
+} idetape_config_t;
+
+/*
+ * 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];
+
+#define ide_tape_f(file) ((file)->private_data)
+
+static struct ide_tape_obj *ide_tape_chrdev_get(unsigned int i)
+{
+ struct ide_tape_obj *tape = NULL;
+
+ down(&idetape_ref_sem);
+ tape = idetape_devs[i];
+ if (tape)
+ kref_get(&tape->kref);
+ up(&idetape_ref_sem);
+ return tape;
+}
+
+/*
+ * Function declarations
+ *
+ */
+static int idetape_chrdev_release (struct inode *inode, struct file *filp);
+static void idetape_write_release (ide_drive_t *drive, unsigned int minor);
+
+/*
+ * Too bad. The drive wants to send us data which we are not ready to accept.
+ * Just throw it away.
+ */
+static void idetape_discard_data (ide_drive_t *drive, unsigned int bcount)
+{
+ while (bcount--)
+ (void) HWIF(drive)->INB(IDE_DATA_REG);
+}
+
+static void idetape_input_buffers (ide_drive_t *drive, idetape_pc_t *pc, unsigned int bcount)
+{
+ struct idetape_bh *bh = pc->bh;
+ int count;
+
+ while (bcount) {
+#if IDETAPE_DEBUG_BUGS
+ if (bh == NULL) {
+ printk(KERN_ERR "ide-tape: bh == NULL in "
+ "idetape_input_buffers\n");
+ idetape_discard_data(drive, bcount);
+ return;
+ }
+#endif /* IDETAPE_DEBUG_BUGS */
+ count = min((unsigned int)(bh->b_size - atomic_read(&bh->b_count)), bcount);
+ HWIF(drive)->atapi_input_bytes(drive, 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, idetape_pc_t *pc, unsigned int bcount)
+{
+ struct idetape_bh *bh = pc->bh;
+ int count;
+
+ while (bcount) {
+#if IDETAPE_DEBUG_BUGS
+ if (bh == NULL) {
+ printk(KERN_ERR "ide-tape: bh == NULL in "
+ "idetape_output_buffers\n");
+ return;
+ }
+#endif /* IDETAPE_DEBUG_BUGS */
+ count = min((unsigned int)pc->b_count, (unsigned int)bcount);
+ HWIF(drive)->atapi_output_bytes(drive, pc->b_data, count);
+ bcount -= count;
+ pc->b_data += count;
+ pc->b_count -= count;
+ if (!pc->b_count) {
+ pc->bh = bh = bh->b_reqnext;
+ if (bh) {
+ pc->b_data = bh->b_data;
+ pc->b_count = atomic_read(&bh->b_count);
+ }
+ }
+ }
+}
+
+static void idetape_update_buffers (idetape_pc_t *pc)
+{
+ struct idetape_bh *bh = pc->bh;
+ int count;
+ unsigned int bcount = pc->actually_transferred;
+
+ if (test_bit(PC_WRITING, &pc->flags))
+ return;
+ while (bcount) {
+#if IDETAPE_DEBUG_BUGS
+ if (bh == NULL) {
+ printk(KERN_ERR "ide-tape: bh == NULL in "
+ "idetape_update_buffers\n");
+ return;
+ }
+#endif /* IDETAPE_DEBUG_BUGS */
+ 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;
+}
+
+/*
+ * idetape_next_pc_storage returns a pointer to a place in which we can
+ * safely store a packet command, even though we intend to leave the
+ * driver. A storage space for a maximum of IDETAPE_PC_STACK packet
+ * commands is allocated at initialization time.
+ */
+static idetape_pc_t *idetape_next_pc_storage (ide_drive_t *drive)
+{
+ idetape_tape_t *tape = drive->driver_data;
+
+#if IDETAPE_DEBUG_LOG
+ if (tape->debug_level >= 5)
+ printk(KERN_INFO "ide-tape: pc_stack_index=%d\n",
+ tape->pc_stack_index);
+#endif /* IDETAPE_DEBUG_LOG */
+ if (tape->pc_stack_index == IDETAPE_PC_STACK)
+ tape->pc_stack_index=0;
+ return (&tape->pc_stack[tape->pc_stack_index++]);
+}
+
+/*
+ * idetape_next_rq_storage is used along with idetape_next_pc_storage.
+ * Since we queue packet commands in the request queue, we need to
+ * allocate a request, along with the allocation of a packet command.
+ */
+
+/**************************************************************
+ * *
+ * This should get fixed to use kmalloc(.., GFP_ATOMIC) *
+ * followed later on by kfree(). -ml *
+ * *
+ **************************************************************/
+
+static struct request *idetape_next_rq_storage (ide_drive_t *drive)
+{
+ idetape_tape_t *tape = drive->driver_data;
+
+#if IDETAPE_DEBUG_LOG
+ if (tape->debug_level >= 5)
+ printk(KERN_INFO "ide-tape: rq_stack_index=%d\n",
+ tape->rq_stack_index);
+#endif /* IDETAPE_DEBUG_LOG */
+ if (tape->rq_stack_index == IDETAPE_PC_STACK)
+ tape->rq_stack_index=0;
+ return (&tape->rq_stack[tape->rq_stack_index++]);
+}
+
+/*
+ * idetape_init_pc initializes a packet command.
+ */
+static void idetape_init_pc (idetape_pc_t *pc)
+{
+ memset(pc->c, 0, 12);
+ pc->retries = 0;
+ pc->flags = 0;
+ pc->request_transfer = 0;
+ pc->buffer = pc->pc_buffer;
+ pc->buffer_size = IDETAPE_PC_BUFFER_SIZE;
+ pc->bh = NULL;
+ pc->b_data = NULL;
+}
+
+/*
+ * idetape_analyze_error is 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, idetape_request_sense_result_t *result)
+{
+ idetape_tape_t *tape = drive->driver_data;
+ idetape_pc_t *pc = tape->failed_pc;
+
+ tape->sense = *result;
+ tape->sense_key = result->sense_key;
+ tape->asc = result->asc;
+ tape->ascq = result->ascq;
+#if IDETAPE_DEBUG_LOG
+ /*
+ * Without debugging, we only log an error if we decided to
+ * give up retrying.
+ */
+ if (tape->debug_level >= 1)
+ printk(KERN_INFO "ide-tape: pc = %x, sense key = %x, "
+ "asc = %x, ascq = %x\n",
+ pc->c[0], result->sense_key,
+ result->asc, result->ascq);
+#endif /* IDETAPE_DEBUG_LOG */
+
+ /*
+ * Correct pc->actually_transferred by asking the tape.
+ */
+ if (test_bit(PC_DMA_ERROR, &pc->flags)) {
+ pc->actually_transferred = pc->request_transfer - tape->tape_block_size * ntohl(get_unaligned(&result->information));
+ idetape_update_buffers(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] == IDETAPE_READ_CMD || pc->c[0] == IDETAPE_WRITE_CMD)
+ && pc->c[4] == 0 && pc->c[3] == 0 && pc->c[2] == 0) { /* length==0 */
+ if (result->sense_key == 5) {
+ /* don't report an error, everything's ok */
+ pc->error = 0;
+ /* don't retry read/write */
+ set_bit(PC_ABORT, &pc->flags);
+ }
+ }
+ if (pc->c[0] == IDETAPE_READ_CMD && result->filemark) {
+ pc->error = IDETAPE_ERROR_FILEMARK;
+ set_bit(PC_ABORT, &pc->flags);
+ }
+ if (pc->c[0] == IDETAPE_WRITE_CMD) {
+ if (result->eom ||
+ (result->sense_key == 0xd && result->asc == 0x0 &&
+ result->ascq == 0x2)) {
+ pc->error = IDETAPE_ERROR_EOD;
+ set_bit(PC_ABORT, &pc->flags);
+ }
+ }
+ if (pc->c[0] == IDETAPE_READ_CMD || pc->c[0] == IDETAPE_WRITE_CMD) {
+ if (result->sense_key == 8) {
+ pc->error = IDETAPE_ERROR_EOD;
+ set_bit(PC_ABORT, &pc->flags);
+ }
+ if (!test_bit(PC_ABORT, &pc->flags) &&
+ pc->actually_transferred)
+ pc->retries = IDETAPE_MAX_PC_RETRIES + 1;
+ }
+}
+
+/*
+ * idetape_active_next_stage will declare the next stage as "active".
+ */
+static void idetape_active_next_stage (ide_drive_t *drive)
+{
+ idetape_tape_t *tape = drive->driver_data;
+ idetape_stage_t *stage = tape->next_stage;
+ struct request *rq = &stage->rq;
+
+#if IDETAPE_DEBUG_LOG
+ if (tape->debug_level >= 4)
+ printk(KERN_INFO "ide-tape: Reached idetape_active_next_stage\n");
+#endif /* IDETAPE_DEBUG_LOG */
+#if IDETAPE_DEBUG_BUGS
+ if (stage == NULL) {
+ printk(KERN_ERR "ide-tape: bug: Trying to activate a non existing stage\n");
+ return;
+ }
+#endif /* IDETAPE_DEBUG_BUGS */
+
+ rq->rq_disk = tape->disk;
+ rq->buffer = NULL;
+ rq->special = (void *)stage->bh;
+ tape->active_data_request = rq;
+ tape->active_stage = stage;
+ tape->next_stage = stage->next;
+}
+
+/*
+ * idetape_increase_max_pipeline_stages is a part of the feedback
+ * loop which tries to find the optimum number of stages. In the
+ * feedback loop, we are starting from a minimum maximum number of
+ * stages, and if we sense that the pipeline is empty, we try to
+ * increase it, until we reach the user compile time memory limit.
+ */
+static void idetape_increase_max_pipeline_stages (ide_drive_t *drive)
+{
+ idetape_tape_t *tape = drive->driver_data;
+ int increase = (tape->max_pipeline - tape->min_pipeline) / 10;
+
+#if IDETAPE_DEBUG_LOG
+ if (tape->debug_level >= 4)
+ printk (KERN_INFO "ide-tape: Reached idetape_increase_max_pipeline_stages\n");
+#endif /* IDETAPE_DEBUG_LOG */
+
+ tape->max_stages += max(increase, 1);
+ tape->max_stages = max(tape->max_stages, tape->min_pipeline);
+ tape->max_stages = min(tape->max_stages, tape->max_pipeline);
+}
+
+/*
+ * idetape_kfree_stage calls kfree to completely free a stage, along with
+ * its related buffers.
+ */
+static void __idetape_kfree_stage (idetape_stage_t *stage)
+{
+ struct idetape_bh *prev_bh, *bh = stage->bh;
+ int size;
+
+ while (bh != NULL) {
+ if (bh->b_data != NULL) {
+ size = (int) bh->b_size;
+ while (size > 0) {
+ free_page((unsigned long) bh->b_data);
+ size -= PAGE_SIZE;
+ bh->b_data += PAGE_SIZE;
+ }
+ }
+ prev_bh = bh;
+ bh = bh->b_reqnext;
+ kfree(prev_bh);
+ }
+ kfree(stage);
+}
+
+static void idetape_kfree_stage (idetape_tape_t *tape, idetape_stage_t *stage)
+{
+ __idetape_kfree_stage(stage);
+}
+
+/*
+ * idetape_remove_stage_head removes tape->first_stage from the pipeline.
+ * The caller should avoid race conditions.
+ */
+static void idetape_remove_stage_head (ide_drive_t *drive)
+{
+ idetape_tape_t *tape = drive->driver_data;
+ idetape_stage_t *stage;
+
+#if IDETAPE_DEBUG_LOG
+ if (tape->debug_level >= 4)
+ printk(KERN_INFO "ide-tape: Reached idetape_remove_stage_head\n");
+#endif /* IDETAPE_DEBUG_LOG */
+#if IDETAPE_DEBUG_BUGS
+ if (tape->first_stage == NULL) {
+ printk(KERN_ERR "ide-tape: bug: tape->first_stage is NULL\n");
+ return;
+ }
+ if (tape->active_stage == tape->first_stage) {
+ printk(KERN_ERR "ide-tape: bug: Trying to free our active pipeline stage\n");
+ return;
+ }
+#endif /* IDETAPE_DEBUG_BUGS */
+ stage = tape->first_stage;
+ tape->first_stage = stage->next;
+ idetape_kfree_stage(tape, stage);
+ tape->nr_stages--;
+ if (tape->first_stage == NULL) {
+ tape->last_stage = NULL;
+#if IDETAPE_DEBUG_BUGS
+ if (tape->next_stage != NULL)
+ printk(KERN_ERR "ide-tape: bug: tape->next_stage != NULL\n");
+ if (tape->nr_stages)
+ printk(KERN_ERR "ide-tape: bug: nr_stages should be 0 now\n");
+#endif /* IDETAPE_DEBUG_BUGS */
+ }
+}
+
+/*
+ * This will free all the pipeline stages starting from new_last_stage->next
+ * to the end of the list, and point tape->last_stage to new_last_stage.
+ */
+static void idetape_abort_pipeline(ide_drive_t *drive,
+ idetape_stage_t *new_last_stage)
+{
+ idetape_tape_t *tape = drive->driver_data;
+ idetape_stage_t *stage = new_last_stage->next;
+ idetape_stage_t *nstage;
+
+#if IDETAPE_DEBUG_LOG
+ if (tape->debug_level >= 4)
+ printk(KERN_INFO "ide-tape: %s: idetape_abort_pipeline called\n", tape->name);
+#endif
+ while (stage) {
+ nstage = stage->next;
+ idetape_kfree_stage(tape, stage);
+ --tape->nr_stages;
+ --tape->nr_pending_stages;
+ stage = nstage;
+ }
+ if (new_last_stage)
+ new_last_stage->next = NULL;
+ tape->last_stage = new_last_stage;
+ tape->next_stage = NULL;
+}
+
+/*
+ * idetape_end_request is used to finish servicing a request, and to
+ * insert a pending pipeline request into the main device queue.
+ */
+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;
+ int remove_stage = 0;
+ idetape_stage_t *active_stage;
+
+#if IDETAPE_DEBUG_LOG
+ if (tape->debug_level >= 4)
+ printk(KERN_INFO "ide-tape: Reached idetape_end_request\n");
+#endif /* IDETAPE_DEBUG_LOG */
+
+ 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;
+
+ spin_lock_irqsave(&tape->spinlock, flags);
+
+ /* The request was a pipelined data transfer request */
+ if (tape->active_data_request == rq) {
+ active_stage = tape->active_stage;
+ tape->active_stage = NULL;
+ tape->active_data_request = NULL;
+ tape->nr_pending_stages--;
+ if (rq->cmd[0] & REQ_IDETAPE_WRITE) {
+ remove_stage = 1;
+ if (error) {
+ set_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);
+ if (error == IDETAPE_ERROR_EOD)
+ idetape_abort_pipeline(drive, active_stage);
+ }
+ } else if (rq->cmd[0] & REQ_IDETAPE_READ) {
+ if (error == IDETAPE_ERROR_EOD) {
+ set_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);
+ idetape_abort_pipeline(drive, active_stage);
+ }
+ }
+ if (tape->next_stage != NULL) {
+ idetape_active_next_stage(drive);
+
+ /*
+ * Insert the next request into the request queue.
+ */
+ (void) ide_do_drive_cmd(drive, tape->active_data_request, ide_end);
+ } else if (!error) {
+ idetape_increase_max_pipeline_stages(drive);
+ }
+ }
+ ide_end_drive_cmd(drive, 0, 0);
+// blkdev_dequeue_request(rq);
+// drive->rq = NULL;
+// end_that_request_last(rq);
+
+ if (remove_stage)
+ idetape_remove_stage_head(drive);
+ if (tape->active_data_request == NULL)
+ clear_bit(IDETAPE_PIPELINE_ACTIVE, &tape->flags);
+ spin_unlock_irqrestore(&tape->spinlock, flags);
+ return 0;
+}
+
+static ide_startstop_t idetape_request_sense_callback (ide_drive_t *drive)
+{
+ idetape_tape_t *tape = drive->driver_data;
+
+#if IDETAPE_DEBUG_LOG
+ if (tape->debug_level >= 4)
+ printk(KERN_INFO "ide-tape: Reached idetape_request_sense_callback\n");
+#endif /* IDETAPE_DEBUG_LOG */
+ if (!tape->pc->error) {
+ idetape_analyze_error(drive, (idetape_request_sense_result_t *) tape->pc->buffer);
+ idetape_end_request(drive, 1, 0);
+ } else {
+ printk(KERN_ERR "ide-tape: Error in REQUEST SENSE itself - Aborting request!\n");
+ idetape_end_request(drive, 0, 0);
+ }
+ return ide_stopped;
+}
+
+static void idetape_create_request_sense_cmd (idetape_pc_t *pc)
+{
+ idetape_init_pc(pc);
+ pc->c[0] = IDETAPE_REQUEST_SENSE_CMD;
+ pc->c[4] = 20;
+ pc->request_transfer = 20;
+ pc->callback = &idetape_request_sense_callback;
+}
+
+static void idetape_init_rq(struct request *rq, u8 cmd)
+{
+ memset(rq, 0, sizeof(*rq));
+ rq->flags = REQ_SPECIAL;
+ rq->cmd[0] = cmd;
+}
+
+/*
+ * idetape_queue_pc_head generates 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.
+ *
+ * idetape_queue_pc_head is called from the request handling part of
+ * the driver (the "bottom" part). Safe storage for the request should
+ * be allocated with idetape_next_pc_storage and idetape_next_rq_storage
+ * before calling idetape_queue_pc_head.
+ *
+ * Memory for those requests is pre-allocated at initialization time, and
+ * is limited to IDETAPE_PC_STACK requests. We assume that we have enough
+ * space for the maximum possible number of inter-dependent packet commands.
+ *
+ * The higher level of the driver - The ioctl handler and the character
+ * device handling functions should queue request to the lower level part
+ * and wait for their completion using idetape_queue_pc_tail or
+ * idetape_queue_rw_tail.
+ */
+static void idetape_queue_pc_head (ide_drive_t *drive, idetape_pc_t *pc,struct request *rq)
+{
+ struct ide_tape_obj *tape = drive->driver_data;
+
+ idetape_init_rq(rq, REQ_IDETAPE_PC1);
+ rq->buffer = (char *) pc;
+ rq->rq_disk = tape->disk;
+ (void) ide_do_drive_cmd(drive, rq, ide_preempt);
+}
+
+/*
+ * idetape_retry_pc is 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.
+ */
+static ide_startstop_t idetape_retry_pc (ide_drive_t *drive)
+{
+ idetape_tape_t *tape = drive->driver_data;
+ idetape_pc_t *pc;
+ struct request *rq;
+ atapi_error_t error;
+
+ error.all = HWIF(drive)->INB(IDE_ERROR_REG);
+ pc = idetape_next_pc_storage(drive);
+ rq = idetape_next_rq_storage(drive);
+ idetape_create_request_sense_cmd(pc);
+ set_bit(IDETAPE_IGNORE_DSC, &tape->flags);
+ idetape_queue_pc_head(drive, pc, rq);
+ return ide_stopped;
+}
+
+/*
+ * idetape_postpone_request postpones 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;
+
+#if IDETAPE_DEBUG_LOG
+ if (tape->debug_level >= 4)
+ printk(KERN_INFO "ide-tape: idetape_postpone_request\n");
+#endif
+ tape->postponed_rq = HWGROUP(drive)->rq;
+ ide_stall_queue(drive, tape->dsc_polling_frequency);
+}
+
+/*
+ * idetape_pc_intr 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.
+ * When data transfer is finished, we will act according to the
+ * algorithm described before idetape_issue_packet_command.
+ *
+ */
+static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ idetape_tape_t *tape = drive->driver_data;
+ atapi_status_t status;
+ atapi_bcount_t bcount;
+ atapi_ireason_t ireason;
+ idetape_pc_t *pc = tape->pc;
+
+ unsigned int temp;
+#if SIMULATE_ERRORS
+ static int error_sim_count = 0;
+#endif
+
+#if IDETAPE_DEBUG_LOG
+ if (tape->debug_level >= 4)
+ printk(KERN_INFO "ide-tape: Reached idetape_pc_intr "
+ "interrupt handler\n");
+#endif /* IDETAPE_DEBUG_LOG */
+
+ /* Clear the interrupt */
+ status.all = HWIF(drive)->INB(IDE_STATUS_REG);
+
+ if (test_bit(PC_DMA_IN_PROGRESS, &pc->flags)) {
+ if (HWIF(drive)->ide_dma_end(drive) || status.b.check) {
+ /*
+ * A DMA error is sometimes expected. For example,
+ * if the tape is crossing a filemark during a
+ * READ command, it will issue an irq and position
+ * itself before the filemark, so that only a partial
+ * data transfer will occur (which causes the DMA
+ * error). In that case, we will later ask the tape
+ * how much bytes of the original request were
+ * actually transferred (we can't receive that
+ * information from the DMA engine on most chipsets).
+ */
+
+ /*
+ * On the contrary, a DMA error is never expected;
+ * it usually indicates a hardware error or abort.
+ * If the tape crosses a filemark during a READ
+ * command, it will issue an irq and position itself
+ * after the filemark (not before). Only a partial
+ * data transfer will occur, but no DMA error.
+ * (AS, 19 Apr 2001)
+ */
+ set_bit(PC_DMA_ERROR, &pc->flags);
+ } else {
+ pc->actually_transferred = pc->request_transfer;
+ idetape_update_buffers(pc);
+ }
+#if IDETAPE_DEBUG_LOG
+ if (tape->debug_level >= 4)
+ printk(KERN_INFO "ide-tape: DMA finished\n");
+#endif /* IDETAPE_DEBUG_LOG */
+ }
+
+ /* No more interrupts */
+ if (!status.b.drq) {
+#if IDETAPE_DEBUG_LOG
+ if (tape->debug_level >= 2)
+ printk(KERN_INFO "ide-tape: Packet command completed, %d bytes transferred\n", pc->actually_transferred);
+#endif /* IDETAPE_DEBUG_LOG */
+ clear_bit(PC_DMA_IN_PROGRESS, &pc->flags);
+
+ local_irq_enable();
+
+#if SIMULATE_ERRORS
+ if ((pc->c[0] == IDETAPE_WRITE_CMD ||
+ pc->c[0] == IDETAPE_READ_CMD) &&
+ (++error_sim_count % 100) == 0) {
+ printk(KERN_INFO "ide-tape: %s: simulating error\n",
+ tape->name);
+ status.b.check = 1;
+ }
+#endif
+ if (status.b.check && pc->c[0] == IDETAPE_REQUEST_SENSE_CMD)
+ status.b.check = 0;
+ if (status.b.check || test_bit(PC_DMA_ERROR, &pc->flags)) { /* Error detected */
+#if IDETAPE_DEBUG_LOG
+ if (tape->debug_level >= 1)
+ printk(KERN_INFO "ide-tape: %s: I/O error\n",
+ tape->name);
+#endif /* IDETAPE_DEBUG_LOG */
+ if (pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) {
+ printk(KERN_ERR "ide-tape: I/O error in request sense command\n");
+ return ide_do_reset(drive);
+ }
+#if IDETAPE_DEBUG_LOG
+ if (tape->debug_level >= 1)
+ printk(KERN_INFO "ide-tape: [cmd %x]: check condition\n", pc->c[0]);
+#endif
+ /* Retry operation */
+ return idetape_retry_pc(drive);
+ }
+ pc->error = 0;
+ if (test_bit(PC_WAIT_FOR_DSC, &pc->flags) &&
+ !status.b.dsc) {
+ /* Media access command */
+ tape->dsc_polling_start = jiffies;
+ tape->dsc_polling_frequency = IDETAPE_DSC_MA_FAST;
+ tape->dsc_timeout = jiffies + IDETAPE_DSC_MA_TIMEOUT;
+ /* Allow ide.c to handle other requests */
+ idetape_postpone_request(drive);
+ return ide_stopped;
+ }
+ if (tape->failed_pc == pc)
+ tape->failed_pc = NULL;
+ /* Command finished - Call the callback function */
+ return pc->callback(drive);
+ }
+ if (test_and_clear_bit(PC_DMA_IN_PROGRESS, &pc->flags)) {
+ printk(KERN_ERR "ide-tape: The tape wants to issue more "
+ "interrupts in DMA mode\n");
+ printk(KERN_ERR "ide-tape: DMA disabled, reverting to PIO\n");
+ (void)__ide_dma_off(drive);
+ return ide_do_reset(drive);
+ }
+ /* Get the number of bytes to transfer on this interrupt. */
+ bcount.b.high = hwif->INB(IDE_BCOUNTH_REG);
+ bcount.b.low = hwif->INB(IDE_BCOUNTL_REG);
+
+ ireason.all = hwif->INB(IDE_IREASON_REG);
+
+ if (ireason.b.cod) {
+ printk(KERN_ERR "ide-tape: CoD != 0 in idetape_pc_intr\n");
+ return ide_do_reset(drive);
+ }
+ if (ireason.b.io == test_bit(PC_WRITING, &pc->flags)) {
+ /* Hopefully, we will never get here */
+ printk(KERN_ERR "ide-tape: We wanted to %s, ",
+ ireason.b.io ? "Write":"Read");
+ printk(KERN_ERR "ide-tape: but the tape wants us to %s !\n",
+ ireason.b.io ? "Read":"Write");
+ return ide_do_reset(drive);
+ }
+ if (!test_bit(PC_WRITING, &pc->flags)) {
+ /* Reading - Check that we have enough space */
+ temp = pc->actually_transferred + bcount.all;
+ if (temp > pc->request_transfer) {
+ if (temp > pc->buffer_size) {
+ printk(KERN_ERR "ide-tape: The tape wants to send us more data than expected - discarding data\n");
+ idetape_discard_data(drive, bcount.all);
+ ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);
+ return ide_started;
+ }
+#if IDETAPE_DEBUG_LOG
+ if (tape->debug_level >= 2)
+ printk(KERN_NOTICE "ide-tape: The tape wants to send us more data than expected - allowing transfer\n");
+#endif /* IDETAPE_DEBUG_LOG */
+ }
+ }
+ if (test_bit(PC_WRITING, &pc->flags)) {
+ if (pc->bh != NULL)
+ idetape_output_buffers(drive, pc, bcount.all);
+ else
+ /* Write the current buffer */
+ HWIF(drive)->atapi_output_bytes(drive, pc->current_position, bcount.all);
+ } else {
+ if (pc->bh != NULL)
+ idetape_input_buffers(drive, pc, bcount.all);
+ else
+ /* Read the current buffer */
+ HWIF(drive)->atapi_input_bytes(drive, pc->current_position, bcount.all);
+ }
+ /* Update the current position */
+ pc->actually_transferred += bcount.all;
+ pc->current_position += bcount.all;
+#if IDETAPE_DEBUG_LOG
+ if (tape->debug_level >= 2)
+ printk(KERN_INFO "ide-tape: [cmd %x] transferred %d bytes on that interrupt\n", pc->c[0], bcount.all);
+#endif
+ /* And set the interrupt handler again */
+ ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);
+ return ide_started;
+}
+
+/*
+ * Packet Command Interface
+ *
+ * The current Packet Command is available in tape->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_packet_command will send the packet command to the
+ * drive, and will set the interrupt handler to idetape_pc_intr.
+ *
+ * 2. On each interrupt, idetape_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_transfer_pc(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ idetape_tape_t *tape = drive->driver_data;
+ idetape_pc_t *pc = tape->pc;
+ atapi_ireason_t ireason;
+ int retries = 100;
+ ide_startstop_t startstop;
+
+ if (ide_wait_stat(&startstop,drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) {
+ printk(KERN_ERR "ide-tape: Strange, packet command initiated yet DRQ isn't asserted\n");
+ return startstop;
+ }
+ ireason.all = hwif->INB(IDE_IREASON_REG);
+ while (retries-- && (!ireason.b.cod || ireason.b.io)) {
+ printk(KERN_ERR "ide-tape: (IO,CoD != (0,1) while issuing "
+ "a packet command, retrying\n");
+ udelay(100);
+ ireason.all = hwif->INB(IDE_IREASON_REG);
+ if (retries == 0) {
+ printk(KERN_ERR "ide-tape: (IO,CoD != (0,1) while "
+ "issuing a packet command, ignoring\n");
+ ireason.b.cod = 1;
+ ireason.b.io = 0;
+ }
+ }
+ if (!ireason.b.cod || ireason.b.io) {
+ printk(KERN_ERR "ide-tape: (IO,CoD) != (0,1) while issuing "
+ "a packet command\n");
+ return ide_do_reset(drive);
+ }
+ /* Set the interrupt routine */
+ ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);
+#ifdef CONFIG_BLK_DEV_IDEDMA
+ /* Begin DMA, if necessary */
+ if (test_bit(PC_DMA_IN_PROGRESS, &pc->flags))
+ hwif->dma_start(drive);
+#endif
+ /* Send the actual packet */
+ HWIF(drive)->atapi_output_bytes(drive, pc->c, 12);
+ return ide_started;
+}
+
+static ide_startstop_t idetape_issue_packet_command (ide_drive_t *drive, idetape_pc_t *pc)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ idetape_tape_t *tape = drive->driver_data;
+ atapi_bcount_t bcount;
+ int dma_ok = 0;
+
+#if IDETAPE_DEBUG_BUGS
+ if (tape->pc->c[0] == IDETAPE_REQUEST_SENSE_CMD &&
+ pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) {
+ printk(KERN_ERR "ide-tape: possible ide-tape.c bug - "
+ "Two request sense in serial were issued\n");
+ }
+#endif /* IDETAPE_DEBUG_BUGS */
+
+ if (tape->failed_pc == NULL && pc->c[0] != IDETAPE_REQUEST_SENSE_CMD)
+ tape->failed_pc = pc;
+ /* Set the current packet command */
+ tape->pc = pc;
+
+ if (pc->retries > IDETAPE_MAX_PC_RETRIES ||
+ test_bit(PC_ABORT, &pc->flags)) {
+ /*
+ * We will "abort" retrying a packet command in case
+ * a legitimate error code was received (crossing a
+ * filemark, or end of the media, for example).
+ */
+ if (!test_bit(PC_ABORT, &pc->flags)) {
+ if (!(pc->c[0] == IDETAPE_TEST_UNIT_READY_CMD &&
+ 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;
+ return pc->callback(drive);
+ }
+#if IDETAPE_DEBUG_LOG
+ if (tape->debug_level >= 2)
+ printk(KERN_INFO "ide-tape: Retry number - %d, cmd = %02X\n", pc->retries, pc->c[0]);
+#endif /* IDETAPE_DEBUG_LOG */
+
+ pc->retries++;
+ /* We haven't transferred any data yet */
+ pc->actually_transferred = 0;
+ pc->current_position = pc->buffer;
+ /* Request to transfer the entire buffer at once */
+ bcount.all = pc->request_transfer;
+
+ if (test_and_clear_bit(PC_DMA_ERROR, &pc->flags)) {
+ printk(KERN_WARNING "ide-tape: DMA disabled, "
+ "reverting to PIO\n");
+ (void)__ide_dma_off(drive);
+ }
+ if (test_bit(PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma)
+ dma_ok = !hwif->dma_setup(drive);
+
+ if (IDE_CONTROL_REG)
+ hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
+ hwif->OUTB(dma_ok ? 1 : 0, IDE_FEATURE_REG); /* Use PIO/DMA */
+ hwif->OUTB(bcount.b.high, IDE_BCOUNTH_REG);
+ hwif->OUTB(bcount.b.low, IDE_BCOUNTL_REG);
+ hwif->OUTB(drive->select.all, IDE_SELECT_REG);
+ if (dma_ok) /* Will begin DMA later */
+ set_bit(PC_DMA_IN_PROGRESS, &pc->flags);
+ if (test_bit(IDETAPE_DRQ_INTERRUPT, &tape->flags)) {
+ ide_set_handler(drive, &idetape_transfer_pc, IDETAPE_WAIT_CMD, NULL);
+ hwif->OUTB(WIN_PACKETCMD, IDE_COMMAND_REG);
+ return ide_started;
+ } else {
+ hwif->OUTB(WIN_PACKETCMD, IDE_COMMAND_REG);
+ return idetape_transfer_pc(drive);
+ }
+}
+
+/*
+ * General packet command callback function.
+ */
+static ide_startstop_t idetape_pc_callback (ide_drive_t *drive)
+{
+ idetape_tape_t *tape = drive->driver_data;
+
+#if IDETAPE_DEBUG_LOG
+ if (tape->debug_level >= 4)
+ printk(KERN_INFO "ide-tape: Reached idetape_pc_callback\n");
+#endif /* IDETAPE_DEBUG_LOG */
+
+ idetape_end_request(drive, tape->pc->error ? 0 : 1, 0);
+ return ide_stopped;
+}
+
+/*
+ * A mode sense command is used to "sense" tape parameters.
+ */
+static void idetape_create_mode_sense_cmd (idetape_pc_t *pc, u8 page_code)
+{
+ idetape_init_pc(pc);
+ pc->c[0] = IDETAPE_MODE_SENSE_CMD;
+ if (page_code != IDETAPE_BLOCK_DESCRIPTOR)
+ pc->c[1] = 8; /* DBD = 1 - Don't return block descriptors */
+ 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;
+ pc->c[4] = 255; /* (We will just discard data in that case) */
+ if (page_code == IDETAPE_BLOCK_DESCRIPTOR)
+ pc->request_transfer = 12;
+ else if (page_code == IDETAPE_CAPABILITIES_PAGE)
+ pc->request_transfer = 24;
+ else
+ pc->request_transfer = 50;
+ pc->callback = &idetape_pc_callback;
+}
+
+static void calculate_speeds(ide_drive_t *drive)
+{
+ idetape_tape_t *tape = drive->driver_data;
+ int full = 125, empty = 75;
+
+ if (time_after(jiffies, tape->controlled_pipeline_head_time + 120 * HZ)) {
+ tape->controlled_previous_pipeline_head = tape->controlled_last_pipeline_head;
+ tape->controlled_previous_head_time = tape->controlled_pipeline_head_time;
+ tape->controlled_last_pipeline_head = tape->pipeline_head;
+ tape->controlled_pipeline_head_time = jiffies;
+ }
+ if (time_after(jiffies, tape->controlled_pipeline_head_time + 60 * HZ))
+ tape->controlled_pipeline_head_speed = (tape->pipeline_head - tape->controlled_last_pipeline_head) * 32 * HZ / (jiffies - tape->controlled_pipeline_head_time);
+ else if (time_after(jiffies, tape->controlled_previous_head_time))
+ tape->controlled_pipeline_head_speed = (tape->pipeline_head - tape->controlled_previous_pipeline_head) * 32 * HZ / (jiffies - tape->controlled_previous_head_time);
+
+ if (tape->nr_pending_stages < tape->max_stages /*- 1 */) {
+ /* -1 for read mode error recovery */
+ if (time_after(jiffies, tape->uncontrolled_previous_head_time + 10 * HZ)) {
+ tape->uncontrolled_pipeline_head_time = jiffies;
+ tape->uncontrolled_pipeline_head_speed = (tape->pipeline_head - tape->uncontrolled_previous_pipeline_head) * 32 * HZ / (jiffies - tape->uncontrolled_previous_head_time);
+ }
+ } else {
+ tape->uncontrolled_previous_head_time = jiffies;
+ tape->uncontrolled_previous_pipeline_head = tape->pipeline_head;
+ if (time_after(jiffies, tape->uncontrolled_pipeline_head_time + 30 * HZ)) {
+ tape->uncontrolled_pipeline_head_time = jiffies;
+ }
+ }
+ tape->pipeline_head_speed = max(tape->uncontrolled_pipeline_head_speed, tape->controlled_pipeline_head_speed);
+ if (tape->speed_control == 0) {
+ tape->max_insert_speed = 5000;
+ } else if (tape->speed_control == 1) {
+ if (tape->nr_pending_stages >= tape->max_stages / 2)
+ tape->max_insert_speed = tape->pipeline_head_speed +
+ (1100 - tape->pipeline_head_speed) * 2 * (tape->nr_pending_stages - tape->max_stages / 2) / tape->max_stages;
+ else
+ tape->max_insert_speed = 500 +
+ (tape->pipeline_head_speed - 500) * 2 * tape->nr_pending_stages / tape->max_stages;
+ if (tape->nr_pending_stages >= tape->max_stages * 99 / 100)
+ tape->max_insert_speed = 5000;
+ } else if (tape->speed_control == 2) {
+ tape->max_insert_speed = tape->pipeline_head_speed * empty / 100 +
+ (tape->pipeline_head_speed * full / 100 - tape->pipeline_head_speed * empty / 100) * tape->nr_pending_stages / tape->max_stages;
+ } else
+ tape->max_insert_speed = tape->speed_control;
+ tape->max_insert_speed = max(tape->max_insert_speed, 500);
+}
+
+static ide_startstop_t idetape_media_access_finished (ide_drive_t *drive)
+{
+ idetape_tape_t *tape = drive->driver_data;
+ idetape_pc_t *pc = tape->pc;
+ atapi_status_t status;
+
+ status.all = HWIF(drive)->INB(IDE_STATUS_REG);
+ if (status.b.dsc) {
+ if (status.b.check) {
+ /* Error detected */
+ if (pc->c[0] != IDETAPE_TEST_UNIT_READY_CMD)
+ printk(KERN_ERR "ide-tape: %s: I/O error, ",
+ tape->name);
+ /* Retry operation */
+ return idetape_retry_pc(drive);
+ }
+ pc->error = 0;
+ if (tape->failed_pc == pc)
+ tape->failed_pc = NULL;
+ } else {
+ pc->error = IDETAPE_ERROR_GENERAL;
+ tape->failed_pc = NULL;
+ }
+ return pc->callback(drive);
+}
+
+static ide_startstop_t idetape_rw_callback (ide_drive_t *drive)
+{
+ idetape_tape_t *tape = drive->driver_data;
+ struct request *rq = HWGROUP(drive)->rq;
+ int blocks = tape->pc->actually_transferred / tape->tape_block_size;
+
+ tape->avg_size += blocks * tape->tape_block_size;
+ tape->insert_size += blocks * tape->tape_block_size;
+ if (tape->insert_size > 1024 * 1024)
+ tape->measure_insert_time = 1;
+ if (tape->measure_insert_time) {
+ tape->measure_insert_time = 0;
+ tape->insert_time = jiffies;
+ tape->insert_size = 0;
+ }
+ if (time_after(jiffies, tape->insert_time))
+ tape->insert_speed = tape->insert_size / 1024 * HZ / (jiffies - tape->insert_time);
+ if (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;
+ }
+
+#if IDETAPE_DEBUG_LOG
+ if (tape->debug_level >= 4)
+ printk(KERN_INFO "ide-tape: Reached idetape_rw_callback\n");
+#endif /* IDETAPE_DEBUG_LOG */
+
+ tape->first_frame_position += blocks;
+ rq->current_nr_sectors -= blocks;
+
+ if (!tape->pc->error)
+ idetape_end_request(drive, 1, 0);
+ else
+ idetape_end_request(drive, tape->pc->error, 0);
+ return ide_stopped;
+}
+
+static void idetape_create_read_cmd(idetape_tape_t *tape, idetape_pc_t *pc, unsigned int length, struct idetape_bh *bh)
+{
+ idetape_init_pc(pc);
+ pc->c[0] = IDETAPE_READ_CMD;
+ put_unaligned(htonl(length), (unsigned int *) &pc->c[1]);
+ pc->c[1] = 1;
+ pc->callback = &idetape_rw_callback;
+ pc->bh = bh;
+ atomic_set(&bh->b_count, 0);
+ pc->buffer = NULL;
+ pc->request_transfer = pc->buffer_size = length * tape->tape_block_size;
+ if (pc->request_transfer == tape->stage_size)
+ set_bit(PC_DMA_RECOMMENDED, &pc->flags);
+}
+
+static void idetape_create_read_buffer_cmd(idetape_tape_t *tape, idetape_pc_t *pc, unsigned int length, struct idetape_bh *bh)
+{
+ int size = 32768;
+ struct idetape_bh *p = bh;
+
+ idetape_init_pc(pc);
+ pc->c[0] = IDETAPE_READ_BUFFER_CMD;
+ pc->c[1] = IDETAPE_RETRIEVE_FAULTY_BLOCK;
+ pc->c[7] = size >> 8;
+ pc->c[8] = size & 0xff;
+ pc->callback = &idetape_pc_callback;
+ pc->bh = bh;
+ atomic_set(&bh->b_count, 0);
+ pc->buffer = NULL;
+ while (p) {
+ atomic_set(&p->b_count, 0);
+ p = p->b_reqnext;
+ }
+ pc->request_transfer = pc->buffer_size = size;
+}
+
+static void idetape_create_write_cmd(idetape_tape_t *tape, idetape_pc_t *pc, unsigned int length, struct idetape_bh *bh)
+{
+ idetape_init_pc(pc);
+ pc->c[0] = IDETAPE_WRITE_CMD;
+ put_unaligned(htonl(length), (unsigned int *) &pc->c[1]);
+ pc->c[1] = 1;
+ pc->callback = &idetape_rw_callback;
+ set_bit(PC_WRITING, &pc->flags);
+ pc->bh = bh;
+ pc->b_data = bh->b_data;
+ pc->b_count = atomic_read(&bh->b_count);
+ pc->buffer = NULL;
+ pc->request_transfer = pc->buffer_size = length * tape->tape_block_size;
+ if (pc->request_transfer == tape->stage_size)
+ set_bit(PC_DMA_RECOMMENDED, &pc->flags);
+}
+
+/*
+ * idetape_do_request is our request handling function.
+ */
+static ide_startstop_t idetape_do_request(ide_drive_t *drive,
+ struct request *rq, sector_t block)
+{
+ idetape_tape_t *tape = drive->driver_data;
+ idetape_pc_t *pc = NULL;
+ struct request *postponed_rq = tape->postponed_rq;
+ atapi_status_t status;
+
+#if IDETAPE_DEBUG_LOG
+#if 0
+ if (tape->debug_level >= 5)
+ printk(KERN_INFO "ide-tape: rq_status: %d, "
+ "dev: %s, cmd: %ld, errors: %d\n", rq->rq_status,
+ rq->rq_disk->disk_name, rq->cmd[0], rq->errors);
+#endif
+ if (tape->debug_level >= 2)
+ printk(KERN_INFO "ide-tape: sector: %ld, "
+ "nr_sectors: %ld, current_nr_sectors: %d\n",
+ rq->sector, rq->nr_sectors, rq->current_nr_sectors);
+#endif /* IDETAPE_DEBUG_LOG */
+
+ if ((rq->flags & REQ_SPECIAL) == 0) {
+ /*
+ * We do not support buffer cache originated requests.
+ */
+ printk(KERN_NOTICE "ide-tape: %s: Unsupported request in "
+ "request queue (%ld)\n", drive->name, rq->flags);
+ ide_end_request(drive, 0, 0);
+ return ide_stopped;
+ }
+
+ /*
+ * Retry a failed packet command
+ */
+ if (tape->failed_pc != NULL &&
+ tape->pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) {
+ return idetape_issue_packet_command(drive, tape->failed_pc);
+ }
+#if IDETAPE_DEBUG_BUGS
+ 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;
+ }
+#endif /* IDETAPE_DEBUG_BUGS */
+
+ tape->postponed_rq = NULL;
+
+ /*
+ * If the tape is still busy, postpone our request and service
+ * the other device meanwhile.
+ */
+ status.all = HWIF(drive)->INB(IDE_STATUS_REG);
+
+ if (!drive->dsc_overlap && !(rq->cmd[0] & REQ_IDETAPE_PC2))
+ set_bit(IDETAPE_IGNORE_DSC, &tape->flags);
+
+ if (drive->post_reset == 1) {
+ set_bit(IDETAPE_IGNORE_DSC, &tape->flags);
+ drive->post_reset = 0;
+ }
+
+ if (tape->tape_still_time > 100 && tape->tape_still_time < 200)
+ tape->measure_insert_time = 1;
+ if (time_after(jiffies, tape->insert_time))
+ tape->insert_speed = tape->insert_size / 1024 * HZ / (jiffies - tape->insert_time);
+ calculate_speeds(drive);
+ if (!test_and_clear_bit(IDETAPE_IGNORE_DSC, &tape->flags) &&
+ !status.b.dsc) {
+ if (postponed_rq == NULL) {
+ tape->dsc_polling_start = jiffies;
+ tape->dsc_polling_frequency = tape->best_dsc_rw_frequency;
+ 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[0] & REQ_IDETAPE_PC2) {
+ idetape_media_access_finished(drive);
+ return ide_stopped;
+ } else {
+ return ide_do_reset(drive);
+ }
+ } else if (jiffies - tape->dsc_polling_start > IDETAPE_DSC_MA_THRESHOLD)
+ tape->dsc_polling_frequency = IDETAPE_DSC_MA_SLOW;
+ idetape_postpone_request(drive);
+ return ide_stopped;
+ }
+ if (rq->cmd[0] & REQ_IDETAPE_READ) {
+ tape->buffer_head++;
+#if USE_IOTRACE
+ IO_trace(IO_IDETAPE_FIFO, tape->pipeline_head, tape->buffer_head, tape->tape_head, tape->minor);
+#endif
+ tape->postpone_cnt = 0;
+ pc = idetape_next_pc_storage(drive);
+ idetape_create_read_cmd(tape, pc, rq->current_nr_sectors, (struct idetape_bh *)rq->special);
+ goto out;
+ }
+ if (rq->cmd[0] & REQ_IDETAPE_WRITE) {
+ tape->buffer_head++;
+#if USE_IOTRACE
+ IO_trace(IO_IDETAPE_FIFO, tape->pipeline_head, tape->buffer_head, tape->tape_head, tape->minor);
+#endif
+ tape->postpone_cnt = 0;
+ pc = idetape_next_pc_storage(drive);
+ idetape_create_write_cmd(tape, pc, rq->current_nr_sectors, (struct idetape_bh *)rq->special);
+ goto out;
+ }
+ if (rq->cmd[0] & REQ_IDETAPE_READ_BUFFER) {
+ tape->postpone_cnt = 0;
+ pc = idetape_next_pc_storage(drive);
+ idetape_create_read_buffer_cmd(tape, pc, rq->current_nr_sectors, (struct idetape_bh *)rq->special);
+ goto out;
+ }
+ if (rq->cmd[0] & REQ_IDETAPE_PC1) {
+ pc = (idetape_pc_t *) rq->buffer;
+ rq->cmd[0] &= ~(REQ_IDETAPE_PC1);
+ rq->cmd[0] |= REQ_IDETAPE_PC2;
+ goto out;
+ }
+ if (rq->cmd[0] & REQ_IDETAPE_PC2) {
+ idetape_media_access_finished(drive);
+ return ide_stopped;
+ }
+ BUG();
+out:
+ return idetape_issue_packet_command(drive, pc);
+}
+
+/*
+ * Pipeline related functions
+ */
+static inline int idetape_pipeline_active (idetape_tape_t *tape)
+{
+ int rc1, rc2;
+
+ rc1 = test_bit(IDETAPE_PIPELINE_ACTIVE, &tape->flags);
+ rc2 = (tape->active_data_request != NULL);
+ return rc1;
+}
+
+/*
+ * idetape_kmalloc_stage uses __get_free_page to allocate a pipeline
+ * stage, along with all the necessary small buffers which together make
+ * a buffer of size tape->stage_size (or a bit more). We attempt to
+ * combine sequential pages as much as possible.
+ *
+ * Returns a pointer to the new allocated stage, or NULL if we
+ * can't (or don't want to) allocate a stage.
+ *
+ * Pipeline stages are optional and are used to increase performance.
+ * If we can't allocate them, we'll manage without them.
+ */
+static idetape_stage_t *__idetape_kmalloc_stage (idetape_tape_t *tape, int full, int clear)
+{
+ idetape_stage_t *stage;
+ struct idetape_bh *prev_bh, *bh;
+ int pages = tape->pages_per_stage;
+ char *b_data = NULL;
+
+ if ((stage = (idetape_stage_t *) kmalloc (sizeof (idetape_stage_t),GFP_KERNEL)) == NULL)
+ return NULL;
+ stage->next = NULL;
+
+ bh = stage->bh = (struct idetape_bh *)kmalloc(sizeof(struct idetape_bh), GFP_KERNEL);
+ if (bh == NULL)
+ goto abort;
+ bh->b_reqnext = NULL;
+ if ((bh->b_data = (char *) __get_free_page (GFP_KERNEL)) == NULL)
+ goto abort;
+ if (clear)
+ memset(bh->b_data, 0, PAGE_SIZE);
+ bh->b_size = PAGE_SIZE;
+ atomic_set(&bh->b_count, full ? bh->b_size : 0);
+
+ while (--pages) {
+ if ((b_data = (char *) __get_free_page (GFP_KERNEL)) == NULL)
+ goto abort;
+ if (clear)
+ memset(b_data, 0, PAGE_SIZE);
+ if (bh->b_data == b_data + PAGE_SIZE) {
+ bh->b_size += PAGE_SIZE;
+ bh->b_data -= PAGE_SIZE;
+ if (full)
+ atomic_add(PAGE_SIZE, &bh->b_count);
+ continue;
+ }
+ if (b_data == bh->b_data + bh->b_size) {
+ bh->b_size += PAGE_SIZE;
+ if (full)
+ atomic_add(PAGE_SIZE, &bh->b_count);
+ continue;
+ }
+ prev_bh = bh;
+ if ((bh = (struct idetape_bh *)kmalloc(sizeof(struct idetape_bh), GFP_KERNEL)) == NULL) {
+ free_page((unsigned long) b_data);
+ goto abort;
+ }
+ bh->b_reqnext = NULL;
+ bh->b_data = b_data;
+ bh->b_size = PAGE_SIZE;
+ atomic_set(&bh->b_count, full ? bh->b_size : 0);
+ prev_bh->b_reqnext = bh;
+ }
+ bh->b_size -= tape->excess_bh_size;
+ if (full)
+ atomic_sub(tape->excess_bh_size, &bh->b_count);
+ return stage;
+abort:
+ __idetape_kfree_stage(stage);
+ return NULL;
+}
+
+static idetape_stage_t *idetape_kmalloc_stage (idetape_tape_t *tape)
+{
+ idetape_stage_t *cache_stage = tape->cache_stage;
+
+#if IDETAPE_DEBUG_LOG
+ if (tape->debug_level >= 4)
+ printk(KERN_INFO "ide-tape: Reached idetape_kmalloc_stage\n");
+#endif /* IDETAPE_DEBUG_LOG */
+
+ if (tape->nr_stages >= tape->max_stages)
+ return NULL;
+ if (cache_stage != NULL) {
+ tape->cache_stage = NULL;
+ return cache_stage;
+ }
+ return __idetape_kmalloc_stage(tape, 0, 0);
+}
+
+static void idetape_copy_stage_from_user (idetape_tape_t *tape, idetape_stage_t *stage, const char __user *buf, int n)
+{
+ struct idetape_bh *bh = tape->bh;
+ int count;
+
+ while (n) {
+#if IDETAPE_DEBUG_BUGS
+ if (bh == NULL) {
+ printk(KERN_ERR "ide-tape: bh == NULL in "
+ "idetape_copy_stage_from_user\n");
+ return;
+ }
+#endif /* IDETAPE_DEBUG_BUGS */
+ count = min((unsigned int)(bh->b_size - atomic_read(&bh->b_count)), (unsigned int)n);
+ copy_from_user(bh->b_data + atomic_read(&bh->b_count), buf, count);
+ 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;
+}
+
+static void idetape_copy_stage_to_user (idetape_tape_t *tape, char __user *buf, idetape_stage_t *stage, int n)
+{
+ struct idetape_bh *bh = tape->bh;
+ int count;
+
+ while (n) {
+#if IDETAPE_DEBUG_BUGS
+ if (bh == NULL) {
+ printk(KERN_ERR "ide-tape: bh == NULL in "
+ "idetape_copy_stage_to_user\n");
+ return;
+ }
+#endif /* IDETAPE_DEBUG_BUGS */
+ count = min(tape->b_count, n);
+ copy_to_user(buf, tape->b_data, count);
+ n -= count;
+ tape->b_data += count;
+ tape->b_count -= count;
+ buf += count;
+ if (!tape->b_count) {
+ tape->bh = bh = bh->b_reqnext;
+ if (bh) {
+ tape->b_data = bh->b_data;
+ tape->b_count = atomic_read(&bh->b_count);
+ }
+ }
+ }
+}
+
+static void idetape_init_merge_stage (idetape_tape_t *tape)
+{
+ struct idetape_bh *bh = tape->merge_stage->bh;
+
+ tape->bh = bh;
+ if (tape->chrdev_direction == idetape_direction_write)
+ atomic_set(&bh->b_count, 0);
+ else {
+ tape->b_data = bh->b_data;
+ tape->b_count = atomic_read(&bh->b_count);
+ }
+}
+
+static void idetape_switch_buffers (idetape_tape_t *tape, idetape_stage_t *stage)
+{
+ struct idetape_bh *tmp;
+
+ tmp = stage->bh;
+ stage->bh = tape->merge_stage->bh;
+ tape->merge_stage->bh = tmp;
+ idetape_init_merge_stage(tape);
+}
+
+/*
+ * idetape_add_stage_tail adds a new stage at the end of the pipeline.
+ */
+static void idetape_add_stage_tail (ide_drive_t *drive,idetape_stage_t *stage)
+{
+ idetape_tape_t *tape = drive->driver_data;
+ unsigned long flags;
+
+#if IDETAPE_DEBUG_LOG
+ if (tape->debug_level >= 4)
+ printk (KERN_INFO "ide-tape: Reached idetape_add_stage_tail\n");
+#endif /* IDETAPE_DEBUG_LOG */
+ spin_lock_irqsave(&tape->spinlock, flags);
+ stage->next = NULL;
+ if (tape->last_stage != NULL)
+ tape->last_stage->next=stage;
+ else
+ tape->first_stage = tape->next_stage=stage;
+ tape->last_stage = stage;
+ if (tape->next_stage == NULL)
+ tape->next_stage = tape->last_stage;
+ tape->nr_stages++;
+ tape->nr_pending_stages++;
+ spin_unlock_irqrestore(&tape->spinlock, flags);
+}
+
+/*
+ * idetape_wait_for_request installs a completion in a pending request
+ * and sleeps until it is serviced.
+ *
+ * The caller should ensure that the request will not be serviced
+ * before we install the completion (usually by disabling interrupts).
+ */
+static void idetape_wait_for_request (ide_drive_t *drive, struct request *rq)
+{
+ DECLARE_COMPLETION(wait);
+ idetape_tape_t *tape = drive->driver_data;
+
+#if IDETAPE_DEBUG_BUGS
+ if (rq == NULL || (rq->flags & REQ_SPECIAL) == 0) {
+ printk (KERN_ERR "ide-tape: bug: Trying to sleep on non-valid request\n");
+ return;
+ }
+#endif /* IDETAPE_DEBUG_BUGS */
+ rq->waiting = &wait;
+ rq->end_io = blk_end_sync_rq;
+ spin_unlock_irq(&tape->spinlock);
+ wait_for_completion(&wait);
+ /* The stage and its struct request have been deallocated */
+ spin_lock_irq(&tape->spinlock);
+}
+
+static ide_startstop_t idetape_read_position_callback (ide_drive_t *drive)
+{
+ idetape_tape_t *tape = drive->driver_data;
+ idetape_read_position_result_t *result;
+
+#if IDETAPE_DEBUG_LOG
+ if (tape->debug_level >= 4)
+ printk(KERN_INFO "ide-tape: Reached idetape_read_position_callback\n");
+#endif /* IDETAPE_DEBUG_LOG */
+
+ if (!tape->pc->error) {
+ result = (idetape_read_position_result_t *) tape->pc->buffer;
+#if IDETAPE_DEBUG_LOG
+ if (tape->debug_level >= 2)
+ printk(KERN_INFO "ide-tape: BOP - %s\n",result->bop ? "Yes":"No");
+ if (tape->debug_level >= 2)
+ printk(KERN_INFO "ide-tape: EOP - %s\n",result->eop ? "Yes":"No");
+#endif /* IDETAPE_DEBUG_LOG */
+ if (result->bpu) {
+ printk(KERN_INFO "ide-tape: Block location is unknown to the tape\n");
+ clear_bit(IDETAPE_ADDRESS_VALID, &tape->flags);
+ idetape_end_request(drive, 0, 0);
+ } else {
+#if IDETAPE_DEBUG_LOG
+ if (tape->debug_level >= 2)
+ printk(KERN_INFO "ide-tape: Block Location - %u\n", ntohl(result->first_block));
+#endif /* IDETAPE_DEBUG_LOG */
+ tape->partition = result->partition;
+ tape->first_frame_position = ntohl(result->first_block);
+ tape->last_frame_position = ntohl(result->last_block);
+ tape->blocks_in_buffer = result->blocks_in_buffer[2];
+ set_bit(IDETAPE_ADDRESS_VALID, &tape->flags);
+ idetape_end_request(drive, 1, 0);
+ }
+ } else {
+ idetape_end_request(drive, 0, 0);
+ }
+ return ide_stopped;
+}
+
+/*
+ * idetape_create_write_filemark_cmd will:
+ *
+ * 1. Write a filemark if write_filemark=1.
+ * 2. Flush the device buffers without writing a filemark
+ * if write_filemark=0.
+ *
+ */
+static void idetape_create_write_filemark_cmd (ide_drive_t *drive, idetape_pc_t *pc,int write_filemark)
+{
+ idetape_init_pc(pc);
+ pc->c[0] = IDETAPE_WRITE_FILEMARK_CMD;
+ pc->c[4] = write_filemark;
+ set_bit(PC_WAIT_FOR_DSC, &pc->flags);
+ pc->callback = &idetape_pc_callback;
+}
+
+static void idetape_create_test_unit_ready_cmd(idetape_pc_t *pc)
+{
+ idetape_init_pc(pc);
+ pc->c[0] = IDETAPE_TEST_UNIT_READY_CMD;
+ pc->callback = &idetape_pc_callback;
+}
+
+/*
+ * idetape_queue_pc_tail is based on the following functions:
+ *
+ * ide_do_drive_cmd from ide.c
+ * cdrom_queue_request and cdrom_queue_packet_command from ide-cd.c
+ *
+ * We add a special packet command request to the tail of the request
+ * queue, and wait for it to be serviced.
+ *
+ * This is not to be called from within the request handling part
+ * of the driver ! We allocate here data in the stack, and it is valid
+ * until the request is finished. This is not the case for the bottom
+ * part of the driver, where we are always leaving the functions to wait
+ * for an interrupt or a timer event.
+ *
+ * From the bottom part of the driver, we should allocate safe memory
+ * using idetape_next_pc_storage and idetape_next_rq_storage, and add
+ * the request to the request list without waiting for it to be serviced !
+ * In that case, we usually use idetape_queue_pc_head.
+ */
+static int __idetape_queue_pc_tail (ide_drive_t *drive, idetape_pc_t *pc)
+{
+ struct ide_tape_obj *tape = drive->driver_data;
+ struct request rq;
+
+ idetape_init_rq(&rq, REQ_IDETAPE_PC1);
+ rq.buffer = (char *) pc;
+ rq.rq_disk = tape->disk;
+ return ide_do_drive_cmd(drive, &rq, ide_wait);
+}
+
+static void idetape_create_load_unload_cmd (ide_drive_t *drive, idetape_pc_t *pc,int cmd)
+{
+ idetape_init_pc(pc);
+ pc->c[0] = IDETAPE_LOAD_UNLOAD_CMD;
+ pc->c[4] = cmd;
+ set_bit(PC_WAIT_FOR_DSC, &pc->flags);
+ pc->callback = &idetape_pc_callback;
+}
+
+static int idetape_wait_ready(ide_drive_t *drive, unsigned long timeout)
+{
+ idetape_tape_t *tape = drive->driver_data;
+ idetape_pc_t pc;
+ int load_attempted = 0;
+
+ /*
+ * Wait for the tape to become ready
+ */
+ set_bit(IDETAPE_MEDIUM_PRESENT, &tape->flags);
+ timeout += jiffies;
+ while (time_before(jiffies, timeout)) {
+ idetape_create_test_unit_ready_cmd(&pc);
+ if (!__idetape_queue_pc_tail(drive, &pc))
+ return 0;
+ if ((tape->sense_key == 2 && tape->asc == 4 && tape->ascq == 2)
+ || (tape->asc == 0x3A)) { /* no media */
+ if (load_attempted)
+ return -ENOMEDIUM;
+ idetape_create_load_unload_cmd(drive, &pc, IDETAPE_LU_LOAD_MASK);
+ __idetape_queue_pc_tail(drive, &pc);
+ 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;
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(HZ / 10);
+ }
+ return -EIO;
+}
+
+static int idetape_queue_pc_tail (ide_drive_t *drive,idetape_pc_t *pc)
+{
+ return __idetape_queue_pc_tail(drive, pc);
+}
+
+static int idetape_flush_tape_buffers (ide_drive_t *drive)
+{
+ idetape_pc_t pc;
+ int rc;
+
+ idetape_create_write_filemark_cmd(drive, &pc, 0);
+ if ((rc = idetape_queue_pc_tail(drive, &pc)))
+ return rc;
+ idetape_wait_ready(drive, 60 * 5 * HZ);
+ return 0;
+}
+
+static void idetape_create_read_position_cmd (idetape_pc_t *pc)
+{
+ idetape_init_pc(pc);
+ pc->c[0] = IDETAPE_READ_POSITION_CMD;
+ pc->request_transfer = 20;
+ pc->callback = &idetape_read_position_callback;
+}
+
+static int idetape_read_position (ide_drive_t *drive)
+{
+ idetape_tape_t *tape = drive->driver_data;
+ idetape_pc_t pc;
+ int position;
+
+#if IDETAPE_DEBUG_LOG
+ if (tape->debug_level >= 4)
+ printk(KERN_INFO "ide-tape: Reached idetape_read_position\n");
+#endif /* IDETAPE_DEBUG_LOG */
+
+ idetape_create_read_position_cmd(&pc);
+ if (idetape_queue_pc_tail(drive, &pc))
+ return -1;
+ position = tape->first_frame_position;
+ return position;
+}
+
+static void idetape_create_locate_cmd (ide_drive_t *drive, idetape_pc_t *pc, unsigned int block, u8 partition, int skip)
+{
+ idetape_init_pc(pc);
+ pc->c[0] = IDETAPE_LOCATE_CMD;
+ pc->c[1] = 2;
+ put_unaligned(htonl(block), (unsigned int *) &pc->c[3]);
+ pc->c[8] = partition;
+ set_bit(PC_WAIT_FOR_DSC, &pc->flags);
+ pc->callback = &idetape_pc_callback;
+}
+
+static int idetape_create_prevent_cmd (ide_drive_t *drive, idetape_pc_t *pc, int prevent)
+{
+ idetape_tape_t *tape = drive->driver_data;
+
+ if (!tape->capabilities.lock)
+ return 0;
+
+ idetape_init_pc(pc);
+ pc->c[0] = IDETAPE_PREVENT_CMD;
+ pc->c[4] = prevent;
+ pc->callback = &idetape_pc_callback;
+ return 1;
+}
+
+static int __idetape_discard_read_pipeline (ide_drive_t *drive)
+{
+ idetape_tape_t *tape = drive->driver_data;
+ unsigned long flags;
+ int cnt;
+
+ if (tape->chrdev_direction != idetape_direction_read)
+ return 0;
+
+ /* Remove merge stage. */
+ cnt = tape->merge_stage_size / tape->tape_block_size;
+ if (test_and_clear_bit(IDETAPE_FILEMARK, &tape->flags))
+ ++cnt; /* Filemarks count as 1 sector */
+ tape->merge_stage_size = 0;
+ if (tape->merge_stage != NULL) {
+ __idetape_kfree_stage(tape->merge_stage);
+ tape->merge_stage = NULL;
+ }
+
+ /* Clear pipeline flags. */
+ clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);
+ tape->chrdev_direction = idetape_direction_none;
+
+ /* Remove pipeline stages. */
+ if (tape->first_stage == NULL)
+ return 0;
+
+ spin_lock_irqsave(&tape->spinlock, flags);
+ tape->next_stage = NULL;
+ if (idetape_pipeline_active(tape))
+ idetape_wait_for_request(drive, tape->active_data_request);
+ spin_unlock_irqrestore(&tape->spinlock, flags);
+
+ while (tape->first_stage != NULL) {
+ struct request *rq_ptr = &tape->first_stage->rq;
+
+ cnt += rq_ptr->nr_sectors - rq_ptr->current_nr_sectors;
+ if (rq_ptr->errors == IDETAPE_ERROR_FILEMARK)
+ ++cnt;
+ idetape_remove_stage_head(drive);
+ }
+ tape->nr_pending_stages = 0;
+ tape->max_stages = tape->min_pipeline;
+ return cnt;
+}
+
+/*
+ * idetape_position_tape positions 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;
+ int retval;
+ idetape_pc_t pc;
+
+ if (tape->chrdev_direction == idetape_direction_read)
+ __idetape_discard_read_pipeline(drive);
+ idetape_wait_ready(drive, 60 * 5 * HZ);
+ idetape_create_locate_cmd(drive, &pc, block, partition, skip);
+ retval = idetape_queue_pc_tail(drive, &pc);
+ if (retval)
+ return (retval);
+
+ idetape_create_read_position_cmd(&pc);
+ return (idetape_queue_pc_tail(drive, &pc));
+}
+
+static void idetape_discard_read_pipeline (ide_drive_t *drive, int restore_position)
+{
+ idetape_tape_t *tape = drive->driver_data;
+ int cnt;
+ int seek, position;
+
+ cnt = __idetape_discard_read_pipeline(drive);
+ if (restore_position) {
+ position = idetape_read_position(drive);
+ seek = position > cnt ? position - cnt : 0;
+ if (idetape_position_tape(drive, seek, 0, 0)) {
+ printk(KERN_INFO "ide-tape: %s: position_tape failed in discard_pipeline()\n", tape->name);
+ return;
+ }
+ }
+}
+
+/*
+ * idetape_queue_rw_tail generates 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;
+
+#if IDETAPE_DEBUG_LOG
+ if (tape->debug_level >= 2)
+ printk(KERN_INFO "ide-tape: idetape_queue_rw_tail: cmd=%d\n",cmd);
+#endif /* IDETAPE_DEBUG_LOG */
+#if IDETAPE_DEBUG_BUGS
+ if (idetape_pipeline_active(tape)) {
+ printk(KERN_ERR "ide-tape: bug: the pipeline is active in idetape_queue_rw_tail\n");
+ return (0);
+ }
+#endif /* IDETAPE_DEBUG_BUGS */
+
+ idetape_init_rq(&rq, cmd);
+ rq.rq_disk = tape->disk;
+ rq.special = (void *)bh;
+ rq.sector = tape->first_frame_position;
+ rq.nr_sectors = rq.current_nr_sectors = blocks;
+ (void) ide_do_drive_cmd(drive, &rq, ide_wait);
+
+ if ((cmd & (REQ_IDETAPE_READ | REQ_IDETAPE_WRITE)) == 0)
+ return 0;
+
+ if (tape->merge_stage)
+ idetape_init_merge_stage(tape);
+ if (rq.errors == IDETAPE_ERROR_GENERAL)
+ return -EIO;
+ return (tape->tape_block_size * (blocks-rq.current_nr_sectors));
+}
+
+/*
+ * idetape_insert_pipeline_into_queue is used to start servicing the
+ * pipeline stages, starting from tape->next_stage.
+ */
+static void idetape_insert_pipeline_into_queue (ide_drive_t *drive)
+{
+ idetape_tape_t *tape = drive->driver_data;
+
+ if (tape->next_stage == NULL)
+ return;
+ if (!idetape_pipeline_active(tape)) {
+ set_bit(IDETAPE_PIPELINE_ACTIVE, &tape->flags);
+ idetape_active_next_stage(drive);
+ (void) ide_do_drive_cmd(drive, tape->active_data_request, ide_end);
+ }
+}
+
+static void idetape_create_inquiry_cmd (idetape_pc_t *pc)
+{
+ idetape_init_pc(pc);
+ pc->c[0] = IDETAPE_INQUIRY_CMD;
+ pc->c[4] = pc->request_transfer = 254;
+ pc->callback = &idetape_pc_callback;
+}
+
+static void idetape_create_rewind_cmd (ide_drive_t *drive, idetape_pc_t *pc)
+{
+ idetape_init_pc(pc);
+ pc->c[0] = IDETAPE_REWIND_CMD;
+ set_bit(PC_WAIT_FOR_DSC, &pc->flags);
+ pc->callback = &idetape_pc_callback;
+}
+
+#if 0
+static void idetape_create_mode_select_cmd (idetape_pc_t *pc, int length)
+{
+ idetape_init_pc(pc);
+ set_bit(PC_WRITING, &pc->flags);
+ pc->c[0] = IDETAPE_MODE_SELECT_CMD;
+ pc->c[1] = 0x10;
+ put_unaligned(htons(length), (unsigned short *) &pc->c[3]);
+ pc->request_transfer = 255;
+ pc->callback = &idetape_pc_callback;
+}
+#endif
+
+static void idetape_create_erase_cmd (idetape_pc_t *pc)
+{
+ idetape_init_pc(pc);
+ pc->c[0] = IDETAPE_ERASE_CMD;
+ pc->c[1] = 1;
+ set_bit(PC_WAIT_FOR_DSC, &pc->flags);
+ pc->callback = &idetape_pc_callback;
+}
+
+static void idetape_create_space_cmd (idetape_pc_t *pc,int count, u8 cmd)
+{
+ idetape_init_pc(pc);
+ pc->c[0] = IDETAPE_SPACE_CMD;
+ put_unaligned(htonl(count), (unsigned int *) &pc->c[1]);
+ pc->c[1] = cmd;
+ set_bit(PC_WAIT_FOR_DSC, &pc->flags);
+ pc->callback = &idetape_pc_callback;
+}
+
+static void idetape_wait_first_stage (ide_drive_t *drive)
+{
+ idetape_tape_t *tape = drive->driver_data;
+ unsigned long flags;
+
+ if (tape->first_stage == NULL)
+ return;
+ spin_lock_irqsave(&tape->spinlock, flags);
+ if (tape->active_stage == tape->first_stage)
+ idetape_wait_for_request(drive, tape->active_data_request);
+ spin_unlock_irqrestore(&tape->spinlock, flags);
+}
+
+/*
+ * idetape_add_chrdev_write_request tries to add a character device
+ * originated write request to our pipeline. In case we don't succeed,
+ * we revert to non-pipelined operation mode for this request.
+ *
+ * 1. Try to allocate a new pipeline stage.
+ * 2. If we can't, wait for more and more requests to be serviced
+ * and try again each time.
+ * 3. If we still can't allocate a stage, fallback to
+ * non-pipelined operation mode for this request.
+ */
+static int idetape_add_chrdev_write_request (ide_drive_t *drive, int blocks)
+{
+ idetape_tape_t *tape = drive->driver_data;
+ idetape_stage_t *new_stage;
+ unsigned long flags;
+ struct request *rq;
+
+#if IDETAPE_DEBUG_LOG
+ if (tape->debug_level >= 3)
+ printk(KERN_INFO "ide-tape: Reached idetape_add_chrdev_write_request\n");
+#endif /* IDETAPE_DEBUG_LOG */
+
+ /*
+ * Attempt to allocate a new stage.
+ * Pay special attention to possible race conditions.
+ */
+ while ((new_stage = idetape_kmalloc_stage(tape)) == NULL) {
+ spin_lock_irqsave(&tape->spinlock, flags);
+ if (idetape_pipeline_active(tape)) {
+ idetape_wait_for_request(drive, tape->active_data_request);
+ spin_unlock_irqrestore(&tape->spinlock, flags);
+ } else {
+ spin_unlock_irqrestore(&tape->spinlock, flags);
+ idetape_insert_pipeline_into_queue(drive);
+ if (idetape_pipeline_active(tape))
+ continue;
+ /*
+ * Linux is short on memory. Fallback to
+ * non-pipelined operation mode for this request.
+ */
+ return idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE, blocks, tape->merge_stage->bh);
+ }
+ }
+ rq = &new_stage->rq;
+ idetape_init_rq(rq, REQ_IDETAPE_WRITE);
+ /* Doesn't actually matter - We always assume sequential access */
+ rq->sector = tape->first_frame_position;
+ rq->nr_sectors = rq->current_nr_sectors = blocks;
+
+ idetape_switch_buffers(tape, new_stage);
+ idetape_add_stage_tail(drive, new_stage);
+ tape->pipeline_head++;
+#if USE_IOTRACE
+ IO_trace(IO_IDETAPE_FIFO, tape->pipeline_head, tape->buffer_head, tape->tape_head, tape->minor);
+#endif
+ calculate_speeds(drive);
+
+ /*
+ * Estimate whether the tape has stopped writing by checking
+ * if our write pipeline is currently empty. If we are not
+ * writing anymore, wait for the pipeline to be full enough
+ * (90%) before starting to service requests, so that we will
+ * be able to keep up with the higher speeds of the tape.
+ */
+ if (!idetape_pipeline_active(tape)) {
+ if (tape->nr_stages >= tape->max_stages * 9 / 10 ||
+ tape->nr_stages >= tape->max_stages - tape->uncontrolled_pipeline_head_speed * 3 * 1024 / tape->tape_block_size) {
+ tape->measure_insert_time = 1;
+ tape->insert_time = jiffies;
+ tape->insert_size = 0;
+ tape->insert_speed = 0;
+ idetape_insert_pipeline_into_queue(drive);
+ }
+ }
+ if (test_and_clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags))
+ /* Return a deferred error */
+ return -EIO;
+ return blocks;
+}
+
+/*
+ * idetape_wait_for_pipeline will wait until all pending pipeline
+ * requests are serviced. Typically called on device close.
+ */
+static void idetape_wait_for_pipeline (ide_drive_t *drive)
+{
+ idetape_tape_t *tape = drive->driver_data;
+ unsigned long flags;
+
+ while (tape->next_stage || idetape_pipeline_active(tape)) {
+ idetape_insert_pipeline_into_queue(drive);
+ spin_lock_irqsave(&tape->spinlock, flags);
+ if (idetape_pipeline_active(tape))
+ idetape_wait_for_request(drive, tape->active_data_request);
+ spin_unlock_irqrestore(&tape->spinlock, flags);
+ }
+}
+
+static void idetape_empty_write_pipeline (ide_drive_t *drive)
+{
+ idetape_tape_t *tape = drive->driver_data;
+ int blocks, min;
+ struct idetape_bh *bh;
+
+#if IDETAPE_DEBUG_BUGS
+ if (tape->chrdev_direction != idetape_direction_write) {
+ printk(KERN_ERR "ide-tape: bug: Trying to empty write pipeline, but we are not writing.\n");
+ return;
+ }
+ if (tape->merge_stage_size > tape->stage_size) {
+ printk(KERN_ERR "ide-tape: bug: merge_buffer too big\n");
+ tape->merge_stage_size = tape->stage_size;
+ }
+#endif /* IDETAPE_DEBUG_BUGS */
+ if (tape->merge_stage_size) {
+ blocks = tape->merge_stage_size / tape->tape_block_size;
+ if (tape->merge_stage_size % tape->tape_block_size) {
+ unsigned int i;
+
+ blocks++;
+ i = tape->tape_block_size - tape->merge_stage_size % tape->tape_block_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_stage_size = 0;
+ }
+ idetape_wait_for_pipeline(drive);
+ if (tape->merge_stage != NULL) {
+ __idetape_kfree_stage(tape->merge_stage);
+ tape->merge_stage = NULL;
+ }
+ clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);
+ tape->chrdev_direction = idetape_direction_none;
+
+ /*
+ * On the next backup, perform the feedback loop again.
+ * (I don't want to keep sense information between backups,
+ * as some systems are constantly on, and the system load
+ * can be totally different on the next backup).
+ */
+ tape->max_stages = tape->min_pipeline;
+#if IDETAPE_DEBUG_BUGS
+ if (tape->first_stage != NULL ||
+ tape->next_stage != NULL ||
+ tape->last_stage != NULL ||
+ tape->nr_stages != 0) {
+ printk(KERN_ERR "ide-tape: ide-tape pipeline bug, "
+ "first_stage %p, next_stage %p, "
+ "last_stage %p, nr_stages %d\n",
+ tape->first_stage, tape->next_stage,
+ tape->last_stage, tape->nr_stages);
+ }
+#endif /* IDETAPE_DEBUG_BUGS */
+}
+
+static void idetape_restart_speed_control (ide_drive_t *drive)
+{
+ idetape_tape_t *tape = drive->driver_data;
+
+ tape->restart_speed_control_req = 0;
+ tape->pipeline_head = 0;
+ tape->controlled_last_pipeline_head = tape->uncontrolled_last_pipeline_head = 0;
+ tape->controlled_previous_pipeline_head = tape->uncontrolled_previous_pipeline_head = 0;
+ tape->pipeline_head_speed = tape->controlled_pipeline_head_speed = 5000;
+ tape->uncontrolled_pipeline_head_speed = 0;
+ tape->controlled_pipeline_head_time = tape->uncontrolled_pipeline_head_time = jiffies;
+ tape->controlled_previous_head_time = tape->uncontrolled_previous_head_time = jiffies;
+}
+
+static int idetape_initiate_read (ide_drive_t *drive, int max_stages)
+{
+ idetape_tape_t *tape = drive->driver_data;
+ idetape_stage_t *new_stage;
+ struct request rq;
+ int bytes_read;
+ int blocks = tape->capabilities.ctl;
+
+ /* Initialize read operation */
+ if (tape->chrdev_direction != idetape_direction_read) {
+ if (tape->chrdev_direction == idetape_direction_write) {
+ idetape_empty_write_pipeline(drive);
+ idetape_flush_tape_buffers(drive);
+ }
+#if IDETAPE_DEBUG_BUGS
+ if (tape->merge_stage || tape->merge_stage_size) {
+ printk (KERN_ERR "ide-tape: merge_stage_size should be 0 now\n");
+ tape->merge_stage_size = 0;
+ }
+#endif /* IDETAPE_DEBUG_BUGS */
+ if ((tape->merge_stage = __idetape_kmalloc_stage(tape, 0, 0)) == NULL)
+ return -ENOMEM;
+ tape->chrdev_direction = idetape_direction_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->dsc_overlap) {
+ bytes_read = idetape_queue_rw_tail(drive, REQ_IDETAPE_READ, 0, tape->merge_stage->bh);
+ if (bytes_read < 0) {
+ __idetape_kfree_stage(tape->merge_stage);
+ tape->merge_stage = NULL;
+ tape->chrdev_direction = idetape_direction_none;
+ return bytes_read;
+ }
+ }
+ }
+ if (tape->restart_speed_control_req)
+ idetape_restart_speed_control(drive);
+ idetape_init_rq(&rq, REQ_IDETAPE_READ);
+ rq.sector = tape->first_frame_position;
+ rq.nr_sectors = rq.current_nr_sectors = blocks;
+ if (!test_bit(IDETAPE_PIPELINE_ERROR, &tape->flags) &&
+ tape->nr_stages < max_stages) {
+ new_stage = idetape_kmalloc_stage(tape);
+ while (new_stage != NULL) {
+ new_stage->rq = rq;
+ idetape_add_stage_tail(drive, new_stage);
+ if (tape->nr_stages >= max_stages)
+ break;
+ new_stage = idetape_kmalloc_stage(tape);
+ }
+ }
+ if (!idetape_pipeline_active(tape)) {
+ if (tape->nr_pending_stages >= 3 * max_stages / 4) {
+ tape->measure_insert_time = 1;
+ tape->insert_time = jiffies;
+ tape->insert_size = 0;
+ tape->insert_speed = 0;
+ idetape_insert_pipeline_into_queue(drive);
+ }
+ }
+ return 0;
+}
+
+/*
+ * idetape_add_chrdev_read_request is called from idetape_chrdev_read
+ * to service a character device read request and add read-ahead
+ * requests to our pipeline.
+ */
+static int idetape_add_chrdev_read_request (ide_drive_t *drive,int blocks)
+{
+ idetape_tape_t *tape = drive->driver_data;
+ unsigned long flags;
+ struct request *rq_ptr;
+ int bytes_read;
+
+#if IDETAPE_DEBUG_LOG
+ if (tape->debug_level >= 4)
+ printk(KERN_INFO "ide-tape: Reached idetape_add_chrdev_read_request, %d blocks\n", blocks);
+#endif /* IDETAPE_DEBUG_LOG */
+
+ /*
+ * If we are at a filemark, return a read length of 0
+ */
+ if (test_bit(IDETAPE_FILEMARK, &tape->flags))
+ return 0;
+
+ /*
+ * Wait for the next block to be available at the head
+ * of the pipeline
+ */
+ idetape_initiate_read(drive, tape->max_stages);
+ if (tape->first_stage == NULL) {
+ if (test_bit(IDETAPE_PIPELINE_ERROR, &tape->flags))
+ return 0;
+ return idetape_queue_rw_tail(drive, REQ_IDETAPE_READ, blocks, tape->merge_stage->bh);
+ }
+ idetape_wait_first_stage(drive);
+ rq_ptr = &tape->first_stage->rq;
+ bytes_read = tape->tape_block_size * (rq_ptr->nr_sectors - rq_ptr->current_nr_sectors);
+ rq_ptr->nr_sectors = rq_ptr->current_nr_sectors = 0;
+
+
+ if (rq_ptr->errors == IDETAPE_ERROR_EOD)
+ return 0;
+ else {
+ idetape_switch_buffers(tape, tape->first_stage);
+ if (rq_ptr->errors == IDETAPE_ERROR_FILEMARK)
+ set_bit(IDETAPE_FILEMARK, &tape->flags);
+ spin_lock_irqsave(&tape->spinlock, flags);
+ idetape_remove_stage_head(drive);
+ spin_unlock_irqrestore(&tape->spinlock, flags);
+ tape->pipeline_head++;
+#if USE_IOTRACE
+ IO_trace(IO_IDETAPE_FIFO, tape->pipeline_head, tape->buffer_head, tape->tape_head, tape->minor);
+#endif
+ calculate_speeds(drive);
+ }
+#if IDETAPE_DEBUG_BUGS
+ if (bytes_read > blocks * tape->tape_block_size) {
+ printk(KERN_ERR "ide-tape: bug: trying to return more bytes than requested\n");
+ bytes_read = blocks * tape->tape_block_size;
+ }
+#endif /* IDETAPE_DEBUG_BUGS */
+ return (bytes_read);
+}
+
+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_stage->bh;
+ count = min(tape->stage_size, bcount);
+ bcount -= count;
+ blocks = count / tape->tape_block_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_stage->bh);
+ }
+}
+
+static int idetape_pipeline_size (ide_drive_t *drive)
+{
+ idetape_tape_t *tape = drive->driver_data;
+ idetape_stage_t *stage;
+ struct request *rq;
+ int size = 0;
+
+ idetape_wait_for_pipeline(drive);
+ stage = tape->first_stage;
+ while (stage != NULL) {
+ rq = &stage->rq;
+ size += tape->tape_block_size * (rq->nr_sectors-rq->current_nr_sectors);
+ if (rq->errors == IDETAPE_ERROR_FILEMARK)
+ size += tape->tape_block_size;
+ stage = stage->next;
+ }
+ size += tape->merge_stage_size;
+ return size;
+}
+
+/*
+ * 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)
+{
+ int retval;
+ idetape_pc_t pc;
+#if IDETAPE_DEBUG_LOG
+ idetape_tape_t *tape = drive->driver_data;
+ if (tape->debug_level >= 2)
+ printk(KERN_INFO "ide-tape: Reached idetape_rewind_tape\n");
+#endif /* IDETAPE_DEBUG_LOG */
+
+ idetape_create_rewind_cmd(drive, &pc);
+ retval = idetape_queue_pc_tail(drive, &pc);
+ if (retval)
+ return retval;
+
+ idetape_create_read_position_cmd(&pc);
+ retval = idetape_queue_pc_tail(drive, &pc);
+ if (retval)
+ return retval;
+ return 0;
+}
+
+/*
+ * Our special ide-tape ioctl's.
+ *
+ * Currently there aren't any ioctl's.
+ * mtio.h compatible commands should be issued to the character device
+ * interface.
+ */
+static int idetape_blkdev_ioctl(ide_drive_t *drive, unsigned int cmd, unsigned long arg)
+{
+ idetape_tape_t *tape = drive->driver_data;
+ idetape_config_t config;
+ void __user *argp = (void __user *)arg;
+
+#if IDETAPE_DEBUG_LOG
+ if (tape->debug_level >= 4)
+ printk(KERN_INFO "ide-tape: Reached idetape_blkdev_ioctl\n");
+#endif /* IDETAPE_DEBUG_LOG */
+ switch (cmd) {
+ case 0x0340:
+ if (copy_from_user(&config, argp, sizeof (idetape_config_t)))
+ return -EFAULT;
+ tape->best_dsc_rw_frequency = config.dsc_rw_frequency;
+ tape->max_stages = config.nr_stages;
+ break;
+ case 0x0350:
+ config.dsc_rw_frequency = (int) tape->best_dsc_rw_frequency;
+ config.nr_stages = tape->max_stages;
+ if (copy_to_user(argp, &config, sizeof (idetape_config_t)))
+ return -EFAULT;
+ break;
+ default:
+ return -EIO;
+ }
+ return 0;
+}
+
+/*
+ * idetape_space_over_filemarks is now a bit more complicated than just
+ * passing the command to the tape since we may have crossed some
+ * filemarks during our pipelined read-ahead mode.
+ *
+ * As a minor side effect, the pipeline enables us to support MTFSFM when
+ * the filemark is in our internal pipeline even if the tape doesn't
+ * support spacing over filemarks in the reverse direction.
+ */
+static int idetape_space_over_filemarks (ide_drive_t *drive,short mt_op,int mt_count)
+{
+ idetape_tape_t *tape = drive->driver_data;
+ idetape_pc_t pc;
+ unsigned long flags;
+ int retval,count=0;
+
+ if (mt_count == 0)
+ return 0;
+ if (MTBSF == mt_op || MTBSFM == mt_op) {
+ if (!tape->capabilities.sprev)
+ return -EIO;
+ mt_count = - mt_count;
+ }
+
+ if (tape->chrdev_direction == idetape_direction_read) {
+ /*
+ * We have a read-ahead buffer. Scan it for crossed
+ * filemarks.
+ */
+ tape->merge_stage_size = 0;
+ if (test_and_clear_bit(IDETAPE_FILEMARK, &tape->flags))
+ ++count;
+ while (tape->first_stage != NULL) {
+ if (count == mt_count) {
+ if (mt_op == MTFSFM)
+ set_bit(IDETAPE_FILEMARK, &tape->flags);
+ return 0;
+ }
+ spin_lock_irqsave(&tape->spinlock, flags);
+ if (tape->first_stage == tape->active_stage) {
+ /*
+ * We have reached the active stage in the read pipeline.
+ * There is no point in allowing the drive to continue
+ * reading any farther, so we stop the pipeline.
+ *
+ * This section should be moved to a separate subroutine,
+ * because a similar function is performed in
+ * __idetape_discard_read_pipeline(), for example.
+ */
+ tape->next_stage = NULL;
+ spin_unlock_irqrestore(&tape->spinlock, flags);
+ idetape_wait_first_stage(drive);
+ tape->next_stage = tape->first_stage->next;
+ } else
+ spin_unlock_irqrestore(&tape->spinlock, flags);
+ if (tape->first_stage->rq.errors == IDETAPE_ERROR_FILEMARK)
+ ++count;
+ idetape_remove_stage_head(drive);
+ }
+ idetape_discard_read_pipeline(drive, 0);
+ }
+
+ /*
+ * The filemark was not found in our internal pipeline.
+ * Now we can issue the space command.
+ */
+ switch (mt_op) {
+ case MTFSF:
+ case MTBSF:
+ idetape_create_space_cmd(&pc,mt_count-count,IDETAPE_SPACE_OVER_FILEMARK);
+ return (idetape_queue_pc_tail(drive, &pc));
+ case MTFSFM:
+ case MTBSFM:
+ if (!tape->capabilities.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 (26 KB on my particular tape).
+ * (32 kB 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 = ide_tape_f(file);
+ ide_drive_t *drive = tape->drive;
+ ssize_t bytes_read,temp, actually_read = 0, rc;
+
+#if IDETAPE_DEBUG_LOG
+ if (tape->debug_level >= 3)
+ printk(KERN_INFO "ide-tape: Reached idetape_chrdev_read, count %Zd\n", count);
+#endif /* IDETAPE_DEBUG_LOG */
+
+ if (tape->chrdev_direction != idetape_direction_read) {
+ if (test_bit(IDETAPE_DETECT_BS, &tape->flags))
+ if (count > tape->tape_block_size &&
+ (count % tape->tape_block_size) == 0)
+ tape->user_bs_factor = count / tape->tape_block_size;
+ }
+ if ((rc = idetape_initiate_read(drive, tape->max_stages)) < 0)
+ return rc;
+ if (count == 0)
+ return (0);
+ if (tape->merge_stage_size) {
+ actually_read = min((unsigned int)(tape->merge_stage_size), (unsigned int)count);
+ idetape_copy_stage_to_user(tape, buf, tape->merge_stage, actually_read);
+ buf += actually_read;
+ tape->merge_stage_size -= actually_read;
+ count -= actually_read;
+ }
+ while (count >= tape->stage_size) {
+ bytes_read = idetape_add_chrdev_read_request(drive, tape->capabilities.ctl);
+ if (bytes_read <= 0)
+ goto finish;
+ idetape_copy_stage_to_user(tape, buf, tape->merge_stage, bytes_read);
+ buf += bytes_read;
+ count -= bytes_read;
+ actually_read += bytes_read;
+ }
+ if (count) {
+ bytes_read = idetape_add_chrdev_read_request(drive, tape->capabilities.ctl);
+ if (bytes_read <= 0)
+ goto finish;
+ temp = min((unsigned long)count, (unsigned long)bytes_read);
+ idetape_copy_stage_to_user(tape, buf, tape->merge_stage, temp);
+ actually_read += temp;
+ tape->merge_stage_size = bytes_read-temp;
+ }
+finish:
+ if (!actually_read && test_bit(IDETAPE_FILEMARK, &tape->flags)) {
+#if IDETAPE_DEBUG_LOG
+ if (tape->debug_level >= 2)
+ printk(KERN_INFO "ide-tape: %s: spacing over filemark\n", tape->name);
+#endif
+ idetape_space_over_filemarks(drive, MTFSF, 1);
+ return 0;
+ }
+ return 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 = ide_tape_f(file);
+ ide_drive_t *drive = tape->drive;
+ ssize_t retval, actually_written = 0;
+
+ /* The drive is write protected. */
+ if (tape->write_prot)
+ return -EACCES;
+
+#if IDETAPE_DEBUG_LOG
+ if (tape->debug_level >= 3)
+ printk(KERN_INFO "ide-tape: Reached idetape_chrdev_write, "
+ "count %Zd\n", count);
+#endif /* IDETAPE_DEBUG_LOG */
+
+ /* Initialize write operation */
+ if (tape->chrdev_direction != idetape_direction_write) {
+ if (tape->chrdev_direction == idetape_direction_read)
+ idetape_discard_read_pipeline(drive, 1);
+#if IDETAPE_DEBUG_BUGS
+ if (tape->merge_stage || tape->merge_stage_size) {
+ printk(KERN_ERR "ide-tape: merge_stage_size "
+ "should be 0 now\n");
+ tape->merge_stage_size = 0;
+ }
+#endif /* IDETAPE_DEBUG_BUGS */
+ if ((tape->merge_stage = __idetape_kmalloc_stage(tape, 0, 0)) == NULL)
+ return -ENOMEM;
+ tape->chrdev_direction = idetape_direction_write;
+ idetape_init_merge_stage(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->dsc_overlap) {
+ retval = idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE, 0, tape->merge_stage->bh);
+ if (retval < 0) {
+ __idetape_kfree_stage(tape->merge_stage);
+ tape->merge_stage = NULL;
+ tape->chrdev_direction = idetape_direction_none;
+ return retval;
+ }
+ }
+ }
+ if (count == 0)
+ return (0);
+ if (tape->restart_speed_control_req)
+ idetape_restart_speed_control(drive);
+ if (tape->merge_stage_size) {
+#if IDETAPE_DEBUG_BUGS
+ if (tape->merge_stage_size >= tape->stage_size) {
+ printk(KERN_ERR "ide-tape: bug: merge buffer too big\n");
+ tape->merge_stage_size = 0;
+ }
+#endif /* IDETAPE_DEBUG_BUGS */
+ actually_written = min((unsigned int)(tape->stage_size - tape->merge_stage_size), (unsigned int)count);
+ idetape_copy_stage_from_user(tape, tape->merge_stage, buf, actually_written);
+ buf += actually_written;
+ tape->merge_stage_size += actually_written;
+ count -= actually_written;
+
+ if (tape->merge_stage_size == tape->stage_size) {
+ tape->merge_stage_size = 0;
+ retval = idetape_add_chrdev_write_request(drive, tape->capabilities.ctl);
+ if (retval <= 0)
+ return (retval);
+ }
+ }
+ while (count >= tape->stage_size) {
+ idetape_copy_stage_from_user(tape, tape->merge_stage, buf, tape->stage_size);
+ buf += tape->stage_size;
+ count -= tape->stage_size;
+ retval = idetape_add_chrdev_write_request(drive, tape->capabilities.ctl);
+ actually_written += tape->stage_size;
+ if (retval <= 0)
+ return (retval);
+ }
+ if (count) {
+ actually_written += count;
+ idetape_copy_stage_from_user(tape, tape->merge_stage, buf, count);
+ tape->merge_stage_size += count;
+ }
+ return (actually_written);
+}
+
+static int idetape_write_filemark (ide_drive_t *drive)
+{
+ idetape_pc_t pc;
+
+ /* Write a filemark */
+ idetape_create_write_filemark_cmd(drive, &pc, 1);
+ if (idetape_queue_pc_tail(drive, &pc)) {
+ printk(KERN_ERR "ide-tape: Couldn't write a filemark\n");
+ return -EIO;
+ }
+ return 0;
+}
+
+/*
+ * idetape_mtioctop is called from idetape_chrdev_ioctl when
+ * the general mtio MTIOCTOP ioctl is requested.
+ *
+ * We currently support the following mtio.h operations:
+ *
+ * MTFSF - Space over mt_count filemarks in the positive direction.
+ * The tape is positioned after the last spaced filemark.
+ *
+ * MTFSFM - Same as MTFSF, but the tape is positioned before the
+ * last filemark.
+ *
+ * MTBSF - Steps background over mt_count filemarks, tape is
+ * positioned before the last filemark.
+ *
+ * MTBSFM - Like MTBSF, only tape is positioned after the last filemark.
+ *
+ * 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 (it is
+ * supported in the rare case in which we crossed the filemark
+ * during our read-ahead pipelined operation mode).
+ *
+ * MTWEOF - Writes mt_count filemarks. Tape is positioned after
+ * the last written filemark.
+ *
+ * MTREW - Rewinds tape.
+ *
+ * MTLOAD - Loads the tape.
+ *
+ * MTOFFL - Puts the tape drive "Offline": Rewinds the tape and
+ * MTUNLOAD prevents further access until the media is replaced.
+ *
+ * MTNOP - Flushes tape buffers.
+ *
+ * MTRETEN - Retension media. This typically consists of one end
+ * to end pass on the media.
+ *
+ * MTEOM - Moves to the end of recorded data.
+ *
+ * MTERASE - Erases tape.
+ *
+ * MTSETBLK - Sets the user block size to mt_count bytes. If
+ * mt_count is 0, we will attempt to autodetect
+ * the block size.
+ *
+ * MTSEEK - Positions the tape in a specific block number, where
+ * each block is assumed to contain which user_block_size
+ * bytes.
+ *
+ * MTSETPART - Switches to another tape partition.
+ *
+ * MTLOCK - Locks the tape door.
+ *
+ * MTUNLOCK - Unlocks the tape door.
+ *
+ * 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;
+ idetape_pc_t pc;
+ int i,retval;
+
+#if IDETAPE_DEBUG_LOG
+ if (tape->debug_level >= 1)
+ printk(KERN_INFO "ide-tape: Handling MTIOCTOP ioctl: "
+ "mt_op=%d, mt_count=%d\n", mt_op, mt_count);
+#endif /* IDETAPE_DEBUG_LOG */
+ /*
+ * Commands which need our pipelined read-ahead stages.
+ */
+ 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;
+ idetape_discard_read_pipeline(drive, 1);
+ for (i = 0; i < mt_count; i++) {
+ retval = idetape_write_filemark(drive);
+ if (retval)
+ return retval;
+ }
+ return (0);
+ case MTREW:
+ idetape_discard_read_pipeline(drive, 0);
+ if (idetape_rewind_tape(drive))
+ return -EIO;
+ return 0;
+ case MTLOAD:
+ idetape_discard_read_pipeline(drive, 0);
+ idetape_create_load_unload_cmd(drive, &pc, IDETAPE_LU_LOAD_MASK);
+ return (idetape_queue_pc_tail(drive, &pc));
+ case MTUNLOAD:
+ case MTOFFL:
+ /*
+ * If door is locked, attempt to unlock before
+ * attempting to eject.
+ */
+ if (tape->door_locked) {
+ if (idetape_create_prevent_cmd(drive, &pc, 0))
+ if (!idetape_queue_pc_tail(drive, &pc))
+ tape->door_locked = DOOR_UNLOCKED;
+ }
+ idetape_discard_read_pipeline(drive, 0);
+ idetape_create_load_unload_cmd(drive, &pc,!IDETAPE_LU_LOAD_MASK);
+ retval = idetape_queue_pc_tail(drive, &pc);
+ if (!retval)
+ clear_bit(IDETAPE_MEDIUM_PRESENT, &tape->flags);
+ return retval;
+ case MTNOP:
+ idetape_discard_read_pipeline(drive, 0);
+ return (idetape_flush_tape_buffers(drive));
+ case MTRETEN:
+ idetape_discard_read_pipeline(drive, 0);
+ idetape_create_load_unload_cmd(drive, &pc,IDETAPE_LU_RETENSION_MASK | IDETAPE_LU_LOAD_MASK);
+ return (idetape_queue_pc_tail(drive, &pc));
+ case MTEOM:
+ idetape_create_space_cmd(&pc, 0, IDETAPE_SPACE_TO_EOD);
+ return (idetape_queue_pc_tail(drive, &pc));
+ case MTERASE:
+ (void) idetape_rewind_tape(drive);
+ idetape_create_erase_cmd(&pc);
+ return (idetape_queue_pc_tail(drive, &pc));
+ case MTSETBLK:
+ if (mt_count) {
+ if (mt_count < tape->tape_block_size || mt_count % tape->tape_block_size)
+ return -EIO;
+ tape->user_bs_factor = mt_count / tape->tape_block_size;
+ clear_bit(IDETAPE_DETECT_BS, &tape->flags);
+ } else
+ set_bit(IDETAPE_DETECT_BS, &tape->flags);
+ return 0;
+ case MTSEEK:
+ idetape_discard_read_pipeline(drive, 0);
+ return idetape_position_tape(drive, mt_count * tape->user_bs_factor, tape->partition, 0);
+ case MTSETPART:
+ idetape_discard_read_pipeline(drive, 0);
+ return (idetape_position_tape(drive, 0, mt_count, 0));
+ case MTFSR:
+ case MTBSR:
+ case MTLOCK:
+ if (!idetape_create_prevent_cmd(drive, &pc, 1))
+ return 0;
+ retval = idetape_queue_pc_tail(drive, &pc);
+ if (retval) return retval;
+ tape->door_locked = DOOR_EXPLICITLY_LOCKED;
+ return 0;
+ case MTUNLOCK:
+ if (!idetape_create_prevent_cmd(drive, &pc, 0))
+ return 0;
+ retval = idetape_queue_pc_tail(drive, &pc);
+ 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.
+ *
+ * The following ioctls are supported:
+ *
+ * MTIOCTOP - Refer to idetape_mtioctop for detailed description.
+ *
+ * MTIOCGET - The mt_dsreg field in the returned mtget structure
+ * will be set to (user block size in bytes <<
+ * MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK.
+ *
+ * The mt_blkno is set to the current user block number.
+ * The other mtget fields are not supported.
+ *
+ * MTIOCPOS - The current tape "block position" is returned. We
+ * assume that each block contains user_block_size
+ * bytes.
+ *
+ * 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 = ide_tape_f(file);
+ ide_drive_t *drive = tape->drive;
+ struct mtop mtop;
+ struct mtget mtget;
+ struct mtpos mtpos;
+ int block_offset = 0, position = tape->first_frame_position;
+ void __user *argp = (void __user *)arg;
+
+#if IDETAPE_DEBUG_LOG
+ if (tape->debug_level >= 3)
+ printk(KERN_INFO "ide-tape: Reached idetape_chrdev_ioctl, "
+ "cmd=%u\n", cmd);
+#endif /* IDETAPE_DEBUG_LOG */
+
+ tape->restart_speed_control_req = 1;
+ if (tape->chrdev_direction == idetape_direction_write) {
+ idetape_empty_write_pipeline(drive);
+ idetape_flush_tape_buffers(drive);
+ }
+ if (cmd == MTIOCGET || cmd == MTIOCPOS) {
+ block_offset = idetape_pipeline_size(drive) / (tape->tape_block_size * tape->user_bs_factor);
+ if ((position = idetape_read_position(drive)) < 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->tape_block_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_direction == idetape_direction_read)
+ idetape_discard_read_pipeline(drive, 1);
+ return idetape_blkdev_ioctl(drive, cmd, arg);
+ }
+}
+
+static void idetape_get_blocksize_from_block_descriptor(ide_drive_t *drive);
+
+/*
+ * Our character device open function.
+ */
+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;
+ idetape_pc_t pc;
+ int retval;
+
+ /*
+ * 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);
+
+#if IDETAPE_DEBUG_LOG
+ printk(KERN_INFO "ide-tape: Reached idetape_chrdev_open\n");
+#endif /* IDETAPE_DEBUG_LOG */
+
+ if (i >= MAX_HWIFS * MAX_DRIVES)
+ return -ENXIO;
+
+ if (!(tape = ide_tape_chrdev_get(i)))
+ return -ENXIO;
+
+ drive = tape->drive;
+
+ filp->private_data = tape;
+
+ if (test_and_set_bit(IDETAPE_BUSY, &tape->flags)) {
+ retval = -EBUSY;
+ goto out_put_tape;
+ }
+
+ retval = idetape_wait_ready(drive, 60 * HZ);
+ if (retval) {
+ clear_bit(IDETAPE_BUSY, &tape->flags);
+ printk(KERN_ERR "ide-tape: %s: drive not ready\n", tape->name);
+ goto out_put_tape;
+ }
+
+ idetape_read_position(drive);
+ if (!test_bit(IDETAPE_ADDRESS_VALID, &tape->flags))
+ (void)idetape_rewind_tape(drive);
+
+ if (tape->chrdev_direction != idetape_direction_read)
+ clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);
+
+ /* Read block size and write protect status from drive. */
+ idetape_get_blocksize_from_block_descriptor(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(IDETAPE_BUSY, &tape->flags);
+ retval = -EROFS;
+ goto out_put_tape;
+ }
+ }
+
+ /*
+ * Lock the tape drive door so user can't eject.
+ */
+ if (tape->chrdev_direction == idetape_direction_none) {
+ if (idetape_create_prevent_cmd(drive, &pc, 1)) {
+ if (!idetape_queue_pc_tail(drive, &pc)) {
+ if (tape->door_locked != DOOR_EXPLICITLY_LOCKED)
+ tape->door_locked = DOOR_LOCKED;
+ }
+ }
+ }
+ idetape_restart_speed_control(drive);
+ tape->restart_speed_control_req = 0;
+ return 0;
+
+out_put_tape:
+ ide_tape_put(tape);
+ return retval;
+}
+
+static void idetape_write_release (ide_drive_t *drive, unsigned int minor)
+{
+ idetape_tape_t *tape = drive->driver_data;
+
+ idetape_empty_write_pipeline(drive);
+ tape->merge_stage = __idetape_kmalloc_stage(tape, 1, 0);
+ if (tape->merge_stage != NULL) {
+ idetape_pad_zeros(drive, tape->tape_block_size * (tape->user_bs_factor - 1));
+ __idetape_kfree_stage(tape->merge_stage);
+ tape->merge_stage = NULL;
+ }
+ idetape_write_filemark(drive);
+ idetape_flush_tape_buffers(drive);
+ idetape_flush_tape_buffers(drive);
+}
+
+/*
+ * Our character device release function.
+ */
+static int idetape_chrdev_release (struct inode *inode, struct file *filp)
+{
+ struct ide_tape_obj *tape = ide_tape_f(filp);
+ ide_drive_t *drive = tape->drive;
+ idetape_pc_t pc;
+ unsigned int minor = iminor(inode);
+
+ lock_kernel();
+ tape = drive->driver_data;
+#if IDETAPE_DEBUG_LOG
+ if (tape->debug_level >= 3)
+ printk(KERN_INFO "ide-tape: Reached idetape_chrdev_release\n");
+#endif /* IDETAPE_DEBUG_LOG */
+
+ if (tape->chrdev_direction == idetape_direction_write)
+ idetape_write_release(drive, minor);
+ if (tape->chrdev_direction == idetape_direction_read) {
+ if (minor < 128)
+ idetape_discard_read_pipeline(drive, 1);
+ else
+ idetape_wait_for_pipeline(drive);
+ }
+ if (tape->cache_stage != NULL) {
+ __idetape_kfree_stage(tape->cache_stage);
+ tape->cache_stage = NULL;
+ }
+ if (minor < 128 && test_bit(IDETAPE_MEDIUM_PRESENT, &tape->flags))
+ (void) idetape_rewind_tape(drive);
+ if (tape->chrdev_direction == idetape_direction_none) {
+ if (tape->door_locked == DOOR_LOCKED) {
+ if (idetape_create_prevent_cmd(drive, &pc, 0)) {
+ if (!idetape_queue_pc_tail(drive, &pc))
+ tape->door_locked = DOOR_UNLOCKED;
+ }
+ }
+ }
+ clear_bit(IDETAPE_BUSY, &tape->flags);
+ ide_tape_put(tape);
+ unlock_kernel();
+ return 0;
+}
+
+/*
+ * idetape_identify_device is called to check the contents of the
+ * ATAPI IDENTIFY command results. We return:
+ *
+ * 1 If the tape can be supported by us, based on the information
+ * we have so far.
+ *
+ * 0 If this tape driver is not currently supported by us.
+ */
+static int idetape_identify_device (ide_drive_t *drive)
+{
+ struct idetape_id_gcw gcw;
+ struct hd_driveid *id = drive->id;
+#if IDETAPE_DEBUG_INFO
+ unsigned short mask,i;
+#endif /* IDETAPE_DEBUG_INFO */
+
+ if (drive->id_read == 0)
+ return 1;
+
+ *((unsigned short *) &gcw) = id->config;
+
+#if IDETAPE_DEBUG_INFO
+ printk(KERN_INFO "ide-tape: Dumping ATAPI Identify Device tape parameters\n");
+ printk(KERN_INFO "ide-tape: Protocol Type: ");
+ switch (gcw.protocol) {
+ case 0: case 1: printk("ATA\n");break;
+ case 2: printk("ATAPI\n");break;
+ case 3: printk("Reserved (Unknown to ide-tape)\n");break;
+ }
+ printk(KERN_INFO "ide-tape: Device Type: %x - ",gcw.device_type);
+ switch (gcw.device_type) {
+ case 0: printk("Direct-access Device\n");break;
+ case 1: printk("Streaming Tape Device\n");break;
+ case 2: case 3: case 4: printk("Reserved\n");break;
+ case 5: printk("CD-ROM Device\n");break;
+ case 6: printk("Reserved\n");
+ case 7: printk("Optical memory Device\n");break;
+ case 0x1f: printk("Unknown or no Device type\n");break;
+ default: printk("Reserved\n");
+ }
+ printk(KERN_INFO "ide-tape: Removable: %s",gcw.removable ? "Yes\n":"No\n");
+ printk(KERN_INFO "ide-tape: Command Packet DRQ Type: ");
+ switch (gcw.drq_type) {
+ case 0: printk("Microprocessor DRQ\n");break;
+ case 1: printk("Interrupt DRQ\n");break;
+ case 2: printk("Accelerated DRQ\n");break;
+ case 3: printk("Reserved\n");break;
+ }
+ printk(KERN_INFO "ide-tape: Command Packet Size: ");
+ switch (gcw.packet_size) {
+ case 0: printk("12 bytes\n");break;
+ case 1: printk("16 bytes\n");break;
+ default: printk("Reserved\n");break;
+ }
+ printk(KERN_INFO "ide-tape: Model: %.40s\n",id->model);
+ printk(KERN_INFO "ide-tape: Firmware Revision: %.8s\n",id->fw_rev);
+ printk(KERN_INFO "ide-tape: Serial Number: %.20s\n",id->serial_no);
+ printk(KERN_INFO "ide-tape: Write buffer size: %d bytes\n",id->buf_size*512);
+ printk(KERN_INFO "ide-tape: DMA: %s",id->capability & 0x01 ? "Yes\n":"No\n");
+ printk(KERN_INFO "ide-tape: LBA: %s",id->capability & 0x02 ? "Yes\n":"No\n");
+ printk(KERN_INFO "ide-tape: IORDY can be disabled: %s",id->capability & 0x04 ? "Yes\n":"No\n");
+ printk(KERN_INFO "ide-tape: IORDY supported: %s",id->capability & 0x08 ? "Yes\n":"Unknown\n");
+ printk(KERN_INFO "ide-tape: ATAPI overlap supported: %s",id->capability & 0x20 ? "Yes\n":"No\n");
+ printk(KERN_INFO "ide-tape: PIO Cycle Timing Category: %d\n",id->tPIO);
+ printk(KERN_INFO "ide-tape: DMA Cycle Timing Category: %d\n",id->tDMA);
+ printk(KERN_INFO "ide-tape: Single Word DMA supported modes: ");
+ for (i=0,mask=1;i<8;i++,mask=mask << 1) {
+ if (id->dma_1word & mask)
+ printk("%d ",i);
+ if (id->dma_1word & (mask << 8))
+ printk("(active) ");
+ }
+ printk("\n");
+ printk(KERN_INFO "ide-tape: Multi Word DMA supported modes: ");
+ for (i=0,mask=1;i<8;i++,mask=mask << 1) {
+ if (id->dma_mword & mask)
+ printk("%d ",i);
+ if (id->dma_mword & (mask << 8))
+ printk("(active) ");
+ }
+ printk("\n");
+ if (id->field_valid & 0x0002) {
+ printk(KERN_INFO "ide-tape: Enhanced PIO Modes: %s\n",
+ id->eide_pio_modes & 1 ? "Mode 3":"None");
+ printk(KERN_INFO "ide-tape: Minimum Multi-word DMA cycle per word: ");
+ if (id->eide_dma_min == 0)
+ printk("Not supported\n");
+ else
+ printk("%d ns\n",id->eide_dma_min);
+
+ printk(KERN_INFO "ide-tape: Manufacturer\'s Recommended Multi-word cycle: ");
+ if (id->eide_dma_time == 0)
+ printk("Not supported\n");
+ else
+ printk("%d ns\n",id->eide_dma_time);
+
+ printk(KERN_INFO "ide-tape: Minimum PIO cycle without IORDY: ");
+ if (id->eide_pio == 0)
+ printk("Not supported\n");
+ else
+ printk("%d ns\n",id->eide_pio);
+
+ printk(KERN_INFO "ide-tape: Minimum PIO cycle with IORDY: ");
+ if (id->eide_pio_iordy == 0)
+ printk("Not supported\n");
+ else
+ printk("%d ns\n",id->eide_pio_iordy);
+
+ } else
+ printk(KERN_INFO "ide-tape: According to the device, fields 64-70 are not valid.\n");
+#endif /* IDETAPE_DEBUG_INFO */
+
+ /* Check that we can support this device */
+
+ if (gcw.protocol !=2 )
+ printk(KERN_ERR "ide-tape: Protocol is not ATAPI\n");
+ else if (gcw.device_type != 1)
+ printk(KERN_ERR "ide-tape: Device type is not set to tape\n");
+ else if (!gcw.removable)
+ printk(KERN_ERR "ide-tape: The removable flag is not set\n");
+ else if (gcw.packet_size != 0) {
+ printk(KERN_ERR "ide-tape: Packet size is not 12 bytes long\n");
+ if (gcw.packet_size == 1)
+ printk(KERN_ERR "ide-tape: Sorry, padding to 16 bytes is still not supported\n");
+ } else
+ return 1;
+ return 0;
+}
+
+/*
+ * Use INQUIRY to get the firmware revision
+ */
+static void idetape_get_inquiry_results (ide_drive_t *drive)
+{
+ char *r;
+ idetape_tape_t *tape = drive->driver_data;
+ idetape_pc_t pc;
+ idetape_inquiry_result_t *inquiry;
+
+ idetape_create_inquiry_cmd(&pc);
+ if (idetape_queue_pc_tail(drive, &pc)) {
+ printk(KERN_ERR "ide-tape: %s: can't get INQUIRY results\n", tape->name);
+ return;
+ }
+ inquiry = (idetape_inquiry_result_t *) pc.buffer;
+ memcpy(tape->vendor_id, inquiry->vendor_id, 8);
+ memcpy(tape->product_id, inquiry->product_id, 16);
+ memcpy(tape->firmware_revision, inquiry->revision_level, 4);
+ ide_fixstring(tape->vendor_id, 10, 0);
+ ide_fixstring(tape->product_id, 18, 0);
+ ide_fixstring(tape->firmware_revision, 6, 0);
+ r = tape->firmware_revision;
+ if (*(r + 1) == '.')
+ tape->firmware_revision_num = (*r - '0') * 100 + (*(r + 2) - '0') * 10 + *(r + 3) - '0';
+ printk(KERN_INFO "ide-tape: %s <-> %s: %s %s rev %s\n", drive->name, tape->name, tape->vendor_id, tape->product_id, tape->firmware_revision);
+}
+
+/*
+ * idetape_get_mode_sense_results asks 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;
+ idetape_pc_t pc;
+ idetape_mode_parameter_header_t *header;
+ idetape_capabilities_page_t *capabilities;
+
+ idetape_create_mode_sense_cmd(&pc, IDETAPE_CAPABILITIES_PAGE);
+ if (idetape_queue_pc_tail(drive, &pc)) {
+ printk(KERN_ERR "ide-tape: Can't get tape parameters - assuming some default values\n");
+ tape->tape_block_size = 512;
+ tape->capabilities.ctl = 52;
+ tape->capabilities.speed = 450;
+ tape->capabilities.buffer_size = 6 * 52;
+ return;
+ }
+ header = (idetape_mode_parameter_header_t *) pc.buffer;
+ capabilities = (idetape_capabilities_page_t *) (pc.buffer + sizeof(idetape_mode_parameter_header_t) + header->bdl);
+
+ capabilities->max_speed = ntohs(capabilities->max_speed);
+ capabilities->ctl = ntohs(capabilities->ctl);
+ capabilities->speed = ntohs(capabilities->speed);
+ capabilities->buffer_size = ntohs(capabilities->buffer_size);
+
+ if (!capabilities->speed) {
+ printk(KERN_INFO "ide-tape: %s: overriding capabilities->speed (assuming 650KB/sec)\n", drive->name);
+ capabilities->speed = 650;
+ }
+ if (!capabilities->max_speed) {
+ printk(KERN_INFO "ide-tape: %s: overriding capabilities->max_speed (assuming 650KB/sec)\n", drive->name);
+ capabilities->max_speed = 650;
+ }
+
+ tape->capabilities = *capabilities; /* Save us a copy */
+ if (capabilities->blk512)
+ tape->tape_block_size = 512;
+ else if (capabilities->blk1024)
+ tape->tape_block_size = 1024;
+
+#if IDETAPE_DEBUG_INFO
+ printk(KERN_INFO "ide-tape: Dumping the results of the MODE SENSE packet command\n");
+ printk(KERN_INFO "ide-tape: Mode Parameter Header:\n");
+ printk(KERN_INFO "ide-tape: Mode Data Length - %d\n",header->mode_data_length);
+ printk(KERN_INFO "ide-tape: Medium Type - %d\n",header->medium_type);
+ printk(KERN_INFO "ide-tape: Device Specific Parameter - %d\n",header->dsp);
+ printk(KERN_INFO "ide-tape: Block Descriptor Length - %d\n",header->bdl);
+
+ printk(KERN_INFO "ide-tape: Capabilities and Mechanical Status Page:\n");
+ printk(KERN_INFO "ide-tape: Page code - %d\n",capabilities->page_code);
+ printk(KERN_INFO "ide-tape: Page length - %d\n",capabilities->page_length);
+ printk(KERN_INFO "ide-tape: Read only - %s\n",capabilities->ro ? "Yes":"No");
+ printk(KERN_INFO "ide-tape: Supports reverse space - %s\n",capabilities->sprev ? "Yes":"No");
+ printk(KERN_INFO "ide-tape: Supports erase initiated formatting - %s\n",capabilities->efmt ? "Yes":"No");
+ printk(KERN_INFO "ide-tape: Supports QFA two Partition format - %s\n",capabilities->qfa ? "Yes":"No");
+ printk(KERN_INFO "ide-tape: Supports locking the medium - %s\n",capabilities->lock ? "Yes":"No");
+ printk(KERN_INFO "ide-tape: The volume is currently locked - %s\n",capabilities->locked ? "Yes":"No");
+ printk(KERN_INFO "ide-tape: The device defaults in the prevent state - %s\n",capabilities->prevent ? "Yes":"No");
+ printk(KERN_INFO "ide-tape: Supports ejecting the medium - %s\n",capabilities->eject ? "Yes":"No");
+ printk(KERN_INFO "ide-tape: Supports error correction - %s\n",capabilities->ecc ? "Yes":"No");
+ printk(KERN_INFO "ide-tape: Supports data compression - %s\n",capabilities->cmprs ? "Yes":"No");
+ printk(KERN_INFO "ide-tape: Supports 512 bytes block size - %s\n",capabilities->blk512 ? "Yes":"No");
+ printk(KERN_INFO "ide-tape: Supports 1024 bytes block size - %s\n",capabilities->blk1024 ? "Yes":"No");
+ printk(KERN_INFO "ide-tape: Supports 32768 bytes block size / Restricted byte count for PIO transfers - %s\n",capabilities->blk32768 ? "Yes":"No");
+ printk(KERN_INFO "ide-tape: Maximum supported speed in KBps - %d\n",capabilities->max_speed);
+ printk(KERN_INFO "ide-tape: Continuous transfer limits in blocks - %d\n",capabilities->ctl);
+ printk(KERN_INFO "ide-tape: Current speed in KBps - %d\n",capabilities->speed);
+ printk(KERN_INFO "ide-tape: Buffer size - %d\n",capabilities->buffer_size*512);
+#endif /* IDETAPE_DEBUG_INFO */
+}
+
+/*
+ * ide_get_blocksize_from_block_descriptor does a mode sense page 0 with block descriptor
+ * and if it succeeds sets the tape block size with the reported value
+ */
+static void idetape_get_blocksize_from_block_descriptor(ide_drive_t *drive)
+{
+
+ idetape_tape_t *tape = drive->driver_data;
+ idetape_pc_t pc;
+ idetape_mode_parameter_header_t *header;
+ idetape_parameter_block_descriptor_t *block_descrp;
+
+ idetape_create_mode_sense_cmd(&pc, IDETAPE_BLOCK_DESCRIPTOR);
+ if (idetape_queue_pc_tail(drive, &pc)) {
+ printk(KERN_ERR "ide-tape: Can't get block descriptor\n");
+ if (tape->tape_block_size == 0) {
+ printk(KERN_WARNING "ide-tape: Cannot deal with zero block size, assume 32k\n");
+ tape->tape_block_size = 32768;
+ }
+ return;
+ }
+ header = (idetape_mode_parameter_header_t *) pc.buffer;
+ block_descrp = (idetape_parameter_block_descriptor_t *) (pc.buffer + sizeof(idetape_mode_parameter_header_t));
+ tape->tape_block_size =( block_descrp->length[0]<<16) + (block_descrp->length[1]<<8) + block_descrp->length[2];
+ tape->drv_write_prot = (header->dsp & 0x80) >> 7;
+
+#if IDETAPE_DEBUG_INFO
+ printk(KERN_INFO "ide-tape: Adjusted block size - %d\n", tape->tape_block_size);
+#endif /* IDETAPE_DEBUG_INFO */
+}
+static void idetape_add_settings (ide_drive_t *drive)
+{
+ idetape_tape_t *tape = drive->driver_data;
+
+/*
+ * drive setting name read/write ioctl ioctl data type min max mul_factor div_factor data pointer set function
+ */
+ ide_add_setting(drive, "buffer", SETTING_READ, -1, -1, TYPE_SHORT, 0, 0xffff, 1, 2, &tape->capabilities.buffer_size, NULL);
+ ide_add_setting(drive, "pipeline_min", SETTING_RW, -1, -1, TYPE_INT, 1, 0xffff, tape->stage_size / 1024, 1, &tape->min_pipeline, NULL);
+ ide_add_setting(drive, "pipeline", SETTING_RW, -1, -1, TYPE_INT, 1, 0xffff, tape->stage_size / 1024, 1, &tape->max_stages, NULL);
+ ide_add_setting(drive, "pipeline_max", SETTING_RW, -1, -1, TYPE_INT, 1, 0xffff, tape->stage_size / 1024, 1, &tape->max_pipeline, NULL);
+ ide_add_setting(drive, "pipeline_used",SETTING_READ, -1, -1, TYPE_INT, 0, 0xffff, tape->stage_size / 1024, 1, &tape->nr_stages, NULL);
+ ide_add_setting(drive, "pipeline_pending",SETTING_READ,-1, -1, TYPE_INT, 0, 0xffff, tape->stage_size / 1024, 1, &tape->nr_pending_stages, NULL);
+ ide_add_setting(drive, "speed", SETTING_READ, -1, -1, TYPE_SHORT, 0, 0xffff, 1, 1, &tape->capabilities.speed, NULL);
+ ide_add_setting(drive, "stage", SETTING_READ, -1, -1, TYPE_INT, 0, 0xffff, 1, 1024, &tape->stage_size, NULL);
+ ide_add_setting(drive, "tdsc", SETTING_RW, -1, -1, TYPE_INT, IDETAPE_DSC_RW_MIN, IDETAPE_DSC_RW_MAX, 1000, HZ, &tape->best_dsc_rw_frequency, NULL);
+ ide_add_setting(drive, "dsc_overlap", SETTING_RW, -1, -1, TYPE_BYTE, 0, 1, 1, 1, &drive->dsc_overlap, NULL);
+ ide_add_setting(drive, "pipeline_head_speed_c",SETTING_READ, -1, -1, TYPE_INT, 0, 0xffff, 1, 1, &tape->controlled_pipeline_head_speed, NULL);
+ ide_add_setting(drive, "pipeline_head_speed_u",SETTING_READ, -1, -1, TYPE_INT, 0, 0xffff, 1, 1, &tape->uncontrolled_pipeline_head_speed, NULL);
+ ide_add_setting(drive, "avg_speed", SETTING_READ, -1, -1, TYPE_INT, 0, 0xffff, 1, 1, &tape->avg_speed, NULL);
+ ide_add_setting(drive, "debug_level",SETTING_RW, -1, -1, TYPE_INT, 0, 0xffff, 1, 1, &tape->debug_level, NULL);
+}
+
+/*
+ * ide_setup 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 t1, tmid, tn, t;
+ int speed;
+ struct idetape_id_gcw gcw;
+ int stage_size;
+ struct sysinfo si;
+
+ spin_lock_init(&tape->spinlock);
+ drive->dsc_overlap = 1;
+#ifdef CONFIG_BLK_DEV_IDEPCI
+ if (HWIF(drive)->pci_dev != NULL) {
+ /*
+ * These two ide-pci host adapters appear to need DSC overlap disabled.
+ * This probably needs further analysis.
+ */
+ if ((HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) ||
+ (HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_TTI_HPT343)) {
+ printk(KERN_INFO "ide-tape: %s: disabling DSC overlap\n", tape->name);
+ drive->dsc_overlap = 0;
+ }
+ }
+#endif /* CONFIG_BLK_DEV_IDEPCI */
+ /* Seagate Travan drives do not support DSC overlap. */
+ if (strstr(drive->id->model, "Seagate STT3401"))
+ drive->dsc_overlap = 0;
+ tape->minor = minor;
+ tape->name[0] = 'h';
+ tape->name[1] = 't';
+ tape->name[2] = '0' + minor;
+ tape->chrdev_direction = idetape_direction_none;
+ tape->pc = tape->pc_stack;
+ tape->max_insert_speed = 10000;
+ tape->speed_control = 1;
+ *((unsigned short *) &gcw) = drive->id->config;
+ if (gcw.drq_type == 1)
+ set_bit(IDETAPE_DRQ_INTERRUPT, &tape->flags);
+
+ tape->min_pipeline = tape->max_pipeline = tape->max_stages = 10;
+
+ idetape_get_inquiry_results(drive);
+ idetape_get_mode_sense_results(drive);
+ idetape_get_blocksize_from_block_descriptor(drive);
+ tape->user_bs_factor = 1;
+ tape->stage_size = tape->capabilities.ctl * tape->tape_block_size;
+ while (tape->stage_size > 0xffff) {
+ printk(KERN_NOTICE "ide-tape: decreasing stage size\n");
+ tape->capabilities.ctl /= 2;
+ tape->stage_size = tape->capabilities.ctl * tape->tape_block_size;
+ }
+ stage_size = tape->stage_size;
+ tape->pages_per_stage = stage_size / PAGE_SIZE;
+ if (stage_size % PAGE_SIZE) {
+ tape->pages_per_stage++;
+ tape->excess_bh_size = PAGE_SIZE - stage_size % PAGE_SIZE;
+ }
+
+ /*
+ * Select the "best" DSC read/write polling frequency
+ * and pipeline size.
+ */
+ speed = max(tape->capabilities.speed, tape->capabilities.max_speed);
+
+ tape->max_stages = speed * 1000 * 10 / tape->stage_size;
+
+ /*
+ * Limit memory use for pipeline to 10% of physical memory
+ */
+ si_meminfo(&si);
+ if (tape->max_stages * tape->stage_size > si.totalram * si.mem_unit / 10)
+ tape->max_stages = si.totalram * si.mem_unit / (10 * tape->stage_size);
+ tape->max_stages = min(tape->max_stages, IDETAPE_MAX_PIPELINE_STAGES);
+ tape->min_pipeline = min(tape->max_stages, IDETAPE_MIN_PIPELINE_STAGES);
+ tape->max_pipeline = min(tape->max_stages * 2, IDETAPE_MAX_PIPELINE_STAGES);
+ if (tape->max_stages == 0)
+ tape->max_stages = tape->min_pipeline = tape->max_pipeline = 1;
+
+ t1 = (tape->stage_size * HZ) / (speed * 1000);
+ tmid = (tape->capabilities.buffer_size * 32 * HZ) / (speed * 125);
+ tn = (IDETAPE_FIFO_THRESHOLD * tape->stage_size * HZ) / (speed * 1000);
+
+ if (tape->max_stages)
+ t = tn;
+ else
+ t = t1;
+
+ /*
+ * Ensure that the number we got makes sense; limit
+ * it within IDETAPE_DSC_RW_MIN and IDETAPE_DSC_RW_MAX.
+ */
+ tape->best_dsc_rw_frequency = max_t(unsigned long, min_t(unsigned long, t, IDETAPE_DSC_RW_MAX), IDETAPE_DSC_RW_MIN);
+ printk(KERN_INFO "ide-tape: %s <-> %s: %dKBps, %d*%dkB buffer, "
+ "%dkB pipeline, %lums tDSC%s\n",
+ drive->name, tape->name, tape->capabilities.speed,
+ (tape->capabilities.buffer_size * 512) / tape->stage_size,
+ tape->stage_size / 1024,
+ tape->max_stages * tape->stage_size / 1024,
+ tape->best_dsc_rw_frequency * 1000 / HZ,
+ drive->using_dma ? ", DMA":"");
+
+ idetape_add_settings(drive);
+}
+
+static int idetape_cleanup (ide_drive_t *drive)
+{
+ idetape_tape_t *tape = drive->driver_data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ide_lock, flags);
+ if (test_bit(IDETAPE_BUSY, &tape->flags) || drive->usage ||
+ tape->first_stage != NULL || tape->merge_stage_size) {
+ spin_unlock_irqrestore(&ide_lock, flags);
+ return 1;
+ }
+
+ spin_unlock_irqrestore(&ide_lock, flags);
+ DRIVER(drive)->busy = 0;
+ (void) ide_unregister_subdriver(drive);
+
+ ide_unregister_region(tape->disk);
+
+ ide_tape_put(tape);
+
+ return 0;
+}
+
+static void ide_tape_release(struct kref *kref)
+{
+ struct ide_tape_obj *tape = to_ide_tape(kref);
+ ide_drive_t *drive = tape->drive;
+ struct gendisk *g = tape->disk;
+
+ drive->dsc_overlap = 0;
+ drive->driver_data = NULL;
+ devfs_remove("%s/mt", drive->devfs_name);
+ devfs_remove("%s/mtn", drive->devfs_name);
+ devfs_unregister_tape(g->number);
+ idetape_devs[tape->minor] = NULL;
+ g->private_data = NULL;
+ put_disk(g);
+ kfree(tape);
+}
+
+#ifdef CONFIG_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 }
+};
+
+#else
+
+#define idetape_proc NULL
+
+#endif
+
+static int idetape_attach(ide_drive_t *drive);
+
+/*
+ * IDE subdriver functions, registered with ide.c
+ */
+static ide_driver_t idetape_driver = {
+ .owner = THIS_MODULE,
+ .name = "ide-tape",
+ .version = IDETAPE_VERSION,
+ .media = ide_tape,
+ .busy = 1,
+ .supports_dsc_overlap = 1,
+ .cleanup = idetape_cleanup,
+ .do_request = idetape_do_request,
+ .end_request = idetape_end_request,
+ .error = __ide_error,
+ .abort = __ide_abort,
+ .proc = idetape_proc,
+ .attach = idetape_attach,
+ .drives = LIST_HEAD_INIT(idetape_driver.drives),
+};
+
+/*
+ * Our character device supporting functions, passed to register_chrdev.
+ */
+static 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 inode *inode, struct file *filp)
+{
+ struct gendisk *disk = inode->i_bdev->bd_disk;
+ struct ide_tape_obj *tape;
+ ide_drive_t *drive;
+
+ if (!(tape = ide_tape_get(disk)))
+ return -ENXIO;
+
+ drive = tape->drive;
+
+ drive->usage++;
+
+ return 0;
+}
+
+static int idetape_release(struct inode *inode, struct file *filp)
+{
+ struct gendisk *disk = inode->i_bdev->bd_disk;
+ struct ide_tape_obj *tape = ide_tape_g(disk);
+ ide_drive_t *drive = tape->drive;
+
+ drive->usage--;
+
+ ide_tape_put(tape);
+
+ return 0;
+}
+
+static int idetape_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct block_device *bdev = inode->i_bdev;
+ struct ide_tape_obj *tape = ide_tape_g(bdev->bd_disk);
+ ide_drive_t *drive = tape->drive;
+ int err = generic_ide_ioctl(drive, file, 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,
+ .ioctl = idetape_ioctl,
+};
+
+static int idetape_attach (ide_drive_t *drive)
+{
+ idetape_tape_t *tape;
+ struct gendisk *g;
+ int minor;
+
+ if (!strstr("ide-tape", drive->driver_req))
+ goto failed;
+ if (!drive->present)
+ goto failed;
+ if (drive->media != ide_tape)
+ goto failed;
+ if (!idetape_identify_device (drive)) {
+ printk(KERN_ERR "ide-tape: %s: not supported by this version of ide-tape\n", drive->name);
+ goto failed;
+ }
+ if (drive->scsi) {
+ printk("ide-tape: passing drive %s to ide-scsi emulation.\n", drive->name);
+ goto failed;
+ }
+ if (strstr(drive->id->model, "OnStream DI-")) {
+ printk(KERN_WARNING "ide-tape: Use drive %s with ide-scsi emulation and osst.\n", drive->name);
+ printk(KERN_WARNING "ide-tape: OnStream support will be removed soon from ide-tape!\n");
+ }
+ tape = (idetape_tape_t *) kmalloc (sizeof (idetape_tape_t), GFP_KERNEL);
+ if (tape == NULL) {
+ printk(KERN_ERR "ide-tape: %s: Can't allocate a tape structure\n", drive->name);
+ goto failed;
+ }
+
+ g = alloc_disk(1 << PARTN_BITS);
+ if (!g)
+ goto out_free_tape;
+
+ ide_init_disk(g, drive);
+
+ if (ide_register_subdriver(drive, &idetape_driver)) {
+ printk(KERN_ERR "ide-tape: %s: Failed to register the driver with ide.c\n", drive->name);
+ goto out_put_disk;
+ }
+
+ memset(tape, 0, sizeof(*tape));
+
+ kref_init(&tape->kref);
+
+ tape->drive = drive;
+ tape->driver = &idetape_driver;
+ tape->disk = g;
+
+ g->private_data = &tape->driver;
+
+ drive->driver_data = tape;
+
+ down(&idetape_ref_sem);
+ for (minor = 0; idetape_devs[minor]; minor++)
+ ;
+ idetape_devs[minor] = tape;
+ up(&idetape_ref_sem);
+
+ idetape_setup(drive, tape, minor);
+
+ devfs_mk_cdev(MKDEV(HWIF(drive)->major, minor),
+ S_IFCHR | S_IRUGO | S_IWUGO,
+ "%s/mt", drive->devfs_name);
+ devfs_mk_cdev(MKDEV(HWIF(drive)->major, minor + 128),
+ S_IFCHR | S_IRUGO | S_IWUGO,
+ "%s/mtn", drive->devfs_name);
+
+ g->number = devfs_register_tape(drive->devfs_name);
+ g->fops = &idetape_block_ops;
+ ide_register_region(g);
+
+ return 0;
+out_put_disk:
+ put_disk(g);
+out_free_tape:
+ kfree(tape);
+failed:
+ return 1;
+}
+
+MODULE_DESCRIPTION("ATAPI Streaming TAPE Driver");
+MODULE_LICENSE("GPL");
+
+static void __exit idetape_exit (void)
+{
+ ide_unregister_driver(&idetape_driver);
+ unregister_chrdev(IDETAPE_MAJOR, "ht");
+}
+
+/*
+ * idetape_init will register the driver for each tape.
+ */
+static int idetape_init (void)
+{
+ if (register_chrdev(IDETAPE_MAJOR, "ht", &idetape_fops)) {
+ printk(KERN_ERR "ide-tape: Failed to register character device interface\n");
+ return -EBUSY;
+ }
+ ide_register_driver(&idetape_driver);
+ return 0;
+}
+
+module_init(idetape_init);
+module_exit(idetape_exit);
+MODULE_ALIAS_CHARDEV_MAJOR(IDETAPE_MAJOR);
diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c
new file mode 100644
index 000000000000..d04f62ab5de1
--- /dev/null
+++ b/drivers/ide/ide-taskfile.c
@@ -0,0 +1,884 @@
+/*
+ * linux/drivers/ide/ide-taskfile.c Version 0.38 March 05, 2003
+ *
+ * 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 Bartlomiej Zolnierkiewicz
+ *
+ * The big the bad and the ugly.
+ *
+ * Problems to be fixed because of BH interface or the lack therefore.
+ *
+ * Fill me in stupid !!!
+ *
+ * HOST:
+ * General refers to the Controller and Driver "pair".
+ * DATA HANDLER:
+ * Under the context of Linux it generally refers to an interrupt handler.
+ * However, it correctly describes the 'HOST'
+ * DATA BLOCK:
+ * The amount of data needed to be transfered as predefined in the
+ * setup of the device.
+ * STORAGE ATOMIC:
+ * The 'DATA BLOCK' associated to the 'DATA HANDLER', and can be as
+ * small as a single sector or as large as the entire command block
+ * request.
+ */
+
+#include <linux/config.h>
+#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/hdreg.h>
+#include <linux/ide.h>
+#include <linux/bitops.h>
+
+#include <asm/byteorder.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+#define DEBUG_TASKFILE 0 /* unset when fixed */
+
+static void ata_bswap_data (void *buffer, int wcount)
+{
+ u16 *p = buffer;
+
+ while (wcount--) {
+ *p = *p << 8 | *p >> 8; p++;
+ *p = *p << 8 | *p >> 8; p++;
+ }
+}
+
+static void taskfile_input_data(ide_drive_t *drive, void *buffer, u32 wcount)
+{
+ HWIF(drive)->ata_input_data(drive, buffer, wcount);
+ if (drive->bswap)
+ ata_bswap_data(buffer, wcount);
+}
+
+static void taskfile_output_data(ide_drive_t *drive, void *buffer, u32 wcount)
+{
+ if (drive->bswap) {
+ ata_bswap_data(buffer, wcount);
+ HWIF(drive)->ata_output_data(drive, buffer, wcount);
+ ata_bswap_data(buffer, wcount);
+ } else {
+ HWIF(drive)->ata_output_data(drive, buffer, wcount);
+ }
+}
+
+int taskfile_lib_get_identify (ide_drive_t *drive, u8 *buf)
+{
+ ide_task_t args;
+ memset(&args, 0, sizeof(ide_task_t));
+ args.tfRegister[IDE_NSECTOR_OFFSET] = 0x01;
+ if (drive->media == ide_disk)
+ args.tfRegister[IDE_COMMAND_OFFSET] = WIN_IDENTIFY;
+ else
+ args.tfRegister[IDE_COMMAND_OFFSET] = WIN_PIDENTIFY;
+ args.command_type = IDE_DRIVE_TASK_IN;
+ args.data_phase = TASKFILE_IN;
+ args.handler = &task_in_intr;
+ return ide_raw_taskfile(drive, &args, buf);
+}
+
+ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ task_struct_t *taskfile = (task_struct_t *) task->tfRegister;
+ hob_struct_t *hobfile = (hob_struct_t *) task->hobRegister;
+ u8 HIHI = (drive->addressing == 1) ? 0xE0 : 0xEF;
+
+ /* ALL Command Block Executions SHALL clear nIEN, unless otherwise */
+ if (IDE_CONTROL_REG) {
+ /* clear nIEN */
+ hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
+ }
+ SELECT_MASK(drive, 0);
+
+ if (drive->addressing == 1) {
+ hwif->OUTB(hobfile->feature, IDE_FEATURE_REG);
+ hwif->OUTB(hobfile->sector_count, IDE_NSECTOR_REG);
+ hwif->OUTB(hobfile->sector_number, IDE_SECTOR_REG);
+ hwif->OUTB(hobfile->low_cylinder, IDE_LCYL_REG);
+ hwif->OUTB(hobfile->high_cylinder, IDE_HCYL_REG);
+ }
+
+ hwif->OUTB(taskfile->feature, IDE_FEATURE_REG);
+ hwif->OUTB(taskfile->sector_count, IDE_NSECTOR_REG);
+ hwif->OUTB(taskfile->sector_number, IDE_SECTOR_REG);
+ hwif->OUTB(taskfile->low_cylinder, IDE_LCYL_REG);
+ hwif->OUTB(taskfile->high_cylinder, IDE_HCYL_REG);
+
+ hwif->OUTB((taskfile->device_head & HIHI) | drive->select.all, IDE_SELECT_REG);
+
+ if (task->handler != NULL) {
+ if (task->prehandler != NULL) {
+ hwif->OUTBSYNC(drive, taskfile->command, IDE_COMMAND_REG);
+ ndelay(400); /* FIXME */
+ return task->prehandler(drive, task->rq);
+ }
+ ide_execute_command(drive, taskfile->command, task->handler, WAIT_WORSTCASE, NULL);
+ return ide_started;
+ }
+
+ if (!drive->using_dma)
+ return ide_stopped;
+
+ switch (taskfile->command) {
+ case WIN_WRITEDMA_ONCE:
+ case WIN_WRITEDMA:
+ case WIN_WRITEDMA_EXT:
+ case WIN_READDMA_ONCE:
+ case WIN_READDMA:
+ case WIN_READDMA_EXT:
+ case WIN_IDENTIFY_DMA:
+ if (!hwif->dma_setup(drive)) {
+ hwif->dma_exec_cmd(drive, taskfile->command);
+ hwif->dma_start(drive);
+ return ide_started;
+ }
+ break;
+ default:
+ if (task->handler == NULL)
+ return ide_stopped;
+ }
+
+ return ide_stopped;
+}
+
+EXPORT_SYMBOL(do_rw_taskfile);
+
+/*
+ * set_multmode_intr() is invoked on completion of a WIN_SETMULT cmd.
+ */
+ide_startstop_t set_multmode_intr (ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ u8 stat;
+
+ if (OK_STAT(stat = hwif->INB(IDE_STATUS_REG),READY_STAT,BAD_STAT)) {
+ drive->mult_count = drive->mult_req;
+ } else {
+ drive->mult_req = drive->mult_count = 0;
+ drive->special.b.recalibrate = 1;
+ (void) ide_dump_status(drive, "set_multmode", stat);
+ }
+ return ide_stopped;
+}
+
+/*
+ * set_geometry_intr() is invoked on completion of a WIN_SPECIFY cmd.
+ */
+ide_startstop_t set_geometry_intr (ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ int retries = 5;
+ u8 stat;
+
+ while (((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) && retries--)
+ udelay(10);
+
+ if (OK_STAT(stat, READY_STAT, BAD_STAT))
+ return ide_stopped;
+
+ if (stat & (ERR_STAT|DRQ_STAT))
+ return ide_error(drive, "set_geometry_intr", stat);
+
+ if (HWGROUP(drive)->handler != NULL)
+ BUG();
+ ide_set_handler(drive, &set_geometry_intr, WAIT_WORSTCASE, NULL);
+ return ide_started;
+}
+
+/*
+ * recal_intr() is invoked on completion of a WIN_RESTORE (recalibrate) cmd.
+ */
+ide_startstop_t recal_intr (ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ u8 stat;
+
+ if (!OK_STAT(stat = hwif->INB(IDE_STATUS_REG), READY_STAT, BAD_STAT))
+ return ide_error(drive, "recal_intr", stat);
+ return ide_stopped;
+}
+
+/*
+ * Handler for commands without a data phase
+ */
+ide_startstop_t task_no_data_intr (ide_drive_t *drive)
+{
+ ide_task_t *args = HWGROUP(drive)->rq->special;
+ ide_hwif_t *hwif = HWIF(drive);
+ u8 stat;
+
+ local_irq_enable();
+ if (!OK_STAT(stat = hwif->INB(IDE_STATUS_REG),READY_STAT,BAD_STAT)) {
+ return ide_error(drive, "task_no_data_intr", stat);
+ /* calls ide_end_drive_cmd */
+ }
+ if (args)
+ ide_end_drive_cmd(drive, stat, hwif->INB(IDE_ERROR_REG));
+
+ return ide_stopped;
+}
+
+EXPORT_SYMBOL(task_no_data_intr);
+
+static u8 wait_drive_not_busy(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ int retries = 100;
+ u8 stat;
+
+ /*
+ * Last sector was transfered, wait until drive is ready.
+ * This can take up to 10 usec, but we will wait max 1 ms
+ * (drive_cmd_intr() waits that long).
+ */
+ while (((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) && retries--)
+ udelay(10);
+
+ if (!retries)
+ printk(KERN_ERR "%s: drive still BUSY!\n", drive->name);
+
+ return stat;
+}
+
+static void ide_pio_sector(ide_drive_t *drive, unsigned int write)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ struct scatterlist *sg = hwif->sg_table;
+ struct page *page;
+#ifdef CONFIG_HIGHMEM
+ unsigned long flags;
+#endif
+ unsigned int offset;
+ u8 *buf;
+
+ page = sg[hwif->cursg].page;
+ offset = sg[hwif->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) == sg[hwif->cursg].length) {
+ hwif->cursg++;
+ hwif->cursg_ofs = 0;
+ }
+
+ /* do the actual data transfer */
+ if (write)
+ taskfile_output_data(drive, buf, SECTOR_WORDS);
+ else
+ taskfile_input_data(drive, buf, SECTOR_WORDS);
+
+ kunmap_atomic(buf, KM_BIO_SRC_IRQ);
+#ifdef CONFIG_HIGHMEM
+ local_irq_restore(flags);
+#endif
+}
+
+static void ide_pio_multi(ide_drive_t *drive, unsigned int write)
+{
+ unsigned int nsect;
+
+ nsect = min_t(unsigned int, drive->hwif->nleft, drive->mult_count);
+ while (nsect--)
+ ide_pio_sector(drive, write);
+}
+
+static inline void ide_pio_datablock(ide_drive_t *drive, struct request *rq,
+ unsigned int write)
+{
+ if (rq->bio) /* fs request */
+ rq->errors = 0;
+
+ switch (drive->hwif->data_phase) {
+ case TASKFILE_MULTI_IN:
+ case TASKFILE_MULTI_OUT:
+ ide_pio_multi(drive, write);
+ break;
+ default:
+ ide_pio_sector(drive, write);
+ break;
+ }
+}
+
+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);
+}
+
+static void task_end_request(ide_drive_t *drive, struct request *rq, u8 stat)
+{
+ if (rq->flags & REQ_DRIVE_TASKFILE) {
+ ide_task_t *task = rq->special;
+
+ if (task->tf_out_flags.all) {
+ u8 err = drive->hwif->INB(IDE_ERROR_REG);
+ ide_end_drive_cmd(drive, stat, err);
+ return;
+ }
+ }
+
+ ide_end_request(drive, 1, rq->hard_nr_sectors);
+}
+
+/*
+ * Handler for command with PIO data-in phase (Read/Read Multiple).
+ */
+ide_startstop_t task_in_intr (ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ struct request *rq = HWGROUP(drive)->rq;
+ u8 stat = hwif->INB(IDE_STATUS_REG);
+
+ /* new way for dealing with premature shared PCI interrupts */
+ if (!OK_STAT(stat, DATA_READY, BAD_R_STAT)) {
+ if (stat & (ERR_STAT | DRQ_STAT))
+ return task_error(drive, rq, __FUNCTION__, stat);
+ /* No data yet, so wait for another IRQ. */
+ ide_set_handler(drive, &task_in_intr, WAIT_WORSTCASE, NULL);
+ return ide_started;
+ }
+
+ ide_pio_datablock(drive, rq, 0);
+
+ /* If it was the last datablock check status and finish transfer. */
+ if (!hwif->nleft) {
+ stat = wait_drive_not_busy(drive);
+ if (!OK_STAT(stat, 0, BAD_R_STAT))
+ return task_error(drive, rq, __FUNCTION__, 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;
+}
+EXPORT_SYMBOL(task_in_intr);
+
+/*
+ * 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->INB(IDE_STATUS_REG);
+
+ if (!OK_STAT(stat, DRIVE_READY, drive->bad_wstat))
+ return task_error(drive, rq, __FUNCTION__, stat);
+
+ /* Deal with unexpected ATA data phase. */
+ if (((stat & DRQ_STAT) == 0) ^ !hwif->nleft)
+ return task_error(drive, rq, __FUNCTION__, 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;
+}
+
+ide_startstop_t pre_task_out_intr (ide_drive_t *drive, struct request *rq)
+{
+ ide_startstop_t startstop;
+
+ if (ide_wait_stat(&startstop, drive, DATA_READY,
+ drive->bad_wstat, WAIT_DRQ)) {
+ printk(KERN_ERR "%s: no DRQ after issuing %sWRITE%s\n",
+ drive->name,
+ drive->hwif->data_phase ? "MULT" : "",
+ drive->addressing ? "_EXT" : "");
+ return startstop;
+ }
+
+ if (!drive->unmask)
+ local_irq_disable();
+
+ ide_set_handler(drive, &task_out_intr, WAIT_WORSTCASE, NULL);
+ ide_pio_datablock(drive, rq, 1);
+
+ return ide_started;
+}
+EXPORT_SYMBOL(pre_task_out_intr);
+
+static int ide_diag_taskfile(ide_drive_t *drive, ide_task_t *args, unsigned long data_size, u8 *buf)
+{
+ struct request rq;
+
+ memset(&rq, 0, sizeof(rq));
+ rq.flags = REQ_DRIVE_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.
+ */
+ if (args->command_type != IDE_DRIVE_TASK_NO_DATA) {
+ if (data_size == 0)
+ rq.nr_sectors = (args->hobRegister[IDE_NSECTOR_OFFSET] << 8) | args->tfRegister[IDE_NSECTOR_OFFSET];
+ else
+ rq.nr_sectors = data_size / SECTOR_SIZE;
+
+ if (!rq.nr_sectors) {
+ printk(KERN_ERR "%s: in/out command without data\n",
+ drive->name);
+ return -EFAULT;
+ }
+
+ rq.hard_nr_sectors = rq.nr_sectors;
+ rq.hard_cur_sectors = rq.current_nr_sectors = rq.nr_sectors;
+
+ if (args->command_type == IDE_DRIVE_TASK_RAW_WRITE)
+ rq.flags |= REQ_RW;
+ }
+
+ rq.special = args;
+ return ide_do_drive_cmd(drive, &rq, ide_wait);
+}
+
+int ide_raw_taskfile (ide_drive_t *drive, ide_task_t *args, u8 *buf)
+{
+ return ide_diag_taskfile(drive, args, 0, buf);
+}
+
+EXPORT_SYMBOL(ide_raw_taskfile);
+
+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;
+ task_ioreg_t *argsptr = args.tfRegister;
+ task_ioreg_t *hobsptr = args.hobRegister;
+ int err = 0;
+ int tasksize = sizeof(struct ide_task_request_s);
+ int taskin = 0;
+ int taskout = 0;
+ u8 io_32bit = drive->io_32bit;
+ char __user *buf = (char __user *)arg;
+
+// printk("IDE Taskfile ...\n");
+
+ req_task = kmalloc(tasksize, GFP_KERNEL);
+ if (req_task == NULL) return -ENOMEM;
+ memset(req_task, 0, tasksize);
+ if (copy_from_user(req_task, buf, tasksize)) {
+ kfree(req_task);
+ return -EFAULT;
+ }
+
+ taskout = (int) req_task->out_size;
+ taskin = (int) req_task->in_size;
+
+ if (taskout) {
+ int outtotal = tasksize;
+ outbuf = kmalloc(taskout, GFP_KERNEL);
+ if (outbuf == NULL) {
+ err = -ENOMEM;
+ goto abort;
+ }
+ memset(outbuf, 0, taskout);
+ if (copy_from_user(outbuf, buf + outtotal, taskout)) {
+ err = -EFAULT;
+ goto abort;
+ }
+ }
+
+ if (taskin) {
+ int intotal = tasksize + taskout;
+ inbuf = kmalloc(taskin, GFP_KERNEL);
+ if (inbuf == NULL) {
+ err = -ENOMEM;
+ goto abort;
+ }
+ memset(inbuf, 0, taskin);
+ if (copy_from_user(inbuf, buf + intotal, taskin)) {
+ err = -EFAULT;
+ goto abort;
+ }
+ }
+
+ memset(&args, 0, sizeof(ide_task_t));
+ memcpy(argsptr, req_task->io_ports, HDIO_DRIVE_TASK_HDR_SIZE);
+ memcpy(hobsptr, req_task->hob_ports, HDIO_DRIVE_HOB_HDR_SIZE);
+
+ args.tf_in_flags = req_task->in_flags;
+ args.tf_out_flags = req_task->out_flags;
+ args.data_phase = req_task->data_phase;
+ args.command_type = req_task->req_cmd;
+
+ drive->io_32bit = 0;
+ switch(req_task->data_phase) {
+ case TASKFILE_OUT_DMAQ:
+ case TASKFILE_OUT_DMA:
+ err = ide_diag_taskfile(drive, &args, taskout, outbuf);
+ break;
+ case TASKFILE_IN_DMAQ:
+ case TASKFILE_IN_DMA:
+ err = ide_diag_taskfile(drive, &args, taskin, inbuf);
+ break;
+ 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, __FUNCTION__);
+ err = -EPERM;
+ goto abort;
+ }
+ /* fall through */
+ case TASKFILE_OUT:
+ args.prehandler = &pre_task_out_intr;
+ args.handler = &task_out_intr;
+ err = ide_diag_taskfile(drive, &args, taskout, 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, __FUNCTION__);
+ err = -EPERM;
+ goto abort;
+ }
+ /* fall through */
+ case TASKFILE_IN:
+ args.handler = &task_in_intr;
+ err = ide_diag_taskfile(drive, &args, taskin, inbuf);
+ break;
+ case TASKFILE_NO_DATA:
+ args.handler = &task_no_data_intr;
+ err = ide_diag_taskfile(drive, &args, 0, NULL);
+ break;
+ default:
+ err = -EFAULT;
+ goto abort;
+ }
+
+ memcpy(req_task->io_ports, &(args.tfRegister), HDIO_DRIVE_TASK_HDR_SIZE);
+ memcpy(req_task->hob_ports, &(args.hobRegister), HDIO_DRIVE_HOB_HDR_SIZE);
+ req_task->in_flags = args.tf_in_flags;
+ req_task->out_flags = args.tf_out_flags;
+
+ 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);
+ if (outbuf != NULL)
+ kfree(outbuf);
+ if (inbuf != NULL)
+ kfree(inbuf);
+
+// printk("IDE Taskfile ioctl ended. rc = %i\n", err);
+
+ drive->io_32bit = io_32bit;
+
+ return err;
+}
+
+int ide_wait_cmd (ide_drive_t *drive, u8 cmd, u8 nsect, u8 feature, u8 sectors, u8 *buf)
+{
+ struct request rq;
+ u8 buffer[4];
+
+ if (!buf)
+ buf = buffer;
+ memset(buf, 0, 4 + SECTOR_WORDS * 4 * sectors);
+ ide_init_drive_cmd(&rq);
+ rq.buffer = buf;
+ *buf++ = cmd;
+ *buf++ = nsect;
+ *buf++ = feature;
+ *buf++ = sectors;
+ return ide_do_drive_cmd(drive, &rq, ide_wait);
+}
+
+/*
+ * FIXME : this needs to map into at taskfile. <andre@linux-ide.org>
+ */
+int ide_cmd_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
+{
+ int err = 0;
+ u8 args[4], *argbuf = args;
+ u8 xfer_rate = 0;
+ int argsize = 4;
+ ide_task_t tfargs;
+
+ if (NULL == (void *) arg) {
+ struct request rq;
+ ide_init_drive_cmd(&rq);
+ return ide_do_drive_cmd(drive, &rq, ide_wait);
+ }
+
+ if (copy_from_user(args, (void __user *)arg, 4))
+ return -EFAULT;
+
+ memset(&tfargs, 0, sizeof(ide_task_t));
+ tfargs.tfRegister[IDE_FEATURE_OFFSET] = args[2];
+ tfargs.tfRegister[IDE_NSECTOR_OFFSET] = args[3];
+ tfargs.tfRegister[IDE_SECTOR_OFFSET] = args[1];
+ tfargs.tfRegister[IDE_LCYL_OFFSET] = 0x00;
+ tfargs.tfRegister[IDE_HCYL_OFFSET] = 0x00;
+ tfargs.tfRegister[IDE_SELECT_OFFSET] = 0x00;
+ tfargs.tfRegister[IDE_COMMAND_OFFSET] = args[0];
+
+ if (args[3]) {
+ argsize = 4 + (SECTOR_WORDS * 4 * args[3]);
+ argbuf = kmalloc(argsize, GFP_KERNEL);
+ if (argbuf == NULL)
+ return -ENOMEM;
+ memcpy(argbuf, args, 4);
+ }
+ if (set_transfer(drive, &tfargs)) {
+ xfer_rate = args[1];
+ if (ide_ata66_check(drive, &tfargs))
+ goto abort;
+ }
+
+ err = ide_wait_cmd(drive, args[0], args[1], args[2], args[3], argbuf);
+
+ 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, argbuf, argsize))
+ err = -EFAULT;
+ if (argsize > 4)
+ kfree(argbuf);
+ return err;
+}
+
+static int ide_wait_cmd_task(ide_drive_t *drive, u8 *buf)
+{
+ struct request rq;
+
+ ide_init_drive_cmd(&rq);
+ rq.flags = REQ_DRIVE_TASK;
+ rq.buffer = buf;
+ return ide_do_drive_cmd(drive, &rq, ide_wait);
+}
+
+/*
+ * FIXME : this needs to map into at taskfile. <andre@linux-ide.org>
+ */
+int ide_task_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
+{
+ void __user *p = (void __user *)arg;
+ int err = 0;
+ u8 args[7], *argbuf = args;
+ int argsize = 7;
+
+ if (copy_from_user(args, p, 7))
+ return -EFAULT;
+ err = ide_wait_cmd_task(drive, argbuf);
+ if (copy_to_user(p, argbuf, argsize))
+ err = -EFAULT;
+ return err;
+}
+
+/*
+ * NOTICE: This is additions from IBM to provide a discrete interface,
+ * for selective taskregister access operations. Nice JOB Klaus!!!
+ * Glad to be able to work and co-develop this with you and IBM.
+ */
+ide_startstop_t flagged_taskfile (ide_drive_t *drive, ide_task_t *task)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ task_struct_t *taskfile = (task_struct_t *) task->tfRegister;
+ hob_struct_t *hobfile = (hob_struct_t *) task->hobRegister;
+#if DEBUG_TASKFILE
+ u8 status;
+#endif
+
+ 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;
+ }
+ }
+
+ /*
+ * (ks) Check taskfile in/out flags.
+ * If set, then execute as it is defined.
+ * If not set, then define default settings.
+ * The default values are:
+ * write and read all taskfile registers (except data)
+ * write and read the hob registers (sector,nsector,lcyl,hcyl)
+ */
+ if (task->tf_out_flags.all == 0) {
+ task->tf_out_flags.all = IDE_TASKFILE_STD_OUT_FLAGS;
+ if (drive->addressing == 1)
+ task->tf_out_flags.all |= (IDE_HOB_STD_OUT_FLAGS << 8);
+ }
+
+ if (task->tf_in_flags.all == 0) {
+ task->tf_in_flags.all = IDE_TASKFILE_STD_IN_FLAGS;
+ if (drive->addressing == 1)
+ task->tf_in_flags.all |= (IDE_HOB_STD_IN_FLAGS << 8);
+ }
+
+ /* ALL Command Block Executions SHALL clear nIEN, unless otherwise */
+ if (IDE_CONTROL_REG)
+ /* clear nIEN */
+ hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
+ SELECT_MASK(drive, 0);
+
+#if DEBUG_TASKFILE
+ status = hwif->INB(IDE_STATUS_REG);
+ if (status & 0x80) {
+ printk("flagged_taskfile -> Bad status. Status = %02x. wait 100 usec ...\n", status);
+ udelay(100);
+ status = hwif->INB(IDE_STATUS_REG);
+ printk("flagged_taskfile -> Status = %02x\n", status);
+ }
+#endif
+
+ if (task->tf_out_flags.b.data) {
+ u16 data = taskfile->data + (hobfile->data << 8);
+ hwif->OUTW(data, IDE_DATA_REG);
+ }
+
+ /* (ks) send hob registers first */
+ if (task->tf_out_flags.b.nsector_hob)
+ hwif->OUTB(hobfile->sector_count, IDE_NSECTOR_REG);
+ if (task->tf_out_flags.b.sector_hob)
+ hwif->OUTB(hobfile->sector_number, IDE_SECTOR_REG);
+ if (task->tf_out_flags.b.lcyl_hob)
+ hwif->OUTB(hobfile->low_cylinder, IDE_LCYL_REG);
+ if (task->tf_out_flags.b.hcyl_hob)
+ hwif->OUTB(hobfile->high_cylinder, IDE_HCYL_REG);
+
+ /* (ks) Send now the standard registers */
+ if (task->tf_out_flags.b.error_feature)
+ hwif->OUTB(taskfile->feature, IDE_FEATURE_REG);
+ /* refers to number of sectors to transfer */
+ if (task->tf_out_flags.b.nsector)
+ hwif->OUTB(taskfile->sector_count, IDE_NSECTOR_REG);
+ /* refers to sector offset or start sector */
+ if (task->tf_out_flags.b.sector)
+ hwif->OUTB(taskfile->sector_number, IDE_SECTOR_REG);
+ if (task->tf_out_flags.b.lcyl)
+ hwif->OUTB(taskfile->low_cylinder, IDE_LCYL_REG);
+ if (task->tf_out_flags.b.hcyl)
+ hwif->OUTB(taskfile->high_cylinder, IDE_HCYL_REG);
+
+ /*
+ * (ks) In the flagged taskfile approch, we will use all specified
+ * registers and the register value will not be changed, except the
+ * select bit (master/slave) in the drive_head register. We must make
+ * sure that the desired drive is selected.
+ */
+ hwif->OUTB(taskfile->device_head | drive->select.all, IDE_SELECT_REG);
+ switch(task->data_phase) {
+
+ case TASKFILE_OUT_DMAQ:
+ case TASKFILE_OUT_DMA:
+ case TASKFILE_IN_DMAQ:
+ case TASKFILE_IN_DMA:
+ hwif->dma_setup(drive);
+ hwif->dma_exec_cmd(drive, taskfile->command);
+ hwif->dma_start(drive);
+ break;
+
+ default:
+ if (task->handler == NULL)
+ return ide_stopped;
+
+ /* Issue the command */
+ if (task->prehandler) {
+ hwif->OUTBSYNC(drive, taskfile->command, IDE_COMMAND_REG);
+ ndelay(400); /* FIXME */
+ return task->prehandler(drive, task->rq);
+ }
+ ide_execute_command(drive, taskfile->command, task->handler, WAIT_WORSTCASE, NULL);
+ }
+
+ return ide_started;
+}
diff --git a/drivers/ide/ide-timing.h b/drivers/ide/ide-timing.h
new file mode 100644
index 000000000000..c1196ce15b4d
--- /dev/null
+++ b/drivers/ide/ide-timing.h
@@ -0,0 +1,281 @@
+#ifndef _IDE_TIMING_H
+#define _IDE_TIMING_H
+
+/*
+ * $Id: ide-timing.h,v 1.6 2001/12/23 22:47:56 vojtech Exp $
+ *
+ * Copyright (c) 1999-2001 Vojtech Pavlik
+ */
+
+/*
+ * 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/hdreg.h>
+
+#define XFER_PIO_5 0x0d
+#define XFER_UDMA_SLOW 0x4f
+
+struct ide_timing {
+ short mode;
+ short setup; /* t1 */
+ short act8b; /* t2 for 8-bit io */
+ short rec8b; /* t2i for 8-bit io */
+ short cyc8b; /* t0 for 8-bit io */
+ short active; /* t2 or tD */
+ short recover; /* t2i or tK */
+ short cycle; /* t0 */
+ short udma; /* t2CYCTYP/2 */
+};
+
+/*
+ * 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_UDMA_SLOW, 0, 0, 0, 0, 0, 0, 0, 150 },
+
+ { XFER_MW_DMA_2, 25, 0, 0, 0, 70, 25, 120, 0 },
+ { XFER_MW_DMA_1, 45, 0, 0, 0, 80, 50, 150, 0 },
+ { XFER_MW_DMA_0, 60, 0, 0, 0, 215, 215, 480, 0 },
+
+ { XFER_SW_DMA_2, 60, 0, 0, 0, 120, 120, 240, 0 },
+ { XFER_SW_DMA_1, 90, 0, 0, 0, 240, 240, 480, 0 },
+ { XFER_SW_DMA_0, 120, 0, 0, 0, 480, 480, 960, 0 },
+
+ { XFER_PIO_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 },
+
+ { -1 }
+};
+
+#define IDE_TIMING_SETUP 0x01
+#define IDE_TIMING_ACT8B 0x02
+#define IDE_TIMING_REC8B 0x04
+#define IDE_TIMING_CYC8B 0x08
+#define IDE_TIMING_8BIT 0x0e
+#define IDE_TIMING_ACTIVE 0x10
+#define IDE_TIMING_RECOVER 0x20
+#define IDE_TIMING_CYCLE 0x40
+#define IDE_TIMING_UDMA 0x80
+#define IDE_TIMING_ALL 0xff
+
+#define MIN(a,b) ((a)<(b)?(a):(b))
+#define MAX(a,b) ((a)>(b)?(a):(b))
+#define FIT(v,min,max) MAX(MIN(v,max),min)
+#define ENOUGH(v,unit) (((v)-1)/(unit)+1)
+#define EZ(v,unit) ((v)?ENOUGH(v,unit):0)
+
+#define XFER_MODE 0xf0
+#define XFER_UDMA_133 0x48
+#define XFER_UDMA_100 0x44
+#define XFER_UDMA_66 0x42
+#define XFER_UDMA 0x40
+#define XFER_MWDMA 0x20
+#define XFER_SWDMA 0x10
+#define XFER_EPIO 0x01
+#define XFER_PIO 0x00
+
+static short ide_find_best_mode(ide_drive_t *drive, int map)
+{
+ struct hd_driveid *id = drive->id;
+ short best = 0;
+
+ if (!id)
+ return XFER_PIO_SLOW;
+
+ if ((map & XFER_UDMA) && (id->field_valid & 4)) { /* Want UDMA and UDMA bitmap valid */
+
+ if ((map & XFER_UDMA_133) == XFER_UDMA_133)
+ if ((best = (id->dma_ultra & 0x0040) ? XFER_UDMA_6 : 0)) return best;
+
+ if ((map & XFER_UDMA_100) == XFER_UDMA_100)
+ if ((best = (id->dma_ultra & 0x0020) ? XFER_UDMA_5 : 0)) return best;
+
+ if ((map & XFER_UDMA_66) == XFER_UDMA_66)
+ if ((best = (id->dma_ultra & 0x0010) ? XFER_UDMA_4 :
+ (id->dma_ultra & 0x0008) ? XFER_UDMA_3 : 0)) return best;
+
+ if ((best = (id->dma_ultra & 0x0004) ? XFER_UDMA_2 :
+ (id->dma_ultra & 0x0002) ? XFER_UDMA_1 :
+ (id->dma_ultra & 0x0001) ? XFER_UDMA_0 : 0)) return best;
+ }
+
+ if ((map & XFER_MWDMA) && (id->field_valid & 2)) { /* Want MWDMA and drive has EIDE fields */
+
+ if ((best = (id->dma_mword & 0x0004) ? XFER_MW_DMA_2 :
+ (id->dma_mword & 0x0002) ? XFER_MW_DMA_1 :
+ (id->dma_mword & 0x0001) ? XFER_MW_DMA_0 : 0)) return best;
+ }
+
+ if (map & XFER_SWDMA) { /* Want SWDMA */
+
+ if (id->field_valid & 2) { /* EIDE SWDMA */
+
+ if ((best = (id->dma_1word & 0x0004) ? XFER_SW_DMA_2 :
+ (id->dma_1word & 0x0002) ? XFER_SW_DMA_1 :
+ (id->dma_1word & 0x0001) ? XFER_SW_DMA_0 : 0)) return best;
+ }
+
+ if (id->capability & 1) { /* Pre-EIDE style SWDMA */
+
+ if ((best = (id->tDMA == 2) ? XFER_SW_DMA_2 :
+ (id->tDMA == 1) ? XFER_SW_DMA_1 :
+ (id->tDMA == 0) ? XFER_SW_DMA_0 : 0)) return best;
+ }
+ }
+
+
+ if ((map & XFER_EPIO) && (id->field_valid & 2)) { /* EIDE PIO modes */
+
+ if ((best = (drive->id->eide_pio_modes & 4) ? XFER_PIO_5 :
+ (drive->id->eide_pio_modes & 2) ? XFER_PIO_4 :
+ (drive->id->eide_pio_modes & 1) ? XFER_PIO_3 : 0)) return best;
+ }
+
+ return (drive->id->tPIO == 2) ? XFER_PIO_2 :
+ (drive->id->tPIO == 1) ? XFER_PIO_1 :
+ (drive->id->tPIO == 0) ? XFER_PIO_0 : XFER_PIO_SLOW;
+}
+
+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);
+}
+
+static 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);
+}
+
+static struct ide_timing* ide_timing_find_mode(short speed)
+{
+ struct ide_timing *t;
+
+ for (t = ide_timing; t->mode != speed; t++)
+ if (t->mode < 0)
+ return NULL;
+ return t;
+}
+
+static int ide_timing_compute(ide_drive_t *drive, short speed, struct ide_timing *t, int T, int UT)
+{
+ struct hd_driveid *id = drive->id;
+ struct ide_timing *s, p;
+
+/*
+ * Find the mode.
+ */
+
+ if (!(s = ide_timing_find_mode(speed)))
+ return -EINVAL;
+
+/*
+ * If the drive is an EIDE drive, it can tell us it needs extended
+ * PIO/MWDMA cycle timing.
+ */
+
+ if (id && id->field_valid & 2) { /* EIDE drive */
+
+ memset(&p, 0, sizeof(p));
+
+ switch (speed & XFER_MODE) {
+
+ case XFER_PIO:
+ if (speed <= XFER_PIO_2) p.cycle = p.cyc8b = id->eide_pio;
+ else p.cycle = p.cyc8b = id->eide_pio_iordy;
+ break;
+
+ case XFER_MWDMA:
+ p.cycle = id->eide_dma_min;
+ break;
+ }
+
+ ide_timing_merge(&p, t, t, IDE_TIMING_CYCLE | IDE_TIMING_CYC8B);
+ }
+
+/*
+ * Convert the timing to bus clock counts.
+ */
+
+ ide_timing_quantize(s, 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_MODE) != XFER_PIO) {
+ ide_timing_compute(drive, ide_find_best_mode(drive, XFER_PIO | XFER_EPIO), &p, T, UT);
+ ide_timing_merge(&p, t, t, IDE_TIMING_ALL);
+ }
+
+/*
+ * Lenghten 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;
+}
+
+#endif
diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c
new file mode 100644
index 000000000000..973dec799b5c
--- /dev/null
+++ b/drivers/ide/ide.c
@@ -0,0 +1,2269 @@
+/*
+ * linux/drivers/ide/ide.c Version 7.00beta2 Mar 05 2003
+ *
+ * Copyright (C) 1994-1998 Linus Torvalds & authors (see below)
+ */
+
+/*
+ * 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.
+ *
+ * Primary: ide0, port 0x1f0; major=3; hda is minor=0; hdb is minor=64
+ * Secondary: ide1, port 0x170; major=22; hdc is minor=0; hdd is minor=64
+ * Tertiary: ide2, port 0x???; major=33; hde is minor=0; hdf is minor=64
+ * Quaternary: ide3, port 0x???; major=34; hdg is minor=0; hdh is minor=64
+ * ...
+ *
+ * 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
+ *
+ * Version 1.0 ALPHA initial code, primary i/f working okay
+ * Version 1.3 BETA dual i/f on shared irq tested & working!
+ * Version 1.4 BETA added auto probing for irq(s)
+ * Version 1.5 BETA added ALPHA (untested) support for IDE cd-roms,
+ * ...
+ * Version 5.50 allow values as small as 20 for idebus=
+ * Version 5.51 force non io_32bit in drive_cmd_intr()
+ * change delay_10ms() to delay_50ms() to fix problems
+ * Version 5.52 fix incorrect invalidation of removable devices
+ * add "hdx=slow" command line option
+ * Version 5.60 start to modularize the driver; the disk and ATAPI
+ * drivers can be compiled as loadable modules.
+ * move IDE probe code to ide-probe.c
+ * move IDE disk code to ide-disk.c
+ * add support for generic IDE device subdrivers
+ * add m68k code from Geert Uytterhoeven
+ * probe all interfaces by default
+ * add ioctl to (re)probe an interface
+ * Version 6.00 use per device request queues
+ * attempt to optimize shared hwgroup performance
+ * add ioctl to manually adjust bandwidth algorithms
+ * add kerneld support for the probe module
+ * fix bug in ide_error()
+ * fix bug in the first ide_get_lock() call for Atari
+ * don't flush leftover data for ATAPI devices
+ * Version 6.01 clear hwgroup->active while the hwgroup sleeps
+ * support HDIO_GETGEO for floppies
+ * Version 6.02 fix ide_ack_intr() call
+ * check partition table on floppies
+ * Version 6.03 handle bad status bit sequencing in ide_wait_stat()
+ * Version 6.10 deleted old entries from this list of updates
+ * replaced triton.c with ide-dma.c generic PCI DMA
+ * added support for BIOS-enabled UltraDMA
+ * rename all "promise" things to "pdc4030"
+ * fix EZ-DRIVE handling on small disks
+ * Version 6.11 fix probe error in ide_scan_devices()
+ * fix ancient "jiffies" polling bugs
+ * mask all hwgroup interrupts on each irq entry
+ * Version 6.12 integrate ioctl and proc interfaces
+ * fix parsing of "idex=" command line parameter
+ * Version 6.13 add support for ide4/ide5 courtesy rjones@orchestream.com
+ * Version 6.14 fixed IRQ sharing among PCI devices
+ * Version 6.15 added SMP awareness to IDE drivers
+ * Version 6.16 fixed various bugs; even more SMP friendly
+ * Version 6.17 fix for newest EZ-Drive problem
+ * Version 6.18 default unpartitioned-disk translation now "BIOS LBA"
+ * Version 6.19 Re-design for a UNIFORM driver for all platforms,
+ * model based on suggestions from Russell King and
+ * Geert Uytterhoeven
+ * Promise DC4030VL now supported.
+ * add support for ide6/ide7
+ * delay_50ms() changed to ide_delay_50ms() and exported.
+ * Version 6.20 Added/Fixed Generic ATA-66 support and hwif detection.
+ * Added hdx=flash to allow for second flash disk
+ * detection w/o the hang loop.
+ * Added support for ide8/ide9
+ * Added idex=ata66 for the quirky chipsets that are
+ * ATA-66 compliant, but have yet to determine a method
+ * of verification of the 80c cable presence.
+ * Specifically Promise's PDC20262 chipset.
+ * Version 6.21 Fixing/Fixed SMP spinlock issue with insight from an old
+ * hat that clarified original low level driver design.
+ * Version 6.30 Added SMP support; fixed multmode issues. -ml
+ * Version 6.31 Debug Share INTR's and request queue streaming
+ * Native ATA-100 support
+ * Prep for Cascades Project
+ * Version 7.00alpha First named revision of ide rearrange
+ *
+ * Some additional driver compile-time options are in ./include/linux/ide.h
+ *
+ * To do, in likely order of completion:
+ * - modify kernel to obtain BIOS geometry for drives on 2nd/3rd/4th i/f
+ *
+ */
+
+#define REVISION "Revision: 7.00alpha2"
+#define VERSION "Id: ide.c 7.00a2 20020906"
+
+#undef REALLY_SLOW_IO /* most systems can safely undef this */
+
+#define _IDE_C /* Tell ide.h it's really us */
+
+#include <linux/config.h>
+#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/devfs_fs_kernel.h>
+#include <linux/completion.h>
+#include <linux/reboot.h>
+#include <linux/cdrom.h>
+#include <linux/seq_file.h>
+#include <linux/device.h>
+#include <linux/bitops.h>
+
+#include <asm/byteorder.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+
+/* default maximum number of failures */
+#define IDE_DEFAULT_MAX_FAILURES 1
+
+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 };
+
+static int idebus_parameter; /* holds the "idebus=" parameter */
+static int system_bus_speed; /* holds what we think is VESA/PCI bus speed */
+static int initializing; /* set while initializing built-in drivers */
+
+DECLARE_MUTEX(ide_cfg_sem);
+ __cacheline_aligned_in_smp DEFINE_SPINLOCK(ide_lock);
+
+#ifdef CONFIG_BLK_DEV_IDEPCI
+static int ide_scan_direction; /* THIS was formerly 2.2.x pci=reverse */
+#endif
+
+#ifdef CONFIG_IDEDMA_AUTO
+int noautodma = 0;
+#else
+int noautodma = 1;
+#endif
+
+EXPORT_SYMBOL(noautodma);
+
+/*
+ * This is declared extern in ide.h, for access by other IDE modules:
+ */
+ide_hwif_t ide_hwifs[MAX_HWIFS]; /* master data repository */
+
+EXPORT_SYMBOL(ide_hwifs);
+
+static struct list_head ide_drives = LIST_HEAD_INIT(ide_drives);
+
+/*
+ * Do not even *think* about calling this!
+ */
+static void init_hwif_data(ide_hwif_t *hwif, unsigned int index)
+{
+ unsigned int unit;
+
+ /* 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;
+
+ hwif->bus_state = BUSSTATE_ON;
+
+ hwif->atapi_dma = 0; /* disable all atapi dma */
+ hwif->ultra_mask = 0x80; /* disable all ultra */
+ hwif->mwdma_mask = 0x80; /* disable all mwdma */
+ hwif->swdma_mask = 0x80; /* disable all swdma */
+
+ sema_init(&hwif->gendev_rel_sem, 0);
+
+ default_hwif_iops(hwif);
+ default_hwif_transport(hwif);
+ for (unit = 0; unit < MAX_DRIVES; ++unit) {
+ ide_drive_t *drive = &hwif->drives[unit];
+
+ drive->media = ide_disk;
+ drive->select.all = (unit<<4)|0xa0;
+ drive->hwif = hwif;
+ drive->ctl = 0x08;
+ drive->ready_stat = READY_STAT;
+ 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' + (index * MAX_DRIVES) + unit;
+ drive->max_failures = IDE_DEFAULT_MAX_FAILURES;
+ drive->using_dma = 0;
+ drive->is_flash = 0;
+ drive->vdma = 0;
+ INIT_LIST_HEAD(&drive->list);
+ sema_init(&drive->gendev_rel_sem, 0);
+ }
+}
+
+static void init_hwif_default(ide_hwif_t *hwif, unsigned int index)
+{
+ hw_regs_t hw;
+
+ memset(&hw, 0, sizeof(hw_regs_t));
+
+ ide_init_hwif_ports(&hw, ide_default_io_base(index), 0, &hwif->irq);
+
+ memcpy(&hwif->hw, &hw, sizeof(hw));
+ memcpy(hwif->io_ports, hw.io_ports, sizeof(hw.io_ports));
+
+ hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET];
+#ifdef CONFIG_BLK_DEV_HD
+ if (hwif->io_ports[IDE_DATA_OFFSET] == HD_DATA)
+ hwif->noprobe = 1; /* may be overridden by ide_setup() */
+#endif
+}
+
+extern void ide_arm_init(void);
+
+/*
+ * init_ide_data() sets reasonable default values into all fields
+ * of all instances of the hwifs and drives, but only on the first call.
+ * Subsequent calls have no effect (they don't wipe out anything).
+ *
+ * This routine is normally called at driver initialization time,
+ * but may also be called MUCH earlier during kernel "command-line"
+ * parameter processing. As such, we cannot depend on any other parts
+ * of the kernel (such as memory allocation) to be functioning yet.
+ *
+ * This is too bad, as otherwise we could dynamically allocate the
+ * ide_drive_t structs as needed, rather than always consuming memory
+ * for the max possible number (MAX_HWIFS * MAX_DRIVES) of them.
+ *
+ * FIXME: We should stuff the setup data into __init and copy the
+ * relevant hwifs/allocate them properly during boot.
+ */
+#define MAGIC_COOKIE 0x12345678
+static void __init init_ide_data (void)
+{
+ ide_hwif_t *hwif;
+ unsigned int index;
+ static unsigned long magic_cookie = MAGIC_COOKIE;
+
+ if (magic_cookie != MAGIC_COOKIE)
+ return; /* already initialized */
+ magic_cookie = 0;
+
+ /* Initialise all interface structures */
+ for (index = 0; index < MAX_HWIFS; ++index) {
+ hwif = &ide_hwifs[index];
+ init_hwif_data(hwif, index);
+ init_hwif_default(hwif, index);
+#if !defined(CONFIG_PPC32) || !defined(CONFIG_PCI)
+ hwif->irq = hwif->hw.irq =
+ ide_init_default_irq(hwif->io_ports[IDE_DATA_OFFSET]);
+#endif
+ }
+#ifdef CONFIG_IDE_ARM
+ initializing = 1;
+ ide_arm_init();
+ initializing = 0;
+#endif
+}
+
+/**
+ * ide_system_bus_speed - guess bus speed
+ *
+ * ide_system_bus_speed() returns what we think is the system VESA/PCI
+ * bus speed (in MHz). This is used for calculating interface PIO timings.
+ * The default is 40 for known PCI systems, 50 otherwise.
+ * The "idebus=xx" parameter can be used to override this value.
+ * The actual value to be used is computed/displayed the first time
+ * through. Drivers should only use this as a last resort.
+ *
+ * Returns a guessed speed in MHz.
+ */
+
+static int ide_system_bus_speed(void)
+{
+#ifdef CONFIG_PCI
+ static struct pci_device_id pci_default[] = {
+ { PCI_DEVICE(PCI_ANY_ID, PCI_ANY_ID) },
+ { }
+ };
+#else
+#define pci_default 0
+#endif /* CONFIG_PCI */
+
+ if (!system_bus_speed) {
+ if (idebus_parameter) {
+ /* user supplied value */
+ system_bus_speed = idebus_parameter;
+ } else if (pci_dev_present(pci_default)) {
+ /* safe default value for PCI */
+ system_bus_speed = 33;
+ } else {
+ /* safe default value for VESA and PCI */
+ system_bus_speed = 50;
+ }
+ printk(KERN_INFO "ide: Assuming %dMHz system bus speed "
+ "for PIO modes%s\n", system_bus_speed,
+ idebus_parameter ? "" : "; override with idebus=xx");
+ }
+ return system_bus_speed;
+}
+
+/*
+ * drives_lock protects the list of drives, drivers_lock the
+ * list of drivers. Currently nobody takes both at once.
+ */
+
+static DEFINE_SPINLOCK(drives_lock);
+static DEFINE_SPINLOCK(drivers_lock);
+static LIST_HEAD(drivers);
+
+/* Iterator for the driver list. */
+
+static void *m_start(struct seq_file *m, loff_t *pos)
+{
+ struct list_head *p;
+ loff_t l = *pos;
+ spin_lock(&drivers_lock);
+ list_for_each(p, &drivers)
+ if (!l--)
+ return list_entry(p, ide_driver_t, drivers);
+ return NULL;
+}
+
+static void *m_next(struct seq_file *m, void *v, loff_t *pos)
+{
+ struct list_head *p = ((ide_driver_t *)v)->drivers.next;
+ (*pos)++;
+ return p==&drivers ? NULL : list_entry(p, ide_driver_t, drivers);
+}
+
+static void m_stop(struct seq_file *m, void *v)
+{
+ spin_unlock(&drivers_lock);
+}
+
+static int show_driver(struct seq_file *m, void *v)
+{
+ ide_driver_t *driver = v;
+ seq_printf(m, "%s version %s\n", driver->name, driver->version);
+ return 0;
+}
+
+struct seq_operations ide_drivers_op = {
+ .start = m_start,
+ .next = m_next,
+ .stop = m_stop,
+ .show = show_driver
+};
+
+#ifdef CONFIG_PROC_FS
+struct proc_dir_entry *proc_ide_root;
+#endif
+
+static struct resource* hwif_request_region(ide_hwif_t *hwif,
+ unsigned long addr, int num)
+{
+ struct resource *res = request_region(addr, num, hwif->name);
+
+ if (!res)
+ printk(KERN_ERR "%s: I/O resource 0x%lX-0x%lX not free.\n",
+ hwif->name, addr, addr+num-1);
+ return res;
+}
+
+/**
+ * ide_hwif_request_regions - request resources for IDE
+ * @hwif: interface to use
+ *
+ * Requests all the needed resources for an interface.
+ * Right now core IDE code does this work which is deeply wrong.
+ * MMIO leaves it to the controller driver,
+ * PIO will migrate this way over time.
+ */
+
+int ide_hwif_request_regions(ide_hwif_t *hwif)
+{
+ unsigned long addr;
+ unsigned int i;
+
+ if (hwif->mmio == 2)
+ return 0;
+ BUG_ON(hwif->mmio == 1);
+ addr = hwif->io_ports[IDE_CONTROL_OFFSET];
+ if (addr && !hwif_request_region(hwif, addr, 1))
+ goto control_region_busy;
+ hwif->straight8 = 0;
+ addr = hwif->io_ports[IDE_DATA_OFFSET];
+ if ((addr | 7) == hwif->io_ports[IDE_STATUS_OFFSET]) {
+ if (!hwif_request_region(hwif, addr, 8))
+ goto data_region_busy;
+ hwif->straight8 = 1;
+ return 0;
+ }
+ for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
+ addr = hwif->io_ports[i];
+ if (!hwif_request_region(hwif, addr, 1)) {
+ while (--i)
+ release_region(addr, 1);
+ goto data_region_busy;
+ }
+ }
+ return 0;
+
+data_region_busy:
+ addr = hwif->io_ports[IDE_CONTROL_OFFSET];
+ if (addr)
+ release_region(addr, 1);
+control_region_busy:
+ /* If any errors are return, we drop the hwif interface. */
+ return -EBUSY;
+}
+
+/**
+ * ide_hwif_release_regions - free IDE resources
+ *
+ * Note that we only release the standard ports,
+ * and do not even try to handle any extra ports
+ * allocated for weird IDE interface chipsets.
+ *
+ * Note also that we don't yet handle mmio resources here. More
+ * importantly our caller should be doing this so we need to
+ * restructure this as a helper function for drivers.
+ */
+
+void ide_hwif_release_regions(ide_hwif_t *hwif)
+{
+ u32 i = 0;
+
+ if (hwif->mmio == 2)
+ return;
+ if (hwif->io_ports[IDE_CONTROL_OFFSET])
+ release_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1);
+ if (hwif->straight8) {
+ release_region(hwif->io_ports[IDE_DATA_OFFSET], 8);
+ return;
+ }
+ for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++)
+ if (hwif->io_ports[i])
+ release_region(hwif->io_ports[i], 1);
+}
+
+/**
+ * ide_hwif_restore - restore hwif to template
+ * @hwif: hwif to update
+ * @tmp_hwif: template
+ *
+ * Restore hwif to a previous state by copying most settngs
+ * from the template.
+ */
+
+static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif)
+{
+ hwif->hwgroup = tmp_hwif->hwgroup;
+
+ hwif->gendev.parent = tmp_hwif->gendev.parent;
+
+ hwif->proc = tmp_hwif->proc;
+
+ hwif->major = tmp_hwif->major;
+ hwif->straight8 = tmp_hwif->straight8;
+ hwif->bus_state = tmp_hwif->bus_state;
+
+ hwif->atapi_dma = tmp_hwif->atapi_dma;
+ hwif->ultra_mask = tmp_hwif->ultra_mask;
+ hwif->mwdma_mask = tmp_hwif->mwdma_mask;
+ hwif->swdma_mask = tmp_hwif->swdma_mask;
+
+ hwif->chipset = tmp_hwif->chipset;
+ hwif->hold = tmp_hwif->hold;
+
+#ifdef CONFIG_BLK_DEV_IDEPCI
+ hwif->pci_dev = tmp_hwif->pci_dev;
+ hwif->cds = tmp_hwif->cds;
+#endif
+
+ hwif->tuneproc = tmp_hwif->tuneproc;
+ hwif->speedproc = tmp_hwif->speedproc;
+ hwif->selectproc = tmp_hwif->selectproc;
+ hwif->reset_poll = tmp_hwif->reset_poll;
+ hwif->pre_reset = tmp_hwif->pre_reset;
+ hwif->resetproc = tmp_hwif->resetproc;
+ hwif->intrproc = tmp_hwif->intrproc;
+ hwif->maskproc = tmp_hwif->maskproc;
+ hwif->quirkproc = tmp_hwif->quirkproc;
+ hwif->busproc = tmp_hwif->busproc;
+
+ hwif->ata_input_data = tmp_hwif->ata_input_data;
+ hwif->ata_output_data = tmp_hwif->ata_output_data;
+ hwif->atapi_input_bytes = tmp_hwif->atapi_input_bytes;
+ hwif->atapi_output_bytes = tmp_hwif->atapi_output_bytes;
+
+ hwif->dma_setup = tmp_hwif->dma_setup;
+ hwif->dma_exec_cmd = tmp_hwif->dma_exec_cmd;
+ hwif->dma_start = tmp_hwif->dma_start;
+ hwif->ide_dma_end = tmp_hwif->ide_dma_end;
+ hwif->ide_dma_check = tmp_hwif->ide_dma_check;
+ hwif->ide_dma_on = tmp_hwif->ide_dma_on;
+ hwif->ide_dma_off_quietly = tmp_hwif->ide_dma_off_quietly;
+ hwif->ide_dma_test_irq = tmp_hwif->ide_dma_test_irq;
+ hwif->ide_dma_host_on = tmp_hwif->ide_dma_host_on;
+ hwif->ide_dma_host_off = tmp_hwif->ide_dma_host_off;
+ hwif->ide_dma_lostirq = tmp_hwif->ide_dma_lostirq;
+ hwif->ide_dma_timeout = tmp_hwif->ide_dma_timeout;
+
+ hwif->OUTB = tmp_hwif->OUTB;
+ hwif->OUTBSYNC = tmp_hwif->OUTBSYNC;
+ hwif->OUTW = tmp_hwif->OUTW;
+ hwif->OUTL = tmp_hwif->OUTL;
+ hwif->OUTSW = tmp_hwif->OUTSW;
+ hwif->OUTSL = tmp_hwif->OUTSL;
+
+ hwif->INB = tmp_hwif->INB;
+ hwif->INW = tmp_hwif->INW;
+ hwif->INL = tmp_hwif->INL;
+ hwif->INSW = tmp_hwif->INSW;
+ hwif->INSL = tmp_hwif->INSL;
+
+ hwif->sg_max_nents = tmp_hwif->sg_max_nents;
+
+ hwif->mmio = tmp_hwif->mmio;
+ hwif->rqsize = tmp_hwif->rqsize;
+ hwif->no_lba48 = tmp_hwif->no_lba48;
+
+#ifndef CONFIG_BLK_DEV_IDECS
+ hwif->irq = tmp_hwif->irq;
+#endif
+
+ hwif->dma_base = tmp_hwif->dma_base;
+ hwif->dma_master = tmp_hwif->dma_master;
+ hwif->dma_command = tmp_hwif->dma_command;
+ hwif->dma_vendor1 = tmp_hwif->dma_vendor1;
+ hwif->dma_status = tmp_hwif->dma_status;
+ hwif->dma_vendor3 = tmp_hwif->dma_vendor3;
+ hwif->dma_prdtable = tmp_hwif->dma_prdtable;
+
+ hwif->dma_extra = tmp_hwif->dma_extra;
+ hwif->config_data = tmp_hwif->config_data;
+ hwif->select_data = tmp_hwif->select_data;
+ hwif->autodma = tmp_hwif->autodma;
+ hwif->udma_four = tmp_hwif->udma_four;
+ hwif->no_dsc = tmp_hwif->no_dsc;
+
+ hwif->hwif_data = tmp_hwif->hwif_data;
+}
+
+/**
+ * ide_unregister - free an ide interface
+ * @index: index of interface (will change soon to a pointer)
+ *
+ * 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 interfce will not be reopened (present/vanishing locking
+ * isnt 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(unsigned int index)
+{
+ ide_drive_t *drive;
+ ide_hwif_t *hwif, *g;
+ static ide_hwif_t tmp_hwif; /* protected by ide_cfg_sem */
+ ide_hwgroup_t *hwgroup;
+ int irq_count = 0, unit, i;
+
+ BUG_ON(index >= MAX_HWIFS);
+
+ BUG_ON(in_interrupt());
+ BUG_ON(irqs_disabled());
+ down(&ide_cfg_sem);
+ spin_lock_irq(&ide_lock);
+ hwif = &ide_hwifs[index];
+ if (!hwif->present)
+ goto abort;
+ for (unit = 0; unit < MAX_DRIVES; ++unit) {
+ drive = &hwif->drives[unit];
+ if (!drive->present)
+ continue;
+ if (drive->usage || DRIVER(drive)->busy)
+ goto abort;
+ drive->dead = 1;
+ }
+ hwif->present = 0;
+
+ spin_unlock_irq(&ide_lock);
+
+ for (unit = 0; unit < MAX_DRIVES; ++unit) {
+ drive = &hwif->drives[unit];
+ if (!drive->present)
+ continue;
+ DRIVER(drive)->cleanup(drive);
+ }
+
+ destroy_proc_ide_interface(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);
+
+ spin_lock_irq(&ide_lock);
+ /*
+ * Note that we only release the standard ports,
+ * and do not even try to handle any extra ports
+ * allocated for weird IDE interface chipsets.
+ */
+ ide_hwif_release_regions(hwif);
+
+ /*
+ * Remove us from the hwgroup, and free
+ * the hwgroup if we were the only member
+ */
+ for (i = 0; i < MAX_DRIVES; ++i) {
+ drive = &hwif->drives[i];
+ if (drive->devfs_name[0] != '\0') {
+ devfs_remove(drive->devfs_name);
+ drive->devfs_name[0] = '\0';
+ }
+ if (!drive->present)
+ continue;
+ 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 = HWIF(hwgroup->drive);
+ }
+ }
+ BUG_ON(hwgroup->drive == drive);
+ if (drive->id != NULL) {
+ kfree(drive->id);
+ drive->id = NULL;
+ }
+ drive->present = 0;
+ /* Messed up locking ... */
+ spin_unlock_irq(&ide_lock);
+ blk_cleanup_queue(drive->queue);
+ device_unregister(&drive->gendev);
+ down(&drive->gendev_rel_sem);
+ spin_lock_irq(&ide_lock);
+ drive->queue = NULL;
+ }
+ 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.
+ */
+ 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);
+ }
+
+ /* More messed up locking ... */
+ spin_unlock_irq(&ide_lock);
+ device_unregister(&hwif->gendev);
+ down(&hwif->gendev_rel_sem);
+
+ /*
+ * 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);
+ spin_lock_irq(&ide_lock);
+
+ if (hwif->dma_base) {
+ (void) ide_release_dma(hwif);
+
+ hwif->dma_base = 0;
+ hwif->dma_master = 0;
+ hwif->dma_command = 0;
+ hwif->dma_vendor1 = 0;
+ hwif->dma_status = 0;
+ hwif->dma_vendor3 = 0;
+ hwif->dma_prdtable = 0;
+ }
+
+ /* copy original settings */
+ tmp_hwif = *hwif;
+
+ /* restore hwif data to pristine status */
+ init_hwif_data(hwif, index);
+ init_hwif_default(hwif, index);
+
+ ide_hwif_restore(hwif, &tmp_hwif);
+
+abort:
+ spin_unlock_irq(&ide_lock);
+ up(&ide_cfg_sem);
+}
+
+EXPORT_SYMBOL(ide_unregister);
+
+
+/**
+ * ide_setup_ports - set up IDE interface ports
+ * @hw: register descriptions
+ * @base: base register
+ * @offsets: table of register offsets
+ * @ctrl: control register
+ * @ack_irq: IRQ ack
+ * @irq: interrupt lie
+ *
+ * Setup hw_regs_t structure described by parameters. You
+ * may set up the hw structure yourself OR use this routine to
+ * do it for you. This is basically a helper
+ *
+ */
+
+void ide_setup_ports ( hw_regs_t *hw,
+ unsigned long base, int *offsets,
+ unsigned long ctrl, unsigned long intr,
+ ide_ack_intr_t *ack_intr,
+/*
+ * ide_io_ops_t *iops,
+ */
+ int irq)
+{
+ int i;
+
+ for (i = 0; i < IDE_NR_PORTS; i++) {
+ if (offsets[i] == -1) {
+ switch(i) {
+ case IDE_CONTROL_OFFSET:
+ hw->io_ports[i] = ctrl;
+ break;
+#if defined(CONFIG_AMIGA) || defined(CONFIG_MAC)
+ case IDE_IRQ_OFFSET:
+ hw->io_ports[i] = intr;
+ break;
+#endif /* (CONFIG_AMIGA) || (CONFIG_MAC) */
+ default:
+ hw->io_ports[i] = 0;
+ break;
+ }
+ } else {
+ hw->io_ports[i] = base + offsets[i];
+ }
+ }
+ hw->irq = irq;
+ hw->dma = NO_DMA;
+ hw->ack_intr = ack_intr;
+/*
+ * hw->iops = iops;
+ */
+}
+
+/**
+ * ide_register_hw_with_fixup - register IDE interface
+ * @hw: hardware registers
+ * @hwifp: pointer to returned hwif
+ * @fixup: fixup function
+ *
+ * Register an IDE interface, specifying exactly the registers etc.
+ * Set init=1 iff calling before probes have taken place.
+ *
+ * Returns -1 on error.
+ */
+
+int ide_register_hw_with_fixup(hw_regs_t *hw, ide_hwif_t **hwifp, void(*fixup)(ide_hwif_t *hwif))
+{
+ int index, retry = 1;
+ ide_hwif_t *hwif;
+
+ do {
+ for (index = 0; index < MAX_HWIFS; ++index) {
+ hwif = &ide_hwifs[index];
+ if (hwif->hw.io_ports[IDE_DATA_OFFSET] == hw->io_ports[IDE_DATA_OFFSET])
+ goto found;
+ }
+ for (index = 0; index < MAX_HWIFS; ++index) {
+ hwif = &ide_hwifs[index];
+ if (hwif->hold)
+ continue;
+ if ((!hwif->present && !hwif->mate && !initializing) ||
+ (!hwif->hw.io_ports[IDE_DATA_OFFSET] && initializing))
+ goto found;
+ }
+ for (index = 0; index < MAX_HWIFS; index++)
+ ide_unregister(index);
+ } while (retry--);
+ return -1;
+found:
+ if (hwif->present)
+ ide_unregister(index);
+ else if (!hwif->hold) {
+ init_hwif_data(hwif, index);
+ init_hwif_default(hwif, index);
+ }
+ if (hwif->present)
+ return -1;
+ memcpy(&hwif->hw, hw, sizeof(*hw));
+ memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->hw.io_ports));
+ hwif->irq = hw->irq;
+ hwif->noprobe = 0;
+ hwif->chipset = hw->chipset;
+
+ if (!initializing) {
+ probe_hwif_init_with_fixup(hwif, fixup);
+ create_proc_ide_interfaces();
+ }
+
+ if (hwifp)
+ *hwifp = hwif;
+
+ return (initializing || hwif->present) ? index : -1;
+}
+
+EXPORT_SYMBOL(ide_register_hw_with_fixup);
+
+int ide_register_hw(hw_regs_t *hw, ide_hwif_t **hwifp)
+{
+ return ide_register_hw_with_fixup(hw, hwifp, NULL);
+}
+
+EXPORT_SYMBOL(ide_register_hw);
+
+/*
+ * Locks for IDE setting functionality
+ */
+
+DECLARE_MUTEX(ide_setting_sem);
+
+/**
+ * __ide_add_setting - add an ide setting option
+ * @drive: drive to use
+ * @name: setting name
+ * @rw: true if the function is read write
+ * @read_ioctl: function to call on read
+ * @write_ioctl: function to call on write
+ * @data_type: type of data
+ * @min: range minimum
+ * @max: range maximum
+ * @mul_factor: multiplication scale
+ * @div_factor: divison scale
+ * @data: private data field
+ * @set: setting
+ * @auto_remove: setting auto removal flag
+ *
+ * Removes the setting named from the device if it is present.
+ * The function takes the settings_lock to protect against
+ * parallel changes. This function must not be called from IRQ
+ * context. Returns 0 on success or -1 on failure.
+ *
+ * BUGS: This code is seriously over-engineered. There is also
+ * magic about how the driver specific features are setup. If
+ * a driver is attached we assume the driver settings are auto
+ * remove.
+ */
+
+static int __ide_add_setting(ide_drive_t *drive, const char *name, int rw, int read_ioctl, int write_ioctl, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set, int auto_remove)
+{
+ ide_settings_t **p = (ide_settings_t **) &drive->settings, *setting = NULL;
+
+ down(&ide_setting_sem);
+ while ((*p) && strcmp((*p)->name, name) < 0)
+ p = &((*p)->next);
+ if ((setting = kmalloc(sizeof(*setting), GFP_KERNEL)) == NULL)
+ goto abort;
+ memset(setting, 0, sizeof(*setting));
+ if ((setting->name = kmalloc(strlen(name) + 1, GFP_KERNEL)) == NULL)
+ goto abort;
+ strcpy(setting->name, name);
+ setting->rw = rw;
+ setting->read_ioctl = read_ioctl;
+ setting->write_ioctl = write_ioctl;
+ setting->data_type = data_type;
+ setting->min = min;
+ setting->max = max;
+ setting->mul_factor = mul_factor;
+ setting->div_factor = div_factor;
+ setting->data = data;
+ setting->set = set;
+
+ setting->next = *p;
+ if (auto_remove)
+ setting->auto_remove = 1;
+ *p = setting;
+ up(&ide_setting_sem);
+ return 0;
+abort:
+ up(&ide_setting_sem);
+ if (setting)
+ kfree(setting);
+ return -1;
+}
+
+int ide_add_setting(ide_drive_t *drive, const char *name, int rw, int read_ioctl, int write_ioctl, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set)
+{
+ return __ide_add_setting(drive, name, rw, read_ioctl, write_ioctl, data_type, min, max, mul_factor, div_factor, data, set, 1);
+}
+
+EXPORT_SYMBOL(ide_add_setting);
+
+/**
+ * __ide_remove_setting - remove an ide setting option
+ * @drive: drive to use
+ * @name: setting name
+ *
+ * Removes the setting named from the device if it is present.
+ * The caller must hold the setting semaphore.
+ */
+
+static void __ide_remove_setting (ide_drive_t *drive, char *name)
+{
+ ide_settings_t **p, *setting;
+
+ p = (ide_settings_t **) &drive->settings;
+
+ while ((*p) && strcmp((*p)->name, name))
+ p = &((*p)->next);
+ if ((setting = (*p)) == NULL)
+ return;
+
+ (*p) = setting->next;
+
+ kfree(setting->name);
+ kfree(setting);
+}
+
+/**
+ * ide_find_setting_by_ioctl - find a drive specific ioctl
+ * @drive: drive to scan
+ * @cmd: ioctl command to handle
+ *
+ * Scan's the device setting table for a matching entry and returns
+ * this or NULL if no entry is found. The caller must hold the
+ * setting semaphore
+ */
+
+static ide_settings_t *ide_find_setting_by_ioctl (ide_drive_t *drive, int cmd)
+{
+ ide_settings_t *setting = drive->settings;
+
+ while (setting) {
+ if (setting->read_ioctl == cmd || setting->write_ioctl == cmd)
+ break;
+ setting = setting->next;
+ }
+
+ return setting;
+}
+
+/**
+ * ide_find_setting_by_name - find a drive specific setting
+ * @drive: drive to scan
+ * @name: setting name
+ *
+ * Scan's the device setting table for a matching entry and returns
+ * this or NULL if no entry is found. The caller must hold the
+ * setting semaphore
+ */
+
+ide_settings_t *ide_find_setting_by_name (ide_drive_t *drive, char *name)
+{
+ ide_settings_t *setting = drive->settings;
+
+ while (setting) {
+ if (strcmp(setting->name, name) == 0)
+ break;
+ setting = setting->next;
+ }
+ return setting;
+}
+
+/**
+ * auto_remove_settings - remove driver specific settings
+ * @drive: drive
+ *
+ * Automatically remove all the driver specific settings for this
+ * drive. This function may sleep and must not be called from IRQ
+ * context. The caller must hold ide_setting_sem.
+ */
+
+static void auto_remove_settings (ide_drive_t *drive)
+{
+ ide_settings_t *setting;
+repeat:
+ setting = drive->settings;
+ while (setting) {
+ if (setting->auto_remove) {
+ __ide_remove_setting(drive, setting->name);
+ goto repeat;
+ }
+ setting = setting->next;
+ }
+}
+
+/**
+ * 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_sem 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
+ */
+
+int ide_read_setting (ide_drive_t *drive, ide_settings_t *setting)
+{
+ int val = -EINVAL;
+ unsigned long flags;
+
+ if ((setting->rw & SETTING_READ)) {
+ spin_lock_irqsave(&ide_lock, flags);
+ switch(setting->data_type) {
+ case TYPE_BYTE:
+ val = *((u8 *) setting->data);
+ break;
+ case TYPE_SHORT:
+ val = *((u16 *) setting->data);
+ break;
+ case TYPE_INT:
+ case TYPE_INTA:
+ val = *((u32 *) setting->data);
+ break;
+ }
+ spin_unlock_irqrestore(&ide_lock, flags);
+ }
+ return val;
+}
+
+/**
+ * ide_spin_wait_hwgroup - wait for group
+ * @drive: drive in the group
+ *
+ * Wait for an IDE device group to go non busy and then return
+ * holding the ide_lock which guards the hwgroup->busy status
+ * and right to use it.
+ */
+
+int ide_spin_wait_hwgroup (ide_drive_t *drive)
+{
+ ide_hwgroup_t *hwgroup = HWGROUP(drive);
+ unsigned long timeout = jiffies + (3 * HZ);
+
+ spin_lock_irq(&ide_lock);
+
+ while (hwgroup->busy) {
+ unsigned long lflags;
+ spin_unlock_irq(&ide_lock);
+ local_irq_set(lflags);
+ if (time_after(jiffies, timeout)) {
+ local_irq_restore(lflags);
+ printk(KERN_ERR "%s: channel busy\n", drive->name);
+ return -EBUSY;
+ }
+ local_irq_restore(lflags);
+ spin_lock_irq(&ide_lock);
+ }
+ return 0;
+}
+
+EXPORT_SYMBOL(ide_spin_wait_hwgroup);
+
+/**
+ * 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_sem 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.
+ */
+
+int ide_write_setting (ide_drive_t *drive, ide_settings_t *setting, int val)
+{
+ int i;
+ u32 *p;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+ if (!(setting->rw & SETTING_WRITE))
+ return -EPERM;
+ if (val < setting->min || val > setting->max)
+ return -EINVAL;
+ if (setting->set)
+ return setting->set(drive, val);
+ if (ide_spin_wait_hwgroup(drive))
+ return -EBUSY;
+ switch (setting->data_type) {
+ case TYPE_BYTE:
+ *((u8 *) setting->data) = val;
+ break;
+ case TYPE_SHORT:
+ *((u16 *) setting->data) = val;
+ break;
+ case TYPE_INT:
+ *((u32 *) setting->data) = val;
+ break;
+ case TYPE_INTA:
+ p = (u32 *) setting->data;
+ for (i = 0; i < 1 << PARTN_BITS; i++, p++)
+ *p = val;
+ break;
+ }
+ spin_unlock_irq(&ide_lock);
+ return 0;
+}
+
+static int set_io_32bit(ide_drive_t *drive, int arg)
+{
+ drive->io_32bit = arg;
+#ifdef CONFIG_BLK_DEV_DTC2278
+ if (HWIF(drive)->chipset == ide_dtc2278)
+ HWIF(drive)->drives[!drive->select.b.unit].io_32bit = arg;
+#endif /* CONFIG_BLK_DEV_DTC2278 */
+ return 0;
+}
+
+static int set_using_dma (ide_drive_t *drive, int arg)
+{
+#ifdef CONFIG_BLK_DEV_IDEDMA
+ if (!drive->id || !(drive->id->capability & 1))
+ return -EPERM;
+ if (HWIF(drive)->ide_dma_check == NULL)
+ return -EPERM;
+ if (arg) {
+ if (HWIF(drive)->ide_dma_check(drive)) return -EIO;
+ if (HWIF(drive)->ide_dma_on(drive)) return -EIO;
+ } else {
+ if (__ide_dma_off(drive))
+ return -EIO;
+ }
+ return 0;
+#else
+ return -EPERM;
+#endif
+}
+
+static int set_pio_mode (ide_drive_t *drive, int arg)
+{
+ struct request rq;
+
+ if (!HWIF(drive)->tuneproc)
+ return -ENOSYS;
+ if (drive->special.b.set_tune)
+ return -EBUSY;
+ ide_init_drive_cmd(&rq);
+ drive->tune_req = (u8) arg;
+ drive->special.b.set_tune = 1;
+ (void) ide_do_drive_cmd(drive, &rq, ide_wait);
+ return 0;
+}
+
+static int set_xfer_rate (ide_drive_t *drive, int arg)
+{
+ int err = ide_wait_cmd(drive,
+ WIN_SETFEATURES, (u8) arg,
+ SETFEATURES_XFER, 0, NULL);
+
+ if (!err && arg) {
+ ide_set_xfer_rate(drive, (u8) arg);
+ ide_driveid_update(drive);
+ }
+ return err;
+}
+
+/**
+ * ide_add_generic_settings - generic ide settings
+ * @drive: drive being configured
+ *
+ * Add the generic parts of the system settings to the /proc files and
+ * ioctls for this IDE device. The caller must not be holding the
+ * ide_setting_sem.
+ */
+
+void ide_add_generic_settings (ide_drive_t *drive)
+{
+/*
+ * drive setting name read/write access read ioctl write ioctl data type min max mul_factor div_factor data pointer set function
+ */
+ __ide_add_setting(drive, "io_32bit", drive->no_io_32bit ? SETTING_READ : SETTING_RW, HDIO_GET_32BIT, HDIO_SET_32BIT, TYPE_BYTE, 0, 1 + (SUPPORT_VLB_SYNC << 1), 1, 1, &drive->io_32bit, set_io_32bit, 0);
+ __ide_add_setting(drive, "keepsettings", SETTING_RW, HDIO_GET_KEEPSETTINGS, HDIO_SET_KEEPSETTINGS, TYPE_BYTE, 0, 1, 1, 1, &drive->keep_settings, NULL, 0);
+ __ide_add_setting(drive, "nice1", SETTING_RW, -1, -1, TYPE_BYTE, 0, 1, 1, 1, &drive->nice1, NULL, 0);
+ __ide_add_setting(drive, "pio_mode", SETTING_WRITE, -1, HDIO_SET_PIO_MODE, TYPE_BYTE, 0, 255, 1, 1, NULL, set_pio_mode, 0);
+ __ide_add_setting(drive, "unmaskirq", drive->no_unmask ? SETTING_READ : SETTING_RW, HDIO_GET_UNMASKINTR, HDIO_SET_UNMASKINTR, TYPE_BYTE, 0, 1, 1, 1, &drive->unmask, NULL, 0);
+ __ide_add_setting(drive, "using_dma", SETTING_RW, HDIO_GET_DMA, HDIO_SET_DMA, TYPE_BYTE, 0, 1, 1, 1, &drive->using_dma, set_using_dma, 0);
+ __ide_add_setting(drive, "init_speed", SETTING_RW, -1, -1, TYPE_BYTE, 0, 70, 1, 1, &drive->init_speed, NULL, 0);
+ __ide_add_setting(drive, "current_speed", SETTING_RW, -1, -1, TYPE_BYTE, 0, 70, 1, 1, &drive->current_speed, set_xfer_rate, 0);
+ __ide_add_setting(drive, "number", SETTING_RW, -1, -1, TYPE_BYTE, 0, 3, 1, 1, &drive->dn, NULL, 0);
+}
+
+/**
+ * system_bus_clock - clock guess
+ *
+ * External version of the bus clock guess used by very old IDE drivers
+ * for things like VLB timings. Should not be used.
+ */
+
+int system_bus_clock (void)
+{
+ return((int) ((!system_bus_speed) ? ide_system_bus_speed() : system_bus_speed ));
+}
+
+EXPORT_SYMBOL(system_bus_clock);
+
+/*
+ * Locking is badly broken here - since way back. That sucker is
+ * root-only, but that's not an excuse... The real question is what
+ * exclusion rules do we want here.
+ */
+int ide_replace_subdriver (ide_drive_t *drive, const char *driver)
+{
+ if (!drive->present || drive->usage || drive->dead)
+ goto abort;
+ if (DRIVER(drive)->cleanup(drive))
+ goto abort;
+ strlcpy(drive->driver_req, driver, sizeof(drive->driver_req));
+ if (ata_attach(drive)) {
+ spin_lock(&drives_lock);
+ list_del_init(&drive->list);
+ spin_unlock(&drives_lock);
+ drive->driver_req[0] = 0;
+ ata_attach(drive);
+ } else {
+ drive->driver_req[0] = 0;
+ }
+ if (drive->driver && !strcmp(drive->driver->name, driver))
+ return 0;
+abort:
+ return 1;
+}
+
+/**
+ * ata_attach - attach an ATA/ATAPI device
+ * @drive: drive to attach
+ *
+ * Takes a drive that is as yet not assigned to any midlayer IDE
+ * driver (or is assigned to the default driver) and figures out
+ * which driver would like to own it. If nobody claims the drive
+ * then it is automatically attached to the default driver used for
+ * unclaimed objects.
+ *
+ * A return of zero indicates attachment to a driver, of one
+ * attachment to the default driver.
+ *
+ * Takes drivers_lock.
+ */
+
+int ata_attach(ide_drive_t *drive)
+{
+ struct list_head *p;
+ spin_lock(&drivers_lock);
+ list_for_each(p, &drivers) {
+ ide_driver_t *driver = list_entry(p, ide_driver_t, drivers);
+ if (!try_module_get(driver->owner))
+ continue;
+ spin_unlock(&drivers_lock);
+ if (driver->attach(drive) == 0) {
+ module_put(driver->owner);
+ drive->gendev.driver = &driver->gen_driver;
+ return 0;
+ }
+ spin_lock(&drivers_lock);
+ module_put(driver->owner);
+ }
+ drive->gendev.driver = NULL;
+ spin_unlock(&drivers_lock);
+ if (ide_register_subdriver(drive, NULL))
+ panic("ide: default attach failed");
+ return 1;
+}
+
+static int generic_ide_suspend(struct device *dev, pm_message_t state)
+{
+ ide_drive_t *drive = dev->driver_data;
+ struct request rq;
+ struct request_pm_state rqpm;
+ ide_task_t args;
+
+ memset(&rq, 0, sizeof(rq));
+ memset(&rqpm, 0, sizeof(rqpm));
+ memset(&args, 0, sizeof(args));
+ rq.flags = REQ_PM_SUSPEND;
+ rq.special = &args;
+ rq.pm = &rqpm;
+ rqpm.pm_step = ide_pm_state_start_suspend;
+ rqpm.pm_state = state;
+
+ return ide_do_drive_cmd(drive, &rq, ide_wait);
+}
+
+static int generic_ide_resume(struct device *dev)
+{
+ ide_drive_t *drive = dev->driver_data;
+ struct request rq;
+ struct request_pm_state rqpm;
+ ide_task_t args;
+
+ memset(&rq, 0, sizeof(rq));
+ memset(&rqpm, 0, sizeof(rqpm));
+ memset(&args, 0, sizeof(args));
+ rq.flags = REQ_PM_RESUME;
+ rq.special = &args;
+ rq.pm = &rqpm;
+ rqpm.pm_step = ide_pm_state_start_resume;
+ rqpm.pm_state = 0;
+
+ return ide_do_drive_cmd(drive, &rq, ide_head_wait);
+}
+
+int generic_ide_ioctl(ide_drive_t *drive, struct file *file, struct block_device *bdev,
+ unsigned int cmd, unsigned long arg)
+{
+ ide_settings_t *setting;
+ ide_driver_t *drv;
+ int err = 0;
+ void __user *p = (void __user *)arg;
+
+ down(&ide_setting_sem);
+ if ((setting = ide_find_setting_by_ioctl(drive, cmd)) != NULL) {
+ if (cmd == setting->read_ioctl) {
+ err = ide_read_setting(drive, setting);
+ up(&ide_setting_sem);
+ return err >= 0 ? put_user(err, (long __user *)arg) : err;
+ } else {
+ if (bdev != bdev->bd_contains)
+ err = -EINVAL;
+ else
+ err = ide_write_setting(drive, setting, arg);
+ up(&ide_setting_sem);
+ return err;
+ }
+ }
+ up(&ide_setting_sem);
+
+ switch (cmd) {
+ case HDIO_GETGEO:
+ {
+ struct hd_geometry geom;
+ if (!p || (drive->media != ide_disk && drive->media != ide_floppy)) return -EINVAL;
+ geom.heads = drive->bios_head;
+ geom.sectors = drive->bios_sect;
+ geom.cylinders = (u16)drive->bios_cyl; /* truncate */
+ geom.start = get_start_sect(bdev);
+ if (copy_to_user(p, &geom, sizeof(struct hd_geometry)))
+ return -EFAULT;
+ return 0;
+ }
+
+ case HDIO_OBSOLETE_IDENTITY:
+ case HDIO_GET_IDENTITY:
+ if (bdev != bdev->bd_contains)
+ return -EINVAL;
+ if (drive->id_read == 0)
+ return -ENOMSG;
+ if (copy_to_user(p, drive->id, (cmd == HDIO_GET_IDENTITY) ? sizeof(*drive->id) : 142))
+ return -EFAULT;
+ return 0;
+
+ case HDIO_GET_NICE:
+ return put_user(drive->dsc_overlap << IDE_NICE_DSC_OVERLAP |
+ drive->atapi_overlap << IDE_NICE_ATAPI_OVERLAP |
+ drive->nice0 << IDE_NICE_0 |
+ drive->nice1 << IDE_NICE_1 |
+ drive->nice2 << IDE_NICE_2,
+ (long __user *) arg);
+
+#ifdef CONFIG_IDE_TASK_IOCTL
+ case HDIO_DRIVE_TASKFILE:
+ if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
+ return -EACCES;
+ switch(drive->media) {
+ case ide_disk:
+ return ide_taskfile_ioctl(drive, cmd, arg);
+ default:
+ return -ENOMSG;
+ }
+#endif /* CONFIG_IDE_TASK_IOCTL */
+
+ 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_SCAN_HWIF:
+ {
+ hw_regs_t hw;
+ int args[3];
+ if (!capable(CAP_SYS_RAWIO)) return -EACCES;
+ if (copy_from_user(args, p, 3 * sizeof(int)))
+ return -EFAULT;
+ memset(&hw, 0, sizeof(hw));
+ ide_init_hwif_ports(&hw, (unsigned long) args[0],
+ (unsigned long) args[1], NULL);
+ hw.irq = args[2];
+ if (ide_register_hw(&hw, NULL) == -1)
+ return -EIO;
+ return 0;
+ }
+ case HDIO_UNREGISTER_HWIF:
+ if (!capable(CAP_SYS_RAWIO)) return -EACCES;
+ /* (arg > MAX_HWIFS) checked in function */
+ ide_unregister(arg);
+ return 0;
+ case HDIO_SET_NICE:
+ if (!capable(CAP_SYS_ADMIN)) return -EACCES;
+ if (arg != (arg & ((1 << IDE_NICE_DSC_OVERLAP) | (1 << IDE_NICE_1))))
+ return -EPERM;
+ drive->dsc_overlap = (arg >> IDE_NICE_DSC_OVERLAP) & 1;
+ drv = *(ide_driver_t **)bdev->bd_disk->private_data;
+ if (drive->dsc_overlap && !drv->supports_dsc_overlap) {
+ drive->dsc_overlap = 0;
+ return -EPERM;
+ }
+ drive->nice1 = (arg >> IDE_NICE_1) & 1;
+ return 0;
+ case HDIO_DRIVE_RESET:
+ {
+ unsigned long flags;
+ if (!capable(CAP_SYS_ADMIN)) return -EACCES;
+
+ /*
+ * Abort the current command on the
+ * group if there is one, taking
+ * care not to allow anything else
+ * to be queued and to die on the
+ * spot if we miss one somehow
+ */
+
+ spin_lock_irqsave(&ide_lock, flags);
+
+ ide_abort(drive, "drive reset");
+
+ if(HWGROUP(drive)->handler)
+ BUG();
+
+ /* Ensure nothing gets queued after we
+ drop the lock. Reset will clear the busy */
+
+ HWGROUP(drive)->busy = 1;
+ spin_unlock_irqrestore(&ide_lock, flags);
+ (void) ide_do_reset(drive);
+
+ return 0;
+ }
+
+ case CDROMEJECT:
+ case CDROMCLOSETRAY:
+ return scsi_cmd_ioctl(file, bdev->bd_disk, cmd, p);
+
+ case HDIO_GET_BUSSTATE:
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+ if (put_user(HWIF(drive)->bus_state, (long __user *)arg))
+ return -EFAULT;
+ return 0;
+
+ case HDIO_SET_BUSSTATE:
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+ if (HWIF(drive)->busproc)
+ return HWIF(drive)->busproc(drive, (int)arg);
+ return -EOPNOTSUPP;
+ default:
+ return -EINVAL;
+ }
+}
+
+EXPORT_SYMBOL(generic_ide_ioctl);
+
+/*
+ * stridx() returns the offset of c within s,
+ * or -1 if c is '\0' or not found within s.
+ */
+static int __init stridx (const char *s, char c)
+{
+ char *i = strchr(s, c);
+ return (i && c) ? i - s : -1;
+}
+
+/*
+ * match_parm() does parsing for ide_setup():
+ *
+ * 1. the first char of s must be '='.
+ * 2. if the remainder matches one of the supplied keywords,
+ * the index (1 based) of the keyword is negated and returned.
+ * 3. if the remainder is a series of no more than max_vals numbers
+ * separated by commas, the numbers are saved in vals[] and a
+ * count of how many were saved is returned. Base10 is assumed,
+ * and base16 is allowed when prefixed with "0x".
+ * 4. otherwise, zero is returned.
+ */
+static int __init match_parm (char *s, const char *keywords[], int vals[], int max_vals)
+{
+ static const char *decimal = "0123456789";
+ static const char *hex = "0123456789abcdef";
+ int i, n;
+
+ if (*s++ == '=') {
+ /*
+ * Try matching against the supplied keywords,
+ * and return -(index+1) if we match one
+ */
+ if (keywords != NULL) {
+ for (i = 0; *keywords != NULL; ++i) {
+ if (!strcmp(s, *keywords++))
+ return -(i+1);
+ }
+ }
+ /*
+ * Look for a series of no more than "max_vals"
+ * numeric values separated by commas, in base10,
+ * or base16 when prefixed with "0x".
+ * Return a count of how many were found.
+ */
+ for (n = 0; (i = stridx(decimal, *s)) >= 0;) {
+ vals[n] = i;
+ while ((i = stridx(decimal, *++s)) >= 0)
+ vals[n] = (vals[n] * 10) + i;
+ if (*s == 'x' && !vals[n]) {
+ while ((i = stridx(hex, *++s)) >= 0)
+ vals[n] = (vals[n] * 0x10) + i;
+ }
+ if (++n == max_vals)
+ break;
+ if (*s == ',' || *s == ';')
+ ++s;
+ }
+ if (!*s)
+ return n;
+ }
+ return 0; /* zero = nothing matched */
+}
+
+#ifdef CONFIG_BLK_DEV_ALI14XX
+static int __initdata probe_ali14xx;
+extern int ali14xx_init(void);
+#endif
+#ifdef CONFIG_BLK_DEV_UMC8672
+static int __initdata probe_umc8672;
+extern int umc8672_init(void);
+#endif
+#ifdef CONFIG_BLK_DEV_DTC2278
+static int __initdata probe_dtc2278;
+extern int dtc2278_init(void);
+#endif
+#ifdef CONFIG_BLK_DEV_HT6560B
+static int __initdata probe_ht6560b;
+extern int ht6560b_init(void);
+#endif
+#ifdef CONFIG_BLK_DEV_QD65XX
+static int __initdata probe_qd65xx;
+extern int qd65xx_init(void);
+#endif
+
+static int __initdata is_chipset_set[MAX_HWIFS];
+
+/*
+ * ide_setup() gets called VERY EARLY during initialization,
+ * to handle kernel "command line" strings beginning with "hdx=" or "ide".
+ *
+ * Remember to update Documentation/ide.txt if you change something here.
+ */
+static int __init ide_setup(char *s)
+{
+ int i, vals[3];
+ ide_hwif_t *hwif;
+ ide_drive_t *drive;
+ unsigned int hw, unit;
+ const char max_drive = 'a' + ((MAX_HWIFS * MAX_DRIVES) - 1);
+ const char max_hwif = '0' + (MAX_HWIFS - 1);
+
+
+ if (strncmp(s,"hd",2) == 0 && s[2] == '=') /* hd= is for hd.c */
+ return 0; /* driver and not us */
+
+ if (strncmp(s,"ide",3) && strncmp(s,"idebus",6) && strncmp(s,"hd",2))
+ return 0;
+
+ printk(KERN_INFO "ide_setup: %s", s);
+ init_ide_data ();
+
+#ifdef CONFIG_BLK_DEV_IDEDOUBLER
+ if (!strcmp(s, "ide=doubler")) {
+ extern int ide_doubler;
+
+ printk(" : Enabled support for IDE doublers\n");
+ ide_doubler = 1;
+ return 1;
+ }
+#endif /* CONFIG_BLK_DEV_IDEDOUBLER */
+
+ if (!strcmp(s, "ide=nodma")) {
+ printk(" : Prevented DMA\n");
+ noautodma = 1;
+ return 1;
+ }
+
+#ifdef CONFIG_BLK_DEV_IDEPCI
+ if (!strcmp(s, "ide=reverse")) {
+ ide_scan_direction = 1;
+ printk(" : Enabled support for IDE inverse scan order.\n");
+ return 1;
+ }
+#endif /* CONFIG_BLK_DEV_IDEPCI */
+
+ /*
+ * Look for drive options: "hdx="
+ */
+ if (s[0] == 'h' && s[1] == 'd' && s[2] >= 'a' && s[2] <= max_drive) {
+ const char *hd_words[] = {
+ "none", "noprobe", "nowerr", "cdrom", "serialize",
+ "autotune", "noautotune", "minus8", "swapdata", "bswap",
+ "minus11", "remap", "remap63", "scsi", NULL };
+ unit = s[2] - 'a';
+ hw = unit / MAX_DRIVES;
+ unit = unit % MAX_DRIVES;
+ hwif = &ide_hwifs[hw];
+ drive = &hwif->drives[unit];
+ if (strncmp(s + 4, "ide-", 4) == 0) {
+ strlcpy(drive->driver_req, s + 4, sizeof(drive->driver_req));
+ goto done;
+ }
+ switch (match_parm(&s[3], hd_words, vals, 3)) {
+ case -1: /* "none" */
+ case -2: /* "noprobe" */
+ drive->noprobe = 1;
+ goto done;
+ case -3: /* "nowerr" */
+ drive->bad_wstat = BAD_R_STAT;
+ hwif->noprobe = 0;
+ goto done;
+ case -4: /* "cdrom" */
+ drive->present = 1;
+ drive->media = ide_cdrom;
+ /* an ATAPI device ignores DRDY */
+ drive->ready_stat = 0;
+ hwif->noprobe = 0;
+ goto done;
+ case -5: /* "serialize" */
+ printk(" -- USE \"ide%d=serialize\" INSTEAD", hw);
+ goto do_serialize;
+ case -6: /* "autotune" */
+ drive->autotune = IDE_TUNE_AUTO;
+ goto obsolete_option;
+ case -7: /* "noautotune" */
+ drive->autotune = IDE_TUNE_NOAUTO;
+ goto obsolete_option;
+ case -9: /* "swapdata" */
+ case -10: /* "bswap" */
+ drive->bswap = 1;
+ goto done;
+ case -12: /* "remap" */
+ drive->remap_0_to_1 = 1;
+ goto done;
+ case -13: /* "remap63" */
+ drive->sect0 = 63;
+ goto done;
+ case -14: /* "scsi" */
+ drive->scsi = 1;
+ goto done;
+ case 3: /* cyl,head,sect */
+ drive->media = ide_disk;
+ drive->ready_stat = READY_STAT;
+ drive->cyl = drive->bios_cyl = vals[0];
+ drive->head = drive->bios_head = vals[1];
+ drive->sect = drive->bios_sect = vals[2];
+ drive->present = 1;
+ drive->forced_geom = 1;
+ hwif->noprobe = 0;
+ goto done;
+ default:
+ goto bad_option;
+ }
+ }
+
+ if (s[0] != 'i' || s[1] != 'd' || s[2] != 'e')
+ goto bad_option;
+ /*
+ * Look for bus speed option: "idebus="
+ */
+ if (s[3] == 'b' && s[4] == 'u' && s[5] == 's') {
+ if (match_parm(&s[6], NULL, vals, 1) != 1)
+ goto bad_option;
+ if (vals[0] >= 20 && vals[0] <= 66) {
+ idebus_parameter = vals[0];
+ } else
+ printk(" -- BAD BUS SPEED! Expected value from 20 to 66");
+ goto done;
+ }
+ /*
+ * Look for interface options: "idex="
+ */
+ if (s[3] >= '0' && s[3] <= max_hwif) {
+ /*
+ * Be VERY CAREFUL changing this: note hardcoded indexes below
+ * (-8, -9, -10) are reserved to ease the hardcoding.
+ */
+ static const char *ide_words[] = {
+ "noprobe", "serialize", "autotune", "noautotune",
+ "reset", "dma", "ata66", "minus8", "minus9",
+ "minus10", "four", "qd65xx", "ht6560b", "cmd640_vlb",
+ "dtc2278", "umc8672", "ali14xx", NULL };
+ hw = s[3] - '0';
+ hwif = &ide_hwifs[hw];
+ i = match_parm(&s[4], ide_words, vals, 3);
+
+ /*
+ * Cryptic check to ensure chipset not already set for hwif.
+ * Note: we can't depend on hwif->chipset here.
+ */
+ if ((i >= -18 && i <= -11) || (i > 0 && i <= 3)) {
+ /* chipset already specified */
+ if (is_chipset_set[hw])
+ goto bad_option;
+ if (i > -18 && i <= -11) {
+ /* these drivers are for "ide0=" only */
+ if (hw != 0)
+ goto bad_hwif;
+ /* chipset already specified for 2nd port */
+ if (is_chipset_set[hw+1])
+ goto bad_option;
+ }
+ is_chipset_set[hw] = 1;
+ printk("\n");
+ }
+
+ switch (i) {
+#ifdef CONFIG_BLK_DEV_ALI14XX
+ case -17: /* "ali14xx" */
+ probe_ali14xx = 1;
+ goto done;
+#endif
+#ifdef CONFIG_BLK_DEV_UMC8672
+ case -16: /* "umc8672" */
+ probe_umc8672 = 1;
+ goto done;
+#endif
+#ifdef CONFIG_BLK_DEV_DTC2278
+ case -15: /* "dtc2278" */
+ probe_dtc2278 = 1;
+ goto done;
+#endif
+#ifdef CONFIG_BLK_DEV_CMD640
+ case -14: /* "cmd640_vlb" */
+ {
+ extern int cmd640_vlb; /* flag for cmd640.c */
+ cmd640_vlb = 1;
+ goto done;
+ }
+#endif
+#ifdef CONFIG_BLK_DEV_HT6560B
+ case -13: /* "ht6560b" */
+ probe_ht6560b = 1;
+ goto done;
+#endif
+#ifdef CONFIG_BLK_DEV_QD65XX
+ case -12: /* "qd65xx" */
+ probe_qd65xx = 1;
+ goto done;
+#endif
+#ifdef CONFIG_BLK_DEV_4DRIVES
+ case -11: /* "four" drives on one set of ports */
+ {
+ ide_hwif_t *mate = &ide_hwifs[hw^1];
+ mate->drives[0].select.all ^= 0x20;
+ mate->drives[1].select.all ^= 0x20;
+ hwif->chipset = mate->chipset = ide_4drives;
+ mate->irq = hwif->irq;
+ memcpy(mate->io_ports, hwif->io_ports, sizeof(hwif->io_ports));
+ goto do_serialize;
+ }
+#endif /* CONFIG_BLK_DEV_4DRIVES */
+ case -10: /* minus10 */
+ case -9: /* minus9 */
+ case -8: /* minus8 */
+ goto bad_option;
+ case -7: /* ata66 */
+#ifdef CONFIG_BLK_DEV_IDEPCI
+ hwif->udma_four = 1;
+ goto obsolete_option;
+#else
+ goto bad_hwif;
+#endif
+ case -6: /* dma */
+ hwif->autodma = 1;
+ goto obsolete_option;
+ case -5: /* "reset" */
+ hwif->reset = 1;
+ goto obsolete_option;
+ case -4: /* "noautotune" */
+ hwif->drives[0].autotune = IDE_TUNE_NOAUTO;
+ hwif->drives[1].autotune = IDE_TUNE_NOAUTO;
+ goto obsolete_option;
+ case -3: /* "autotune" */
+ hwif->drives[0].autotune = IDE_TUNE_AUTO;
+ hwif->drives[1].autotune = IDE_TUNE_AUTO;
+ goto obsolete_option;
+ case -2: /* "serialize" */
+ do_serialize:
+ hwif->mate = &ide_hwifs[hw^1];
+ hwif->mate->mate = hwif;
+ hwif->serialized = hwif->mate->serialized = 1;
+ goto obsolete_option;
+
+ case -1: /* "noprobe" */
+ hwif->noprobe = 1;
+ goto done;
+
+ case 1: /* base */
+ vals[1] = vals[0] + 0x206; /* default ctl */
+ case 2: /* base,ctl */
+ vals[2] = 0; /* default irq = probe for it */
+ case 3: /* base,ctl,irq */
+ hwif->hw.irq = vals[2];
+ ide_init_hwif_ports(&hwif->hw, (unsigned long) vals[0], (unsigned long) vals[1], &hwif->irq);
+ memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
+ hwif->irq = vals[2];
+ hwif->noprobe = 0;
+ hwif->chipset = ide_forced;
+ goto obsolete_option;
+
+ case 0: goto bad_option;
+ default:
+ printk(" -- SUPPORT NOT CONFIGURED IN THIS KERNEL\n");
+ return 1;
+ }
+ }
+bad_option:
+ printk(" -- BAD OPTION\n");
+ return 1;
+obsolete_option:
+ printk(" -- OBSOLETE OPTION, WILL BE REMOVED SOON!\n");
+ return 1;
+bad_hwif:
+ printk("-- NOT SUPPORTED ON ide%d", hw);
+done:
+ printk("\n");
+ return 1;
+}
+
+extern void pnpide_init(void);
+extern void h8300_ide_init(void);
+
+/*
+ * probe_for_hwifs() finds/initializes "known" IDE interfaces
+ */
+static void __init probe_for_hwifs (void)
+{
+#ifdef CONFIG_BLK_DEV_IDEPCI
+ ide_scan_pcibus(ide_scan_direction);
+#endif /* CONFIG_BLK_DEV_IDEPCI */
+
+#ifdef CONFIG_ETRAX_IDE
+ {
+ extern void init_e100_ide(void);
+ init_e100_ide();
+ }
+#endif /* CONFIG_ETRAX_IDE */
+#ifdef CONFIG_BLK_DEV_CMD640
+ {
+ extern void ide_probe_for_cmd640x(void);
+ ide_probe_for_cmd640x();
+ }
+#endif /* CONFIG_BLK_DEV_CMD640 */
+#ifdef CONFIG_BLK_DEV_IDE_PMAC
+ {
+ extern void pmac_ide_probe(void);
+ pmac_ide_probe();
+ }
+#endif /* CONFIG_BLK_DEV_IDE_PMAC */
+#ifdef CONFIG_BLK_DEV_GAYLE
+ {
+ extern void gayle_init(void);
+ gayle_init();
+ }
+#endif /* CONFIG_BLK_DEV_GAYLE */
+#ifdef CONFIG_BLK_DEV_FALCON_IDE
+ {
+ extern void falconide_init(void);
+ falconide_init();
+ }
+#endif /* CONFIG_BLK_DEV_FALCON_IDE */
+#ifdef CONFIG_BLK_DEV_MAC_IDE
+ {
+ extern void macide_init(void);
+ macide_init();
+ }
+#endif /* CONFIG_BLK_DEV_MAC_IDE */
+#ifdef CONFIG_BLK_DEV_Q40IDE
+ {
+ extern void q40ide_init(void);
+ q40ide_init();
+ }
+#endif /* CONFIG_BLK_DEV_Q40IDE */
+#ifdef CONFIG_BLK_DEV_BUDDHA
+ {
+ extern void buddha_init(void);
+ buddha_init();
+ }
+#endif /* CONFIG_BLK_DEV_BUDDHA */
+#ifdef CONFIG_BLK_DEV_IDEPNP
+ pnpide_init();
+#endif
+#ifdef CONFIG_H8300
+ h8300_ide_init();
+#endif
+}
+
+int ide_register_subdriver(ide_drive_t *drive, ide_driver_t *driver)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ide_lock, flags);
+ if (!drive->present || drive->driver != NULL ||
+ drive->usage || drive->dead) {
+ spin_unlock_irqrestore(&ide_lock, flags);
+ return 1;
+ }
+ drive->driver = driver;
+ spin_unlock_irqrestore(&ide_lock, flags);
+ spin_lock(&drives_lock);
+ list_add_tail(&drive->list, driver ? &driver->drives : &ide_drives);
+ spin_unlock(&drives_lock);
+// printk(KERN_INFO "%s: attached %s driver.\n", drive->name, driver->name);
+#ifdef CONFIG_PROC_FS
+ if (driver)
+ ide_add_proc_entries(drive->proc, driver->proc, drive);
+#endif
+ return 0;
+}
+
+EXPORT_SYMBOL(ide_register_subdriver);
+
+/**
+ * ide_unregister_subdriver - disconnect drive from driver
+ * @drive: drive to unplug
+ *
+ * Disconnect a drive from the driver it was attached to and then
+ * clean up the various proc files and other objects attached to it.
+ *
+ * Takes ide_setting_sem, ide_lock and drives_lock.
+ * Caller must hold none of the locks.
+ *
+ * No locking versus subdriver unload because we are moving to the
+ * default driver anyway. Wants double checking.
+ */
+
+int ide_unregister_subdriver (ide_drive_t *drive)
+{
+ unsigned long flags;
+
+ down(&ide_setting_sem);
+ spin_lock_irqsave(&ide_lock, flags);
+ if (drive->usage || drive->driver == NULL || DRIVER(drive)->busy) {
+ spin_unlock_irqrestore(&ide_lock, flags);
+ up(&ide_setting_sem);
+ return 1;
+ }
+#ifdef CONFIG_PROC_FS
+ ide_remove_proc_entries(drive->proc, DRIVER(drive)->proc);
+#endif
+ auto_remove_settings(drive);
+ drive->driver = NULL;
+ spin_unlock_irqrestore(&ide_lock, flags);
+ up(&ide_setting_sem);
+ spin_lock(&drives_lock);
+ list_del_init(&drive->list);
+ spin_unlock(&drives_lock);
+ /* drive will be added to &ide_drives in ata_attach() */
+ return 0;
+}
+
+EXPORT_SYMBOL(ide_unregister_subdriver);
+
+static int ide_drive_remove(struct device * dev)
+{
+ ide_drive_t * drive = container_of(dev,ide_drive_t,gendev);
+ DRIVER(drive)->cleanup(drive);
+ return 0;
+}
+
+/**
+ * ide_register_driver - register IDE device driver
+ * @driver: the IDE device driver
+ *
+ * Register a new device driver and then scan the devices
+ * on the IDE bus in case any should be attached to the
+ * driver we have just registered. If so attach them.
+ *
+ * Takes drivers_lock and drives_lock.
+ */
+
+int ide_register_driver(ide_driver_t *driver)
+{
+ struct list_head list;
+ struct list_head *list_loop;
+ struct list_head *tmp_storage;
+
+ spin_lock(&drivers_lock);
+ list_add(&driver->drivers, &drivers);
+ spin_unlock(&drivers_lock);
+
+ INIT_LIST_HEAD(&list);
+ spin_lock(&drives_lock);
+ list_splice_init(&ide_drives, &list);
+ spin_unlock(&drives_lock);
+
+ list_for_each_safe(list_loop, tmp_storage, &list) {
+ ide_drive_t *drive = container_of(list_loop, ide_drive_t, list);
+ list_del_init(&drive->list);
+ if (drive->present)
+ ata_attach(drive);
+ }
+ driver->gen_driver.name = (char *) driver->name;
+ driver->gen_driver.bus = &ide_bus_type;
+ driver->gen_driver.remove = ide_drive_remove;
+ return driver_register(&driver->gen_driver);
+}
+
+EXPORT_SYMBOL(ide_register_driver);
+
+/**
+ * ide_unregister_driver - unregister IDE device driver
+ * @driver: the IDE device driver
+ *
+ * Called when a driver module is being unloaded. We reattach any
+ * devices to whatever driver claims them next (typically the default
+ * driver).
+ *
+ * Takes drivers_lock and called functions will take ide_setting_sem.
+ */
+
+void ide_unregister_driver(ide_driver_t *driver)
+{
+ ide_drive_t *drive;
+
+ spin_lock(&drivers_lock);
+ list_del(&driver->drivers);
+ spin_unlock(&drivers_lock);
+
+ driver_unregister(&driver->gen_driver);
+
+ while(!list_empty(&driver->drives)) {
+ drive = list_entry(driver->drives.next, ide_drive_t, list);
+ if (driver->cleanup(drive)) {
+ printk(KERN_ERR "%s: cleanup_module() called while still busy\n", drive->name);
+ BUG();
+ }
+ ata_attach(drive);
+ }
+}
+
+EXPORT_SYMBOL(ide_unregister_driver);
+
+/*
+ * Probe module
+ */
+
+EXPORT_SYMBOL(ide_lock);
+
+struct bus_type ide_bus_type = {
+ .name = "ide",
+ .suspend = generic_ide_suspend,
+ .resume = generic_ide_resume,
+};
+
+/*
+ * This is gets invoked once during initialization, to set *everything* up
+ */
+static int __init ide_init(void)
+{
+ printk(KERN_INFO "Uniform Multi-Platform E-IDE driver " REVISION "\n");
+ devfs_mk_dir("ide");
+ system_bus_speed = ide_system_bus_speed();
+
+ bus_register(&ide_bus_type);
+
+ init_ide_data();
+
+#ifdef CONFIG_PROC_FS
+ proc_ide_root = proc_mkdir("ide", NULL);
+#endif
+
+#ifdef CONFIG_BLK_DEV_ALI14XX
+ if (probe_ali14xx)
+ (void)ali14xx_init();
+#endif
+#ifdef CONFIG_BLK_DEV_UMC8672
+ if (probe_umc8672)
+ (void)umc8672_init();
+#endif
+#ifdef CONFIG_BLK_DEV_DTC2278
+ if (probe_dtc2278)
+ (void)dtc2278_init();
+#endif
+#ifdef CONFIG_BLK_DEV_HT6560B
+ if (probe_ht6560b)
+ (void)ht6560b_init();
+#endif
+#ifdef CONFIG_BLK_DEV_QD65XX
+ if (probe_qd65xx)
+ (void)qd65xx_init();
+#endif
+
+ initializing = 1;
+ /* Probe for special PCI and other "known" interface chipsets. */
+ probe_for_hwifs();
+ initializing = 0;
+
+#ifdef CONFIG_PROC_FS
+ proc_ide_create();
+#endif
+ return 0;
+}
+
+#ifdef MODULE
+static char *options = NULL;
+module_param(options, charp, 0);
+MODULE_LICENSE("GPL");
+
+static void __init parse_options (char *line)
+{
+ char *next = line;
+
+ if (line == NULL || !*line)
+ return;
+ while ((line = next) != NULL) {
+ if ((next = strchr(line,' ')) != NULL)
+ *next++ = 0;
+ if (!ide_setup(line))
+ printk (KERN_INFO "Unknown option '%s'\n", line);
+ }
+}
+
+int init_module (void)
+{
+ parse_options(options);
+ return ide_init();
+}
+
+void cleanup_module (void)
+{
+ int index;
+
+ for (index = 0; index < MAX_HWIFS; ++index)
+ ide_unregister(index);
+
+#ifdef CONFIG_PROC_FS
+ proc_ide_destroy();
+#endif
+ devfs_remove("ide");
+
+ bus_unregister(&ide_bus_type);
+}
+
+#else /* !MODULE */
+
+__setup("", ide_setup);
+
+module_init(ide_init);
+
+#endif /* MODULE */
diff --git a/drivers/ide/legacy/Makefile b/drivers/ide/legacy/Makefile
new file mode 100644
index 000000000000..c7971061767e
--- /dev/null
+++ b/drivers/ide/legacy/Makefile
@@ -0,0 +1,13 @@
+
+obj-$(CONFIG_BLK_DEV_ALI14XX) += ali14xx.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_UMC8672) += umc8672.o
+
+obj-$(CONFIG_BLK_DEV_IDECS) += ide-cs.o
+
+# Last of all
+obj-$(CONFIG_BLK_DEV_HD) += hd.o
+
+EXTRA_CFLAGS := -Idrivers/ide
diff --git a/drivers/ide/legacy/ali14xx.c b/drivers/ide/legacy/ali14xx.c
new file mode 100644
index 000000000000..fb88711812e6
--- /dev/null
+++ b/drivers/ide/legacy/ali14xx.c
@@ -0,0 +1,253 @@
+/*
+ * linux/drivers/ide/legacy/ali14xx.c Version 0.03 Feb 09, 1996
+ *
+ * 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
+ */
+
+#undef REALLY_SLOW_IO /* most systems can safely undef this */
+
+#include <linux/module.h>
+#include <linux/config.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/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+/* port addresses for auto-detection */
+#define ALI_NUM_PORTS 4
+static int ports[ALI_NUM_PORTS] __initdata = {0x074, 0x0f4, 0x034, 0x0e4};
+
+/* register initialization data */
+typedef struct { u8 reg, data; } RegInitializer;
+
+static 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}
+};
+
+#define ALI_MAX_PIO 4
+
+/* 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);
+}
+
+/*
+ * Set PIO mode for the specified drive.
+ * This function computes timing parameters
+ * and sets controller registers accordingly.
+ */
+static void ali14xx_tune_drive (ide_drive_t *drive, u8 pio)
+{
+ int driveNum;
+ int time1, time2;
+ u8 param1, param2, param3, param4;
+ unsigned long flags;
+ ide_pio_data_t d;
+ int bus_speed = system_bus_clock();
+
+ pio = ide_get_best_pio_mode(drive, pio, ALI_MAX_PIO, &d);
+
+ /* calculate timing, according to PIO mode */
+ time1 = d.cycle_time;
+ time2 = ide_pio_timings[pio].active_time;
+ 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 = (HWIF(drive)->index << 1) + drive->select.b.unit;
+ spin_lock_irqsave(&ide_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(&ide_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) {
+ 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 int __init ali14xx_probe(void)
+{
+ ide_hwif_t *hwif, *mate;
+
+ 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;
+ }
+
+ hwif = &ide_hwifs[0];
+ mate = &ide_hwifs[1];
+
+ hwif->chipset = ide_ali14xx;
+ hwif->tuneproc = &ali14xx_tune_drive;
+ hwif->mate = mate;
+
+ mate->chipset = ide_ali14xx;
+ mate->tuneproc = &ali14xx_tune_drive;
+ mate->mate = hwif;
+ mate->channel = 1;
+
+ probe_hwif_init(hwif);
+ probe_hwif_init(mate);
+
+ create_proc_ide_interfaces();
+
+ return 0;
+}
+
+/* Can be called directly from ide.c. */
+int __init ali14xx_init(void)
+{
+ /* auto-detect IDE controller port */
+ if (findPort()) {
+ if (ali14xx_probe())
+ return -ENODEV;
+ return 0;
+ }
+ printk(KERN_ERR "ali14xx: not found.\n");
+ return -ENODEV;
+}
+
+#ifdef MODULE
+module_init(ali14xx_init);
+#endif
+
+MODULE_AUTHOR("see local file");
+MODULE_DESCRIPTION("support of ALI 14XX IDE chipsets");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/legacy/buddha.c b/drivers/ide/legacy/buddha.c
new file mode 100644
index 000000000000..0391a3122878
--- /dev/null
+++ b/drivers/ide/legacy/buddha.c
@@ -0,0 +1,235 @@
+/*
+ * linux/drivers/ide/legacy/buddha.c -- 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/hdreg.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
+
+ /*
+ * 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_DATA 0x00
+#define BUDDHA_ERROR 0x06 /* see err-bits */
+#define BUDDHA_NSECTOR 0x0a /* nr of sectors to read/write */
+#define BUDDHA_SECTOR 0x0e /* starting sector */
+#define BUDDHA_LCYL 0x12 /* starting cylinder */
+#define BUDDHA_HCYL 0x16 /* high byte of starting cyl */
+#define BUDDHA_SELECT 0x1a /* 101dhhhh , d=drive, hhhh=head */
+#define BUDDHA_STATUS 0x1e /* see status-bits */
+#define BUDDHA_CONTROL 0x11a
+#define XSURF_CONTROL -1 /* X-Surf has no CS1* (Control/AltStat) */
+
+static int buddha_offsets[IDE_NR_PORTS] __initdata = {
+ BUDDHA_DATA, BUDDHA_ERROR, BUDDHA_NSECTOR, BUDDHA_SECTOR, BUDDHA_LCYL,
+ BUDDHA_HCYL, BUDDHA_SELECT, BUDDHA_STATUS, BUDDHA_CONTROL, -1
+};
+
+static int xsurf_offsets[IDE_NR_PORTS] __initdata = {
+ BUDDHA_DATA, BUDDHA_ERROR, BUDDHA_NSECTOR, BUDDHA_SECTOR, BUDDHA_LCYL,
+ BUDDHA_HCYL, BUDDHA_SELECT, BUDDHA_STATUS, XSURF_CONTROL, -1
+};
+
+ /*
+ * 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;
+
+
+ /*
+ * Check and acknowledge the interrupt status
+ */
+
+static int buddha_ack_intr(ide_hwif_t *hwif)
+{
+ unsigned char ch;
+
+ ch = z_readb(hwif->io_ports[IDE_IRQ_OFFSET]);
+ 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[IDE_IRQ_OFFSET]);
+ /* X-Surf needs a 0 written to IRQ register to ensure ISA bit A11 stays at 0 */
+ z_writeb(0, hwif->io_ports[IDE_IRQ_OFFSET]);
+ if (!(ch & 0x80))
+ return 0;
+ return 1;
+}
+
+ /*
+ * Probe for a Buddha or Catweasel IDE interface
+ */
+
+void __init buddha_init(void)
+{
+ hw_regs_t hw;
+ ide_hwif_t *hwif;
+ int i, index;
+
+ struct zorro_dev *z = NULL;
+ u_long buddha_board = 0;
+ BuddhaType type;
+ int buddha_num_hwifs;
+
+ while ((z = zorro_find_device(ZORRO_WILDCARD, z))) {
+ unsigned long board;
+ 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);
+
+ for(i=0;i<buddha_num_hwifs;i++) {
+ if(type != BOARD_XSURF) {
+ ide_setup_ports(&hw, (buddha_board+buddha_bases[i]),
+ buddha_offsets, 0,
+ (buddha_board+buddha_irqports[i]),
+ buddha_ack_intr,
+// budda_iops,
+ IRQ_AMIGA_PORTS);
+ } else {
+ ide_setup_ports(&hw, (buddha_board+xsurf_bases[i]),
+ xsurf_offsets, 0,
+ (buddha_board+xsurf_irqports[i]),
+ xsurf_ack_intr,
+// xsurf_iops,
+ IRQ_AMIGA_PORTS);
+ }
+
+ index = ide_register_hw(&hw, &hwif);
+ if (index != -1) {
+ hwif->mmio = 2;
+ printk("ide%d: ", index);
+ switch(type) {
+ case BOARD_BUDDHA:
+ printk("Buddha");
+ break;
+ case BOARD_CATWEASEL:
+ printk("Catweasel");
+ break;
+ case BOARD_XSURF:
+ printk("X-Surf");
+ break;
+ }
+ printk(" IDE interface\n");
+ }
+ }
+ }
+}
diff --git a/drivers/ide/legacy/dtc2278.c b/drivers/ide/legacy/dtc2278.c
new file mode 100644
index 000000000000..20eb5b872ca9
--- /dev/null
+++ b/drivers/ide/legacy/dtc2278.c
@@ -0,0 +1,165 @@
+/*
+ * linux/drivers/ide/legacy/dtc2278.c Version 0.02 Feb 10, 1996
+ *
+ * Copyright (C) 1996 Linus Torvalds & author (see below)
+ */
+
+#undef REALLY_SLOW_IO /* most systems can safely undef this */
+
+#include <linux/module.h>
+#include <linux/config.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/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+/*
+ * 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 void tune_dtc2278 (ide_drive_t *drive, u8 pio)
+{
+ unsigned long flags;
+
+ pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+
+ if (pio >= 3) {
+ spin_lock_irqsave(&ide_lock, flags);
+ /*
+ * This enables PIO mode4 (3?) on the first interface
+ */
+ sub22(1,0xc3);
+ sub22(0,0xa0);
+ spin_unlock_irqrestore(&ide_lock, flags);
+ } else {
+ /* we don't know how to set it back again.. */
+ }
+
+ /*
+ * 32bit I/O has to be enabled for *both* drives at the same time.
+ */
+ drive->io_32bit = 1;
+ HWIF(drive)->drives[!drive->select.b.unit].io_32bit = 1;
+}
+
+static int __init probe_dtc2278(void)
+{
+ unsigned long flags;
+ ide_hwif_t *hwif, *mate;
+
+ hwif = &ide_hwifs[0];
+ mate = &ide_hwifs[1];
+
+ if (hwif->chipset != ide_unknown || mate->chipset != ide_unknown)
+ return 1;
+
+ 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);
+
+ hwif->serialized = 1;
+ hwif->chipset = ide_dtc2278;
+ hwif->tuneproc = &tune_dtc2278;
+ hwif->drives[0].no_unmask = 1;
+ hwif->drives[1].no_unmask = 1;
+ hwif->mate = mate;
+
+ mate->serialized = 1;
+ mate->chipset = ide_dtc2278;
+ mate->drives[0].no_unmask = 1;
+ mate->drives[1].no_unmask = 1;
+ mate->mate = hwif;
+ mate->channel = 1;
+
+ probe_hwif_init(hwif);
+ probe_hwif_init(mate);
+
+ create_proc_ide_interfaces();
+
+ return 0;
+}
+
+/* Can be called directly from ide.c. */
+int __init dtc2278_init(void)
+{
+ if (probe_dtc2278()) {
+ printk(KERN_ERR "dtc2278: ide interfaces already in use!\n");
+ return -EBUSY;
+ }
+ return 0;
+}
+
+#ifdef MODULE
+module_init(dtc2278_init);
+#endif
+
+MODULE_AUTHOR("See Local File");
+MODULE_DESCRIPTION("support of DTC-2278 VLB IDE chipsets");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/legacy/falconide.c b/drivers/ide/legacy/falconide.c
new file mode 100644
index 000000000000..a9f2cd5bb81e
--- /dev/null
+++ b/drivers/ide/legacy/falconide.c
@@ -0,0 +1,78 @@
+/*
+ * linux/drivers/ide/legacy/falconide.c -- 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/types.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.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>
+
+
+ /*
+ * Base of the IDE interface
+ */
+
+#define ATA_HD_BASE 0xfff00000
+
+ /*
+ * Offsets from the above base
+ */
+
+#define ATA_HD_DATA 0x00
+#define ATA_HD_ERROR 0x05 /* see err-bits */
+#define ATA_HD_NSECTOR 0x09 /* nr of sectors to read/write */
+#define ATA_HD_SECTOR 0x0d /* starting sector */
+#define ATA_HD_LCYL 0x11 /* starting cylinder */
+#define ATA_HD_HCYL 0x15 /* high byte of starting cyl */
+#define ATA_HD_SELECT 0x19 /* 101dhhhh , d=drive, hhhh=head */
+#define ATA_HD_STATUS 0x1d /* see status-bits */
+#define ATA_HD_CONTROL 0x39
+
+static int falconide_offsets[IDE_NR_PORTS] __initdata = {
+ ATA_HD_DATA, ATA_HD_ERROR, ATA_HD_NSECTOR, ATA_HD_SECTOR, ATA_HD_LCYL,
+ ATA_HD_HCYL, ATA_HD_SELECT, ATA_HD_STATUS, ATA_HD_CONTROL, -1
+};
+
+
+ /*
+ * falconide_intr_lock is used to obtain access to the IDE interrupt,
+ * which is shared between several drivers.
+ */
+
+int falconide_intr_lock;
+
+
+ /*
+ * Probe for a Falcon IDE interface
+ */
+
+void __init falconide_init(void)
+{
+ if (MACH_IS_ATARI && ATARIHW_PRESENT(IDE)) {
+ hw_regs_t hw;
+ int index;
+
+ ide_setup_ports(&hw, ATA_HD_BASE, falconide_offsets,
+ 0, 0, NULL,
+// falconide_iops,
+ IRQ_MFP_IDE);
+ index = ide_register_hw(&hw, NULL);
+
+ if (index != -1)
+ printk("ide%d: Falcon IDE interface\n", index);
+ }
+}
diff --git a/drivers/ide/legacy/gayle.c b/drivers/ide/legacy/gayle.c
new file mode 100644
index 000000000000..3fac3e9ec47d
--- /dev/null
+++ b/drivers/ide/legacy/gayle.c
@@ -0,0 +1,186 @@
+/*
+ * linux/drivers/ide/legacy/gayle.c -- 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/config.h>
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+#include <linux/zorro.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 */
+
+ /*
+ * Offsets from one of the above bases
+ */
+
+#define GAYLE_DATA 0x00
+#define GAYLE_ERROR 0x06 /* see err-bits */
+#define GAYLE_NSECTOR 0x0a /* nr of sectors to read/write */
+#define GAYLE_SECTOR 0x0e /* starting sector */
+#define GAYLE_LCYL 0x12 /* starting cylinder */
+#define GAYLE_HCYL 0x16 /* high byte of starting cyl */
+#define GAYLE_SELECT 0x1a /* 101dhhhh , d=drive, hhhh=head */
+#define GAYLE_STATUS 0x1e /* see status-bits */
+#define GAYLE_CONTROL 0x101a
+
+static int gayle_offsets[IDE_NR_PORTS] __initdata = {
+ GAYLE_DATA, GAYLE_ERROR, GAYLE_NSECTOR, GAYLE_SECTOR, GAYLE_LCYL,
+ GAYLE_HCYL, GAYLE_SELECT, GAYLE_STATUS, -1, -1
+};
+
+
+ /*
+ * 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
+#define GAYLE_IDEREG_SIZE 0x2000
+#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)
+#define GAYLE_IDEREG_SIZE (ide_doubler ? 0x1000 : 0x2000)
+int ide_doubler = 0; /* support 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[IDE_IRQ_OFFSET]);
+ 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[IDE_IRQ_OFFSET]);
+ if (!(ch & GAYLE_IRQ_IDE))
+ return 0;
+ (void)z_readb(hwif->io_ports[IDE_STATUS_OFFSET]);
+ z_writeb(0x7c, hwif->io_ports[IDE_IRQ_OFFSET]);
+ return 1;
+}
+
+ /*
+ * Probe for a Gayle IDE interface (and optionally for an IDE doubler)
+ */
+
+void __init gayle_init(void)
+{
+ int a4000, i;
+
+ if (!MACH_IS_AMIGA)
+ return;
+
+ 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;
+
+found:
+ for (i = 0; i < GAYLE_NUM_PROBE_HWIFS; i++) {
+ unsigned long base, ctrlport, irqport;
+ ide_ack_intr_t *ack_intr;
+ hw_regs_t hw;
+ ide_hwif_t *hwif;
+ int index;
+ unsigned long phys_base, res_start, res_n;
+
+ 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
+ */
+
+ phys_base += i*GAYLE_NEXT_PORT;
+
+ res_start = ((unsigned long)phys_base) & ~(GAYLE_NEXT_PORT-1);
+ res_n = GAYLE_IDEREG_SIZE;
+
+ if (!request_mem_region(res_start, res_n, "IDE"))
+ continue;
+
+ base = (unsigned long)ZTWO_VADDR(phys_base);
+ ctrlport = GAYLE_HAS_CONTROL_REG ? (base + GAYLE_CONTROL) : 0;
+
+ ide_setup_ports(&hw, base, gayle_offsets,
+ ctrlport, irqport, ack_intr,
+// &gayle_iops,
+ IRQ_AMIGA_PORTS);
+
+ index = ide_register_hw(&hw, &hwif);
+ if (index != -1) {
+ hwif->mmio = 2;
+ switch (i) {
+ case 0:
+ printk("ide%d: Gayle IDE interface (A%d style)\n", index,
+ a4000 ? 4000 : 1200);
+ break;
+#ifdef CONFIG_BLK_DEV_IDEDOUBLER
+ case 1:
+ printk("ide%d: IDE doubler\n", index);
+ break;
+#endif /* CONFIG_BLK_DEV_IDEDOUBLER */
+ }
+ } else
+ release_mem_region(res_start, res_n);
+ }
+}
diff --git a/drivers/ide/legacy/hd.c b/drivers/ide/legacy/hd.c
new file mode 100644
index 000000000000..c4090550ec13
--- /dev/null
+++ b/drivers/ide/legacy/hd.c
@@ -0,0 +1,864 @@
+/*
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ *
+ * This is the low-level hd interrupt support. It traverses the
+ * request-list, using interrupts to jump between functions. As
+ * all the functions are called within interrupts, we may not
+ * sleep. Special care is recommended.
+ *
+ * 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
+ *
+ * IRQ-unmask, drive-id, multiple-mode, support for ">16 heads",
+ * and general streamlining by Mark Lord.
+ *
+ * Removed 99% of above. Use Mark's ide driver for those options.
+ * This is now a lightweight ST-506 driver. (Paul Gortmaker)
+ *
+ * Modified 1995 Russell King for ARM processor.
+ *
+ * Bugfix: max_sectors must be <= 255 or the wheels tend to come
+ * off in a hurry once you queue things up - Paul G. 02/2001
+ */
+
+/* Uncomment the following if you want verbose error reports. */
+/* #define VERBOSE_ERRORS */
+
+#include <linux/blkdev.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/interrupt.h>
+#include <linux/timer.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/genhd.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/mc146818rtc.h> /* CMOS defines */
+#include <linux/init.h>
+#include <linux/blkpg.h>
+#include <linux/hdreg.h>
+
+#define REALLY_SLOW_IO
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+#ifdef __arm__
+#undef HD_IRQ
+#endif
+#include <asm/irq.h>
+#ifdef __arm__
+#define HD_IRQ IRQ_HARDDISK
+#endif
+
+/* Hd controller regster ports */
+
+#define HD_DATA 0x1f0 /* _CTL when writing */
+#define HD_ERROR 0x1f1 /* see err-bits */
+#define HD_NSECTOR 0x1f2 /* nr of sectors to read/write */
+#define HD_SECTOR 0x1f3 /* starting sector */
+#define HD_LCYL 0x1f4 /* starting cylinder */
+#define HD_HCYL 0x1f5 /* high byte of starting cyl */
+#define HD_CURRENT 0x1f6 /* 101dhhhh , d=drive, hhhh=head */
+#define HD_STATUS 0x1f7 /* see status-bits */
+#define HD_FEATURE HD_ERROR /* same io address, read=error, write=feature */
+#define HD_PRECOMP HD_FEATURE /* obsolete use of this port - predates IDE */
+#define HD_COMMAND HD_STATUS /* same io address, read=status, write=cmd */
+
+#define HD_CMD 0x3f6 /* used for resets */
+#define HD_ALTSTATUS 0x3f6 /* same as HD_STATUS but doesn't clear irq */
+
+/* Bits of HD_STATUS */
+#define ERR_STAT 0x01
+#define INDEX_STAT 0x02
+#define ECC_STAT 0x04 /* Corrected error */
+#define DRQ_STAT 0x08
+#define SEEK_STAT 0x10
+#define SERVICE_STAT SEEK_STAT
+#define WRERR_STAT 0x20
+#define READY_STAT 0x40
+#define BUSY_STAT 0x80
+
+/* Bits for HD_ERROR */
+#define MARK_ERR 0x01 /* Bad address mark */
+#define TRK0_ERR 0x02 /* couldn't find track 0 */
+#define ABRT_ERR 0x04 /* Command aborted */
+#define MCR_ERR 0x08 /* media change request */
+#define ID_ERR 0x10 /* ID field not found */
+#define MC_ERR 0x20 /* media changed */
+#define ECC_ERR 0x40 /* Uncorrectable ECC error */
+#define BBD_ERR 0x80 /* pre-EIDE meaning: block marked bad */
+#define ICRC_ERR 0x80 /* new meaning: CRC error during transfer */
+
+static DEFINE_SPINLOCK(hd_lock);
+static struct request_queue *hd_queue;
+
+#define MAJOR_NR HD_MAJOR
+#define QUEUE (hd_queue)
+#define CURRENT elv_next_request(hd_queue)
+
+#define TIMEOUT_VALUE (6*HZ)
+#define HD_DELAY 0
+
+#define MAX_ERRORS 16 /* Max read/write errors/sector */
+#define RESET_FREQ 8 /* Reset controller every 8th retry */
+#define RECAL_FREQ 4 /* Recalibrate every 4th retry */
+#define MAX_HD 2
+
+#define STAT_OK (READY_STAT|SEEK_STAT)
+#define OK_STATUS(s) (((s)&(STAT_OK|(BUSY_STAT|WRERR_STAT|ERR_STAT)))==STAT_OK)
+
+static void recal_intr(void);
+static void bad_rw_intr(void);
+
+static int reset;
+static int hd_error;
+
+/*
+ * This struct defines the HD's and their types.
+ */
+struct hd_i_struct {
+ unsigned int head,sect,cyl,wpcom,lzone,ctl;
+ int unit;
+ int recalibrate;
+ int special_op;
+};
+
+#ifdef HD_TYPE
+static struct hd_i_struct hd_info[] = { HD_TYPE };
+static int NR_HD = ((sizeof (hd_info))/(sizeof (struct hd_i_struct)));
+#else
+static struct hd_i_struct hd_info[MAX_HD];
+static int NR_HD;
+#endif
+
+static struct gendisk *hd_gendisk[MAX_HD];
+
+static struct timer_list device_timer;
+
+#define TIMEOUT_VALUE (6*HZ)
+
+#define SET_TIMER \
+ do { \
+ mod_timer(&device_timer, jiffies + TIMEOUT_VALUE); \
+ } while (0)
+
+static void (*do_hd)(void) = NULL;
+#define SET_HANDLER(x) \
+if ((do_hd = (x)) != NULL) \
+ SET_TIMER; \
+else \
+ del_timer(&device_timer);
+
+
+#if (HD_DELAY > 0)
+unsigned long last_req;
+
+unsigned long read_timer(void)
+{
+ extern spinlock_t i8253_lock;
+ unsigned long t, flags;
+ int i;
+
+ spin_lock_irqsave(&i8253_lock, flags);
+ t = jiffies * 11932;
+ outb_p(0, 0x43);
+ i = inb_p(0x40);
+ i |= inb(0x40) << 8;
+ spin_unlock_irqrestore(&i8253_lock, flags);
+ return(t - i);
+}
+#endif
+
+static void __init hd_setup(char *str, int *ints)
+{
+ int hdind = 0;
+
+ if (ints[0] != 3)
+ return;
+ if (hd_info[0].head != 0)
+ hdind=1;
+ hd_info[hdind].head = ints[2];
+ hd_info[hdind].sect = ints[3];
+ hd_info[hdind].cyl = ints[1];
+ hd_info[hdind].wpcom = 0;
+ hd_info[hdind].lzone = ints[1];
+ hd_info[hdind].ctl = (ints[2] > 8 ? 8 : 0);
+ NR_HD = hdind+1;
+}
+
+static void dump_status (const char *msg, unsigned int stat)
+{
+ char *name = "hd?";
+ if (CURRENT)
+ name = CURRENT->rq_disk->disk_name;
+
+#ifdef VERBOSE_ERRORS
+ printk("%s: %s: status=0x%02x { ", name, msg, stat & 0xff);
+ if (stat & BUSY_STAT) printk("Busy ");
+ if (stat & READY_STAT) printk("DriveReady ");
+ if (stat & WRERR_STAT) printk("WriteFault ");
+ if (stat & SEEK_STAT) printk("SeekComplete ");
+ if (stat & DRQ_STAT) printk("DataRequest ");
+ if (stat & ECC_STAT) printk("CorrectedError ");
+ if (stat & INDEX_STAT) printk("Index ");
+ if (stat & ERR_STAT) printk("Error ");
+ printk("}\n");
+ if ((stat & ERR_STAT) == 0) {
+ hd_error = 0;
+ } else {
+ hd_error = inb(HD_ERROR);
+ printk("%s: %s: error=0x%02x { ", name, msg, hd_error & 0xff);
+ if (hd_error & BBD_ERR) printk("BadSector ");
+ if (hd_error & ECC_ERR) printk("UncorrectableError ");
+ if (hd_error & ID_ERR) printk("SectorIdNotFound ");
+ if (hd_error & ABRT_ERR) printk("DriveStatusError ");
+ if (hd_error & TRK0_ERR) printk("TrackZeroNotFound ");
+ if (hd_error & MARK_ERR) printk("AddrMarkNotFound ");
+ printk("}");
+ if (hd_error & (BBD_ERR|ECC_ERR|ID_ERR|MARK_ERR)) {
+ printk(", CHS=%d/%d/%d", (inb(HD_HCYL)<<8) + inb(HD_LCYL),
+ inb(HD_CURRENT) & 0xf, inb(HD_SECTOR));
+ if (CURRENT)
+ printk(", sector=%ld", CURRENT->sector);
+ }
+ printk("\n");
+ }
+#else
+ printk("%s: %s: status=0x%02x.\n", name, msg, stat & 0xff);
+ if ((stat & ERR_STAT) == 0) {
+ hd_error = 0;
+ } else {
+ hd_error = inb(HD_ERROR);
+ printk("%s: %s: error=0x%02x.\n", name, msg, hd_error & 0xff);
+ }
+#endif
+}
+
+static void check_status(void)
+{
+ int i = inb_p(HD_STATUS);
+
+ if (!OK_STATUS(i)) {
+ dump_status("check_status", i);
+ bad_rw_intr();
+ }
+}
+
+static int controller_busy(void)
+{
+ int retries = 100000;
+ unsigned char status;
+
+ do {
+ status = inb_p(HD_STATUS);
+ } while ((status & BUSY_STAT) && --retries);
+ return status;
+}
+
+static int status_ok(void)
+{
+ unsigned char status = inb_p(HD_STATUS);
+
+ if (status & BUSY_STAT)
+ return 1; /* Ancient, but does it make sense??? */
+ if (status & WRERR_STAT)
+ return 0;
+ if (!(status & READY_STAT))
+ return 0;
+ if (!(status & SEEK_STAT))
+ return 0;
+ return 1;
+}
+
+static int controller_ready(unsigned int drive, unsigned int head)
+{
+ int retry = 100;
+
+ do {
+ if (controller_busy() & BUSY_STAT)
+ return 0;
+ outb_p(0xA0 | (drive<<4) | head, HD_CURRENT);
+ if (status_ok())
+ return 1;
+ } while (--retry);
+ return 0;
+}
+
+
+static void hd_out(struct hd_i_struct *disk,
+ unsigned int nsect,
+ unsigned int sect,
+ unsigned int head,
+ unsigned int cyl,
+ unsigned int cmd,
+ void (*intr_addr)(void))
+{
+ unsigned short port;
+
+#if (HD_DELAY > 0)
+ while (read_timer() - last_req < HD_DELAY)
+ /* nothing */;
+#endif
+ if (reset)
+ return;
+ if (!controller_ready(disk->unit, head)) {
+ reset = 1;
+ return;
+ }
+ SET_HANDLER(intr_addr);
+ outb_p(disk->ctl,HD_CMD);
+ port=HD_DATA;
+ outb_p(disk->wpcom>>2,++port);
+ outb_p(nsect,++port);
+ outb_p(sect,++port);
+ outb_p(cyl,++port);
+ outb_p(cyl>>8,++port);
+ outb_p(0xA0|(disk->unit<<4)|head,++port);
+ outb_p(cmd,++port);
+}
+
+static void hd_request (void);
+
+static int drive_busy(void)
+{
+ unsigned int i;
+ unsigned char c;
+
+ for (i = 0; i < 500000 ; i++) {
+ c = inb_p(HD_STATUS);
+ if ((c & (BUSY_STAT | READY_STAT | SEEK_STAT)) == STAT_OK)
+ return 0;
+ }
+ dump_status("reset timed out", c);
+ return 1;
+}
+
+static void reset_controller(void)
+{
+ int i;
+
+ outb_p(4,HD_CMD);
+ for(i = 0; i < 1000; i++) barrier();
+ outb_p(hd_info[0].ctl & 0x0f,HD_CMD);
+ for(i = 0; i < 1000; i++) barrier();
+ if (drive_busy())
+ printk("hd: controller still busy\n");
+ else if ((hd_error = inb(HD_ERROR)) != 1)
+ printk("hd: controller reset failed: %02x\n",hd_error);
+}
+
+static void reset_hd(void)
+{
+ static int i;
+
+repeat:
+ if (reset) {
+ reset = 0;
+ i = -1;
+ reset_controller();
+ } else {
+ check_status();
+ if (reset)
+ goto repeat;
+ }
+ if (++i < NR_HD) {
+ struct hd_i_struct *disk = &hd_info[i];
+ disk->special_op = disk->recalibrate = 1;
+ hd_out(disk,disk->sect,disk->sect,disk->head-1,
+ disk->cyl,WIN_SPECIFY,&reset_hd);
+ if (reset)
+ goto repeat;
+ } else
+ hd_request();
+}
+
+/*
+ * Ok, don't know what to do with the unexpected interrupts: on some machines
+ * doing a reset and a retry seems to result in an eternal loop. Right now I
+ * ignore it, and just set the timeout.
+ *
+ * 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.
+ */
+static void unexpected_hd_interrupt(void)
+{
+ unsigned int stat = inb_p(HD_STATUS);
+
+ if (stat & (BUSY_STAT|DRQ_STAT|ECC_STAT|ERR_STAT)) {
+ dump_status ("unexpected interrupt", stat);
+ SET_TIMER;
+ }
+}
+
+/*
+ * bad_rw_intr() now tries to be a bit smarter and does things
+ * according to the error returned by the controller.
+ * -Mika Liljeberg (liljeber@cs.Helsinki.FI)
+ */
+static void bad_rw_intr(void)
+{
+ struct request *req = CURRENT;
+ if (req != NULL) {
+ struct hd_i_struct *disk = req->rq_disk->private_data;
+ if (++req->errors >= MAX_ERRORS || (hd_error & BBD_ERR)) {
+ end_request(req, 0);
+ disk->special_op = disk->recalibrate = 1;
+ } else if (req->errors % RESET_FREQ == 0)
+ reset = 1;
+ else if ((hd_error & TRK0_ERR) || req->errors % RECAL_FREQ == 0)
+ disk->special_op = disk->recalibrate = 1;
+ /* Otherwise just retry */
+ }
+}
+
+static inline int wait_DRQ(void)
+{
+ int retries = 100000, stat;
+
+ while (--retries > 0)
+ if ((stat = inb_p(HD_STATUS)) & DRQ_STAT)
+ return 0;
+ dump_status("wait_DRQ", stat);
+ return -1;
+}
+
+static void read_intr(void)
+{
+ struct request *req;
+ int i, retries = 100000;
+
+ do {
+ i = (unsigned) inb_p(HD_STATUS);
+ if (i & BUSY_STAT)
+ continue;
+ if (!OK_STATUS(i))
+ break;
+ if (i & DRQ_STAT)
+ goto ok_to_read;
+ } while (--retries > 0);
+ dump_status("read_intr", i);
+ bad_rw_intr();
+ hd_request();
+ return;
+ok_to_read:
+ req = CURRENT;
+ insw(HD_DATA,req->buffer,256);
+ req->sector++;
+ req->buffer += 512;
+ req->errors = 0;
+ i = --req->nr_sectors;
+ --req->current_nr_sectors;
+#ifdef DEBUG
+ printk("%s: read: sector %ld, remaining = %ld, buffer=%p\n",
+ req->rq_disk->disk_name, req->sector, req->nr_sectors,
+ req->buffer+512));
+#endif
+ if (req->current_nr_sectors <= 0)
+ end_request(req, 1);
+ if (i > 0) {
+ SET_HANDLER(&read_intr);
+ return;
+ }
+ (void) inb_p(HD_STATUS);
+#if (HD_DELAY > 0)
+ last_req = read_timer();
+#endif
+ if (elv_next_request(QUEUE))
+ hd_request();
+ return;
+}
+
+static void write_intr(void)
+{
+ struct request *req = CURRENT;
+ int i;
+ int retries = 100000;
+
+ do {
+ i = (unsigned) inb_p(HD_STATUS);
+ if (i & BUSY_STAT)
+ continue;
+ if (!OK_STATUS(i))
+ break;
+ if ((req->nr_sectors <= 1) || (i & DRQ_STAT))
+ goto ok_to_write;
+ } while (--retries > 0);
+ dump_status("write_intr", i);
+ bad_rw_intr();
+ hd_request();
+ return;
+ok_to_write:
+ req->sector++;
+ i = --req->nr_sectors;
+ --req->current_nr_sectors;
+ req->buffer += 512;
+ if (!i || (req->bio && req->current_nr_sectors <= 0))
+ end_request(req, 1);
+ if (i > 0) {
+ SET_HANDLER(&write_intr);
+ outsw(HD_DATA,req->buffer,256);
+ local_irq_enable();
+ } else {
+#if (HD_DELAY > 0)
+ last_req = read_timer();
+#endif
+ hd_request();
+ }
+ return;
+}
+
+static void recal_intr(void)
+{
+ check_status();
+#if (HD_DELAY > 0)
+ last_req = read_timer();
+#endif
+ hd_request();
+}
+
+/*
+ * This is another of the error-routines I don't know what to do with. The
+ * best idea seems to just set reset, and start all over again.
+ */
+static void hd_times_out(unsigned long dummy)
+{
+ char *name;
+
+ do_hd = NULL;
+
+ if (!CURRENT)
+ return;
+
+ disable_irq(HD_IRQ);
+ local_irq_enable();
+ reset = 1;
+ name = CURRENT->rq_disk->disk_name;
+ printk("%s: timeout\n", name);
+ if (++CURRENT->errors >= MAX_ERRORS) {
+#ifdef DEBUG
+ printk("%s: too many errors\n", name);
+#endif
+ end_request(CURRENT, 0);
+ }
+ local_irq_disable();
+ hd_request();
+ enable_irq(HD_IRQ);
+}
+
+static int do_special_op(struct hd_i_struct *disk, struct request *req)
+{
+ if (disk->recalibrate) {
+ disk->recalibrate = 0;
+ hd_out(disk,disk->sect,0,0,0,WIN_RESTORE,&recal_intr);
+ return reset;
+ }
+ if (disk->head > 16) {
+ printk ("%s: cannot handle device with more than 16 heads - giving up\n", req->rq_disk->disk_name);
+ end_request(req, 0);
+ }
+ disk->special_op = 0;
+ return 1;
+}
+
+/*
+ * The driver enables interrupts as much as possible. In order to do this,
+ * (a) the device-interrupt is disabled before entering hd_request(),
+ * and (b) the timeout-interrupt is disabled before the sti().
+ *
+ * Interrupts are still masked (by default) whenever we are exchanging
+ * data/cmds with a drive, because some drives seem to have very poor
+ * tolerance for latency during I/O. The IDE driver has support to unmask
+ * interrupts for non-broken hardware, so use that driver if required.
+ */
+static void hd_request(void)
+{
+ unsigned int block, nsect, sec, track, head, cyl;
+ struct hd_i_struct *disk;
+ struct request *req;
+
+ if (do_hd)
+ return;
+repeat:
+ del_timer(&device_timer);
+ local_irq_enable();
+
+ req = CURRENT;
+ if (!req) {
+ do_hd = NULL;
+ return;
+ }
+
+ if (reset) {
+ local_irq_disable();
+ reset_hd();
+ return;
+ }
+ disk = req->rq_disk->private_data;
+ block = req->sector;
+ nsect = req->nr_sectors;
+ if (block >= get_capacity(req->rq_disk) ||
+ ((block+nsect) > get_capacity(req->rq_disk))) {
+ printk("%s: bad access: block=%d, count=%d\n",
+ req->rq_disk->disk_name, block, nsect);
+ end_request(req, 0);
+ goto repeat;
+ }
+
+ if (disk->special_op) {
+ if (do_special_op(disk, req))
+ goto repeat;
+ return;
+ }
+ sec = block % disk->sect + 1;
+ track = block / disk->sect;
+ head = track % disk->head;
+ cyl = track / disk->head;
+#ifdef DEBUG
+ printk("%s: %sing: CHS=%d/%d/%d, sectors=%d, buffer=%p\n",
+ req->rq_disk->disk_name, (req->cmd == READ)?"read":"writ",
+ cyl, head, sec, nsect, req->buffer);
+#endif
+ if (req->flags & REQ_CMD) {
+ switch (rq_data_dir(req)) {
+ case READ:
+ hd_out(disk,nsect,sec,head,cyl,WIN_READ,&read_intr);
+ if (reset)
+ goto repeat;
+ break;
+ case WRITE:
+ hd_out(disk,nsect,sec,head,cyl,WIN_WRITE,&write_intr);
+ if (reset)
+ goto repeat;
+ if (wait_DRQ()) {
+ bad_rw_intr();
+ goto repeat;
+ }
+ outsw(HD_DATA,req->buffer,256);
+ break;
+ default:
+ printk("unknown hd-command\n");
+ end_request(req, 0);
+ break;
+ }
+ }
+}
+
+static void do_hd_request (request_queue_t * q)
+{
+ disable_irq(HD_IRQ);
+ hd_request();
+ enable_irq(HD_IRQ);
+}
+
+static int hd_ioctl(struct inode * inode, struct file * file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct hd_i_struct *disk = inode->i_bdev->bd_disk->private_data;
+ struct hd_geometry __user *loc = (struct hd_geometry __user *) arg;
+ struct hd_geometry g;
+
+ if (cmd != HDIO_GETGEO)
+ return -EINVAL;
+ if (!loc)
+ return -EINVAL;
+ g.heads = disk->head;
+ g.sectors = disk->sect;
+ g.cylinders = disk->cyl;
+ g.start = get_start_sect(inode->i_bdev);
+ return copy_to_user(loc, &g, sizeof g) ? -EFAULT : 0;
+}
+
+/*
+ * Releasing a block device means we sync() it, so that it can safely
+ * be forgotten about...
+ */
+
+static irqreturn_t hd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ void (*handler)(void) = do_hd;
+
+ do_hd = NULL;
+ del_timer(&device_timer);
+ if (!handler)
+ handler = unexpected_hd_interrupt;
+ handler();
+ local_irq_enable();
+ return IRQ_HANDLED;
+}
+
+static struct block_device_operations hd_fops = {
+ .ioctl = hd_ioctl,
+};
+
+/*
+ * This is the hard disk IRQ description. The SA_INTERRUPT in sa_flags
+ * means we run the IRQ-handler with interrupts disabled: this is bad for
+ * interrupt latency, but anything else has led to problems on some
+ * machines.
+ *
+ * We enable interrupts in some of the routines after making sure it's
+ * safe.
+ */
+
+static int __init hd_init(void)
+{
+ int drive;
+
+ if (register_blkdev(MAJOR_NR,"hd"))
+ return -1;
+
+ hd_queue = blk_init_queue(do_hd_request, &hd_lock);
+ if (!hd_queue) {
+ unregister_blkdev(MAJOR_NR,"hd");
+ return -ENOMEM;
+ }
+
+ blk_queue_max_sectors(hd_queue, 255);
+ init_timer(&device_timer);
+ device_timer.function = hd_times_out;
+ blk_queue_hardsect_size(hd_queue, 512);
+
+#ifdef __i386__
+ if (!NR_HD) {
+ extern struct drive_info drive_info;
+ unsigned char *BIOS = (unsigned char *) &drive_info;
+ unsigned long flags;
+ int cmos_disks;
+
+ for (drive=0 ; drive<2 ; drive++) {
+ hd_info[drive].cyl = *(unsigned short *) BIOS;
+ hd_info[drive].head = *(2+BIOS);
+ hd_info[drive].wpcom = *(unsigned short *) (5+BIOS);
+ hd_info[drive].ctl = *(8+BIOS);
+ hd_info[drive].lzone = *(unsigned short *) (12+BIOS);
+ hd_info[drive].sect = *(14+BIOS);
+#ifdef does_not_work_for_everybody_with_scsi_but_helps_ibm_vp
+ if (hd_info[drive].cyl && NR_HD == drive)
+ NR_HD++;
+#endif
+ BIOS += 16;
+ }
+
+ /*
+ We query CMOS about hard disks : it could be that
+ we have a SCSI/ESDI/etc controller that is BIOS
+ compatible with ST-506, and thus showing up in our
+ BIOS table, but not register compatible, and therefore
+ not present in CMOS.
+
+ Furthermore, we will assume that our ST-506 drives
+ <if any> are the primary drives in the system, and
+ the ones reflected as drive 1 or 2.
+
+ The first drive is stored in the high nibble of CMOS
+ byte 0x12, the second in the low nibble. This will be
+ either a 4 bit drive type or 0xf indicating use byte 0x19
+ for an 8 bit type, drive 1, 0x1a for drive 2 in CMOS.
+
+ Needless to say, a non-zero value means we have
+ an AT controller hard disk for that drive.
+
+ Currently the rtc_lock is a bit academic since this
+ driver is non-modular, but someday... ? Paul G.
+ */
+
+ spin_lock_irqsave(&rtc_lock, flags);
+ cmos_disks = CMOS_READ(0x12);
+ spin_unlock_irqrestore(&rtc_lock, flags);
+
+ if (cmos_disks & 0xf0) {
+ if (cmos_disks & 0x0f)
+ NR_HD = 2;
+ else
+ NR_HD = 1;
+ }
+ }
+#endif /* __i386__ */
+#ifdef __arm__
+ if (!NR_HD) {
+ /* We don't know anything about the drive. This means
+ * that you *MUST* specify the drive parameters to the
+ * kernel yourself.
+ */
+ printk("hd: no drives specified - use hd=cyl,head,sectors"
+ " on kernel command line\n");
+ }
+#endif
+ if (!NR_HD)
+ goto out;
+
+ for (drive=0 ; drive < NR_HD ; drive++) {
+ struct gendisk *disk = alloc_disk(64);
+ struct hd_i_struct *p = &hd_info[drive];
+ if (!disk)
+ goto Enomem;
+ disk->major = MAJOR_NR;
+ disk->first_minor = drive << 6;
+ disk->fops = &hd_fops;
+ sprintf(disk->disk_name, "hd%c", 'a'+drive);
+ disk->private_data = p;
+ set_capacity(disk, p->head * p->sect * p->cyl);
+ disk->queue = hd_queue;
+ p->unit = drive;
+ hd_gendisk[drive] = disk;
+ printk ("%s: %luMB, CHS=%d/%d/%d\n",
+ disk->disk_name, (unsigned long)get_capacity(disk)/2048,
+ p->cyl, p->head, p->sect);
+ }
+
+ if (request_irq(HD_IRQ, hd_interrupt, SA_INTERRUPT, "hd", NULL)) {
+ printk("hd: unable to get IRQ%d for the hard disk driver\n",
+ HD_IRQ);
+ goto out1;
+ }
+ if (!request_region(HD_DATA, 8, "hd")) {
+ printk(KERN_WARNING "hd: port 0x%x busy\n", HD_DATA);
+ goto out2;
+ }
+ if (!request_region(HD_CMD, 1, "hd(cmd)")) {
+ printk(KERN_WARNING "hd: port 0x%x busy\n", HD_CMD);
+ goto out3;
+ }
+
+ /* Let them fly */
+ for(drive=0; drive < NR_HD; drive++)
+ add_disk(hd_gendisk[drive]);
+
+ return 0;
+
+out3:
+ release_region(HD_DATA, 8);
+out2:
+ free_irq(HD_IRQ, NULL);
+out1:
+ for (drive = 0; drive < NR_HD; drive++)
+ put_disk(hd_gendisk[drive]);
+ NR_HD = 0;
+out:
+ del_timer(&device_timer);
+ unregister_blkdev(MAJOR_NR,"hd");
+ blk_cleanup_queue(hd_queue);
+ return -1;
+Enomem:
+ while (drive--)
+ put_disk(hd_gendisk[drive]);
+ goto out;
+}
+
+static int parse_hd_setup (char *line) {
+ int ints[6];
+
+ (void) get_options(line, ARRAY_SIZE(ints), ints);
+ hd_setup(NULL, ints);
+
+ return 1;
+}
+__setup("hd=", parse_hd_setup);
+
+module_init(hd_init);
diff --git a/drivers/ide/legacy/ht6560b.c b/drivers/ide/legacy/ht6560b.c
new file mode 100644
index 000000000000..a77fb249d5cf
--- /dev/null
+++ b/drivers/ide/legacy/ht6560b.c
@@ -0,0 +1,370 @@
+/*
+ * linux/drivers/ide/legacy/ht6560b.c Version 0.07 Feb 1, 2000
+ *
+ * Copyright (C) 1995-2000 Linus Torvalds & author (see below)
+ */
+
+/*
+ *
+ * Version 0.01 Initial version hacked out of ide.c
+ *
+ * Version 0.02 Added support for PIO modes, auto-tune
+ *
+ * Version 0.03 Some cleanups
+ *
+ * Version 0.05 PIO mode cycle timings auto-tune using bus-speed
+ *
+ * Version 0.06 Prefetch mode now defaults no OFF. To set
+ * prefetch mode OFF/ON use "hdparm -p8/-p9".
+ * Unmask irq is disabled when prefetch mode
+ * is enabled.
+ *
+ * Version 0.07 Trying to fix CD-ROM detection problem.
+ * "Prefetch" mode bit OFF for ide disks and
+ * ON for anything else.
+ *
+ *
+ * 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 <janevert@iae.nl>
+ *
+ * Try: http://www.maf.iki.fi/~maf/ht6560b/
+ */
+
+#define HT6560B_VERSION "v0.07"
+
+#undef REALLY_SLOW_IO /* most systems can safely undef this */
+
+#include <linux/module.h>
+#include <linux/config.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/hdreg.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 IDE_SELECT_REG 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)
+{
+ 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);
+
+ if (select != current_select || timing != current_timing) {
+ current_select = select;
+ current_timing = timing;
+ if (drive->media != ide_disk || !drive->present)
+ select |= HT_PREFETCH_MODE;
+ (void) HWIF(drive)->INB(HT_CONFIG_PORT);
+ (void) HWIF(drive)->INB(HT_CONFIG_PORT);
+ (void) HWIF(drive)->INB(HT_CONFIG_PORT);
+ (void) HWIF(drive)->INB(HT_CONFIG_PORT);
+ HWIF(drive)->OUTB(select, HT_CONFIG_PORT);
+ /*
+ * Set timing for this drive:
+ */
+ HWIF(drive)->OUTB(timing, IDE_SELECT_REG);
+ (void) HWIF(drive)->INB(IDE_STATUS_REG);
+#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); /* IDE_SELECT_REG */
+ (void) inb(0x1f7); /* IDE_STATUS_REG */
+
+ printk("\nht6560b " HT6560B_VERSION
+ ": chipset detected and initialized"
+#ifdef DEBUG
+ " with debug enabled"
+#endif
+ );
+ return 1;
+}
+
+static u8 ht_pio2timings(ide_drive_t *drive, u8 pio)
+{
+ int active_time, recovery_time;
+ int active_cycles, recovery_cycles;
+ ide_pio_data_t d;
+ int bus_speed = system_bus_clock();
+
+ if (pio) {
+ pio = ide_get_best_pio_mode(drive, pio, 5, &d);
+
+ /*
+ * Just like opti621.c we try to calculate the
+ * actual cycle time for recovery and activity
+ * according system bus speed.
+ */
+ active_time = ide_pio_timings[pio].active_time;
+ recovery_time = d.cycle_time
+ - active_time
+ - ide_pio_timings[pio].setup_time;
+ /*
+ * 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 */
+ }
+}
+
+/*
+ * 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(&ide_lock, flags);
+
+ /*
+ * Prefetch mode and unmask irq seems to conflict
+ */
+ if (state) {
+ drive->drive_data |= t; /* enable prefetch mode */
+ drive->no_unmask = 1;
+ drive->unmask = 0;
+ } else {
+ drive->drive_data &= ~t; /* disable prefetch mode */
+ drive->no_unmask = 0;
+ }
+
+ spin_unlock_irqrestore(&ide_lock, flags);
+
+#ifdef DEBUG
+ printk("ht6560b: drive %s prefetch mode %sabled\n", drive->name, (state ? "en" : "dis"));
+#endif
+}
+
+static void tune_ht6560b (ide_drive_t *drive, 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(&ide_lock, flags);
+
+ drive->drive_data &= 0xff00;
+ drive->drive_data |= timing;
+
+ spin_unlock_irqrestore(&ide_lock, flags);
+
+#ifdef DEBUG
+ printk("ht6560b: drive %s tuned to pio mode %#x timing=%#x\n", drive->name, pio, timing);
+#endif
+}
+
+/* Can be called directly from ide.c. */
+int __init ht6560b_init(void)
+{
+ ide_hwif_t *hwif, *mate;
+ int t;
+
+ hwif = &ide_hwifs[0];
+ mate = &ide_hwifs[1];
+
+ if (!request_region(HT_CONFIG_PORT, 1, hwif->name)) {
+ printk(KERN_NOTICE "%s: HT_CONFIG_PORT not found\n",
+ __FUNCTION__);
+ return -ENODEV;
+ }
+
+ if (!try_to_init_ht6560b()) {
+ printk(KERN_NOTICE "%s: HBA not found\n", __FUNCTION__);
+ goto release_region;
+ }
+
+ hwif->chipset = ide_ht6560b;
+ hwif->selectproc = &ht6560b_selectproc;
+ hwif->tuneproc = &tune_ht6560b;
+ hwif->serialized = 1; /* is this needed? */
+ hwif->mate = mate;
+
+ mate->chipset = ide_ht6560b;
+ mate->selectproc = &ht6560b_selectproc;
+ mate->tuneproc = &tune_ht6560b;
+ mate->serialized = 1; /* is this needed? */
+ mate->mate = hwif;
+ mate->channel = 1;
+
+ /*
+ * Setting default configurations for drives
+ */
+ t = (HT_CONFIG_DEFAULT << 8);
+ t |= HT_TIMING_DEFAULT;
+ hwif->drives[0].drive_data = t;
+ hwif->drives[1].drive_data = t;
+
+ t |= (HT_SECONDARY_IF << 8);
+ mate->drives[0].drive_data = t;
+ mate->drives[1].drive_data = t;
+
+ probe_hwif_init(hwif);
+ probe_hwif_init(mate);
+
+ create_proc_ide_interfaces();
+
+ return 0;
+
+release_region:
+ release_region(HT_CONFIG_PORT, 1);
+ return -ENODEV;
+}
+
+#ifdef MODULE
+module_init(ht6560b_init);
+#endif
+
+MODULE_AUTHOR("See Local File");
+MODULE_DESCRIPTION("HT-6560B EIDE-controller support");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/legacy/ide-cs.c b/drivers/ide/legacy/ide-cs.c
new file mode 100644
index 000000000000..e20327e54b1a
--- /dev/null
+++ b/drivers/ide/legacy/ide-cs.c
@@ -0,0 +1,481 @@
+/*======================================================================
+
+ A driver for PCMCIA IDE/ATA disk cards
+
+ ide-cs.c 1.3 2002/10/26 05:45:31
+
+ 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/sched.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/hdreg.h>
+#include <linux/major.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+#include <pcmcia/version.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>
+
+/*====================================================================*/
+
+/* 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 PCMCIA_DEBUG
+INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG);
+#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
+static char *version =
+"ide-cs.c 1.3 2002/10/26 05:45:31 (David Hinds)";
+#else
+#define DEBUG(n, args...)
+#endif
+
+/*====================================================================*/
+
+static const char ide_major[] = {
+ IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR,
+ IDE4_MAJOR, IDE5_MAJOR
+};
+
+typedef struct ide_info_t {
+ dev_link_t link;
+ int ndev;
+ dev_node_t node;
+ int hd;
+} ide_info_t;
+
+static void ide_release(dev_link_t *);
+static int ide_event(event_t event, int priority,
+ event_callback_args_t *args);
+
+static dev_info_t dev_info = "ide-cs";
+
+static dev_link_t *ide_attach(void);
+static void ide_detach(dev_link_t *);
+
+static dev_link_t *dev_list = NULL;
+
+/*======================================================================
+
+ ide_attach() creates an "instance" of the driver, allocating
+ local data structures for one device. The device is registered
+ with Card Services.
+
+======================================================================*/
+
+static dev_link_t *ide_attach(void)
+{
+ ide_info_t *info;
+ dev_link_t *link;
+ client_reg_t client_reg;
+ int ret;
+
+ DEBUG(0, "ide_attach()\n");
+
+ /* Create new ide device */
+ info = kmalloc(sizeof(*info), GFP_KERNEL);
+ if (!info) return NULL;
+ memset(info, 0, sizeof(*info));
+ link = &info->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_EXCLUSIVE;
+ link->irq.IRQInfo1 = IRQ_LEVEL_ID;
+ link->conf.Attributes = CONF_ENABLE_IRQ;
+ link->conf.Vcc = 50;
+ link->conf.IntType = INT_MEMORY_AND_IO;
+
+ /* Register with Card Services */
+ link->next = dev_list;
+ dev_list = link;
+ client_reg.dev_info = &dev_info;
+ client_reg.EventMask =
+ CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+ CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
+ CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+ client_reg.event_handler = &ide_event;
+ client_reg.Version = 0x0210;
+ client_reg.event_callback_args.client_data = link;
+ ret = pcmcia_register_client(&link->handle, &client_reg);
+ if (ret != CS_SUCCESS) {
+ cs_error(link->handle, RegisterClient, ret);
+ ide_detach(link);
+ return NULL;
+ }
+
+ return 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(dev_link_t *link)
+{
+ dev_link_t **linkp;
+ int ret;
+
+ DEBUG(0, "ide_detach(0x%p)\n", link);
+
+ /* Locate device structure */
+ for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
+ if (*linkp == link) break;
+ if (*linkp == NULL)
+ return;
+
+ if (link->state & DEV_CONFIG)
+ ide_release(link);
+
+ if (link->handle) {
+ ret = pcmcia_deregister_client(link->handle);
+ if (ret != CS_SUCCESS)
+ cs_error(link->handle, DeregisterClient, ret);
+ }
+
+ /* Unlink, free device structure */
+ *linkp = link->next;
+ kfree(link->priv);
+
+} /* ide_detach */
+
+static int idecs_register(unsigned long io, unsigned long ctl, unsigned long irq)
+{
+ hw_regs_t hw;
+ memset(&hw, 0, sizeof(hw));
+ ide_init_hwif_ports(&hw, io, ctl, NULL);
+ hw.irq = irq;
+ hw.chipset = ide_pci;
+ return ide_register_hw_with_fixup(&hw, NULL, ide_undecoded_slave);
+}
+
+/*======================================================================
+
+ 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)
+
+static void ide_config(dev_link_t *link)
+{
+ client_handle_t handle = link->handle;
+ ide_info_t *info = link->priv;
+ tuple_t tuple;
+ struct {
+ u_short buf[128];
+ cisparse_t parse;
+ config_info_t conf;
+ cistpl_cftable_entry_t dflt;
+ } *stk = NULL;
+ cistpl_cftable_entry_t *cfg;
+ int i, pass, last_ret = 0, last_fn = 0, hd, is_kme = 0;
+ unsigned long io_base, ctl_base;
+
+ DEBUG(0, "ide_config(0x%p)\n", link);
+
+ stk = kmalloc(sizeof(*stk), GFP_KERNEL);
+ if (!stk) goto err_mem;
+ memset(stk, 0, sizeof(*stk));
+ cfg = &stk->parse.cftable_entry;
+
+ tuple.TupleData = (cisdata_t *)&stk->buf;
+ tuple.TupleOffset = 0;
+ tuple.TupleDataMax = 255;
+ tuple.Attributes = 0;
+ tuple.DesiredTuple = CISTPL_CONFIG;
+ CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
+ CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
+ CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &stk->parse));
+ link->conf.ConfigBase = stk->parse.config.base;
+ link->conf.Present = stk->parse.config.rmask[0];
+
+ tuple.DesiredTuple = CISTPL_MANFID;
+ if (!pcmcia_get_first_tuple(handle, &tuple) &&
+ !pcmcia_get_tuple_data(handle, &tuple) &&
+ !pcmcia_parse_tuple(handle, &tuple, &stk->parse))
+ is_kme = ((stk->parse.manfid.manf == MANFID_KME) &&
+ ((stk->parse.manfid.card == PRODID_KME_KXLC005_A) ||
+ (stk->parse.manfid.card == PRODID_KME_KXLC005_B)));
+
+ /* Configure card */
+ link->state |= DEV_CONFIG;
+
+ /* Not sure if this is right... look up the current Vcc */
+ CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(handle, &stk->conf));
+ link->conf.Vcc = stk->conf.Vcc;
+
+ pass = io_base = ctl_base = 0;
+ tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+ tuple.Attributes = 0;
+ CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
+ while (1) {
+ if (pcmcia_get_tuple_data(handle, &tuple) != 0) goto next_entry;
+ if (pcmcia_parse_tuple(handle, &tuple, &stk->parse) != 0) goto next_entry;
+
+ /* Check for matching Vcc, unless we're desperate */
+ if (!pass) {
+ if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) {
+ if (stk->conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000)
+ goto next_entry;
+ } else if (stk->dflt.vcc.present & (1 << CISTPL_POWER_VNOM)) {
+ if (stk->conf.Vcc != stk->dflt.vcc.param[CISTPL_POWER_VNOM] / 10000)
+ goto next_entry;
+ }
+ }
+
+ if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM))
+ link->conf.Vpp1 = link->conf.Vpp2 =
+ cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
+ else if (stk->dflt.vpp1.present & (1 << CISTPL_POWER_VNOM))
+ link->conf.Vpp1 = link->conf.Vpp2 =
+ stk->dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000;
+
+ if ((cfg->io.nwin > 0) || (stk->dflt.io.nwin > 0)) {
+ cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &stk->dflt.io;
+ link->conf.ConfigIndex = cfg->index;
+ link->io.BasePort1 = io->win[0].base;
+ link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
+ if (!(io->flags & CISTPL_IO_16BIT))
+ link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+ if (io->nwin == 2) {
+ link->io.NumPorts1 = 8;
+ link->io.BasePort2 = io->win[1].base;
+ link->io.NumPorts2 = (is_kme) ? 2 : 1;
+ if (pcmcia_request_io(link->handle, &link->io) != 0)
+ goto next_entry;
+ io_base = link->io.BasePort1;
+ ctl_base = link->io.BasePort2;
+ } else if ((io->nwin == 1) && (io->win[0].len >= 16)) {
+ link->io.NumPorts1 = io->win[0].len;
+ link->io.NumPorts2 = 0;
+ if (pcmcia_request_io(link->handle, &link->io) != 0)
+ goto next_entry;
+ io_base = link->io.BasePort1;
+ ctl_base = link->io.BasePort1 + 0x0e;
+ } else goto next_entry;
+ /* If we've got this far, we're done */
+ break;
+ }
+
+ next_entry:
+ if (cfg->flags & CISTPL_CFTABLE_DEFAULT)
+ memcpy(&stk->dflt, cfg, sizeof(stk->dflt));
+ if (pass) {
+ CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(handle, &tuple));
+ } else if (pcmcia_get_next_tuple(handle, &tuple) != 0) {
+ CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
+ memset(&stk->dflt, 0, sizeof(stk->dflt));
+ pass++;
+ }
+ }
+
+ CS_CHECK(RequestIRQ, pcmcia_request_irq(handle, &link->irq));
+ CS_CHECK(RequestConfiguration, pcmcia_request_configuration(handle, &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);
+
+ /* retry registration in case device is still spinning up */
+ for (hd = -1, i = 0; i < 10; i++) {
+ hd = idecs_register(io_base, ctl_base, link->irq.AssignedIRQ);
+ if (hd >= 0) break;
+ if (link->io.NumPorts1 == 0x20) {
+ outb(0x02, ctl_base + 0x10);
+ hd = idecs_register(io_base + 0x10, ctl_base + 0x10,
+ link->irq.AssignedIRQ);
+ if (hd >= 0) {
+ io_base += 0x10;
+ ctl_base += 0x10;
+ break;
+ }
+ }
+ __set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(HZ/10);
+ }
+
+ if (hd < 0) {
+ printk(KERN_NOTICE "ide-cs: ide_register() at 0x%3lx & 0x%3lx"
+ ", irq %u failed\n", io_base, ctl_base,
+ link->irq.AssignedIRQ);
+ goto failed;
+ }
+
+ info->ndev = 1;
+ sprintf(info->node.dev_name, "hd%c", 'a' + (hd * 2));
+ info->node.major = ide_major[hd];
+ info->node.minor = 0;
+ info->hd = hd;
+ link->dev = &info->node;
+ printk(KERN_INFO "ide-cs: %s: Vcc = %d.%d, Vpp = %d.%d\n",
+ info->node.dev_name, link->conf.Vcc / 10, link->conf.Vcc % 10,
+ link->conf.Vpp1 / 10, link->conf.Vpp1 % 10);
+
+ link->state &= ~DEV_CONFIG_PENDING;
+ kfree(stk);
+ return;
+
+err_mem:
+ printk(KERN_NOTICE "ide-cs: ide_config failed memory allocation\n");
+ goto failed;
+
+cs_failed:
+ cs_error(link->handle, last_fn, last_ret);
+failed:
+ kfree(stk);
+ ide_release(link);
+ link->state &= ~DEV_CONFIG_PENDING;
+} /* 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.
+
+======================================================================*/
+
+void ide_release(dev_link_t *link)
+{
+ ide_info_t *info = link->priv;
+
+ 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_unregister(info->hd);
+ }
+ info->ndev = 0;
+ link->dev = NULL;
+
+ pcmcia_release_configuration(link->handle);
+ pcmcia_release_io(link->handle, &link->io);
+ pcmcia_release_irq(link->handle, &link->irq);
+
+ link->state &= ~DEV_CONFIG;
+
+} /* 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.
+
+======================================================================*/
+
+int ide_event(event_t event, int priority,
+ event_callback_args_t *args)
+{
+ dev_link_t *link = args->client_data;
+
+ DEBUG(1, "ide_event(0x%06x)\n", event);
+
+ switch (event) {
+ case CS_EVENT_CARD_REMOVAL:
+ link->state &= ~DEV_PRESENT;
+ if (link->state & DEV_CONFIG)
+ ide_release(link);
+ break;
+ case CS_EVENT_CARD_INSERTION:
+ link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+ ide_config(link);
+ break;
+ case CS_EVENT_PM_SUSPEND:
+ link->state |= DEV_SUSPEND;
+ /* Fall through... */
+ case CS_EVENT_RESET_PHYSICAL:
+ if (link->state & DEV_CONFIG)
+ pcmcia_release_configuration(link->handle);
+ break;
+ case CS_EVENT_PM_RESUME:
+ link->state &= ~DEV_SUSPEND;
+ /* Fall through... */
+ case CS_EVENT_CARD_RESET:
+ if (DEV_OK(link))
+ pcmcia_request_configuration(link->handle, &link->conf);
+ break;
+ }
+ return 0;
+} /* ide_event */
+
+static struct pcmcia_driver ide_cs_driver = {
+ .owner = THIS_MODULE,
+ .drv = {
+ .name = "ide-cs",
+ },
+ .attach = ide_attach,
+ .detach = ide_detach,
+};
+
+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);
+ BUG_ON(dev_list != NULL);
+}
+
+module_init(init_ide_cs);
+module_exit(exit_ide_cs);
diff --git a/drivers/ide/legacy/macide.c b/drivers/ide/legacy/macide.c
new file mode 100644
index 000000000000..90cac609d9cf
--- /dev/null
+++ b/drivers/ide/legacy/macide.c
@@ -0,0 +1,155 @@
+/*
+ * linux/drivers/ide/legacy/macide.c -- 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/config.h>
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.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_DATA 0x00
+#define IDE_ERROR 0x04 /* see err-bits */
+#define IDE_NSECTOR 0x08 /* nr of sectors to read/write */
+#define IDE_SECTOR 0x0c /* starting sector */
+#define IDE_LCYL 0x10 /* starting cylinder */
+#define IDE_HCYL 0x14 /* high byte of starting cyl */
+#define IDE_SELECT 0x18 /* 101dhhhh , d=drive, hhhh=head */
+#define IDE_STATUS 0x1c /* see status-bits */
+#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);
+
+static int macide_offsets[IDE_NR_PORTS] = {
+ IDE_DATA, IDE_ERROR, IDE_NSECTOR, IDE_SECTOR, IDE_LCYL,
+ IDE_HCYL, IDE_SELECT, IDE_STATUS, IDE_CONTROL
+};
+
+int macide_ack_intr(ide_hwif_t* hwif)
+{
+ if (*ide_ifr & 0x20) {
+ *ide_ifr &= ~0x20;
+ return 1;
+ }
+ return 0;
+}
+
+#ifdef CONFIG_BLK_DEV_MAC_MEDIABAY
+static void macide_mediabay_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ int state = baboon->mb_status & 0x04;
+
+ printk(KERN_INFO "macide: media bay %s detected\n", state? "removal":"insertion");
+}
+#endif
+
+/*
+ * Probe for a Macintosh IDE interface
+ */
+
+void macide_init(void)
+{
+ hw_regs_t hw;
+ ide_hwif_t *hwif;
+ int index = -1;
+
+ switch (macintosh_config->ide_type) {
+ case MAC_IDE_QUADRA:
+ ide_setup_ports(&hw, IDE_BASE, macide_offsets,
+ 0, 0, macide_ack_intr,
+// quadra_ide_iops,
+ IRQ_NUBUS_F);
+ index = ide_register_hw(&hw, &hwif);
+ break;
+ case MAC_IDE_PB:
+ ide_setup_ports(&hw, IDE_BASE, macide_offsets,
+ 0, 0, macide_ack_intr,
+// macide_pb_iops,
+ IRQ_NUBUS_C);
+ index = ide_register_hw(&hw, &hwif);
+ break;
+ case MAC_IDE_BABOON:
+ ide_setup_ports(&hw, BABOON_BASE, macide_offsets,
+ 0, 0, NULL,
+// macide_baboon_iops,
+ IRQ_BABOON_1);
+ index = ide_register_hw(&hw, &hwif);
+ if (index == -1) break;
+ if (macintosh_config->ident == MAC_MODEL_PB190) {
+
+ /* Fix breakage in ide-disk.c: drive capacity */
+ /* is not initialized for drives without a */
+ /* hardware ID, and we can't get that without */
+ /* probing the drive which freezes a 190. */
+
+ ide_drive_t *drive = &ide_hwifs[index].drives[0];
+ drive->capacity64 = drive->cyl*drive->head*drive->sect;
+
+#ifdef CONFIG_BLK_DEV_MAC_MEDIABAY
+ request_irq(IRQ_BABOON_2, macide_mediabay_interrupt,
+ IRQ_FLG_FAST, "mediabay",
+ macide_mediabay_interrupt);
+#endif
+ }
+ break;
+
+ default:
+ return;
+ }
+
+ if (index != -1) {
+ hwif->mmio = 2;
+ if (macintosh_config->ide_type == MAC_IDE_QUADRA)
+ printk(KERN_INFO "ide%d: Macintosh Quadra IDE interface\n", index);
+ else if (macintosh_config->ide_type == MAC_IDE_PB)
+ printk(KERN_INFO "ide%d: Macintosh Powerbook IDE interface\n", index);
+ else if (macintosh_config->ide_type == MAC_IDE_BABOON)
+ printk(KERN_INFO "ide%d: Macintosh Powerbook Baboon IDE interface\n", index);
+ else
+ printk(KERN_INFO "ide%d: Unknown Macintosh IDE interface\n", index);
+ }
+}
diff --git a/drivers/ide/legacy/q40ide.c b/drivers/ide/legacy/q40ide.c
new file mode 100644
index 000000000000..2a78b792f7fb
--- /dev/null
+++ b/drivers/ide/legacy/q40ide.c
@@ -0,0 +1,150 @@
+/*
+ * linux/drivers/ide/legacy/q40ide.c -- 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/hdreg.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 */
+};
+
+
+ /*
+ * Offsets from one of the above bases
+ */
+
+/* used to do addr translation here but it is easier to do in setup ports */
+/*#define IDE_OFF_B(x) ((unsigned long)Q40_ISA_IO_B((IDE_##x##_OFFSET)))*/
+
+#define IDE_OFF_B(x) ((unsigned long)((IDE_##x##_OFFSET)))
+#define IDE_OFF_W(x) ((unsigned long)((IDE_##x##_OFFSET)))
+
+static const int pcide_offsets[IDE_NR_PORTS] = {
+ IDE_OFF_W(DATA), IDE_OFF_B(ERROR), IDE_OFF_B(NSECTOR), IDE_OFF_B(SECTOR),
+ IDE_OFF_B(LCYL), IDE_OFF_B(HCYL), 6 /*IDE_OFF_B(CURRENT)*/, IDE_OFF_B(STATUS),
+ 518/*IDE_OFF(CMD)*/
+};
+
+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;
+ }
+}
+
+
+/*
+ * This is very similar to ide_setup_ports except that addresses
+ * are pretranslated for q40 ISA access
+ */
+void q40_ide_setup_ports ( hw_regs_t *hw,
+ unsigned long base, int *offsets,
+ unsigned long ctrl, unsigned long intr,
+ ide_ack_intr_t *ack_intr,
+/*
+ * ide_io_ops_t *iops,
+ */
+ int irq)
+{
+ int i;
+
+ for (i = 0; i < IDE_NR_PORTS; i++) {
+ /* BIG FAT WARNING:
+ assumption: only DATA port is ever used in 16 bit mode */
+ if ( i==0 )
+ hw->io_ports[i] = Q40_ISA_IO_W(base + offsets[i]);
+ else
+ hw->io_ports[i] = Q40_ISA_IO_B(base + offsets[i]);
+ }
+
+ hw->irq = irq;
+ hw->dma = NO_DMA;
+ hw->ack_intr = ack_intr;
+/*
+ * hw->iops = iops;
+ */
+}
+
+
+
+/*
+ * 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
+ */
+
+void q40ide_init(void)
+{
+ int i;
+ ide_hwif_t *hwif;
+ int index;
+ const char *name;
+
+ if (!MACH_IS_Q40)
+ return ;
+
+ for (i = 0; i < Q40IDE_NUM_HWIFS; i++) {
+ hw_regs_t hw;
+
+ 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,(unsigned long) pcide_bases[i], (int *)pcide_offsets,
+ pcide_bases[i]+0x206,
+ 0, NULL,
+// m68kide_iops,
+ q40ide_default_irq(pcide_bases[i]));
+ index = ide_register_hw(&hw, &hwif);
+ // **FIXME**
+ if (index != -1)
+ hwif->mmio = 2;
+ }
+}
+
diff --git a/drivers/ide/legacy/qd65xx.c b/drivers/ide/legacy/qd65xx.c
new file mode 100644
index 000000000000..563fab0098be
--- /dev/null
+++ b/drivers/ide/legacy/qd65xx.c
@@ -0,0 +1,511 @@
+/*
+ * linux/drivers/ide/legacy/qd65xx.c Version 0.07 Sep 30, 2001
+ *
+ * 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
+ *
+ * Please set local bus speed using kernel parameter idebus
+ * for example, "idebus=33" stands for 33Mhz VLbus
+ * To activate controller support, use "ide0=qd65xx"
+ * To enable tuning, use "ide0=autotune"
+ * To enable second channel tuning (qd6580 only), use "ide1=autotune"
+ */
+
+/*
+ * Rewritten from the work of Colten Edwards <pje120@cs.usask.ca> by
+ * Samuel Thibault <samuel.thibault@fnac.net>
+ */
+
+#undef REALLY_SLOW_IO /* most systems can safely undef this */
+
+#include <linux/module.h>
+#include <linux/config.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/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+#include <asm/system.h>
+#include <asm/io.h>
+
+#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 */
+
+static void qd_write_reg (u8 content, unsigned long reg)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ide_lock, flags);
+ outb(content,reg);
+ spin_unlock_irqrestore(&ide_lock, flags);
+}
+
+static u8 __init qd_read_reg (unsigned long reg)
+{
+ unsigned long flags;
+ u8 read;
+
+ spin_lock_irqsave(&ide_lock, flags);
+ read = inb(reg);
+ spin_unlock_irqrestore(&ide_lock, flags);
+ return read;
+}
+
+/*
+ * qd_select:
+ *
+ * This routine is invoked from ide.c to prepare for access to a given drive.
+ */
+
+static void qd_select (ide_drive_t *drive)
+{
+ u8 index = (( (QD_TIMREG(drive)) & 0x80 ) >> 7) |
+ (QD_TIMREG(drive) & 0x02);
+
+ if (timings[index] != QD_TIMING(drive))
+ qd_write_reg(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)
+{
+ u8 active_cycle,recovery_cycle;
+
+ if (system_bus_clock()<=33) {
+ active_cycle = 9 - IDE_IN(active_time * system_bus_clock() / 1000 + 1, 2, 9);
+ recovery_cycle = 15 - IDE_IN(recovery_time * system_bus_clock() / 1000 + 1, 0, 15);
+ } else {
+ active_cycle = 8 - IDE_IN(active_time * system_bus_clock() / 1000 + 1, 1, 8);
+ recovery_cycle = 18 - IDE_IN(recovery_time * system_bus_clock() / 1000 + 1, 3, 18);
+ }
+
+ return((recovery_cycle<<4) | 0x08 | active_cycle);
+}
+
+/*
+ * qd6580_compute_timing
+ *
+ * idem for qd6580
+ */
+
+static u8 qd6580_compute_timing (int active_time, int recovery_time)
+{
+ u8 active_cycle = 17 - IDE_IN(active_time * system_bus_clock() / 1000 + 1, 2, 17);
+ u8 recovery_cycle = 15 - IDE_IN(recovery_time * system_bus_clock() / 1000 + 1, 2, 15);
+
+ return((recovery_cycle<<4) | active_cycle);
+}
+
+/*
+ * 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 model[40];
+
+ if (!*drive->id->model) return 0;
+
+ strncpy(model,drive->id->model,40);
+ ide_fixstring(model,40,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_timing_ok:
+ *
+ * check whether timings don't conflict
+ */
+
+static int qd_timing_ok (ide_drive_t drives[])
+{
+ return (IDE_IMPLY(drives[0].present && drives[1].present,
+ IDE_IMPLY(QD_TIMREG(drives) == QD_TIMREG(drives+1),
+ QD_TIMING(drives) == QD_TIMING(drives+1))));
+ /* if same timing register, must be same timing */
+}
+
+/*
+ * qd_set_timing:
+ *
+ * records the timing, and enables selectproc as needed
+ */
+
+static void qd_set_timing (ide_drive_t *drive, u8 timing)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+
+ drive->drive_data &= 0xff00;
+ drive->drive_data |= timing;
+ if (qd_timing_ok(hwif->drives)) {
+ qd_select(drive); /* selects once */
+ hwif->selectproc = NULL;
+ } else
+ hwif->selectproc = &qd_select;
+
+ printk(KERN_DEBUG "%s: %#x\n", drive->name, timing);
+}
+
+/*
+ * qd6500_tune_drive
+ */
+
+static void qd6500_tune_drive (ide_drive_t *drive, u8 pio)
+{
+ int active_time = 175;
+ int recovery_time = 415; /* worst case values from the dos driver */
+
+ if (drive->id && !qd_find_disk_type(drive, &active_time, &recovery_time)
+ && drive->id->tPIO && (drive->id->field_valid & 0x02)
+ && drive->id->eide_pio >= 240) {
+
+ printk(KERN_INFO "%s: PIO mode%d\n", drive->name,
+ drive->id->tPIO);
+ active_time = 110;
+ recovery_time = drive->id->eide_pio - 120;
+ }
+
+ qd_set_timing(drive, qd6500_compute_timing(HWIF(drive), active_time, recovery_time));
+}
+
+/*
+ * qd6580_tune_drive
+ */
+
+static void qd6580_tune_drive (ide_drive_t *drive, u8 pio)
+{
+ ide_pio_data_t d;
+ int base = HWIF(drive)->select_data;
+ int active_time = 175;
+ int recovery_time = 415; /* worst case values from the dos driver */
+
+ if (drive->id && !qd_find_disk_type(drive, &active_time, &recovery_time)) {
+ pio = ide_get_best_pio_mode(drive, pio, 255, &d);
+ pio = min_t(u8, pio, 4);
+
+ switch (pio) {
+ case 0: break;
+ case 3:
+ if (d.cycle_time >= 110) {
+ active_time = 86;
+ recovery_time = d.cycle_time - 102;
+ } else
+ printk(KERN_WARNING "%s: Strange recovery time !\n",drive->name);
+ break;
+ case 4:
+ if (d.cycle_time >= 69) {
+ active_time = 70;
+ recovery_time = d.cycle_time - 61;
+ } else
+ printk(KERN_WARNING "%s: Strange recovery time !\n",drive->name);
+ break;
+ default:
+ if (d.cycle_time >= 180) {
+ active_time = 110;
+ recovery_time = d.cycle_time - 120;
+ } else {
+ active_time = ide_pio_timings[pio].active_time;
+ recovery_time = d.cycle_time
+ -active_time;
+ }
+ }
+ printk(KERN_INFO "%s: PIO mode%d\n", drive->name,pio);
+ }
+
+ if (!HWIF(drive)->channel && drive->media != ide_disk) {
+ qd_write_reg(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)
+{
+ u8 savereg;
+ u8 readreg;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ide_lock, flags);
+ savereg = inb_p(port);
+ outb_p(QD_TESTVAL, port); /* safe value */
+ readreg = inb_p(port);
+ outb(savereg, port);
+ spin_unlock_irqrestore(&ide_lock, 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);
+}
+
+/*
+ * qd_setup:
+ *
+ * called to setup an ata channel : adjusts attributes & links for tuning
+ */
+
+static void __init qd_setup(ide_hwif_t *hwif, int base, int config,
+ unsigned int data0, unsigned int data1,
+ void (*tuneproc) (ide_drive_t *, u8 pio))
+{
+ hwif->chipset = ide_qd65xx;
+ hwif->channel = hwif->index;
+ hwif->select_data = base;
+ hwif->config_data = config;
+ hwif->drives[0].drive_data = data0;
+ hwif->drives[1].drive_data = data1;
+ hwif->drives[0].io_32bit =
+ hwif->drives[1].io_32bit = 1;
+ hwif->tuneproc = tuneproc;
+ probe_hwif_init(hwif);
+}
+
+/*
+ * qd_unsetup:
+ *
+ * called to unsetup an ata channel : back to default values, unlinks tuning
+ */
+/*
+static void __exit qd_unsetup(ide_hwif_t *hwif)
+{
+ u8 config = hwif->config_data;
+ int base = hwif->select_data;
+ void *tuneproc = (void *) hwif->tuneproc;
+
+ if (hwif->chipset != ide_qd65xx)
+ return;
+
+ printk(KERN_NOTICE "%s: back to defaults\n", hwif->name);
+
+ hwif->selectproc = NULL;
+ hwif->tuneproc = NULL;
+
+ if (tuneproc == (void *) qd6500_tune_drive) {
+ // will do it for both
+ qd_write_reg(QD6500_DEF_DATA, QD_TIMREG(&hwif->drives[0]));
+ } else if (tuneproc == (void *) qd6580_tune_drive) {
+ if (QD_CONTROL(hwif) & QD_CONTR_SEC_DISABLED) {
+ qd_write_reg(QD6580_DEF_DATA, QD_TIMREG(&hwif->drives[0]));
+ qd_write_reg(QD6580_DEF_DATA2, QD_TIMREG(&hwif->drives[1]));
+ } else {
+ qd_write_reg(hwif->channel ? QD6580_DEF_DATA2 : QD6580_DEF_DATA, QD_TIMREG(&hwif->drives[0]));
+ }
+ } else {
+ printk(KERN_WARNING "Unknown qd65xx tuning fonction !\n");
+ printk(KERN_WARNING "keeping settings !\n");
+ }
+}
+*/
+
+/*
+ * 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)
+{
+ ide_hwif_t *hwif;
+ u8 config;
+ u8 unit;
+
+ config = qd_read_reg(QD_CONFIG_PORT);
+
+ if (! ((config & QD_CONFIG_BASEPORT) >> 1 == (base == 0xb0)) )
+ return 1;
+
+ unit = ! (config & QD_CONFIG_IDE_BASEPORT);
+
+ if ((config & 0xf0) == QD_CONFIG_QD6500) {
+
+ if (qd_testreg(base)) return 1; /* bad register */
+
+ /* qd6500 found */
+
+ hwif = &ide_hwifs[unit];
+ printk(KERN_NOTICE "%s: qd6500 at %#x\n", hwif->name, base);
+ printk(KERN_DEBUG "qd6500: config=%#x, ID3=%u\n",
+ config, QD_ID3);
+
+ if (config & QD_CONFIG_DISABLED) {
+ printk(KERN_WARNING "qd6500 is disabled !\n");
+ return 1;
+ }
+
+ qd_setup(hwif, base, config, QD6500_DEF_DATA, QD6500_DEF_DATA,
+ &qd6500_tune_drive);
+
+ create_proc_ide_interfaces();
+
+ return 1;
+ }
+
+ if (((config & 0xf0) == QD_CONFIG_QD6580_A) ||
+ ((config & 0xf0) == QD_CONFIG_QD6580_B)) {
+
+ u8 control;
+
+ if (qd_testreg(base) || qd_testreg(base+0x02)) return 1;
+ /* bad registers */
+
+ /* qd6580 found */
+
+ control = qd_read_reg(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);
+
+ if (control & QD_CONTR_SEC_DISABLED) {
+ /* secondary disabled */
+
+ hwif = &ide_hwifs[unit];
+ printk(KERN_INFO "%s: qd6580: single IDE board\n",
+ hwif->name);
+ qd_setup(hwif, base, config | (control << 8),
+ QD6580_DEF_DATA, QD6580_DEF_DATA2,
+ &qd6580_tune_drive);
+ qd_write_reg(QD_DEF_CONTR,QD_CONTROL_PORT);
+
+ create_proc_ide_interfaces();
+
+ return 1;
+ } else {
+ ide_hwif_t *mate;
+
+ hwif = &ide_hwifs[0];
+ mate = &ide_hwifs[1];
+ /* secondary enabled */
+ printk(KERN_INFO "%s&%s: qd6580: dual IDE board\n",
+ hwif->name, mate->name);
+
+ qd_setup(hwif, base, config | (control << 8),
+ QD6580_DEF_DATA, QD6580_DEF_DATA,
+ &qd6580_tune_drive);
+ qd_setup(mate, base, config | (control << 8),
+ QD6580_DEF_DATA2, QD6580_DEF_DATA2,
+ &qd6580_tune_drive);
+ qd_write_reg(QD_DEF_CONTR,QD_CONTROL_PORT);
+
+ create_proc_ide_interfaces();
+
+ return 0; /* no other qd65xx possible */
+ }
+ }
+ /* no qd65xx found */
+ return 1;
+}
+
+/* Can be called directly from ide.c. */
+int __init qd65xx_init(void)
+{
+ if (qd_probe(0x30))
+ qd_probe(0xb0);
+ if (ide_hwifs[0].chipset != ide_qd65xx &&
+ ide_hwifs[1].chipset != ide_qd65xx)
+ return -ENODEV;
+ return 0;
+}
+
+#ifdef MODULE
+module_init(qd65xx_init);
+#endif
+
+MODULE_AUTHOR("Samuel Thibault");
+MODULE_DESCRIPTION("support of qd65xx vlb ide chipset");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/legacy/qd65xx.h b/drivers/ide/legacy/qd65xx.h
new file mode 100644
index 000000000000..633a42456ef6
--- /dev/null
+++ b/drivers/ide/legacy/qd65xx.h
@@ -0,0 +1,140 @@
+/*
+ * linux/drivers/ide/legacy/qd65xx.h
+ *
+ * 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_CONTROL(hwif) (((hwif)->config_data & 0xff00) >> 8)
+
+#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/legacy/umc8672.c b/drivers/ide/legacy/umc8672.c
new file mode 100644
index 000000000000..cdbdb2ff9f15
--- /dev/null
+++ b/drivers/ide/legacy/umc8672.c
@@ -0,0 +1,183 @@
+/*
+ * linux/drivers/ide/legacy/umc8672.c Version 0.05 Jul 31, 1996
+ *
+ * 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/config.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/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+/*
+ * 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] = {
+ {0xf, 0xb, 0x2, 0x2, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 },
+ {0x3, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 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 tune_umc (ide_drive_t *drive, u8 pio)
+{
+ unsigned long flags;
+ ide_hwgroup_t *hwgroup = ide_hwifs[HWIF(drive)->index^1].hwgroup;
+
+ pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+ 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 (hwgroup && hwgroup->handler != NULL) {
+ 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 int __init umc8672_probe(void)
+{
+ unsigned long flags;
+ ide_hwif_t *hwif, *mate;
+
+ 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);
+
+ hwif = &ide_hwifs[0];
+ mate = &ide_hwifs[1];
+
+ hwif->chipset = ide_umc8672;
+ hwif->tuneproc = &tune_umc;
+ hwif->mate = mate;
+
+ mate->chipset = ide_umc8672;
+ mate->tuneproc = &tune_umc;
+ mate->mate = hwif;
+ mate->channel = 1;
+
+ probe_hwif_init(hwif);
+ probe_hwif_init(mate);
+
+ create_proc_ide_interfaces();
+
+ return 0;
+}
+
+/* Can be called directly from ide.c. */
+int __init umc8672_init(void)
+{
+ if (umc8672_probe())
+ return -ENODEV;
+ return 0;
+}
+
+#ifdef MODULE
+module_init(umc8672_init);
+#endif
+
+MODULE_AUTHOR("Wolfram Podien");
+MODULE_DESCRIPTION("Support for UMC 8672 IDE chipset");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/pci/Makefile b/drivers/ide/pci/Makefile
new file mode 100644
index 000000000000..55e6e553e497
--- /dev/null
+++ b/drivers/ide/pci/Makefile
@@ -0,0 +1,34 @@
+
+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_CMD64X) += cmd64x.o
+obj-$(CONFIG_BLK_DEV_CS5520) += cs5520.o
+obj-$(CONFIG_BLK_DEV_CS5530) += cs5530.o
+obj-$(CONFIG_BLK_DEV_SC1200) += sc1200.o
+obj-$(CONFIG_BLK_DEV_CY82C693) += cy82c693.o
+obj-$(CONFIG_BLK_DEV_HPT34X) += hpt34x.o
+obj-$(CONFIG_BLK_DEV_HPT366) += hpt366.o
+#obj-$(CONFIG_BLK_DEV_HPT37X) += hpt37x.o
+obj-$(CONFIG_BLK_DEV_IT8172) += it8172.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_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) += generic.o
+
+EXTRA_CFLAGS := -Idrivers/ide
diff --git a/drivers/ide/pci/aec62xx.c b/drivers/ide/pci/aec62xx.c
new file mode 100644
index 000000000000..52cadc005d72
--- /dev/null
+++ b/drivers/ide/pci/aec62xx.c
@@ -0,0 +1,485 @@
+/*
+ * linux/drivers/ide/pci/aec62xx.c Version 0.11 March 27, 2002
+ *
+ * Copyright (C) 1999-2002 Andre Hedrick <andre@linux-ide.org>
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+struct chipset_bus_clock_list_entry {
+ u8 xfer_speed;
+ u8 chipset_settings;
+ u8 ultra_settings;
+};
+
+static 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 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 }
+};
+
+#define BUSCLOCK(D) \
+ ((struct chipset_bus_clock_list_entry *) pci_get_drvdata((D)))
+
+#if 0
+ if (dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) {
+ (void) pci_read_config_byte(dev, 0x54, &art);
+ p += sprintf(p, "DMA Mode: %s(%s)",
+ (c0&0x20)?((art&0x03)?"UDMA":" DMA"):" PIO",
+ (art&0x02)?"2":(art&0x01)?"1":"0");
+ p += sprintf(p, " %s(%s)",
+ (c0&0x40)?((art&0x0c)?"UDMA":" DMA"):" PIO",
+ (art&0x08)?"2":(art&0x04)?"1":"0");
+ p += sprintf(p, " %s(%s)",
+ (c1&0x20)?((art&0x30)?"UDMA":" DMA"):" PIO",
+ (art&0x20)?"2":(art&0x10)?"1":"0");
+ p += sprintf(p, " %s(%s)\n",
+ (c1&0x40)?((art&0xc0)?"UDMA":" DMA"):" PIO",
+ (art&0x80)?"2":(art&0x40)?"1":"0");
+ } else {
+#endif
+
+/*
+ * 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 u8 aec62xx_ratemask (ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ u8 mode;
+
+ switch(hwif->pci_dev->device) {
+ case PCI_DEVICE_ID_ARTOP_ATP865:
+ case PCI_DEVICE_ID_ARTOP_ATP865R:
+#if 0
+ mode = (hwif->INB(hwif->dma_master) & 0x10) ? 4 : 3;
+#else
+ mode = (hwif->INB(((hwif->channel) ?
+ hwif->mate->dma_status :
+ hwif->dma_status)) & 0x10) ? 4 : 3;
+#endif
+ break;
+ case PCI_DEVICE_ID_ARTOP_ATP860:
+ case PCI_DEVICE_ID_ARTOP_ATP860R:
+ mode = 2;
+ break;
+ case PCI_DEVICE_ID_ARTOP_ATP850UF:
+ default:
+ return 1;
+ }
+
+ if (!eighty_ninty_three(drive))
+ mode = min(mode, (u8)1);
+ return mode;
+}
+
+static int aec6210_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = hwif->pci_dev;
+ u16 d_conf = 0;
+ u8 speed = ide_rate_filter(aec62xx_ratemask(drive), xferspeed);
+ 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, BUSCLOCK(dev));
+ 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, BUSCLOCK(dev));
+ tmp2 = ((ultra_conf << (2*drive->dn)) | (tmp1 & ~(3 << (2*drive->dn))));
+ pci_write_config_byte(dev, 0x54, tmp2);
+ local_irq_restore(flags);
+ return(ide_config_drive_speed(drive, speed));
+}
+
+static int aec6260_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = hwif->pci_dev;
+ u8 speed = ide_rate_filter(aec62xx_ratemask(drive), xferspeed);
+ u8 unit = (drive->select.b.unit & 0x01);
+ 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, BUSCLOCK(dev));
+ 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, BUSCLOCK(dev));
+ tmp2 = ((ultra_conf << (4*unit)) | (tmp1 & ~(7 << (4*unit))));
+ pci_write_config_byte(dev, (0x44|hwif->channel), tmp2);
+ local_irq_restore(flags);
+ return(ide_config_drive_speed(drive, speed));
+}
+
+static int aec62xx_tune_chipset (ide_drive_t *drive, u8 speed)
+{
+ switch (HWIF(drive)->pci_dev->device) {
+ case PCI_DEVICE_ID_ARTOP_ATP865:
+ case PCI_DEVICE_ID_ARTOP_ATP865R:
+ case PCI_DEVICE_ID_ARTOP_ATP860:
+ case PCI_DEVICE_ID_ARTOP_ATP860R:
+ return ((int) aec6260_tune_chipset(drive, speed));
+ case PCI_DEVICE_ID_ARTOP_ATP850UF:
+ return ((int) aec6210_tune_chipset(drive, speed));
+ default:
+ return -1;
+ }
+}
+
+static int config_chipset_for_dma (ide_drive_t *drive)
+{
+ u8 speed = ide_dma_speed(drive, aec62xx_ratemask(drive));
+
+ if (!(speed))
+ return 0;
+
+ (void) aec62xx_tune_chipset(drive, speed);
+ return ide_dma_enable(drive);
+}
+
+static void aec62xx_tune_drive (ide_drive_t *drive, u8 pio)
+{
+ u8 speed = 0;
+ u8 new_pio = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL);
+
+ switch(pio) {
+ case 5: speed = new_pio; break;
+ case 4: speed = XFER_PIO_4; break;
+ case 3: speed = XFER_PIO_3; break;
+ case 2: speed = XFER_PIO_2; break;
+ case 1: speed = XFER_PIO_1; break;
+ default: speed = XFER_PIO_0; break;
+ }
+ (void) aec62xx_tune_chipset(drive, speed);
+}
+
+static int aec62xx_config_drive_xfer_rate (ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct hd_driveid *id = drive->id;
+
+ if ((id->capability & 1) && drive->autodma) {
+
+ if (ide_use_dma(drive)) {
+ if (config_chipset_for_dma(drive))
+ return hwif->ide_dma_on(drive);
+ }
+
+ goto fast_ata_pio;
+
+ } else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+ aec62xx_tune_drive(drive, 5);
+ return hwif->ide_dma_off_quietly(drive);
+ }
+ /* IORDY not supported */
+ return 0;
+}
+
+static int aec62xx_irq_timeout (ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = hwif->pci_dev;
+
+ switch(dev->device) {
+ case PCI_DEVICE_ID_ARTOP_ATP860:
+ case PCI_DEVICE_ID_ARTOP_ATP860R:
+ case PCI_DEVICE_ID_ARTOP_ATP865:
+ case PCI_DEVICE_ID_ARTOP_ATP865R:
+ printk(" AEC62XX time out ");
+#if 0
+ {
+ int i = 0;
+ u8 reg49h = 0;
+ pci_read_config_byte(HWIF(drive)->pci_dev, 0x49, &reg49h);
+ for (i=0;i<256;i++)
+ pci_write_config_byte(HWIF(drive)->pci_dev, 0x49, reg49h|0x10);
+ pci_write_config_byte(HWIF(drive)->pci_dev, 0x49, reg49h & ~0x10);
+ }
+ return 0;
+#endif
+ default:
+ break;
+ }
+#if 0
+ {
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = hwif->pci_dev;
+ u8 tmp1 = 0, tmp2 = 0, mode6 = 0;
+
+ pci_read_config_byte(dev, 0x44, &tmp1);
+ pci_read_config_byte(dev, 0x45, &tmp2);
+ printk(" AEC6280 r44=%x r45=%x ",tmp1,tmp2);
+ mode6 = HWIF(drive)->INB(((hwif->channel) ?
+ hwif->mate->dma_status :
+ hwif->dma_status));
+ printk(" AEC6280 133=%x ", (mode6 & 0x10));
+ }
+#endif
+ return 0;
+}
+
+static unsigned int __devinit init_chipset_aec62xx(struct pci_dev *dev, const char *name)
+{
+ int bus_speed = system_bus_clock();
+
+ if (dev->resource[PCI_ROM_RESOURCE].start) {
+ pci_write_config_dword(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
+ printk(KERN_INFO "%s: ROM enabled at 0x%08lx\n", name, dev->resource[PCI_ROM_RESOURCE].start);
+ }
+
+ if (bus_speed <= 33)
+ pci_set_drvdata(dev, (void *) aec6xxx_33_base);
+ else
+ pci_set_drvdata(dev, (void *) aec6xxx_34_base);
+
+ return dev->irq;
+}
+
+static void __devinit init_hwif_aec62xx(ide_hwif_t *hwif)
+{
+ hwif->autodma = 0;
+ hwif->tuneproc = &aec62xx_tune_drive;
+ hwif->speedproc = &aec62xx_tune_chipset;
+
+ if (hwif->pci_dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) {
+ hwif->serialized = hwif->channel;
+ hwif->no_dsc = 1;
+ }
+
+ if (hwif->mate)
+ hwif->mate->serialized = hwif->serialized;
+
+ if (!hwif->dma_base) {
+ hwif->drives[0].autotune = 1;
+ hwif->drives[1].autotune = 1;
+ return;
+ }
+
+ hwif->ultra_mask = 0x7f;
+ hwif->mwdma_mask = 0x07;
+ hwif->swdma_mask = 0x07;
+
+ hwif->ide_dma_check = &aec62xx_config_drive_xfer_rate;
+ hwif->ide_dma_lostirq = &aec62xx_irq_timeout;
+ hwif->ide_dma_timeout = &aec62xx_irq_timeout;
+ if (!noautodma)
+ hwif->autodma = 1;
+ hwif->drives[0].autodma = hwif->autodma;
+ hwif->drives[1].autodma = hwif->autodma;
+}
+
+static void __devinit init_dma_aec62xx(ide_hwif_t *hwif, unsigned long dmabase)
+{
+ struct pci_dev *dev = hwif->pci_dev;
+
+ if (dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) {
+ u8 reg54h = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ide_lock, flags);
+ pci_read_config_byte(dev, 0x54, &reg54h);
+ pci_write_config_byte(dev, 0x54, reg54h & ~(hwif->channel ? 0xF0 : 0x0F));
+ spin_unlock_irqrestore(&ide_lock, flags);
+ } else {
+ u8 ata66 = 0;
+ pci_read_config_byte(hwif->pci_dev, 0x49, &ata66);
+ if (!(hwif->udma_four))
+ hwif->udma_four = (ata66&(hwif->channel?0x02:0x01))?0:1;
+ }
+
+ ide_setup_dma(hwif, dmabase, 8);
+}
+
+static int __devinit init_setup_aec62xx(struct pci_dev *dev, ide_pci_device_t *d)
+{
+ return ide_setup_pci_device(dev, d);
+}
+
+static int __devinit init_setup_aec6x80(struct pci_dev *dev, ide_pci_device_t *d)
+{
+ unsigned long bar4reg = pci_resource_start(dev, 4);
+
+ if (inb(bar4reg+2) & 0x10) {
+ strcpy(d->name, "AEC6880");
+ if (dev->device == PCI_DEVICE_ID_ARTOP_ATP865R)
+ strcpy(d->name, "AEC6880R");
+ } else {
+ strcpy(d->name, "AEC6280");
+ if (dev->device == PCI_DEVICE_ID_ARTOP_ATP865R)
+ strcpy(d->name, "AEC6280R");
+ }
+
+ return ide_setup_pci_device(dev, d);
+}
+
+static ide_pci_device_t aec62xx_chipsets[] __devinitdata = {
+ { /* 0 */
+ .name = "AEC6210",
+ .init_setup = init_setup_aec62xx,
+ .init_chipset = init_chipset_aec62xx,
+ .init_hwif = init_hwif_aec62xx,
+ .init_dma = init_dma_aec62xx,
+ .channels = 2,
+ .autodma = AUTODMA,
+ .enablebits = {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
+ .bootable = OFF_BOARD,
+ },{ /* 1 */
+ .name = "AEC6260",
+ .init_setup = init_setup_aec62xx,
+ .init_chipset = init_chipset_aec62xx,
+ .init_hwif = init_hwif_aec62xx,
+ .init_dma = init_dma_aec62xx,
+ .channels = 2,
+ .autodma = NOAUTODMA,
+ .bootable = OFF_BOARD,
+ },{ /* 2 */
+ .name = "AEC6260R",
+ .init_setup = init_setup_aec62xx,
+ .init_chipset = init_chipset_aec62xx,
+ .init_hwif = init_hwif_aec62xx,
+ .init_dma = init_dma_aec62xx,
+ .channels = 2,
+ .autodma = AUTODMA,
+ .enablebits = {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
+ .bootable = NEVER_BOARD,
+ },{ /* 3 */
+ .name = "AEC6X80",
+ .init_setup = init_setup_aec6x80,
+ .init_chipset = init_chipset_aec62xx,
+ .init_hwif = init_hwif_aec62xx,
+ .init_dma = init_dma_aec62xx,
+ .channels = 2,
+ .autodma = AUTODMA,
+ .bootable = OFF_BOARD,
+ },{ /* 4 */
+ .name = "AEC6X80R",
+ .init_setup = init_setup_aec6x80,
+ .init_chipset = init_chipset_aec62xx,
+ .init_hwif = init_hwif_aec62xx,
+ .init_dma = init_dma_aec62xx,
+ .channels = 2,
+ .autodma = AUTODMA,
+ .enablebits = {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
+ .bootable = OFF_BOARD,
+ }
+};
+
+/**
+ * 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.
+ */
+
+static int __devinit aec62xx_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ ide_pci_device_t *d = &aec62xx_chipsets[id->driver_data];
+
+ return d->init_setup(dev, d);
+}
+
+static struct pci_device_id aec62xx_pci_tbl[] = {
+ { PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP850UF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP860, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 },
+ { PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP860R, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2 },
+ { PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP865, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3 },
+ { PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP865R, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 },
+ { 0, },
+};
+MODULE_DEVICE_TABLE(pci, aec62xx_pci_tbl);
+
+static struct pci_driver driver = {
+ .name = "AEC62xx_IDE",
+ .id_table = aec62xx_pci_tbl,
+ .probe = aec62xx_init_one,
+};
+
+static int aec62xx_ide_init(void)
+{
+ return ide_pci_register_driver(&driver);
+}
+
+module_init(aec62xx_ide_init);
+
+MODULE_AUTHOR("Andre Hedrick");
+MODULE_DESCRIPTION("PCI driver module for ARTOP AEC62xx IDE");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/pci/alim15x3.c b/drivers/ide/pci/alim15x3.c
new file mode 100644
index 000000000000..67efb38a9f6c
--- /dev/null
+++ b/drivers/ide/pci/alim15x3.c
@@ -0,0 +1,913 @@
+/*
+ * linux/drivers/ide/pci/alim15x3.c Version 0.17 2003/01/02
+ *
+ * Copyright (C) 1998-2000 Michel Aubry, Maintainer
+ * Copyright (C) 1998-2000 Andrzej Krzysztofowicz, Maintainer
+ * Copyright (C) 1999-2000 CJ, cjtsai@ali.com.tw, Maintainer
+ *
+ * Copyright (C) 1998-2000 Andre Hedrick (andre@linux-ide.org)
+ * May be copied or modified under the terms of the GNU General Public License
+ * Copyright (C) 2002 Alan Cox <alan@redhat.com>
+ * ALi (now ULi M5228) support by Clear Zhang <Clear.Zhang@ali.com.tw>
+ *
+ * (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/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#define DISPLAY_ALI_TIMINGS
+
+/*
+ * 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;
+
+#if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 ali_proc = 0;
+
+static struct pci_dev *bmide_dev;
+
+static char *fifo[4] = {
+ "FIFO Off",
+ "FIFO On ",
+ "DMA mode",
+ "PIO mode" };
+
+static char *udmaT[8] = {
+ "1.5T",
+ " 2T",
+ "2.5T",
+ " 3T",
+ "3.5T",
+ " 4T",
+ " 6T",
+ " 8T"
+};
+
+static char *channel_status[8] = {
+ "OK ",
+ "busy ",
+ "DRQ ",
+ "DRQ busy ",
+ "error ",
+ "error busy ",
+ "error DRQ ",
+ "error DRQ busy"
+};
+
+/**
+ * ali_get_info - generate proc file for ALi IDE
+ * @buffer: buffer to fill
+ * @addr: address of user start in buffer
+ * @offset: offset into 'file'
+ * @count: buffer count
+ *
+ * Walks the Ali devices and outputs summary data on the tuning and
+ * anything else that will help with debugging
+ */
+
+static int ali_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+ unsigned long bibma;
+ u8 reg53h, reg5xh, reg5yh, reg5xh1, reg5yh1, c0, c1, rev, tmp;
+ char *q, *p = buffer;
+
+ /* fetch rev. */
+ pci_read_config_byte(bmide_dev, 0x08, &rev);
+ if (rev >= 0xc1) /* M1543C or newer */
+ udmaT[7] = " ???";
+ else
+ fifo[3] = " ??? ";
+
+ /* first fetch bibma: */
+
+ bibma = pci_resource_start(bmide_dev, 4);
+
+ /*
+ * at that point bibma+0x2 et bibma+0xa are byte
+ * registers to investigate:
+ */
+ c0 = inb(bibma + 0x02);
+ c1 = inb(bibma + 0x0a);
+
+ p += sprintf(p,
+ "\n Ali M15x3 Chipset.\n");
+ p += sprintf(p,
+ " ------------------\n");
+ pci_read_config_byte(bmide_dev, 0x78, &reg53h);
+ p += sprintf(p, "PCI Clock: %d.\n", reg53h);
+
+ pci_read_config_byte(bmide_dev, 0x53, &reg53h);
+ p += sprintf(p,
+ "CD_ROM FIFO:%s, CD_ROM DMA:%s\n",
+ (reg53h & 0x02) ? "Yes" : "No ",
+ (reg53h & 0x01) ? "Yes" : "No " );
+ pci_read_config_byte(bmide_dev, 0x74, &reg53h);
+ p += sprintf(p,
+ "FIFO Status: contains %d Words, runs%s%s\n\n",
+ (reg53h & 0x3f),
+ (reg53h & 0x40) ? " OVERWR" : "",
+ (reg53h & 0x80) ? " OVERRD." : "." );
+
+ p += sprintf(p,
+ "-------------------primary channel"
+ "-------------------secondary channel"
+ "---------\n\n");
+
+ pci_read_config_byte(bmide_dev, 0x09, &reg53h);
+ p += sprintf(p,
+ "channel status: %s"
+ " %s\n",
+ (reg53h & 0x20) ? "On " : "Off",
+ (reg53h & 0x10) ? "On " : "Off" );
+
+ p += sprintf(p,
+ "both channels togth: %s"
+ " %s\n",
+ (c0&0x80) ? "No " : "Yes",
+ (c1&0x80) ? "No " : "Yes" );
+
+ pci_read_config_byte(bmide_dev, 0x76, &reg53h);
+ p += sprintf(p,
+ "Channel state: %s %s\n",
+ channel_status[reg53h & 0x07],
+ channel_status[(reg53h & 0x70) >> 4] );
+
+ pci_read_config_byte(bmide_dev, 0x58, &reg5xh);
+ pci_read_config_byte(bmide_dev, 0x5c, &reg5yh);
+ p += sprintf(p,
+ "Add. Setup Timing: %dT"
+ " %dT\n",
+ (reg5xh & 0x07) ? (reg5xh & 0x07) : 8,
+ (reg5yh & 0x07) ? (reg5yh & 0x07) : 8 );
+
+ pci_read_config_byte(bmide_dev, 0x59, &reg5xh);
+ pci_read_config_byte(bmide_dev, 0x5d, &reg5yh);
+ p += sprintf(p,
+ "Command Act. Count: %dT"
+ " %dT\n"
+ "Command Rec. Count: %dT"
+ " %dT\n\n",
+ (reg5xh & 0x70) ? ((reg5xh & 0x70) >> 4) : 8,
+ (reg5yh & 0x70) ? ((reg5yh & 0x70) >> 4) : 8,
+ (reg5xh & 0x0f) ? (reg5xh & 0x0f) : 16,
+ (reg5yh & 0x0f) ? (reg5yh & 0x0f) : 16 );
+
+ p += sprintf(p,
+ "----------------drive0-----------drive1"
+ "------------drive0-----------drive1------\n\n");
+ p += sprintf(p,
+ "DMA enabled: %s %s"
+ " %s %s\n",
+ (c0&0x20) ? "Yes" : "No ",
+ (c0&0x40) ? "Yes" : "No ",
+ (c1&0x20) ? "Yes" : "No ",
+ (c1&0x40) ? "Yes" : "No " );
+
+ pci_read_config_byte(bmide_dev, 0x54, &reg5xh);
+ pci_read_config_byte(bmide_dev, 0x55, &reg5yh);
+ q = "FIFO threshold: %2d Words %2d Words"
+ " %2d Words %2d Words\n";
+ if (rev < 0xc1) {
+ if ((rev == 0x20) &&
+ (pci_read_config_byte(bmide_dev, 0x4f, &tmp), (tmp &= 0x20))) {
+ p += sprintf(p, q, 8, 8, 8, 8);
+ } else {
+ p += sprintf(p, q,
+ (reg5xh & 0x03) + 12,
+ ((reg5xh & 0x30)>>4) + 12,
+ (reg5yh & 0x03) + 12,
+ ((reg5yh & 0x30)>>4) + 12 );
+ }
+ } else {
+ int t1 = (tmp = (reg5xh & 0x03)) ? (tmp << 3) : 4;
+ int t2 = (tmp = ((reg5xh & 0x30)>>4)) ? (tmp << 3) : 4;
+ int t3 = (tmp = (reg5yh & 0x03)) ? (tmp << 3) : 4;
+ int t4 = (tmp = ((reg5yh & 0x30)>>4)) ? (tmp << 3) : 4;
+ p += sprintf(p, q, t1, t2, t3, t4);
+ }
+
+#if 0
+ p += sprintf(p,
+ "FIFO threshold: %2d Words %2d Words"
+ " %2d Words %2d Words\n",
+ (reg5xh & 0x03) + 12,
+ ((reg5xh & 0x30)>>4) + 12,
+ (reg5yh & 0x03) + 12,
+ ((reg5yh & 0x30)>>4) + 12 );
+#endif
+
+ p += sprintf(p,
+ "FIFO mode: %s %s %s %s\n",
+ fifo[((reg5xh & 0x0c) >> 2)],
+ fifo[((reg5xh & 0xc0) >> 6)],
+ fifo[((reg5yh & 0x0c) >> 2)],
+ fifo[((reg5yh & 0xc0) >> 6)] );
+
+ pci_read_config_byte(bmide_dev, 0x5a, &reg5xh);
+ pci_read_config_byte(bmide_dev, 0x5b, &reg5xh1);
+ pci_read_config_byte(bmide_dev, 0x5e, &reg5yh);
+ pci_read_config_byte(bmide_dev, 0x5f, &reg5yh1);
+
+ p += sprintf(p,/*
+ "------------------drive0-----------drive1"
+ "------------drive0-----------drive1------\n")*/
+ "Dt RW act. Cnt %2dT %2dT"
+ " %2dT %2dT\n"
+ "Dt RW rec. Cnt %2dT %2dT"
+ " %2dT %2dT\n\n",
+ (reg5xh & 0x70) ? ((reg5xh & 0x70) >> 4) : 8,
+ (reg5xh1 & 0x70) ? ((reg5xh1 & 0x70) >> 4) : 8,
+ (reg5yh & 0x70) ? ((reg5yh & 0x70) >> 4) : 8,
+ (reg5yh1 & 0x70) ? ((reg5yh1 & 0x70) >> 4) : 8,
+ (reg5xh & 0x0f) ? (reg5xh & 0x0f) : 16,
+ (reg5xh1 & 0x0f) ? (reg5xh1 & 0x0f) : 16,
+ (reg5yh & 0x0f) ? (reg5yh & 0x0f) : 16,
+ (reg5yh1 & 0x0f) ? (reg5yh1 & 0x0f) : 16 );
+
+ p += sprintf(p,
+ "-----------------------------------UDMA Timings"
+ "--------------------------------\n\n");
+
+ pci_read_config_byte(bmide_dev, 0x56, &reg5xh);
+ pci_read_config_byte(bmide_dev, 0x57, &reg5yh);
+ p += sprintf(p,
+ "UDMA: %s %s"
+ " %s %s\n"
+ "UDMA timings: %s %s"
+ " %s %s\n\n",
+ (reg5xh & 0x08) ? "OK" : "No",
+ (reg5xh & 0x80) ? "OK" : "No",
+ (reg5yh & 0x08) ? "OK" : "No",
+ (reg5yh & 0x80) ? "OK" : "No",
+ udmaT[(reg5xh & 0x07)],
+ udmaT[(reg5xh & 0x70) >> 4],
+ udmaT[reg5yh & 0x07],
+ udmaT[(reg5yh & 0x70) >> 4] );
+
+ return p-buffer; /* => must be less than 4k! */
+}
+#endif /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+/**
+ * ali15x3_tune_drive - set up a drive
+ * @drive: drive to tune
+ * @pio: unused
+ *
+ * Select the best PIO timing for the drive in question. Then
+ * program the controller for this drive set up
+ */
+
+static void ali15x3_tune_drive (ide_drive_t *drive, u8 pio)
+{
+ ide_pio_data_t d;
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = hwif->pci_dev;
+ int s_time, a_time, c_time;
+ u8 s_clc, a_clc, r_clc;
+ unsigned long flags;
+ int bus_speed = system_bus_clock();
+ int port = hwif->channel ? 0x5c : 0x58;
+ int portFIFO = hwif->channel ? 0x55 : 0x54;
+ u8 cd_dma_fifo = 0;
+ int unit = drive->select.b.unit & 1;
+
+ pio = ide_get_best_pio_mode(drive, pio, 5, &d);
+ s_time = ide_pio_timings[pio].setup_time;
+ a_time = ide_pio_timings[pio].active_time;
+ 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;
+ c_time = ide_pio_timings[pio].cycle_time;
+
+#if 0
+ if ((r_clc = ((c_time - s_time - a_time) * bus_speed + 999) / 1000) >= 16)
+ r_clc = 0;
+#endif
+
+ 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+drive->select.b.unit+2, (a_clc << 4) | r_clc);
+ local_irq_restore(flags);
+
+ /*
+ * setup active rec
+ * { 70, 165, 365 }, PIO Mode 0
+ * { 50, 125, 208 }, PIO Mode 1
+ * { 30, 100, 110 }, PIO Mode 2
+ * { 30, 80, 70 }, PIO Mode 3 with IORDY
+ * { 25, 70, 25 }, PIO Mode 4 with IORDY ns
+ * { 20, 50, 30 } PIO Mode 5 with IORDY (nonstandard)
+ */
+
+}
+
+/**
+ * ali15x3_can_ultra - check for ultra DMA support
+ * @drive: drive to do the check
+ *
+ * Check the drive and controller revisions. Return 0 if UDMA is
+ * not available, or 1 if UDMA can be used. The actual rules for
+ * the ALi are
+ * No UDMA on revisions <= 0x20
+ * Disk only for revisions < 0xC2
+ * Not WDC drives for revisions < 0xC2
+ *
+ * FIXME: WDC ifdef needs to die
+ */
+
+static u8 ali15x3_can_ultra (ide_drive_t *drive)
+{
+#ifndef CONFIG_WDC_ALI15X3
+ struct hd_driveid *id = drive->id;
+#endif /* CONFIG_WDC_ALI15X3 */
+
+ if (m5229_revision <= 0x20) {
+ return 0;
+ } else if ((m5229_revision < 0xC2) &&
+#ifndef CONFIG_WDC_ALI15X3
+ ((chip_is_1543c_e && strstr(id->model, "WDC ")) ||
+ (drive->media!=ide_disk))) {
+#else /* CONFIG_WDC_ALI15X3 */
+ (drive->media!=ide_disk)) {
+#endif /* CONFIG_WDC_ALI15X3 */
+ return 0;
+ } else {
+ return 1;
+ }
+}
+
+/**
+ * ali15x3_ratemask - generate DMA mode list
+ * @drive: drive to compute against
+ *
+ * Generate a list of the available DMA modes for the drive.
+ * FIXME: this function contains lots of bogus masking we can dump
+ *
+ * Return the highest available mode (UDMA33, UDMA66, UDMA100,..)
+ */
+
+static u8 ali15x3_ratemask (ide_drive_t *drive)
+{
+ u8 mode = 0, can_ultra = ali15x3_can_ultra(drive);
+
+ if (m5229_revision > 0xC4 && can_ultra) {
+ mode = 4;
+ } else if (m5229_revision == 0xC4 && can_ultra) {
+ mode = 3;
+ } else if (m5229_revision >= 0xC2 && can_ultra) {
+ mode = 2;
+ } else if (can_ultra) {
+ return 1;
+ } else {
+ return 0;
+ }
+
+ /*
+ * If the drive sees no suitable cable then UDMA 33
+ * is the highest permitted mode
+ */
+
+ if (!eighty_ninty_three(drive))
+ mode = min(mode, (u8)1);
+ return mode;
+}
+
+/**
+ * ali15x3_tune_chipset - set up chiset for new speed
+ * @drive: drive to configure for
+ * @xferspeed: desired speed
+ *
+ * Configure the hardware for the desired IDE transfer mode.
+ * We also do the needed drive configuration through helpers
+ */
+
+static int ali15x3_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = hwif->pci_dev;
+ u8 speed = ide_rate_filter(ali15x3_ratemask(drive), xferspeed);
+ u8 speed1 = speed;
+ u8 unit = (drive->select.b.unit & 0x01);
+ 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);
+
+ if (speed < XFER_SW_DMA_0)
+ ali15x3_tune_drive(drive, speed);
+ } 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);
+ }
+ }
+ return (ide_config_drive_speed(drive, speed));
+}
+
+
+/**
+ * config_chipset_for_dma - set up DMA mode
+ * @drive: drive to configure for
+ *
+ * Place a drive into DMA mode and tune the chipset for
+ * the selected speed.
+ *
+ * Returns true if DMA mode can be used
+ */
+
+static int config_chipset_for_dma (ide_drive_t *drive)
+{
+ u8 speed = ide_dma_speed(drive, ali15x3_ratemask(drive));
+
+ if (!(speed))
+ return 0;
+
+ (void) ali15x3_tune_chipset(drive, speed);
+ return ide_dma_enable(drive);
+}
+
+/**
+ * ali15x3_config_drive_for_dma - configure for DMA
+ * @drive: drive to configure
+ *
+ * Configure a drive for DMA operation. If DMA is not possible we
+ * drop the drive into PIO mode instead.
+ *
+ * FIXME: exactly what are we trying to return here
+ */
+
+static int ali15x3_config_drive_for_dma(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct hd_driveid *id = drive->id;
+
+ if ((m5229_revision<=0x20) && (drive->media!=ide_disk))
+ return hwif->ide_dma_off_quietly(drive);
+
+ drive->init_speed = 0;
+
+ if ((id != NULL) && ((id->capability & 1) != 0) && drive->autodma) {
+ /* Consult the list of known "bad" drives */
+ if (__ide_dma_bad_drive(drive))
+ goto ata_pio;
+ if ((id->field_valid & 4) && (m5229_revision >= 0xC2)) {
+ if (id->dma_ultra & hwif->ultra_mask) {
+ /* Force if Capable UltraDMA */
+ int dma = config_chipset_for_dma(drive);
+ if ((id->field_valid & 2) && !dma)
+ goto try_dma_modes;
+ }
+ } else if (id->field_valid & 2) {
+try_dma_modes:
+ if ((id->dma_mword & hwif->mwdma_mask) ||
+ (id->dma_1word & hwif->swdma_mask)) {
+ /* Force if Capable regular DMA modes */
+ if (!config_chipset_for_dma(drive))
+ goto no_dma_set;
+ }
+ } else if (__ide_dma_good_drive(drive) &&
+ (id->eide_dma_time < 150)) {
+ /* Consult the list of known "good" drives */
+ if (!config_chipset_for_dma(drive))
+ goto no_dma_set;
+ } else {
+ goto ata_pio;
+ }
+ } else {
+ata_pio:
+ hwif->tuneproc(drive, 255);
+no_dma_set:
+ return hwif->ide_dma_off_quietly(drive);
+ }
+ return hwif->ide_dma_on(drive);
+}
+
+/**
+ * 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
+ * @name: Name of the controller
+ *
+ * This function initializes the ALI IDE controller and where
+ * appropriate also sets up the 1533 southbridge.
+ */
+
+static unsigned int __init init_chipset_ali15x3 (struct pci_dev *dev, const char *name)
+{
+ unsigned long flags;
+ u8 tmpbyte;
+ struct pci_dev *north = pci_find_slot(0, PCI_DEVFN(0,0));
+
+ pci_read_config_byte(dev, PCI_REVISION_ID, &m5229_revision);
+
+ isa_dev = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL);
+
+#if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS)
+ if (!ali_proc) {
+ ali_proc = 1;
+ bmide_dev = dev;
+ ide_pci_create_host_proc("ali", ali_get_info);
+ }
+#endif /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+ 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);
+ local_irq_restore(flags);
+ return 0;
+ }
+
+ /*
+ * 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) {
+ local_irq_restore(flags);
+ return 0;
+ }
+
+ 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);
+ }
+ }
+ local_irq_restore(flags);
+ return 0;
+}
+
+/**
+ * ata66_ali15x3 - check for UDMA 66 support
+ * @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 unsigned int __init ata66_ali15x3 (ide_hwif_t *hwif)
+{
+ struct pci_dev *dev = hwif->pci_dev;
+ unsigned int ata66 = 0;
+ u8 cable_80_pin[2] = { 0, 0 };
+
+ unsigned long flags;
+ u8 tmpbyte;
+
+ local_irq_save(flags);
+
+ if (m5229_revision >= 0xC2) {
+ /*
+ * Ultra66 cable detection (from Host View)
+ * m5229, 0x4a, bit0: primary, bit1: secondary 80 pin
+ */
+ pci_read_config_byte(dev, 0x4a, &tmpbyte);
+ /*
+ * 0x4a, bit0 is 0 => primary channel
+ * has 80-pin (from host view)
+ */
+ if (!(tmpbyte & 0x01)) cable_80_pin[0] = 1;
+ /*
+ * 0x4a, bit1 is 0 => secondary channel
+ * has 80-pin (from host view)
+ */
+ if (!(tmpbyte & 0x02)) cable_80_pin[1] = 1;
+ /*
+ * Allow ata66 if cable of current channel has 80 pins
+ */
+ ata66 = (hwif->channel)?cable_80_pin[1]:cable_80_pin[0];
+ } else {
+ /*
+ * check m1533, 0x5e, bit 1~4 == 1001 => & 00011110 = 00010010
+ */
+ pci_read_config_byte(isa_dev, 0x5e, &tmpbyte);
+ chip_is_1543c_e = ((tmpbyte & 0x1e) == 0x12) ? 1: 0;
+ }
+
+ /*
+ * 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
+ */
+
+ pci_read_config_byte(dev, 0x53, &tmpbyte);
+
+ if(m5229_revision <= 0x20)
+ tmpbyte = (tmpbyte & (~0x02)) | 0x01;
+ else
+ tmpbyte |= 0x01;
+
+ pci_write_config_byte(dev, 0x53, tmpbyte);
+
+ local_irq_restore(flags);
+
+ return(ata66);
+}
+
+/**
+ * init_hwif_common_ali15x3 - Set up ALI IDE hardware
+ * @hwif: IDE interface
+ *
+ * Initialize the IDE structure side of the ALi 15x3 driver.
+ */
+
+static void __init init_hwif_common_ali15x3 (ide_hwif_t *hwif)
+{
+ hwif->autodma = 0;
+ hwif->tuneproc = &ali15x3_tune_drive;
+ hwif->speedproc = &ali15x3_tune_chipset;
+
+ /* don't use LBA48 DMA on ALi devices before rev 0xC5 */
+ hwif->no_lba48_dma = (m5229_revision <= 0xC4) ? 1 : 0;
+
+ if (!hwif->dma_base) {
+ hwif->drives[0].autotune = 1;
+ hwif->drives[1].autotune = 1;
+ return;
+ }
+
+ hwif->atapi_dma = 1;
+
+ if (m5229_revision > 0x20)
+ hwif->ultra_mask = 0x7f;
+ hwif->mwdma_mask = 0x07;
+ hwif->swdma_mask = 0x07;
+
+ if (m5229_revision >= 0x20) {
+ /*
+ * M1543C or newer for DMAing
+ */
+ hwif->ide_dma_check = &ali15x3_config_drive_for_dma;
+ hwif->dma_setup = &ali15x3_dma_setup;
+ if (!noautodma)
+ hwif->autodma = 1;
+ if (!(hwif->udma_four))
+ hwif->udma_four = ata66_ali15x3(hwif);
+ }
+ hwif->drives[0].autodma = hwif->autodma;
+ hwif->drives[1].autodma = hwif->autodma;
+}
+
+/**
+ * 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 systems
+ */
+
+static void __init init_hwif_ali15x3 (ide_hwif_t *hwif)
+{
+ 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 (hwif->pci_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;
+ }
+
+ init_hwif_common_ali15x3(hwif);
+}
+
+/**
+ * init_dma_ali15x3 - set up DMA on ALi15x3
+ * @hwif: IDE interface
+ * @dmabase: DMA interface base PCI address
+ *
+ * Set up the DMA functionality on the ALi 15x3. For the ALi
+ * controllers this is generic so we can let the generic code do
+ * the actual work.
+ */
+
+static void __init init_dma_ali15x3 (ide_hwif_t *hwif, unsigned long dmabase)
+{
+ if (m5229_revision < 0x20)
+ return;
+ if (!(hwif->channel))
+ hwif->OUTB(hwif->INB(dmabase+2) & 0x60, dmabase+2);
+ ide_setup_dma(hwif, dmabase, 8);
+}
+
+static ide_pci_device_t ali15x3_chipset __devinitdata = {
+ .name = "ALI15X3",
+ .init_chipset = init_chipset_ali15x3,
+ .init_hwif = init_hwif_ali15x3,
+ .init_dma = init_dma_ali15x3,
+ .channels = 2,
+ .autodma = AUTODMA,
+ .bootable = ON_BOARD,
+};
+
+/**
+ * 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)
+{
+ ide_pci_device_t *d = &ali15x3_chipset;
+
+ if(pci_find_device(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RS100, NULL))
+ printk(KERN_ERR "Warning: ATI Radeon IGP Northbridge is not yet fully tested.\n");
+
+#if defined(CONFIG_SPARC64)
+ d->init_hwif = init_hwif_common_ali15x3;
+#endif /* CONFIG_SPARC64 */
+ return ide_setup_pci_device(dev, d);
+}
+
+
+static struct pci_device_id alim15x3_pci_tbl[] = {
+ { PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M5229, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M5228, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { 0, },
+};
+MODULE_DEVICE_TABLE(pci, alim15x3_pci_tbl);
+
+static struct pci_driver driver = {
+ .name = "ALI15x3_IDE",
+ .id_table = alim15x3_pci_tbl,
+ .probe = alim15x3_init_one,
+};
+
+static int ali15x3_ide_init(void)
+{
+ return ide_pci_register_driver(&driver);
+}
+
+module_init(ali15x3_ide_init);
+
+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/pci/amd74xx.c b/drivers/ide/pci/amd74xx.c
new file mode 100644
index 000000000000..47225e324356
--- /dev/null
+++ b/drivers/ide/pci/amd74xx.c
@@ -0,0 +1,543 @@
+/*
+ * Version 2.13
+ *
+ * AMD 755/756/766/8111 and nVidia nForce/2/2s/3/3s/CK804/MCP04
+ * IDE driver for Linux.
+ *
+ * Copyright (c) 2000-2002 Vojtech Pavlik
+ *
+ * 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/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/ide.h>
+#include <asm/io.h>
+
+#include "ide-timing.h"
+
+#define DISPLAY_AMD_TIMINGS
+
+#define AMD_IDE_ENABLE (0x00 + amd_config->base)
+#define AMD_IDE_CONFIG (0x01 + amd_config->base)
+#define AMD_CABLE_DETECT (0x02 + amd_config->base)
+#define AMD_DRIVE_TIMING (0x08 + amd_config->base)
+#define AMD_8BIT_TIMING (0x0e + amd_config->base)
+#define AMD_ADDRESS_SETUP (0x0c + amd_config->base)
+#define AMD_UDMA_TIMING (0x10 + amd_config->base)
+
+#define AMD_UDMA 0x07
+#define AMD_UDMA_33 0x01
+#define AMD_UDMA_66 0x02
+#define AMD_UDMA_100 0x03
+#define AMD_UDMA_133 0x04
+#define AMD_CHECK_SWDMA 0x08
+#define AMD_BAD_SWDMA 0x10
+#define AMD_BAD_FIFO 0x20
+#define AMD_CHECK_SERENADE 0x40
+
+/*
+ * AMD SouthBridge chips.
+ */
+
+static struct amd_ide_chip {
+ unsigned short id;
+ unsigned long base;
+ unsigned char flags;
+} amd_ide_chips[] = {
+ { PCI_DEVICE_ID_AMD_COBRA_7401, 0x40, AMD_UDMA_33 | AMD_BAD_SWDMA },
+ { PCI_DEVICE_ID_AMD_VIPER_7409, 0x40, AMD_UDMA_66 | AMD_CHECK_SWDMA },
+ { PCI_DEVICE_ID_AMD_VIPER_7411, 0x40, AMD_UDMA_100 | AMD_BAD_FIFO },
+ { PCI_DEVICE_ID_AMD_OPUS_7441, 0x40, AMD_UDMA_100 },
+ { PCI_DEVICE_ID_AMD_8111_IDE, 0x40, AMD_UDMA_133 | AMD_CHECK_SERENADE },
+ { PCI_DEVICE_ID_NVIDIA_NFORCE_IDE, 0x50, AMD_UDMA_100 },
+ { PCI_DEVICE_ID_NVIDIA_NFORCE2_IDE, 0x50, AMD_UDMA_133 },
+ { PCI_DEVICE_ID_NVIDIA_NFORCE2S_IDE, 0x50, AMD_UDMA_133 },
+ { PCI_DEVICE_ID_NVIDIA_NFORCE2S_SATA, 0x50, AMD_UDMA_133 },
+ { PCI_DEVICE_ID_NVIDIA_NFORCE3_IDE, 0x50, AMD_UDMA_133 },
+ { PCI_DEVICE_ID_NVIDIA_NFORCE3S_IDE, 0x50, AMD_UDMA_133 },
+ { PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA, 0x50, AMD_UDMA_133 },
+ { PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA2, 0x50, AMD_UDMA_133 },
+ { PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_IDE, 0x50, AMD_UDMA_133 },
+ { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE, 0x50, AMD_UDMA_133 },
+ { 0 }
+};
+
+static struct amd_ide_chip *amd_config;
+static ide_pci_device_t *amd_chipset;
+static unsigned int amd_80w;
+static unsigned int amd_clock;
+
+static char *amd_dma[] = { "MWDMA16", "UDMA33", "UDMA66", "UDMA100", "UDMA133" };
+static unsigned char amd_cyc2udma[] = { 6, 6, 5, 4, 0, 1, 1, 2, 2, 3, 3, 3, 3, 3, 3, 7 };
+
+/*
+ * AMD /proc entry.
+ */
+
+#ifdef CONFIG_PROC_FS
+
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 amd74xx_proc;
+
+static unsigned char amd_udma2cyc[] = { 4, 6, 8, 10, 3, 2, 1, 15 };
+static unsigned long amd_base;
+static struct pci_dev *bmide_dev;
+extern int (*amd74xx_display_info)(char *, char **, off_t, int); /* ide-proc.c */
+
+#define amd_print(format, arg...) p += sprintf(p, format "\n" , ## arg)
+#define amd_print_drive(name, format, arg...)\
+ p += sprintf(p, name); for (i = 0; i < 4; i++) p += sprintf(p, format, ## arg); p += sprintf(p, "\n");
+
+static int amd74xx_get_info(char *buffer, char **addr, off_t offset, int count)
+{
+ int speed[4], cycle[4], setup[4], active[4], recover[4], den[4],
+ uen[4], udma[4], active8b[4], recover8b[4];
+ struct pci_dev *dev = bmide_dev;
+ unsigned int v, u, i;
+ unsigned short c, w;
+ unsigned char t;
+ int len;
+ char *p = buffer;
+
+ amd_print("----------AMD BusMastering IDE Configuration----------------");
+
+ amd_print("Driver Version: 2.13");
+ amd_print("South Bridge: %s", pci_name(bmide_dev));
+
+ pci_read_config_byte(dev, PCI_REVISION_ID, &t);
+ amd_print("Revision: IDE %#x", t);
+ amd_print("Highest DMA rate: %s", amd_dma[amd_config->flags & AMD_UDMA]);
+
+ amd_print("BM-DMA base: %#lx", amd_base);
+ amd_print("PCI clock: %d.%dMHz", amd_clock / 1000, amd_clock / 100 % 10);
+
+ amd_print("-----------------------Primary IDE-------Secondary IDE------");
+
+ pci_read_config_byte(dev, AMD_IDE_CONFIG, &t);
+ amd_print("Prefetch Buffer: %10s%20s", (t & 0x80) ? "yes" : "no", (t & 0x20) ? "yes" : "no");
+ amd_print("Post Write Buffer: %10s%20s", (t & 0x40) ? "yes" : "no", (t & 0x10) ? "yes" : "no");
+
+ pci_read_config_byte(dev, AMD_IDE_ENABLE, &t);
+ amd_print("Enabled: %10s%20s", (t & 0x02) ? "yes" : "no", (t & 0x01) ? "yes" : "no");
+
+ c = inb(amd_base + 0x02) | (inb(amd_base + 0x0a) << 8);
+ amd_print("Simplex only: %10s%20s", (c & 0x80) ? "yes" : "no", (c & 0x8000) ? "yes" : "no");
+
+ amd_print("Cable Type: %10s%20s", (amd_80w & 1) ? "80w" : "40w", (amd_80w & 2) ? "80w" : "40w");
+
+ if (!amd_clock)
+ return p - buffer;
+
+ amd_print("-------------------drive0----drive1----drive2----drive3-----");
+
+ pci_read_config_byte(dev, AMD_ADDRESS_SETUP, &t);
+ pci_read_config_dword(dev, AMD_DRIVE_TIMING, &v);
+ pci_read_config_word(dev, AMD_8BIT_TIMING, &w);
+ pci_read_config_dword(dev, AMD_UDMA_TIMING, &u);
+
+ for (i = 0; i < 4; i++) {
+ setup[i] = ((t >> ((3 - i) << 1)) & 0x3) + 1;
+ recover8b[i] = ((w >> ((1 - (i >> 1)) << 3)) & 0xf) + 1;
+ active8b[i] = ((w >> (((1 - (i >> 1)) << 3) + 4)) & 0xf) + 1;
+ active[i] = ((v >> (((3 - i) << 3) + 4)) & 0xf) + 1;
+ recover[i] = ((v >> ((3 - i) << 3)) & 0xf) + 1;
+
+ udma[i] = amd_udma2cyc[((u >> ((3 - i) << 3)) & 0x7)];
+ uen[i] = ((u >> ((3 - i) << 3)) & 0x40) ? 1 : 0;
+ den[i] = (c & ((i & 1) ? 0x40 : 0x20) << ((i & 2) << 2));
+
+ if (den[i] && uen[i] && udma[i] == 1) {
+ speed[i] = amd_clock * 3;
+ cycle[i] = 666666 / amd_clock;
+ continue;
+ }
+
+ if (den[i] && uen[i] && udma[i] == 15) {
+ speed[i] = amd_clock * 4;
+ cycle[i] = 500000 / amd_clock;
+ continue;
+ }
+
+ speed[i] = 4 * amd_clock / ((den[i] && uen[i]) ? udma[i] : (active[i] + recover[i]) * 2);
+ cycle[i] = 1000000 * ((den[i] && uen[i]) ? udma[i] : (active[i] + recover[i]) * 2) / amd_clock / 2;
+ }
+
+ amd_print_drive("Transfer Mode: ", "%10s", den[i] ? (uen[i] ? "UDMA" : "DMA") : "PIO");
+
+ amd_print_drive("Address Setup: ", "%8dns", 1000000 * setup[i] / amd_clock);
+ amd_print_drive("Cmd Active: ", "%8dns", 1000000 * active8b[i] / amd_clock);
+ amd_print_drive("Cmd Recovery: ", "%8dns", 1000000 * recover8b[i] / amd_clock);
+ amd_print_drive("Data Active: ", "%8dns", 1000000 * active[i] / amd_clock);
+ amd_print_drive("Data Recovery: ", "%8dns", 1000000 * recover[i] / amd_clock);
+ amd_print_drive("Cycle Time: ", "%8dns", cycle[i]);
+ amd_print_drive("Transfer Rate: ", "%4d.%dMB/s", speed[i] / 1000, speed[i] / 100 % 10);
+
+ /* hoping p - buffer is less than 4K... */
+ len = (p - buffer) - offset;
+ *addr = buffer + offset;
+
+ return len > count ? count : len;
+}
+
+#endif
+
+/*
+ * amd_set_speed() writes timing values to the chipset registers
+ */
+
+static void amd_set_speed(struct pci_dev *dev, unsigned char dn, struct ide_timing *timing)
+{
+ unsigned char t;
+
+ pci_read_config_byte(dev, AMD_ADDRESS_SETUP, &t);
+ t = (t & ~(3 << ((3 - dn) << 1))) | ((FIT(timing->setup, 1, 4) - 1) << ((3 - dn) << 1));
+ pci_write_config_byte(dev, AMD_ADDRESS_SETUP, t);
+
+ pci_write_config_byte(dev, AMD_8BIT_TIMING + (1 - (dn >> 1)),
+ ((FIT(timing->act8b, 1, 16) - 1) << 4) | (FIT(timing->rec8b, 1, 16) - 1));
+
+ pci_write_config_byte(dev, AMD_DRIVE_TIMING + (3 - dn),
+ ((FIT(timing->active, 1, 16) - 1) << 4) | (FIT(timing->recover, 1, 16) - 1));
+
+ switch (amd_config->flags & AMD_UDMA) {
+ case AMD_UDMA_33: t = timing->udma ? (0xc0 | (FIT(timing->udma, 2, 5) - 2)) : 0x03; break;
+ case AMD_UDMA_66: t = timing->udma ? (0xc0 | amd_cyc2udma[FIT(timing->udma, 2, 10)]) : 0x03; break;
+ case AMD_UDMA_100: t = timing->udma ? (0xc0 | amd_cyc2udma[FIT(timing->udma, 1, 10)]) : 0x03; break;
+ case AMD_UDMA_133: t = timing->udma ? (0xc0 | amd_cyc2udma[FIT(timing->udma, 1, 15)]) : 0x03; break;
+ default: return;
+ }
+
+ pci_write_config_byte(dev, AMD_UDMA_TIMING + (3 - dn), t);
+}
+
+/*
+ * amd_set_drive() computes timing values configures the drive and
+ * the chipset to a desired transfer mode. It also can be called
+ * by upper layers.
+ */
+
+static int amd_set_drive(ide_drive_t *drive, u8 speed)
+{
+ ide_drive_t *peer = HWIF(drive)->drives + (~drive->dn & 1);
+ struct ide_timing t, p;
+ int T, UT;
+
+ if (speed != XFER_PIO_SLOW && speed != drive->current_speed)
+ if (ide_config_drive_speed(drive, speed))
+ printk(KERN_WARNING "ide%d: Drive %d didn't accept speed setting. Oh, well.\n",
+ drive->dn >> 1, drive->dn & 1);
+
+ T = 1000000000 / amd_clock;
+ UT = T / min_t(int, max_t(int, amd_config->flags & AMD_UDMA, 1), 2);
+
+ ide_timing_compute(drive, speed, &t, T, UT);
+
+ if (peer->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(HWIF(drive)->pci_dev, drive->dn, &t);
+
+ if (!drive->init_speed)
+ drive->init_speed = speed;
+ drive->current_speed = speed;
+
+ return 0;
+}
+
+/*
+ * amd74xx_tune_drive() is a callback from upper layers for
+ * PIO-only tuning.
+ */
+
+static void amd74xx_tune_drive(ide_drive_t *drive, u8 pio)
+{
+ if (pio == 255) {
+ amd_set_drive(drive, ide_find_best_mode(drive, XFER_PIO | XFER_EPIO));
+ return;
+ }
+
+ amd_set_drive(drive, XFER_PIO_0 + min_t(byte, pio, 5));
+}
+
+/*
+ * amd74xx_dmaproc() is a callback from upper layers that can do
+ * a lot, but we use it for DMA/PIO tuning only, delegating everything
+ * else to the default ide_dmaproc().
+ */
+
+static int amd74xx_ide_dma_check(ide_drive_t *drive)
+{
+ int w80 = HWIF(drive)->udma_four;
+
+ u8 speed = ide_find_best_mode(drive,
+ XFER_PIO | XFER_EPIO | XFER_MWDMA | XFER_UDMA |
+ ((amd_config->flags & AMD_BAD_SWDMA) ? 0 : XFER_SWDMA) |
+ (w80 && (amd_config->flags & AMD_UDMA) >= AMD_UDMA_66 ? XFER_UDMA_66 : 0) |
+ (w80 && (amd_config->flags & AMD_UDMA) >= AMD_UDMA_100 ? XFER_UDMA_100 : 0) |
+ (w80 && (amd_config->flags & AMD_UDMA) >= AMD_UDMA_133 ? XFER_UDMA_133 : 0));
+
+ amd_set_drive(drive, speed);
+
+ if (drive->autodma && (speed & XFER_MODE) != XFER_PIO)
+ return HWIF(drive)->ide_dma_on(drive);
+ return HWIF(drive)->ide_dma_off_quietly(drive);
+}
+
+/*
+ * The initialization callback. Here we determine the IDE chip type
+ * and initialize its drive independent registers.
+ */
+
+static unsigned int __init init_chipset_amd74xx(struct pci_dev *dev, const char *name)
+{
+ unsigned char t;
+ unsigned int u;
+ int i;
+
+/*
+ * Check for bad SWDMA.
+ */
+
+ if (amd_config->flags & AMD_CHECK_SWDMA) {
+ pci_read_config_byte(dev, PCI_REVISION_ID, &t);
+ if (t <= 7)
+ amd_config->flags |= AMD_BAD_SWDMA;
+ }
+
+/*
+ * Check 80-wire cable presence.
+ */
+
+ switch (amd_config->flags & AMD_UDMA) {
+
+ case AMD_UDMA_133:
+ case AMD_UDMA_100:
+ pci_read_config_byte(dev, AMD_CABLE_DETECT, &t);
+ pci_read_config_dword(dev, AMD_UDMA_TIMING, &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 "%s: BIOS didn't set cable bits correctly. Enabling workaround.\n",
+ amd_chipset->name);
+ amd_80w |= (1 << (1 - (i >> 4)));
+ }
+ break;
+
+ case AMD_UDMA_66:
+ pci_read_config_dword(dev, AMD_UDMA_TIMING, &u);
+ for (i = 24; i >= 0; i -= 8)
+ if ((u >> i) & 4)
+ amd_80w |= (1 << (1 - (i >> 4)));
+ break;
+ }
+
+/*
+ * Take care of prefetch & postwrite.
+ */
+
+ pci_read_config_byte(dev, AMD_IDE_CONFIG, &t);
+ pci_write_config_byte(dev, AMD_IDE_CONFIG,
+ (amd_config->flags & AMD_BAD_FIFO) ? (t & 0x0f) : (t | 0xf0));
+
+/*
+ * Take care of incorrectly wired Serenade mainboards.
+ */
+
+ if ((amd_config->flags & AMD_CHECK_SERENADE) &&
+ dev->subsystem_vendor == PCI_VENDOR_ID_AMD &&
+ dev->subsystem_device == PCI_DEVICE_ID_AMD_SERENADE)
+ amd_config->flags = AMD_UDMA_100;
+
+/*
+ * Determine the system bus clock.
+ */
+
+ amd_clock = system_bus_clock() * 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",
+ amd_chipset->name, amd_clock);
+ printk(KERN_WARNING "%s: Use ide0=ata66 if you want to assume 80-wire cable\n",
+ amd_chipset->name);
+ amd_clock = 33333;
+ }
+
+/*
+ * Print the boot message.
+ */
+
+ pci_read_config_byte(dev, PCI_REVISION_ID, &t);
+ printk(KERN_INFO "%s: %s (rev %02x) %s controller\n",
+ amd_chipset->name, pci_name(dev), t, amd_dma[amd_config->flags & AMD_UDMA]);
+
+/*
+ * Register /proc/ide/amd74xx entry
+ */
+
+#if defined(DISPLAY_AMD_TIMINGS) && defined(CONFIG_PROC_FS)
+ if (!amd74xx_proc) {
+ amd_base = pci_resource_start(dev, 4);
+ bmide_dev = dev;
+ ide_pci_create_host_proc("amd74xx", amd74xx_get_info);
+ amd74xx_proc = 1;
+ }
+#endif /* DISPLAY_AMD_TIMINGS && CONFIG_PROC_FS */
+
+ return dev->irq;
+}
+
+static void __init init_hwif_amd74xx(ide_hwif_t *hwif)
+{
+ int i;
+
+ if (hwif->irq == 0) /* 0 is bogus but will do for now */
+ hwif->irq = pci_get_legacy_ide_irq(hwif->pci_dev, hwif->channel);
+
+ hwif->autodma = 0;
+
+ hwif->tuneproc = &amd74xx_tune_drive;
+ hwif->speedproc = &amd_set_drive;
+
+ for (i = 0; i < 2; i++) {
+ hwif->drives[i].io_32bit = 1;
+ hwif->drives[i].unmask = 1;
+ hwif->drives[i].autotune = 1;
+ hwif->drives[i].dn = hwif->channel * 2 + i;
+ }
+
+ if (!hwif->dma_base)
+ return;
+
+ hwif->atapi_dma = 1;
+ hwif->ultra_mask = 0x7f;
+ hwif->mwdma_mask = 0x07;
+ hwif->swdma_mask = 0x07;
+
+ if (!hwif->udma_four)
+ hwif->udma_four = (amd_80w >> hwif->channel) & 1;
+ hwif->ide_dma_check = &amd74xx_ide_dma_check;
+ if (!noautodma)
+ hwif->autodma = 1;
+ hwif->drives[0].autodma = hwif->autodma;
+ hwif->drives[1].autodma = hwif->autodma;
+}
+
+#define DECLARE_AMD_DEV(name_str) \
+ { \
+ .name = name_str, \
+ .init_chipset = init_chipset_amd74xx, \
+ .init_hwif = init_hwif_amd74xx, \
+ .channels = 2, \
+ .autodma = AUTODMA, \
+ .enablebits = {{0x40,0x02,0x02}, {0x40,0x01,0x01}}, \
+ .bootable = ON_BOARD, \
+ }
+
+#define DECLARE_NV_DEV(name_str) \
+ { \
+ .name = name_str, \
+ .init_chipset = init_chipset_amd74xx, \
+ .init_hwif = init_hwif_amd74xx, \
+ .channels = 2, \
+ .autodma = AUTODMA, \
+ .enablebits = {{0x50,0x02,0x02}, {0x50,0x01,0x01}}, \
+ .bootable = ON_BOARD, \
+ }
+
+static ide_pci_device_t amd74xx_chipsets[] __devinitdata = {
+ /* 0 */ DECLARE_AMD_DEV("AMD7401"),
+ /* 1 */ DECLARE_AMD_DEV("AMD7409"),
+ /* 2 */ DECLARE_AMD_DEV("AMD7411"),
+ /* 3 */ DECLARE_AMD_DEV("AMD7441"),
+ /* 4 */ DECLARE_AMD_DEV("AMD8111"),
+
+ /* 5 */ DECLARE_NV_DEV("NFORCE"),
+ /* 6 */ DECLARE_NV_DEV("NFORCE2"),
+ /* 7 */ DECLARE_NV_DEV("NFORCE2-U400R"),
+ /* 8 */ DECLARE_NV_DEV("NFORCE2-U400R-SATA"),
+ /* 9 */ DECLARE_NV_DEV("NFORCE3-150"),
+ /* 10 */ DECLARE_NV_DEV("NFORCE3-250"),
+ /* 11 */ DECLARE_NV_DEV("NFORCE3-250-SATA"),
+ /* 12 */ DECLARE_NV_DEV("NFORCE3-250-SATA2"),
+ /* 13 */ DECLARE_NV_DEV("NFORCE-CK804"),
+ /* 14 */ DECLARE_NV_DEV("NFORCE-MCP04"),
+};
+
+static int __devinit amd74xx_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ amd_chipset = amd74xx_chipsets + id->driver_data;
+ amd_config = amd_ide_chips + id->driver_data;
+ if (dev->device != amd_config->id) {
+ printk(KERN_ERR "%s: assertion 0x%02x == 0x%02x failed !\n",
+ pci_name(dev), dev->device, amd_config->id);
+ return -ENODEV;
+ }
+ return ide_setup_pci_device(dev, amd_chipset);
+}
+
+static struct pci_device_id amd74xx_pci_tbl[] = {
+ { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_COBRA_7401, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7409, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 },
+ { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7411, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2 },
+ { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_OPUS_7441, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3 },
+ { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5 },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6 },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 7 },
+#ifdef CONFIG_BLK_DEV_IDE_SATA
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_SATA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 },
+#endif
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 9 },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 10 },
+#ifdef CONFIG_BLK_DEV_IDE_SATA
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 11 },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 12 },
+#endif
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 13 },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 14 },
+ { 0, },
+};
+MODULE_DEVICE_TABLE(pci, amd74xx_pci_tbl);
+
+static struct pci_driver driver = {
+ .name = "AMD_IDE",
+ .id_table = amd74xx_pci_tbl,
+ .probe = amd74xx_probe,
+};
+
+static int amd74xx_ide_init(void)
+{
+ return ide_pci_register_driver(&driver);
+}
+
+module_init(amd74xx_ide_init);
+
+MODULE_AUTHOR("Vojtech Pavlik");
+MODULE_DESCRIPTION("AMD PCI IDE driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/pci/atiixp.c b/drivers/ide/pci/atiixp.c
new file mode 100644
index 000000000000..df9ee9a78435
--- /dev/null
+++ b/drivers/ide/pci/atiixp.c
@@ -0,0 +1,370 @@
+/*
+ * linux/drivers/ide/pci/atiixp.c Version 0.01-bart2 Feb. 26, 2004
+ *
+ * Copyright (C) 2003 ATI Inc. <hyu@ati.com>
+ * Copyright (C) 2004 Bartlomiej Zolnierkiewicz
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#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 int save_mdma_mode[4];
+
+/**
+ * atiixp_ratemask - compute rate mask for ATIIXP IDE
+ * @drive: IDE drive to compute for
+ *
+ * Returns the available modes for the ATIIXP IDE controller.
+ */
+
+static u8 atiixp_ratemask(ide_drive_t *drive)
+{
+ u8 mode = 3;
+
+ if (!eighty_ninty_three(drive))
+ mode = min(mode, (u8)1);
+ return mode;
+}
+
+/**
+ * atiixp_dma_2_pio - return the PIO mode matching DMA
+ * @xfer_rate: transfer speed
+ *
+ * Returns the nearest equivalent PIO timing for the PIO or DMA
+ * mode requested by the controller.
+ */
+
+static u8 atiixp_dma_2_pio(u8 xfer_rate) {
+ switch(xfer_rate) {
+ case XFER_UDMA_6:
+ case XFER_UDMA_5:
+ case XFER_UDMA_4:
+ case XFER_UDMA_3:
+ case XFER_UDMA_2:
+ case XFER_UDMA_1:
+ case XFER_UDMA_0:
+ case XFER_MW_DMA_2:
+ case XFER_PIO_4:
+ return 4;
+ case XFER_MW_DMA_1:
+ case XFER_PIO_3:
+ return 3;
+ case XFER_SW_DMA_2:
+ case XFER_PIO_2:
+ return 2;
+ case XFER_MW_DMA_0:
+ case XFER_SW_DMA_1:
+ case XFER_SW_DMA_0:
+ case XFER_PIO_1:
+ case XFER_PIO_0:
+ case XFER_PIO_SLOW:
+ default:
+ return 0;
+ }
+}
+
+static int atiixp_ide_dma_host_on(ide_drive_t *drive)
+{
+ struct pci_dev *dev = drive->hwif->pci_dev;
+ unsigned long flags;
+ u16 tmp16;
+
+ spin_lock_irqsave(&ide_lock, flags);
+
+ pci_read_config_word(dev, ATIIXP_IDE_UDMA_CONTROL, &tmp16);
+ if (save_mdma_mode[drive->dn])
+ tmp16 &= ~(1 << drive->dn);
+ else
+ tmp16 |= (1 << drive->dn);
+ pci_write_config_word(dev, ATIIXP_IDE_UDMA_CONTROL, tmp16);
+
+ spin_unlock_irqrestore(&ide_lock, flags);
+
+ return __ide_dma_host_on(drive);
+}
+
+static int atiixp_ide_dma_host_off(ide_drive_t *drive)
+{
+ struct pci_dev *dev = drive->hwif->pci_dev;
+ unsigned long flags;
+ u16 tmp16;
+
+ spin_lock_irqsave(&ide_lock, flags);
+
+ pci_read_config_word(dev, ATIIXP_IDE_UDMA_CONTROL, &tmp16);
+ tmp16 &= ~(1 << drive->dn);
+ pci_write_config_word(dev, ATIIXP_IDE_UDMA_CONTROL, tmp16);
+
+ spin_unlock_irqrestore(&ide_lock, flags);
+
+ return __ide_dma_host_off(drive);
+}
+
+/**
+ * atiixp_tune_drive - tune a drive attached to a ATIIXP
+ * @drive: drive to tune
+ * @pio: desired PIO mode
+ *
+ * Set the interface PIO mode.
+ */
+
+static void atiixp_tuneproc(ide_drive_t *drive, u8 pio)
+{
+ struct pci_dev *dev = drive->hwif->pci_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(&ide_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(&ide_lock, flags);
+}
+
+/**
+ * atiixp_tune_chipset - tune a ATIIXP interface
+ * @drive: IDE drive to tune
+ * @xferspeed: speed to configure
+ *
+ * Set a ATIIXP interface channel to the desired speeds. This involves
+ * requires the right timing data into the ATIIXP configuration space
+ * then setting the drive parameters appropriately
+ */
+
+static int atiixp_speedproc(ide_drive_t *drive, u8 xferspeed)
+{
+ struct pci_dev *dev = drive->hwif->pci_dev;
+ unsigned long flags;
+ int timing_shift = (drive->dn & 2) ? 16 : 0 + (drive->dn & 1) ? 0 : 8;
+ u32 tmp32;
+ u16 tmp16;
+ u8 speed, pio;
+
+ speed = ide_rate_filter(atiixp_ratemask(drive), xferspeed);
+
+ spin_lock_irqsave(&ide_lock, flags);
+
+ save_mdma_mode[drive->dn] = 0;
+ 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);
+ } else {
+ if ((speed >= XFER_MW_DMA_0) && (speed <= XFER_MW_DMA_2)) {
+ save_mdma_mode[drive->dn] = speed;
+ pci_read_config_dword(dev, ATIIXP_IDE_MDMA_TIMING, &tmp32);
+ tmp32 &= ~(0xff << timing_shift);
+ tmp32 |= (mdma_timing[speed & 0x03].recover_width << timing_shift) |
+ (mdma_timing[speed & 0x03].command_width << (timing_shift + 4));
+ pci_write_config_dword(dev, ATIIXP_IDE_MDMA_TIMING, tmp32);
+ }
+ }
+
+ spin_unlock_irqrestore(&ide_lock, flags);
+
+ if (speed >= XFER_SW_DMA_0)
+ pio = atiixp_dma_2_pio(speed);
+ else
+ pio = speed - XFER_PIO_0;
+
+ atiixp_tuneproc(drive, pio);
+
+ return ide_config_drive_speed(drive, speed);
+}
+
+/**
+ * atiixp_config_drive_for_dma - configure drive for DMA
+ * @drive: IDE drive to configure
+ *
+ * Set up a ATIIXP interface channel for the best available speed.
+ * We prefer UDMA if it is available and then MWDMA. If DMA is
+ * not available we switch to PIO and return 0.
+ */
+
+static int atiixp_config_drive_for_dma(ide_drive_t *drive)
+{
+ u8 speed = ide_dma_speed(drive, atiixp_ratemask(drive));
+
+ /* If no DMA speed was available then disable DMA and use PIO. */
+ if (!speed) {
+ u8 tspeed = ide_get_best_pio_mode(drive, 255, 5, NULL);
+ speed = atiixp_dma_2_pio(XFER_PIO_0 + tspeed) + XFER_PIO_0;
+ }
+
+ (void) atiixp_speedproc(drive, speed);
+ return ide_dma_enable(drive);
+}
+
+/**
+ * atiixp_dma_check - set up an IDE device
+ * @drive: IDE drive to configure
+ *
+ * Set up the ATIIXP interface for the best available speed on this
+ * interface, preferring DMA to PIO.
+ */
+
+static int atiixp_dma_check(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct hd_driveid *id = drive->id;
+ u8 tspeed, speed;
+
+ drive->init_speed = 0;
+
+ if ((id->capability & 1) && drive->autodma) {
+
+ if (ide_use_dma(drive)) {
+ if (atiixp_config_drive_for_dma(drive))
+ return hwif->ide_dma_on(drive);
+ }
+
+ goto fast_ata_pio;
+
+ } else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+ tspeed = ide_get_best_pio_mode(drive, 255, 5, NULL);
+ speed = atiixp_dma_2_pio(XFER_PIO_0 + tspeed) + XFER_PIO_0;
+ hwif->speedproc(drive, speed);
+ return hwif->ide_dma_off_quietly(drive);
+ }
+ /* IORDY not supported */
+ return 0;
+}
+
+/**
+ * init_hwif_atiixp - fill in the hwif for the ATIIXP
+ * @hwif: IDE interface
+ *
+ * Set up the ide_hwif_t for the ATIIXP interface according to the
+ * capabilities of the hardware.
+ */
+
+static void __devinit init_hwif_atiixp(ide_hwif_t *hwif)
+{
+ if (!hwif->irq)
+ hwif->irq = hwif->channel ? 15 : 14;
+
+ hwif->autodma = 0;
+ hwif->tuneproc = &atiixp_tuneproc;
+ hwif->speedproc = &atiixp_speedproc;
+ hwif->drives[0].autotune = 1;
+ hwif->drives[1].autotune = 1;
+
+ if (!hwif->dma_base)
+ return;
+
+ hwif->atapi_dma = 1;
+ hwif->ultra_mask = 0x3f;
+ hwif->mwdma_mask = 0x06;
+ hwif->swdma_mask = 0x04;
+
+ /* FIXME: proper cable detection needed */
+ hwif->udma_four = 1;
+ hwif->ide_dma_host_on = &atiixp_ide_dma_host_on;
+ hwif->ide_dma_host_off = &atiixp_ide_dma_host_off;
+ hwif->ide_dma_check = &atiixp_dma_check;
+ if (!noautodma)
+ hwif->autodma = 1;
+
+ hwif->drives[1].autodma = hwif->autodma;
+ hwif->drives[0].autodma = hwif->autodma;
+}
+
+static ide_pci_device_t atiixp_pci_info[] __devinitdata = {
+ { /* 0 */
+ .name = "ATIIXP",
+ .init_hwif = init_hwif_atiixp,
+ .channels = 2,
+ .autodma = AUTODMA,
+ .enablebits = {{0x48,0x01,0x00}, {0x48,0x08,0x00}},
+ .bootable = ON_BOARD,
+ }
+};
+
+/**
+ * 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_setup_pci_device(dev, &atiixp_pci_info[id->driver_data]);
+}
+
+static struct pci_device_id atiixp_pci_tbl[] = {
+ { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP200_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP300_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP400_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { 0, },
+};
+MODULE_DEVICE_TABLE(pci, atiixp_pci_tbl);
+
+static struct pci_driver driver = {
+ .name = "ATIIXP_IDE",
+ .id_table = atiixp_pci_tbl,
+ .probe = atiixp_init_one,
+};
+
+static int atiixp_ide_init(void)
+{
+ return ide_pci_register_driver(&driver);
+}
+
+module_init(atiixp_ide_init);
+
+MODULE_AUTHOR("HUI YU");
+MODULE_DESCRIPTION("PCI driver module for ATI IXP IDE");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/pci/cmd640.c b/drivers/ide/pci/cmd640.c
new file mode 100644
index 000000000000..92a2b7caed58
--- /dev/null
+++ b/drivers/ide/pci/cmd640.c
@@ -0,0 +1,879 @@
+/*
+ * linux/drivers/ide/pci/cmd640.c Version 1.02 Sep 01, 1996
+ *
+ * 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)
+ */
+
+#undef REALLY_SLOW_IO /* most systems can safely undef this */
+#define CMD640_PREFETCH_MASKS 1
+
+//#define CMD640_DUMP_REGS
+
+#include <linux/config.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/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+/*
+ * This flag is set in ide.c by the parameter: ide0=cmd640_vlb
+ */
+int cmd640_vlb = 0;
+
+/*
+ * 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 */
+
+/*
+ * These are initialized to point at the devices we control
+ */
+static ide_hwif_t *cmd_hwif0, *cmd_hwif1;
+static ide_drive_t *cmd_drives[4];
+
+/*
+ * 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)
+{
+ u8 b;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ide_lock, flags);
+ b = __get_cmd640_reg(reg);
+ spin_unlock_irqrestore(&ide_lock, flags);
+ return b;
+}
+
+static void put_cmd640_reg(u16 reg, u8 val)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ide_lock, flags);
+ __put_cmd640_reg(reg,val);
+ spin_unlock_irqrestore(&ide_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(&ide_lock, flags);
+
+ outb_p(0x0a, 0x170 + IDE_SELECT_OFFSET); /* select drive0 */
+ udelay(100);
+ if ((inb_p(0x170 + IDE_SELECT_OFFSET) & 0x1f) != 0x0a) {
+ outb_p(0x1a, 0x170 + IDE_SELECT_OFFSET); /* select drive1 */
+ udelay(100);
+ if ((inb_p(0x170 + IDE_SELECT_OFFSET) & 0x1f) != 0x1a) {
+ spin_unlock_irqrestore(&ide_lock, flags);
+ return 0; /* nothing responded */
+ }
+ }
+ spin_unlock_irqrestore(&ide_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
+
+/*
+ * Check whether prefetch is on for a drive,
+ * and initialize the unmask flags for safe operation.
+ */
+static void __init check_prefetch (unsigned int index)
+{
+ ide_drive_t *drive = cmd_drives[index];
+ u8 b = get_cmd640_reg(prefetch_regs[index]);
+
+ if (b & prefetch_masks[index]) { /* is prefetch off? */
+ drive->no_unmask = 0;
+ drive->no_io_32bit = 1;
+ drive->io_32bit = 0;
+ } else {
+#if CMD640_PREFETCH_MASKS
+ drive->no_unmask = 1;
+ drive->unmask = 0;
+#endif
+ drive->no_io_32bit = 0;
+ }
+}
+
+/*
+ * Figure out which devices we control
+ */
+static void __init setup_device_ptrs (void)
+{
+ unsigned int i;
+
+ cmd_hwif0 = &ide_hwifs[0]; /* default, if not found below */
+ cmd_hwif1 = &ide_hwifs[1]; /* default, if not found below */
+ for (i = 0; i < MAX_HWIFS; i++) {
+ ide_hwif_t *hwif = &ide_hwifs[i];
+ if (hwif->chipset == ide_unknown || hwif->chipset == ide_forced) {
+ if (hwif->io_ports[IDE_DATA_OFFSET] == 0x1f0)
+ cmd_hwif0 = hwif;
+ else if (hwif->io_ports[IDE_DATA_OFFSET] == 0x170)
+ cmd_hwif1 = hwif;
+ }
+ }
+ cmd_drives[0] = &cmd_hwif0->drives[0];
+ cmd_drives[1] = &cmd_hwif0->drives[1];
+ cmd_drives[2] = &cmd_hwif1->drives[0];
+ cmd_drives[3] = &cmd_hwif1->drives[1];
+}
+
+#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
+
+/*
+ * Sets prefetch mode for a drive.
+ */
+static void set_prefetch_mode (unsigned int index, int mode)
+{
+ ide_drive_t *drive = cmd_drives[index];
+ int reg = prefetch_regs[index];
+ u8 b;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ide_lock, flags);
+ b = __get_cmd640_reg(reg);
+ if (mode) { /* want prefetch on? */
+#if CMD640_PREFETCH_MASKS
+ drive->no_unmask = 1;
+ drive->unmask = 0;
+#endif
+ drive->no_io_32bit = 0;
+ b &= ~prefetch_masks[index]; /* enable prefetch */
+ } else {
+ drive->no_unmask = 0;
+ drive->no_io_32bit = 1;
+ drive->io_32bit = 0;
+ b |= prefetch_masks[index]; /* disable prefetch */
+ }
+ __put_cmd640_reg(reg, b);
+ spin_unlock_irqrestore(&ide_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
+ */
+inline static u8 pack_nibbles (u8 upper, u8 lower)
+{
+ return ((upper & 0x0f) << 4) | (lower & 0x0f);
+}
+
+/*
+ * This routine retrieves the initial drive timings from the chipset.
+ */
+static void __init retrieve_drive_counts (unsigned int index)
+{
+ u8 b;
+
+ /*
+ * Get the internal setup timing, and convert to clock count
+ */
+ b = get_cmd640_reg(arttim_regs[index]) & ~0x3f;
+ switch (b) {
+ case 0x00: b = 4; break;
+ case 0x80: b = 3; break;
+ case 0x40: b = 2; break;
+ default: b = 5; break;
+ }
+ setup_counts[index] = b;
+
+ /*
+ * Get the active/recovery counts
+ */
+ b = get_cmd640_reg(drwtim_regs[index]);
+ active_counts[index] = (b >> 4) ? (b >> 4) : 0x10;
+ recovery_counts[index] = (b & 0x0f) ? (b & 0x0f) : 0x10;
+}
+
+
+/*
+ * 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 (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) {
+ unsigned int mate;
+ if (cmd_drives[mate = index ^ 1]->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(&ide_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(&ide_lock, flags);
+}
+
+/*
+ * Set a specific pio_mode for a drive
+ */
+static void cmd640_set_mode (unsigned int index, u8 pio_mode, unsigned int cycle_time)
+{
+ int setup_time, active_time, recovery_time, clock_time;
+ u8 setup_count, active_count, recovery_count, recovery_count2, cycle_count;
+ int bus_speed = system_bus_clock();
+
+ if (pio_mode > 5)
+ pio_mode = 5;
+ setup_time = ide_pio_timings[pio_mode].setup_time;
+ active_time = ide_pio_timings[pio_mode].active_time;
+ recovery_time = cycle_time - (setup_time + active_time);
+ clock_time = 1000 / bus_speed;
+ cycle_count = (cycle_time + clock_time - 1) / clock_time;
+
+ setup_count = (setup_time + clock_time - 1) / clock_time;
+
+ active_count = (active_time + clock_time - 1) / clock_time;
+ if (active_count < 2)
+ active_count = 2; /* minimum allowed by cmd640 */
+
+ recovery_count = (recovery_time + clock_time - 1) / 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 (index);
+}
+
+/*
+ * Drive PIO mode selection:
+ */
+static void cmd640_tune_drive (ide_drive_t *drive, u8 mode_wanted)
+{
+ u8 b;
+ ide_pio_data_t d;
+ unsigned int index = 0;
+
+ while (drive != cmd_drives[index]) {
+ if (++index > 3) {
+ printk("%s: bad news in cmd640_tune_drive\n", drive->name);
+ return;
+ }
+ }
+ switch (mode_wanted) {
+ case 6: /* set fast-devsel off */
+ case 7: /* set fast-devsel on */
+ mode_wanted &= 1;
+ b = get_cmd640_reg(CNTRL) & ~0x27;
+ if (mode_wanted)
+ b |= 0x27;
+ put_cmd640_reg(CNTRL, b);
+ printk("%s: %sabled cmd640 fast host timing (devsel)\n", drive->name, mode_wanted ? "en" : "dis");
+ return;
+
+ case 8: /* set prefetch off */
+ case 9: /* set prefetch on */
+ mode_wanted &= 1;
+ set_prefetch_mode(index, mode_wanted);
+ printk("%s: %sabled cmd640 prefetch\n", drive->name, mode_wanted ? "en" : "dis");
+ return;
+ }
+
+ (void) ide_get_best_pio_mode (drive, mode_wanted, 5, &d);
+ cmd640_set_mode (index, d.pio_mode, d.cycle_time);
+
+ printk ("%s: selected cmd640 PIO mode%d (%dns)%s",
+ drive->name,
+ d.pio_mode,
+ d.cycle_time,
+ d.overridden ? " (overriding vendor mode)" : "");
+ display_clocks(index);
+ return;
+}
+
+#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
+
+static int pci_conf1(void)
+{
+ u32 tmp;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ide_lock, flags);
+ outb(0x01, 0xCFB);
+ tmp = inl(0xCF8);
+ outl(0x80000000, 0xCF8);
+ if (inl(0xCF8) == 0x80000000) {
+ outl(tmp, 0xCF8);
+ spin_unlock_irqrestore(&ide_lock, flags);
+ return 1;
+ }
+ outl(tmp, 0xCF8);
+ spin_unlock_irqrestore(&ide_lock, flags);
+ return 0;
+}
+
+static int pci_conf2(void)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ide_lock, flags);
+ outb(0x00, 0xCFB);
+ outb(0x00, 0xCF8);
+ outb(0x00, 0xCFA);
+ if (inb(0xCF8) == 0x00 && inb(0xCF8) == 0x00) {
+ spin_unlock_irqrestore(&ide_lock, flags);
+ return 1;
+ }
+ spin_unlock_irqrestore(&ide_lock, flags);
+ return 0;
+}
+
+/*
+ * Probe for a cmd640 chipset, and initialize it if found. Called from ide.c
+ */
+int __init ide_probe_for_cmd640x (void)
+{
+#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
+ int second_port_toggled = 0;
+#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
+ int second_port_cmd640 = 0;
+ const char *bus_type, *port2;
+ unsigned int index;
+ u8 b, cfr;
+
+ 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;
+ }
+
+ /*
+ * Initialize data for primary port
+ */
+ setup_device_ptrs ();
+ printk("%s: buggy cmd640%c interface on %s, config=0x%02x\n",
+ cmd_hwif0->name, 'a' + cmd640_chip_version - 1, bus_type, cfr);
+ cmd_hwif0->chipset = ide_cmd640;
+#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
+ cmd_hwif0->tuneproc = &cmd640_tune_drive;
+#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
+
+ /*
+ * 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);
+
+ /*
+ * Try to enable the secondary interface, if not already enabled
+ */
+ if (cmd_hwif1->noprobe) {
+ port2 = "not probed";
+ } else {
+ b = get_cmd640_reg(CNTRL);
+ 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;
+#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
+ second_port_toggled = 1;
+#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
+ 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) {
+ cmd_hwif0->serialized = 1;
+ cmd_hwif1->serialized = 1;
+ cmd_hwif1->chipset = ide_cmd640;
+ cmd_hwif0->mate = cmd_hwif1;
+ cmd_hwif1->mate = cmd_hwif0;
+ cmd_hwif1->channel = 1;
+#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
+ cmd_hwif1->tuneproc = &cmd640_tune_drive;
+#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
+ }
+ printk(KERN_INFO "%s: %sserialized, secondary interface %s\n", cmd_hwif1->name,
+ cmd_hwif0->serialized ? "" : "not ", port2);
+
+ /*
+ * Establish initial timings/prefetch for all drives.
+ * Do not unnecessarily disturb any prior BIOS setup of these.
+ */
+ for (index = 0; index < (2 + (second_port_cmd640 << 1)); index++) {
+ ide_drive_t *drive = cmd_drives[index];
+#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
+ if (drive->autotune || ((index > 1) && second_port_toggled)) {
+ /*
+ * Reset timing to the slowest speed and turn off prefetch.
+ * This way, the drive identify code has a better chance.
+ */
+ setup_counts [index] = 4; /* max possible */
+ active_counts [index] = 16; /* max possible */
+ recovery_counts [index] = 16; /* max possible */
+ program_drive_counts (index);
+ set_prefetch_mode (index, 0);
+ printk("cmd640: drive%d timings/prefetch cleared\n", index);
+ } else {
+ /*
+ * Record timings/prefetch without changing them.
+ * This preserves any prior BIOS setup.
+ */
+ retrieve_drive_counts (index);
+ check_prefetch (index);
+ printk("cmd640: drive%d timings/prefetch(%s) preserved",
+ index, drive->no_io_32bit ? "off" : "on");
+ display_clocks(index);
+ }
+#else
+ /*
+ * Set the drive unmask flags to match the prefetch setting
+ */
+ check_prefetch (index);
+ printk("cmd640: drive%d timings/prefetch(%s) preserved\n",
+ index, drive->no_io_32bit ? "off" : "on");
+#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
+ }
+
+#ifdef CMD640_DUMP_REGS
+ cmd640_dump_regs();
+#endif
+ return 1;
+}
+
diff --git a/drivers/ide/pci/cmd64x.c b/drivers/ide/pci/cmd64x.c
new file mode 100644
index 000000000000..3de9ab897e42
--- /dev/null
+++ b/drivers/ide/pci/cmd64x.c
@@ -0,0 +1,821 @@
+/* $Id: cmd64x.c,v 1.21 2000/01/30 23:23:16
+ *
+ * linux/drivers/ide/pci/cmd64x.c Version 1.30 Sept 10, 2002
+ *
+ * cmd64x.c: Enable interrupts at initialization time on Ultra/PCI machines.
+ * Note, this driver is not used at all on other systems because
+ * there the "BIOS" has done all of the following already.
+ * Due to massive hardware bugs, UltraDMA is only supported
+ * on the 646U2 and not on the 646U.
+ *
+ * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be)
+ * Copyright (C) 1998 David S. Miller (davem@redhat.com)
+ *
+ * Copyright (C) 1999-2002 Andre Hedrick <andre@linux-ide.org>
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#define DISPLAY_CMD64X_TIMINGS
+
+#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 0x02
+#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 ARTTIM23_INTR_CH1 0x10
+#define ARTTIM2 0x57
+#define ARTTIM3 0x57
+#define DRWTIM23 0x58
+#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 MRDMODE_BLK_CH0 0x10
+#define MRDMODE_BLK_CH1 0x20
+#define BMIDESR0 0x72
+#define UDIDETCR0 0x73
+#define DTPR0 0x74
+#define BMIDECR1 0x78
+#define BMIDECSR 0x79
+#define BMIDESR1 0x7A
+#define UDIDETCR1 0x7B
+#define DTPR1 0x7C
+
+#if defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 cmd64x_proc = 0;
+
+#define CMD_MAX_DEVS 5
+
+static struct pci_dev *cmd_devs[CMD_MAX_DEVS];
+static int n_cmd_devs;
+
+static char * print_cmd64x_get_info (char *buf, struct pci_dev *dev, int index)
+{
+ char *p = buf;
+
+ u8 reg53 = 0, reg54 = 0, reg55 = 0, reg56 = 0; /* primary */
+ u8 reg57 = 0, reg58 = 0, reg5b; /* secondary */
+ u8 reg72 = 0, reg73 = 0; /* primary */
+ u8 reg7a = 0, reg7b = 0; /* secondary */
+ u8 reg50 = 0, reg71 = 0; /* extra */
+
+ p += sprintf(p, "\nController: %d\n", index);
+ p += sprintf(p, "CMD%x Chipset.\n", dev->device);
+ (void) pci_read_config_byte(dev, CFR, &reg50);
+ (void) pci_read_config_byte(dev, ARTTIM0, &reg53);
+ (void) pci_read_config_byte(dev, DRWTIM0, &reg54);
+ (void) pci_read_config_byte(dev, ARTTIM1, &reg55);
+ (void) pci_read_config_byte(dev, DRWTIM1, &reg56);
+ (void) pci_read_config_byte(dev, ARTTIM2, &reg57);
+ (void) pci_read_config_byte(dev, DRWTIM2, &reg58);
+ (void) pci_read_config_byte(dev, DRWTIM3, &reg5b);
+ (void) pci_read_config_byte(dev, MRDMODE, &reg71);
+ (void) pci_read_config_byte(dev, BMIDESR0, &reg72);
+ (void) pci_read_config_byte(dev, UDIDETCR0, &reg73);
+ (void) pci_read_config_byte(dev, BMIDESR1, &reg7a);
+ (void) pci_read_config_byte(dev, UDIDETCR1, &reg7b);
+
+ p += sprintf(p, "--------------- Primary Channel "
+ "---------------- Secondary Channel "
+ "-------------\n");
+ p += sprintf(p, " %sabled "
+ " %sabled\n",
+ (reg72&0x80)?"dis":" en",
+ (reg7a&0x80)?"dis":" en");
+ p += sprintf(p, "--------------- drive0 "
+ "--------- drive1 -------- drive0 "
+ "---------- drive1 ------\n");
+ p += sprintf(p, "DMA enabled: %s %s"
+ " %s %s\n",
+ (reg72&0x20)?"yes":"no ", (reg72&0x40)?"yes":"no ",
+ (reg7a&0x20)?"yes":"no ", (reg7a&0x40)?"yes":"no ");
+
+ p += sprintf(p, "DMA Mode: %s(%s) %s(%s)",
+ (reg72&0x20)?((reg73&0x01)?"UDMA":" DMA"):" PIO",
+ (reg72&0x20)?(
+ ((reg73&0x30)==0x30)?(((reg73&0x35)==0x35)?"3":"0"):
+ ((reg73&0x20)==0x20)?(((reg73&0x25)==0x25)?"3":"1"):
+ ((reg73&0x10)==0x10)?(((reg73&0x15)==0x15)?"4":"2"):
+ ((reg73&0x00)==0x00)?(((reg73&0x05)==0x05)?"5":"2"):
+ "X"):"?",
+ (reg72&0x40)?((reg73&0x02)?"UDMA":" DMA"):" PIO",
+ (reg72&0x40)?(
+ ((reg73&0xC0)==0xC0)?(((reg73&0xC5)==0xC5)?"3":"0"):
+ ((reg73&0x80)==0x80)?(((reg73&0x85)==0x85)?"3":"1"):
+ ((reg73&0x40)==0x40)?(((reg73&0x4A)==0x4A)?"4":"2"):
+ ((reg73&0x00)==0x00)?(((reg73&0x0A)==0x0A)?"5":"2"):
+ "X"):"?");
+ p += sprintf(p, " %s(%s) %s(%s)\n",
+ (reg7a&0x20)?((reg7b&0x01)?"UDMA":" DMA"):" PIO",
+ (reg7a&0x20)?(
+ ((reg7b&0x30)==0x30)?(((reg7b&0x35)==0x35)?"3":"0"):
+ ((reg7b&0x20)==0x20)?(((reg7b&0x25)==0x25)?"3":"1"):
+ ((reg7b&0x10)==0x10)?(((reg7b&0x15)==0x15)?"4":"2"):
+ ((reg7b&0x00)==0x00)?(((reg7b&0x05)==0x05)?"5":"2"):
+ "X"):"?",
+ (reg7a&0x40)?((reg7b&0x02)?"UDMA":" DMA"):" PIO",
+ (reg7a&0x40)?(
+ ((reg7b&0xC0)==0xC0)?(((reg7b&0xC5)==0xC5)?"3":"0"):
+ ((reg7b&0x80)==0x80)?(((reg7b&0x85)==0x85)?"3":"1"):
+ ((reg7b&0x40)==0x40)?(((reg7b&0x4A)==0x4A)?"4":"2"):
+ ((reg7b&0x00)==0x00)?(((reg7b&0x0A)==0x0A)?"5":"2"):
+ "X"):"?" );
+ p += sprintf(p, "PIO Mode: %s %s"
+ " %s %s\n",
+ "?", "?", "?", "?");
+ p += sprintf(p, " %s %s\n",
+ (reg50 & CFR_INTR_CH0) ? "interrupting" : "polling ",
+ (reg57 & ARTTIM23_INTR_CH1) ? "interrupting" : "polling");
+ p += sprintf(p, " %s %s\n",
+ (reg71 & MRDMODE_INTR_CH0) ? "pending" : "clear ",
+ (reg71 & MRDMODE_INTR_CH1) ? "pending" : "clear");
+ p += sprintf(p, " %s %s\n",
+ (reg71 & MRDMODE_BLK_CH0) ? "blocked" : "enabled",
+ (reg71 & MRDMODE_BLK_CH1) ? "blocked" : "enabled");
+
+ return (char *)p;
+}
+
+static int cmd64x_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+ char *p = buffer;
+ int i;
+
+ p += sprintf(p, "\n");
+ for (i = 0; i < n_cmd_devs; i++) {
+ struct pci_dev *dev = cmd_devs[i];
+ p = print_cmd64x_get_info(p, dev, i);
+ }
+ return p-buffer; /* => must be less than 4k! */
+}
+
+#endif /* defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+/*
+ * Registers and masks for easy access by drive index:
+ */
+#if 0
+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};
+#endif
+
+/*
+ * This routine writes the prepared setup/active/recovery counts
+ * for a drive into the cmd646 chipset registers to active them.
+ */
+static void program_drive_counts (ide_drive_t *drive, int setup_count, int active_count, int recovery_count)
+{
+ unsigned long flags;
+ struct pci_dev *dev = HWIF(drive)->pci_dev;
+ ide_drive_t *drives = HWIF(drive)->drives;
+ u8 temp_b;
+ static const u8 setup_counts[] = {0x40, 0x40, 0x40, 0x80, 0, 0xc0};
+ static const u8 recovery_counts[] =
+ {15, 15, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 0};
+ static const u8 arttim_regs[2][2] = {
+ { ARTTIM0, ARTTIM1 },
+ { ARTTIM23, ARTTIM23 }
+ };
+ static const u8 drwtim_regs[2][2] = {
+ { DRWTIM0, DRWTIM1 },
+ { DRWTIM2, DRWTIM3 }
+ };
+ int channel = (int) HWIF(drive)->channel;
+ int slave = (drives != drive); /* Is this really the best way to determine this?? */
+
+ cmdprintk("program_drive_count parameters = s(%d),a(%d),r(%d),p(%d)\n",
+ setup_count, active_count, recovery_count, drive->present);
+ /*
+ * Set up address setup count registers.
+ * Primary interface has individual count/timing registers for
+ * each drive. Secondary interface has one common set of registers,
+ * for address setup so we merge these timings, using the slowest
+ * value.
+ */
+ if (channel) {
+ drive->drive_data = setup_count;
+ setup_count = max(drives[0].drive_data,
+ drives[1].drive_data);
+ cmdprintk("Secondary interface, setup_count = %d\n",
+ setup_count);
+ }
+
+ /*
+ * Convert values to internal chipset representation
+ */
+ setup_count = (setup_count > 5) ? 0xc0 : (int) setup_counts[setup_count];
+ active_count &= 0xf; /* Remember, max value is 16 */
+ recovery_count = (int) recovery_counts[recovery_count];
+
+ cmdprintk("Final values = %d,%d,%d\n",
+ setup_count, active_count, recovery_count);
+
+ /*
+ * Now that everything is ready, program the new timings
+ */
+ local_irq_save(flags);
+ /*
+ * Program the address_setup clocks into ARTTIM reg,
+ * and then the active/recovery counts into the DRWTIM reg
+ */
+ (void) pci_read_config_byte(dev, arttim_regs[channel][slave], &temp_b);
+ (void) pci_write_config_byte(dev, arttim_regs[channel][slave],
+ ((u8) setup_count) | (temp_b & 0x3f));
+ (void) pci_write_config_byte(dev, drwtim_regs[channel][slave],
+ (u8) ((active_count << 4) | recovery_count));
+ cmdprintk ("Write %x to %x\n",
+ ((u8) setup_count) | (temp_b & 0x3f),
+ arttim_regs[channel][slave]);
+ cmdprintk ("Write %x to %x\n",
+ (u8) ((active_count << 4) | recovery_count),
+ drwtim_regs[channel][slave]);
+ local_irq_restore(flags);
+}
+
+/*
+ * Attempts to set the interface PIO mode.
+ * The preferred method of selecting PIO modes (e.g. mode 4) is
+ * "echo 'piomode:4' > /proc/ide/hdx/settings". Special cases are
+ * 8: prefetch off, 9: prefetch on, 255: auto-select best mode.
+ * Called with 255 at boot time.
+ */
+
+static void cmd64x_tuneproc (ide_drive_t *drive, u8 mode_wanted)
+{
+ int setup_time, active_time, recovery_time;
+ int clock_time, pio_mode, cycle_time;
+ u8 recovery_count2, cycle_count;
+ int setup_count, active_count, recovery_count;
+ int bus_speed = system_bus_clock();
+ /*byte b;*/
+ ide_pio_data_t d;
+
+ switch (mode_wanted) {
+ case 8: /* set prefetch off */
+ case 9: /* set prefetch on */
+ mode_wanted &= 1;
+ /*set_prefetch_mode(index, mode_wanted);*/
+ cmdprintk("%s: %sabled cmd640 prefetch\n",
+ drive->name, mode_wanted ? "en" : "dis");
+ return;
+ }
+
+ mode_wanted = ide_get_best_pio_mode (drive, mode_wanted, 5, &d);
+ pio_mode = d.pio_mode;
+ cycle_time = d.cycle_time;
+
+ /*
+ * I copied all this complicated stuff from cmd640.c and made a few
+ * minor changes. For now I am just going to pray that it is correct.
+ */
+ if (pio_mode > 5)
+ pio_mode = 5;
+ setup_time = ide_pio_timings[pio_mode].setup_time;
+ active_time = ide_pio_timings[pio_mode].active_time;
+ recovery_time = cycle_time - (setup_time + active_time);
+ clock_time = 1000 / bus_speed;
+ cycle_count = (cycle_time + clock_time - 1) / clock_time;
+
+ setup_count = (setup_time + clock_time - 1) / clock_time;
+
+ active_count = (active_time + clock_time - 1) / clock_time;
+
+ recovery_count = (recovery_time + clock_time - 1) / clock_time;
+ recovery_count2 = cycle_count - (setup_count + active_count);
+ if (recovery_count2 > recovery_count)
+ recovery_count = recovery_count2;
+ if (recovery_count > 16) {
+ active_count += recovery_count - 16;
+ recovery_count = 16;
+ }
+ if (active_count > 16)
+ active_count = 16; /* maximum allowed by cmd646 */
+
+ /*
+ * 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, setup_count, active_count, recovery_count);
+
+ cmdprintk("%s: selected cmd646 PIO mode%d : %d (%dns)%s, "
+ "clocks=%d/%d/%d\n",
+ drive->name, pio_mode, mode_wanted, cycle_time,
+ d.overridden ? " (overriding vendor mode)" : "",
+ setup_count, active_count, recovery_count);
+}
+
+static u8 cmd64x_ratemask (ide_drive_t *drive)
+{
+ struct pci_dev *dev = HWIF(drive)->pci_dev;
+ u8 mode = 0;
+
+ switch(dev->device) {
+ case PCI_DEVICE_ID_CMD_649:
+ mode = 3;
+ break;
+ case PCI_DEVICE_ID_CMD_648:
+ mode = 2;
+ break;
+ case PCI_DEVICE_ID_CMD_643:
+ return 0;
+
+ case PCI_DEVICE_ID_CMD_646:
+ {
+ unsigned int class_rev = 0;
+ pci_read_config_dword(dev,
+ PCI_CLASS_REVISION, &class_rev);
+ class_rev &= 0xff;
+ /*
+ * 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.
+ */
+ switch(class_rev) {
+ case 0x07:
+ case 0x05:
+ return 1;
+ case 0x03:
+ case 0x01:
+ default:
+ return 0;
+ }
+ }
+ }
+ if (!eighty_ninty_three(drive))
+ mode = min(mode, (u8)1);
+ return mode;
+}
+
+static void config_cmd64x_chipset_for_pio (ide_drive_t *drive, u8 set_speed)
+{
+ u8 speed = 0x00;
+ u8 set_pio = ide_get_best_pio_mode(drive, 4, 5, NULL);
+
+ cmd64x_tuneproc(drive, set_pio);
+ speed = XFER_PIO_0 + set_pio;
+ if (set_speed)
+ (void) ide_config_drive_speed(drive, speed);
+}
+
+static void config_chipset_for_pio (ide_drive_t *drive, u8 set_speed)
+{
+ config_cmd64x_chipset_for_pio(drive, set_speed);
+}
+
+static int cmd64x_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = hwif->pci_dev;
+
+ u8 unit = (drive->select.b.unit & 0x01);
+ u8 regU = 0, pciU = (hwif->channel) ? UDIDETCR1 : UDIDETCR0;
+ u8 regD = 0, pciD = (hwif->channel) ? BMIDESR1 : BMIDESR0;
+
+ u8 speed = ide_rate_filter(cmd64x_ratemask(drive), xferspeed);
+
+ if (speed > XFER_PIO_4) {
+ (void) pci_read_config_byte(dev, pciD, &regD);
+ (void) pci_read_config_byte(dev, pciU, &regU);
+ regD &= ~(unit ? 0x40 : 0x20);
+ regU &= ~(unit ? 0xCA : 0x35);
+ (void) pci_write_config_byte(dev, pciD, regD);
+ (void) pci_write_config_byte(dev, pciU, regU);
+ (void) pci_read_config_byte(dev, pciD, &regD);
+ (void) pci_read_config_byte(dev, pciU, &regU);
+ }
+
+ 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: regD |= (unit ? 0x40 : 0x10); break;
+ case XFER_MW_DMA_1: regD |= (unit ? 0x80 : 0x20); break;
+ case XFER_MW_DMA_0: regD |= (unit ? 0xC0 : 0x30); break;
+ case XFER_SW_DMA_2: regD |= (unit ? 0x40 : 0x10); break;
+ case XFER_SW_DMA_1: regD |= (unit ? 0x80 : 0x20); break;
+ case XFER_SW_DMA_0: regD |= (unit ? 0xC0 : 0x30); break;
+ case XFER_PIO_4: cmd64x_tuneproc(drive, 4); break;
+ case XFER_PIO_3: cmd64x_tuneproc(drive, 3); break;
+ case XFER_PIO_2: cmd64x_tuneproc(drive, 2); break;
+ case XFER_PIO_1: cmd64x_tuneproc(drive, 1); break;
+ case XFER_PIO_0: cmd64x_tuneproc(drive, 0); break;
+
+ default:
+ return 1;
+ }
+
+ if (speed > XFER_PIO_4) {
+ (void) pci_write_config_byte(dev, pciU, regU);
+ regD |= (unit ? 0x40 : 0x20);
+ (void) pci_write_config_byte(dev, pciD, regD);
+ }
+
+ return (ide_config_drive_speed(drive, speed));
+}
+
+static int config_chipset_for_dma (ide_drive_t *drive)
+{
+ u8 speed = ide_dma_speed(drive, cmd64x_ratemask(drive));
+
+ config_chipset_for_pio(drive, !speed);
+
+ if (!speed)
+ return 0;
+
+ if(ide_set_xfer_rate(drive, speed))
+ return 0;
+
+ if (!drive->init_speed)
+ drive->init_speed = speed;
+
+ return ide_dma_enable(drive);
+}
+
+static int cmd64x_config_drive_for_dma (ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct hd_driveid *id = drive->id;
+
+ if ((id != NULL) && ((id->capability & 1) != 0) && drive->autodma) {
+
+ if (ide_use_dma(drive)) {
+ if (config_chipset_for_dma(drive))
+ return hwif->ide_dma_on(drive);
+ }
+
+ goto fast_ata_pio;
+
+ } else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+ config_chipset_for_pio(drive, 1);
+ return hwif->ide_dma_off_quietly(drive);
+ }
+ /* IORDY not supported */
+ return 0;
+}
+
+static int cmd64x_alt_dma_status (struct pci_dev *dev)
+{
+ switch(dev->device) {
+ case PCI_DEVICE_ID_CMD_648:
+ case PCI_DEVICE_ID_CMD_649:
+ return 1;
+ default:
+ break;
+ }
+ return 0;
+}
+
+static int cmd64x_ide_dma_end (ide_drive_t *drive)
+{
+ u8 dma_stat = 0, dma_cmd = 0;
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = hwif->pci_dev;
+
+ drive->waiting_for_dma = 0;
+ /* read DMA command state */
+ dma_cmd = hwif->INB(hwif->dma_command);
+ /* stop DMA */
+ hwif->OUTB((dma_cmd & ~1), hwif->dma_command);
+ /* get DMA status */
+ dma_stat = hwif->INB(hwif->dma_status);
+ /* clear the INTR & ERROR bits */
+ hwif->OUTB(dma_stat|6, hwif->dma_status);
+ if (cmd64x_alt_dma_status(dev)) {
+ u8 dma_intr = 0;
+ u8 dma_mask = (hwif->channel) ? ARTTIM23_INTR_CH1 :
+ CFR_INTR_CH0;
+ u8 dma_reg = (hwif->channel) ? ARTTIM2 : CFR;
+ (void) pci_read_config_byte(dev, dma_reg, &dma_intr);
+ /* clear the INTR bit */
+ (void) pci_write_config_byte(dev, dma_reg, dma_intr|dma_mask);
+ }
+ /* purge DMA mappings */
+ ide_destroy_dmatable(drive);
+ /* verify good DMA status */
+ return (dma_stat & 7) != 4;
+}
+
+static int cmd64x_ide_dma_test_irq (ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = hwif->pci_dev;
+ u8 dma_alt_stat = 0, mask = (hwif->channel) ? MRDMODE_INTR_CH1 :
+ MRDMODE_INTR_CH0;
+ u8 dma_stat = hwif->INB(hwif->dma_status);
+
+ (void) pci_read_config_byte(dev, MRDMODE, &dma_alt_stat);
+#ifdef DEBUG
+ printk("%s: dma_stat: 0x%02x dma_alt_stat: "
+ "0x%02x mask: 0x%02x\n", drive->name,
+ dma_stat, dma_alt_stat, mask);
+#endif
+ if (!(dma_alt_stat & mask))
+ return 0;
+
+ /* return 1 if INTR asserted */
+ if ((dma_stat & 4) == 4)
+ return 1;
+
+ return 0;
+}
+
+/*
+ * ASUS P55T2P4D with CMD646 chipset revision 0x01 requires the old
+ * event order for DMA transfers.
+ */
+
+static int cmd646_1_ide_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 = hwif->INB(hwif->dma_status);
+ /* read DMA command state */
+ dma_cmd = hwif->INB(hwif->dma_command);
+ /* stop DMA */
+ hwif->OUTB((dma_cmd & ~1), hwif->dma_command);
+ /* clear the INTR & ERROR bits */
+ hwif->OUTB(dma_stat|6, hwif->dma_status);
+ /* and free any DMA resources */
+ ide_destroy_dmatable(drive);
+ /* verify good DMA status */
+ return (dma_stat & 7) != 4;
+}
+
+static unsigned int __devinit init_chipset_cmd64x(struct pci_dev *dev, const char *name)
+{
+ u32 class_rev = 0;
+ u8 mrdmode = 0;
+
+ pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
+ class_rev &= 0xff;
+
+#ifdef __i386__
+ if (dev->resource[PCI_ROM_RESOURCE].start) {
+ pci_write_config_byte(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
+ printk(KERN_INFO "%s: ROM enabled at 0x%08lx\n", name, dev->resource[PCI_ROM_RESOURCE].start);
+ }
+#endif
+
+ switch(dev->device) {
+ case PCI_DEVICE_ID_CMD_643:
+ break;
+ case PCI_DEVICE_ID_CMD_646:
+ printk(KERN_INFO "%s: chipset revision 0x%02X, ", name, class_rev);
+ switch(class_rev) {
+ case 0x07:
+ case 0x05:
+ printk("UltraDMA Capable");
+ break;
+ case 0x03:
+ printk("MultiWord DMA Force Limited");
+ break;
+ case 0x01:
+ default:
+ printk("MultiWord DMA Limited, IRQ workaround enabled");
+ break;
+ }
+ printk("\n");
+ break;
+ case PCI_DEVICE_ID_CMD_648:
+ case PCI_DEVICE_ID_CMD_649:
+ break;
+ default:
+ break;
+ }
+
+ /* 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 */
+
+ /* Setup interrupts. */
+ (void) pci_read_config_byte(dev, MRDMODE, &mrdmode);
+ mrdmode &= ~(0x30);
+ (void) pci_write_config_byte(dev, MRDMODE, mrdmode);
+
+ /* Use MEMORY READ LINE for reads.
+ * NOTE: Although not mentioned in the PCI0646U specs,
+ * these bits are write only and won't be read
+ * back as set or not. The PCI0646U2 specs clarify
+ * this point.
+ */
+ (void) pci_write_config_byte(dev, MRDMODE, mrdmode | 0x02);
+
+ /* Set reasonable active/recovery/address-setup values. */
+ (void) pci_write_config_byte(dev, ARTTIM0, 0x40);
+ (void) pci_write_config_byte(dev, DRWTIM0, 0x3f);
+ (void) pci_write_config_byte(dev, ARTTIM1, 0x40);
+ (void) pci_write_config_byte(dev, DRWTIM1, 0x3f);
+#ifdef __i386__
+ (void) pci_write_config_byte(dev, ARTTIM23, 0x1c);
+#else
+ (void) pci_write_config_byte(dev, ARTTIM23, 0x5c);
+#endif
+ (void) pci_write_config_byte(dev, DRWTIM23, 0x3f);
+ (void) pci_write_config_byte(dev, DRWTIM3, 0x3f);
+#ifdef CONFIG_PPC
+ (void) pci_write_config_byte(dev, UDIDETCR0, 0xf0);
+#endif /* CONFIG_PPC */
+
+#if defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS)
+
+ cmd_devs[n_cmd_devs++] = dev;
+
+ if (!cmd64x_proc) {
+ cmd64x_proc = 1;
+ ide_pci_create_host_proc("cmd64x", cmd64x_get_info);
+ }
+#endif /* DISPLAY_CMD64X_TIMINGS && CONFIG_PROC_FS */
+
+ return 0;
+}
+
+static unsigned int __devinit ata66_cmd64x(ide_hwif_t *hwif)
+{
+ u8 ata66 = 0, mask = (hwif->channel) ? 0x02 : 0x01;
+
+ switch(hwif->pci_dev->device) {
+ case PCI_DEVICE_ID_CMD_643:
+ case PCI_DEVICE_ID_CMD_646:
+ return ata66;
+ default:
+ break;
+ }
+ pci_read_config_byte(hwif->pci_dev, BMIDECSR, &ata66);
+ return (ata66 & mask) ? 1 : 0;
+}
+
+static void __devinit init_hwif_cmd64x(ide_hwif_t *hwif)
+{
+ struct pci_dev *dev = hwif->pci_dev;
+ unsigned int class_rev;
+
+ hwif->autodma = 0;
+ pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
+ class_rev &= 0xff;
+
+ hwif->tuneproc = &cmd64x_tuneproc;
+ hwif->speedproc = &cmd64x_tune_chipset;
+
+ if (!hwif->dma_base) {
+ hwif->drives[0].autotune = 1;
+ hwif->drives[1].autotune = 1;
+ return;
+ }
+
+ hwif->atapi_dma = 1;
+
+ hwif->ultra_mask = 0x3f;
+ hwif->mwdma_mask = 0x07;
+ hwif->swdma_mask = 0x07;
+
+ if (dev->device == PCI_DEVICE_ID_CMD_643)
+ hwif->ultra_mask = 0x80;
+ if (dev->device == PCI_DEVICE_ID_CMD_646)
+ hwif->ultra_mask = (class_rev > 0x04) ? 0x07 : 0x80;
+ if (dev->device == PCI_DEVICE_ID_CMD_648)
+ hwif->ultra_mask = 0x1f;
+
+ hwif->ide_dma_check = &cmd64x_config_drive_for_dma;
+ if (!(hwif->udma_four))
+ hwif->udma_four = ata66_cmd64x(hwif);
+
+ if (dev->device == PCI_DEVICE_ID_CMD_646) {
+ hwif->chipset = ide_cmd646;
+ if (class_rev == 0x01) {
+ hwif->ide_dma_end = &cmd646_1_ide_dma_end;
+ } else {
+ hwif->ide_dma_end = &cmd64x_ide_dma_end;
+ hwif->ide_dma_test_irq = &cmd64x_ide_dma_test_irq;
+ }
+ } else {
+ hwif->ide_dma_end = &cmd64x_ide_dma_end;
+ hwif->ide_dma_test_irq = &cmd64x_ide_dma_test_irq;
+ }
+
+
+ if (!noautodma)
+ hwif->autodma = 1;
+ hwif->drives[0].autodma = hwif->autodma;
+ hwif->drives[1].autodma = hwif->autodma;
+}
+
+static ide_pci_device_t cmd64x_chipsets[] __devinitdata = {
+ { /* 0 */
+ .name = "CMD643",
+ .init_chipset = init_chipset_cmd64x,
+ .init_hwif = init_hwif_cmd64x,
+ .channels = 2,
+ .autodma = AUTODMA,
+ .bootable = ON_BOARD,
+ },{ /* 1 */
+ .name = "CMD646",
+ .init_chipset = init_chipset_cmd64x,
+ .init_hwif = init_hwif_cmd64x,
+ .channels = 2,
+ .autodma = AUTODMA,
+ .enablebits = {{0x00,0x00,0x00}, {0x51,0x80,0x80}},
+ .bootable = ON_BOARD,
+ },{ /* 2 */
+ .name = "CMD648",
+ .init_chipset = init_chipset_cmd64x,
+ .init_hwif = init_hwif_cmd64x,
+ .channels = 2,
+ .autodma = AUTODMA,
+ .bootable = ON_BOARD,
+ },{ /* 3 */
+ .name = "CMD649",
+ .init_chipset = init_chipset_cmd64x,
+ .init_hwif = init_hwif_cmd64x,
+ .channels = 2,
+ .autodma = AUTODMA,
+ .bootable = ON_BOARD,
+ }
+};
+
+static int __devinit cmd64x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ return ide_setup_pci_device(dev, &cmd64x_chipsets[id->driver_data]);
+}
+
+static struct pci_device_id cmd64x_pci_tbl[] = {
+ { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_643, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_646, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+ { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_648, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
+ { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_649, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3},
+ { 0, },
+};
+MODULE_DEVICE_TABLE(pci, cmd64x_pci_tbl);
+
+static struct pci_driver driver = {
+ .name = "CMD64x_IDE",
+ .id_table = cmd64x_pci_tbl,
+ .probe = cmd64x_init_one,
+};
+
+static int cmd64x_ide_init(void)
+{
+ return ide_pci_register_driver(&driver);
+}
+
+module_init(cmd64x_ide_init);
+
+MODULE_AUTHOR("Eddie Dost, David Miller, Andre Hedrick");
+MODULE_DESCRIPTION("PCI driver module for CMD64x IDE");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/pci/cs5520.c b/drivers/ide/pci/cs5520.c
new file mode 100644
index 000000000000..7dc24682d197
--- /dev/null
+++ b/drivers/ide/pci/cs5520.c
@@ -0,0 +1,274 @@
+/*
+ * 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/config.h>
+#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/hdreg.h>
+
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+#include <linux/dma-mapping.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+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 int cs5520_tune_chipset(ide_drive_t *drive, u8 xferspeed)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *pdev = hwif->pci_dev;
+ u8 speed = min((u8)XFER_PIO_4, xferspeed);
+ int pio = speed;
+ u8 reg;
+ int controller = drive->dn > 1 ? 1 : 0;
+ int error;
+
+ switch(speed)
+ {
+ case XFER_PIO_4:
+ case XFER_PIO_3:
+ case XFER_PIO_2:
+ case XFER_PIO_1:
+ case XFER_PIO_0:
+ pio -= XFER_PIO_0;
+ break;
+ default:
+ pio = 0;
+ printk(KERN_ERR "cs55x0: bad ide timing.\n");
+ }
+
+ printk("PIO clocking = %d\n", pio);
+
+ /* FIXME: if DMA = 1 do we need to set the DMA bit here ? */
+
+ /* 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));
+
+ /* Set the DMA enable/disable flag */
+ reg = inb(hwif->dma_base + 0x02 + 8*controller);
+ reg |= 1<<((drive->dn&1)+5);
+ outb(reg, hwif->dma_base + 0x02 + 8*controller);
+
+ error = ide_config_drive_speed(drive, speed);
+ /* ATAPI is harder so leave it for now */
+ if(!error && drive->media == ide_disk)
+ error = hwif->ide_dma_on(drive);
+
+ return error;
+}
+
+static void cs5520_tune_drive(ide_drive_t *drive, u8 pio)
+{
+ pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+ cs5520_tune_chipset(drive, (XFER_PIO_0 + pio));
+}
+
+static int cs5520_config_drive_xfer_rate(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+
+ /* Tune the drive for PIO modes up to PIO 4 */
+ cs5520_tune_drive(drive, 4);
+ /* Then tell the core to use DMA operations */
+ return hwif->ide_dma_on(drive);
+}
+
+/*
+ * We provide a callback for our nonstandard DMA location
+ */
+
+static void __devinit cs5520_init_setup_dma(struct pci_dev *dev, ide_pci_device_t *d, ide_hwif_t *hwif)
+{
+ unsigned long bmide = pci_resource_start(dev, 2); /* Not the usual 4 */
+ if(hwif->mate && hwif->mate->dma_base) /* Second channel at primary + 8 */
+ bmide += 8;
+ ide_setup_dma(hwif, bmide, 8);
+}
+
+/*
+ * We wrap the DMA activate to set the vdma flag. This is needed
+ * so that the IDE DMA layer issues PIO not DMA commands over the
+ * DMA channel
+ */
+
+static int cs5520_dma_on(ide_drive_t *drive)
+{
+ drive->vdma = 1;
+ return 0;
+}
+
+static void __devinit init_hwif_cs5520(ide_hwif_t *hwif)
+{
+ hwif->tuneproc = &cs5520_tune_drive;
+ hwif->speedproc = &cs5520_tune_chipset;
+ hwif->ide_dma_check = &cs5520_config_drive_xfer_rate;
+ hwif->ide_dma_on = &cs5520_dma_on;
+
+ if(!noautodma)
+ hwif->autodma = 1;
+
+ if(!hwif->dma_base)
+ {
+ hwif->drives[0].autotune = 1;
+ hwif->drives[1].autotune = 1;
+ return;
+ }
+
+ hwif->atapi_dma = 0;
+ hwif->ultra_mask = 0;
+ hwif->swdma_mask = 0;
+ hwif->mwdma_mask = 0;
+
+ hwif->drives[0].autodma = hwif->autodma;
+ hwif->drives[1].autodma = hwif->autodma;
+}
+
+#define DECLARE_CS_DEV(name_str) \
+ { \
+ .name = name_str, \
+ .init_setup_dma = cs5520_init_setup_dma, \
+ .init_hwif = init_hwif_cs5520, \
+ .channels = 2, \
+ .autodma = AUTODMA, \
+ .bootable = ON_BOARD, \
+ .flags = IDEPCI_FLAG_ISA_PORTS, \
+ }
+
+static ide_pci_device_t cyrix_chipsets[] __devinitdata = {
+ /* 0 */ DECLARE_CS_DEV("Cyrix 5510"),
+ /* 1 */ DECLARE_CS_DEV("Cyrix 5520")
+};
+
+/*
+ * 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)
+{
+ ata_index_t index;
+ ide_pci_device_t *d = &cyrix_chipsets[id->driver_data];
+
+ 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_bars(dev, 1<<2))
+ {
+ printk(KERN_WARNING "%s: Unable to enable 55x0.\n", d->name);
+ return 1;
+ }
+ pci_set_master(dev);
+ if (pci_set_dma_mask(dev, DMA_32BIT_MASK)) {
+ printk(KERN_WARNING "cs5520: No suitable DMA available.\n");
+ return -ENODEV;
+ }
+
+ index.all = 0xf0f0;
+
+ /*
+ * Now the chipset is configured we can let the core
+ * do all the device setup for us
+ */
+
+ ide_pci_setup_ports(dev, d, 14, &index);
+
+ if((index.b.low & 0xf0) != 0xf0)
+ probe_hwif_init(&ide_hwifs[index.b.low]);
+ if((index.b.high & 0xf0) != 0xf0)
+ probe_hwif_init(&ide_hwifs[index.b.high]);
+ return 0;
+}
+
+static struct pci_device_id cs5520_pci_tbl[] = {
+ { PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5510, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5520, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+ { 0, },
+};
+MODULE_DEVICE_TABLE(pci, cs5520_pci_tbl);
+
+static struct pci_driver driver = {
+ .name = "Cyrix_IDE",
+ .id_table = cs5520_pci_tbl,
+ .probe = cs5520_init_one,
+};
+
+static int cs5520_ide_init(void)
+{
+ return ide_pci_register_driver(&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/pci/cs5530.c b/drivers/ide/pci/cs5530.c
new file mode 100644
index 000000000000..0381961db263
--- /dev/null
+++ b/drivers/ide/pci/cs5530.c
@@ -0,0 +1,384 @@
+/*
+ * linux/drivers/ide/pci/cs5530.c Version 0.7 Sept 10, 2002
+ *
+ * Copyright (C) 2000 Andre Hedrick <andre@linux-ide.org>
+ * Ditto of GNU General Public License.
+ *
+ * Copyright (C) 2000 Mark Lord <mlord@pobox.com>
+ * May be copied or modified under the terms of the GNU General Public License
+ *
+ * Development of this chipset driver was funded
+ * by the nice folks at National Semiconductor.
+ *
+ * Documentation:
+ * CS5530 documentation available from National Semiconductor.
+ */
+
+#include <linux/config.h>
+#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/hdreg.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/ide.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+
+/**
+ * cs5530_xfer_set_mode - set a new transfer mode at the drive
+ * @drive: drive to tune
+ * @mode: new mode
+ *
+ * Logging wrapper to the IDE driver speed configuration. This can
+ * probably go away now.
+ */
+
+static int cs5530_set_xfer_mode (ide_drive_t *drive, u8 mode)
+{
+ printk(KERN_DEBUG "%s: cs5530_set_xfer_mode(%s)\n",
+ drive->name, ide_xfer_verbose(mode));
+ return (ide_config_drive_speed(drive, mode));
+}
+
+/*
+ * 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_tuneproc - select/set PIO modes
+ *
+ * cs5530_tuneproc() handles selection/setting of PIO modes
+ * for both the chipset and drive.
+ *
+ * The ide_init_cs5530() routine guarantees that all drives
+ * will have valid default PIO timings set up before we get here.
+ */
+
+static void cs5530_tuneproc (ide_drive_t *drive, u8 pio) /* pio=255 means "autotune" */
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ unsigned int format;
+ unsigned long basereg = CS5530_BASEREG(hwif);
+ static u8 modes[5] = { XFER_PIO_0, XFER_PIO_1, XFER_PIO_2, XFER_PIO_3, XFER_PIO_4};
+
+ pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+ if (!cs5530_set_xfer_mode(drive, modes[pio])) {
+ format = (hwif->INL(basereg+4) >> 31) & 1;
+ hwif->OUTL(cs5530_pio_timings[format][pio],
+ basereg+(drive->select.b.unit<<3));
+ }
+}
+
+/**
+ * cs5530_config_dma - select/set DMA and UDMA modes
+ * @drive: drive to tune
+ *
+ * cs5530_config_dma() handles selection/setting of DMA/UDMA modes
+ * for both the chipset and drive. The CS5530 has limitations about
+ * mixing DMA/UDMA on the same cable.
+ */
+
+static int cs5530_config_dma (ide_drive_t *drive)
+{
+ int udma_ok = 1, mode = 0;
+ ide_hwif_t *hwif = HWIF(drive);
+ int unit = drive->select.b.unit;
+ ide_drive_t *mate = &hwif->drives[unit^1];
+ struct hd_driveid *id = drive->id;
+ unsigned int reg, timings;
+ unsigned long basereg;
+
+ /*
+ * Default to DMA-off in case we run into trouble here.
+ */
+ hwif->ide_dma_off_quietly(drive);
+ /* turn off DMA while we fiddle */
+ hwif->ide_dma_host_off(drive);
+ /* clear DMA_capable bit */
+
+ /*
+ * 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 MWDMA_2
+ * but instead drop to PIO
+ */
+ if (mate->present) {
+ struct hd_driveid *mateid = mate->id;
+ if (mateid && (mateid->capability & 1) &&
+ !__ide_dma_bad_drive(mate)) {
+ if ((mateid->field_valid & 4) &&
+ (mateid->dma_ultra & 7))
+ udma_ok = 1;
+ else if ((mateid->field_valid & 2) &&
+ (mateid->dma_mword & 7))
+ udma_ok = 0;
+ else
+ udma_ok = 1;
+ }
+ }
+
+ /*
+ * Now see what the current drive is capable of,
+ * selecting UDMA only if the mate said it was ok.
+ */
+ if (id && (id->capability & 1) && drive->autodma &&
+ !__ide_dma_bad_drive(drive)) {
+ if (udma_ok && (id->field_valid & 4) && (id->dma_ultra & 7)) {
+ if (id->dma_ultra & 4)
+ mode = XFER_UDMA_2;
+ else if (id->dma_ultra & 2)
+ mode = XFER_UDMA_1;
+ else if (id->dma_ultra & 1)
+ mode = XFER_UDMA_0;
+ }
+ if (!mode && (id->field_valid & 2) && (id->dma_mword & 7)) {
+ if (id->dma_mword & 4)
+ mode = XFER_MW_DMA_2;
+ else if (id->dma_mword & 2)
+ mode = XFER_MW_DMA_1;
+ else if (id->dma_mword & 1)
+ mode = XFER_MW_DMA_0;
+ }
+ }
+
+ /*
+ * Tell the drive to switch to the new mode; abort on failure.
+ */
+ if (!mode || cs5530_set_xfer_mode(drive, mode))
+ return 1; /* failure */
+
+ /*
+ * Now tune the chipset to match the drive:
+ */
+ 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;
+ default:
+ printk(KERN_ERR "%s: cs5530_config_dma: huh? mode=%02x\n",
+ drive->name, mode);
+ return 1; /* failure */
+ }
+ basereg = CS5530_BASEREG(hwif);
+ reg = hwif->INL(basereg+4); /* get drive0 config register */
+ timings |= reg & 0x80000000; /* preserve PIO format bit */
+ if (unit == 0) { /* are we configuring drive0? */
+ hwif->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 */
+ hwif->OUTL(reg, basereg+4); /* write drive0 config register */
+ hwif->OUTL(timings, basereg+12); /* write drive1 config register */
+ }
+ (void) hwif->ide_dma_host_on(drive);
+ /* set DMA_capable bit */
+
+ /*
+ * Finally, turn DMA on in software, and exit.
+ */
+ return hwif->ide_dma_on(drive); /* success */
+}
+
+/**
+ * init_chipset_5530 - set up 5530 bridge
+ * @dev: PCI device
+ * @name: device name
+ *
+ * Initialize the cs5530 bridge for reliable IDE DMA operation.
+ */
+
+static unsigned int __init init_chipset_cs5530 (struct pci_dev *dev, const char *name)
+{
+ struct pci_dev *master_0 = NULL, *cs5530_0 = NULL;
+ unsigned long flags;
+
+ dev = NULL;
+ while ((dev = pci_find_device(PCI_VENDOR_ID_CYRIX, PCI_ANY_ID, dev)) != NULL) {
+ switch (dev->device) {
+ case PCI_DEVICE_ID_CYRIX_PCI_MASTER:
+ master_0 = dev;
+ break;
+ case PCI_DEVICE_ID_CYRIX_5530_LEGACY:
+ cs5530_0 = dev;
+ break;
+ }
+ }
+ if (!master_0) {
+ printk(KERN_ERR "%s: unable to locate PCI MASTER function\n", name);
+ return 0;
+ }
+ if (!cs5530_0) {
+ printk(KERN_ERR "%s: unable to locate CS5530 LEGACY function\n", name);
+ return 0;
+ }
+
+ spin_lock_irqsave(&ide_lock, flags);
+ /* all CPUs (there should only be one CPU with this chipset) */
+
+ /*
+ * 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_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);
+
+ spin_unlock_irqrestore(&ide_lock, flags);
+
+ 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 __init init_hwif_cs5530 (ide_hwif_t *hwif)
+{
+ unsigned long basereg;
+ u32 d0_timings;
+ hwif->autodma = 0;
+
+ if (hwif->mate)
+ hwif->serialized = hwif->mate->serialized = 1;
+
+ hwif->tuneproc = &cs5530_tuneproc;
+ basereg = CS5530_BASEREG(hwif);
+ d0_timings = hwif->INL(basereg+0);
+ if (CS5530_BAD_PIO(d0_timings)) {
+ /* PIO timings not initialized? */
+ hwif->OUTL(cs5530_pio_timings[(d0_timings>>31)&1][0], basereg+0);
+ if (!hwif->drives[0].autotune)
+ hwif->drives[0].autotune = 1;
+ /* needs autotuning later */
+ }
+ if (CS5530_BAD_PIO(hwif->INL(basereg+8))) {
+ /* PIO timings not initialized? */
+ hwif->OUTL(cs5530_pio_timings[(d0_timings>>31)&1][0], basereg+8);
+ if (!hwif->drives[1].autotune)
+ hwif->drives[1].autotune = 1;
+ /* needs autotuning later */
+ }
+
+ hwif->atapi_dma = 1;
+ hwif->ultra_mask = 0x07;
+ hwif->mwdma_mask = 0x07;
+
+ hwif->ide_dma_check = &cs5530_config_dma;
+ if (!noautodma)
+ hwif->autodma = 1;
+ hwif->drives[0].autodma = hwif->autodma;
+ hwif->drives[1].autodma = hwif->autodma;
+}
+
+static ide_pci_device_t cs5530_chipset __devinitdata = {
+ .name = "CS5530",
+ .init_chipset = init_chipset_cs5530,
+ .init_hwif = init_hwif_cs5530,
+ .channels = 2,
+ .autodma = AUTODMA,
+ .bootable = ON_BOARD,
+};
+
+static int __devinit cs5530_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ return ide_setup_pci_device(dev, &cs5530_chipset);
+}
+
+static struct pci_device_id cs5530_pci_tbl[] = {
+ { PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { 0, },
+};
+MODULE_DEVICE_TABLE(pci, cs5530_pci_tbl);
+
+static struct pci_driver driver = {
+ .name = "CS5530 IDE",
+ .id_table = cs5530_pci_tbl,
+ .probe = cs5530_init_one,
+};
+
+static int cs5530_ide_init(void)
+{
+ return ide_pci_register_driver(&driver);
+}
+
+module_init(cs5530_ide_init);
+
+MODULE_AUTHOR("Mark Lord");
+MODULE_DESCRIPTION("PCI driver module for Cyrix/NS 5530 IDE");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/pci/cy82c693.c b/drivers/ide/pci/cy82c693.c
new file mode 100644
index 000000000000..80d67e99ccb5
--- /dev/null
+++ b/drivers/ide/pci/cy82c693.c
@@ -0,0 +1,531 @@
+/*
+ * linux/drivers/ide/pci/cy82c693.c Version 0.40 Sep. 10, 2002
+ *
+ * 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.
+ * - use idebus=xx parameter to set PCI bus speed - needed to calc
+ * timings for PIO modes (default will be 40)
+ * - 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/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+/* the current version */
+#define CY82_VERSION "CY82C693U driver v0.34 99-13-12 Andreas S. Krebs (akrebs@altavista.net)"
+
+/*
+ * The following are used to debug the driver.
+ */
+#define CY82C693_DEBUG_LOGS 0
+#define CY82C693_DEBUG_INFO 0
+
+/* define CY82C693_SETDMA_CLOCK to set DMA Controller Clock Speed to ATCLK */
+#undef CY82C693_SETDMA_CLOCK
+
+/*
+ * 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_CTRLREG1 0x01
+#define CY82_INDEX_CHANNEL0 0x30
+#define CY82_INDEX_CHANNEL1 0x31
+#define CY82_INDEX_TIMEOUT 0x32
+
+/* the max PIO mode - from datasheet */
+#define CY82C693_MAX_PIO 4
+
+/* 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)
+{
+ int clk1, clk2;
+ int bus_speed = system_bus_clock(); /* get speed of PCI bus */
+
+ /* we don't check against CY82C693's min and max speed,
+ * so you can play with the idebus=xx parameter
+ */
+
+ if (pio > CY82C693_MAX_PIO)
+ pio = CY82C693_MAX_PIO;
+
+ /* let's calc the address setup time clocks */
+ p_pclk->address_time = (u8)calc_clk(ide_pio_timings[pio].setup_time, bus_speed);
+
+ /* let's calc the active and recovery time clocks */
+ clk1 = calc_clk(ide_pio_timings[pio].active_time, bus_speed);
+
+ /* calc recovery timing */
+ clk2 = ide_pio_timings[pio].cycle_time -
+ ide_pio_timings[pio].active_time -
+ ide_pio_timings[pio].setup_time;
+
+ 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_dma_enable (ide_drive_t *drive, int mode, int single)
+{
+ u8 index = 0, data = 0;
+
+ if (mode>2) /* make sure we set a valid mode */
+ mode = 2;
+
+ if (mode > drive->id->tDMA) /* to be absolutly sure we have a valid mode */
+ mode = drive->id->tDMA;
+
+ index = (HWIF(drive)->channel==0) ? CY82_INDEX_CHANNEL0 : CY82_INDEX_CHANNEL1;
+
+#if CY82C693_DEBUG_LOGS
+ /* for debug let's show the previous values */
+
+ HWIF(drive)->OUTB(index, CY82_INDEX_PORT);
+ data = HWIF(drive)->INB(CY82_DATA_PORT);
+
+ printk (KERN_INFO "%s (ch=%d, dev=%d): DMA mode is %d (single=%d)\n",
+ drive->name, HWIF(drive)->channel, drive->select.b.unit,
+ (data&0x3), ((data>>2)&1));
+#endif /* CY82C693_DEBUG_LOGS */
+
+ data = (u8)mode|(u8)(single<<2);
+
+ HWIF(drive)->OUTB(index, CY82_INDEX_PORT);
+ HWIF(drive)->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(drive)->channel, drive->select.b.unit,
+ mode, 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;
+ HWIF(drive)->OUTB(CY82_INDEX_TIMEOUT, CY82_INDEX_PORT);
+ HWIF(drive)->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 */
+}
+
+/*
+ * used to set DMA mode for CY82C693 (single and multi modes)
+ */
+static int cy82c693_ide_dma_on (ide_drive_t *drive)
+{
+ struct hd_driveid *id = drive->id;
+
+#if CY82C693_DEBUG_INFO
+ printk (KERN_INFO "dma_on: %s\n", drive->name);
+#endif /* CY82C693_DEBUG_INFO */
+
+ if (id != NULL) {
+ /* Enable DMA on any drive that has DMA
+ * (multi or single) enabled
+ */
+ if (id->field_valid & 2) { /* regular DMA */
+ int mmode, smode;
+
+ mmode = id->dma_mword & (id->dma_mword >> 8);
+ smode = id->dma_1word & (id->dma_1word >> 8);
+
+ if (mmode != 0) {
+ /* enable multi */
+ cy82c693_dma_enable(drive, (mmode >> 1), 0);
+ } else if (smode != 0) {
+ /* enable single */
+ cy82c693_dma_enable(drive, (smode >> 1), 1);
+ }
+ }
+ }
+ return __ide_dma_on(drive);
+}
+
+/*
+ * tune ide drive - set PIO mode
+ */
+static void cy82c693_tune_drive (ide_drive_t *drive, u8 pio)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = hwif->pci_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_find_slot(dev->bus->number, dev->devfn+1);
+ if (!dev) {
+ printk(KERN_ERR "%s: tune_drive: "
+ "Cannot find secondary interface!\n",
+ drive->name);
+ return;
+ }
+ }
+
+#if CY82C693_DEBUG_LOGS
+ /* for debug let's show the register values */
+
+ if (drive->select.b.unit == 0) {
+ /*
+ * get master drive registers
+ * address setup control register
+ * is 32 bit !!!
+ */
+ pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl);
+ addrCtrl &= 0x0F;
+
+ /* now let's get the remaining registers */
+ pci_read_config_byte(dev, CY82_IDE_MASTER_IOR, &pclk.time_16r);
+ pci_read_config_byte(dev, CY82_IDE_MASTER_IOW, &pclk.time_16w);
+ pci_read_config_byte(dev, CY82_IDE_MASTER_8BIT, &pclk.time_8);
+ } else {
+ /*
+ * set slave drive registers
+ * address setup control register
+ * is 32 bit !!!
+ */
+ pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl);
+
+ addrCtrl &= 0xF0;
+ addrCtrl >>= 4;
+
+ /* now let's get the remaining registers */
+ pci_read_config_byte(dev, CY82_IDE_SLAVE_IOR, &pclk.time_16r);
+ pci_read_config_byte(dev, CY82_IDE_SLAVE_IOW, &pclk.time_16w);
+ pci_read_config_byte(dev, CY82_IDE_SLAVE_8BIT, &pclk.time_8);
+ }
+
+ printk(KERN_INFO "%s (ch=%d, dev=%d): PIO timing is "
+ "(addr=0x%X, ior=0x%X, iow=0x%X, 8bit=0x%X)\n",
+ drive->name, hwif->channel, drive->select.b.unit,
+ addrCtrl, pclk.time_16r, pclk.time_16w, pclk.time_8);
+#endif /* CY82C693_DEBUG_LOGS */
+
+ /* first let's calc the pio modes */
+ pio = ide_get_best_pio_mode(drive, pio, CY82C693_MAX_PIO, NULL);
+
+#if CY82C693_DEBUG_INFO
+ printk (KERN_INFO "%s: Selected PIO mode %d\n", drive->name, pio);
+#endif /* CY82C693_DEBUG_INFO */
+
+ /* let's calc the values for this PIO mode */
+ compute_clocks(pio, &pclk);
+
+ /* now let's write the clocks registers */
+ if (drive->select.b.unit == 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->select.b.unit,
+ addrCtrl, pclk.time_16r, pclk.time_16w, pclk.time_8);
+#endif /* CY82C693_DEBUG_INFO */
+}
+
+/*
+ * this function is called during init and is used to setup the cy82c693 chip
+ */
+static unsigned int __init init_chipset_cy82c693(struct pci_dev *dev, const char *name)
+{
+ if (PCI_FUNC(dev->devfn) != 1)
+ return 0;
+
+#ifdef CY82C693_SETDMA_CLOCK
+ u8 data = 0;
+#endif /* CY82C693_SETDMA_CLOCK */
+
+ /* write info about this verion of the driver */
+ printk(KERN_INFO CY82_VERSION "\n");
+
+#ifdef CY82C693_SETDMA_CLOCK
+ /* okay let's set the DMA clock speed */
+
+ outb(CY82_INDEX_CTRLREG1, CY82_INDEX_PORT);
+ data = inb(CY82_DATA_PORT);
+
+#if CY82C693_DEBUG_INFO
+ printk(KERN_INFO "%s: Peripheral Configuration Register: 0x%X\n",
+ name, data);
+#endif /* CY82C693_DEBUG_INFO */
+
+ /*
+ * for some reason sometimes the DMA controller
+ * speed is set to ATCLK/2 ???? - we fix this here
+ *
+ * note: i don't know what causes this strange behaviour,
+ * but even changing the dma speed doesn't solve it :-(
+ * the ide performance is still only half the normal speed
+ *
+ * if anybody knows what goes wrong with my machine, please
+ * let me know - ASK
+ */
+
+ data |= 0x03;
+
+ outb(CY82_INDEX_CTRLREG1, CY82_INDEX_PORT);
+ outb(data, CY82_DATA_PORT);
+
+#if CY82C693_DEBUG_INFO
+ printk (KERN_INFO "%s: New Peripheral Configuration Register: 0x%X\n",
+ name, data);
+#endif /* CY82C693_DEBUG_INFO */
+
+#endif /* CY82C693_SETDMA_CLOCK */
+ return 0;
+}
+
+/*
+ * the init function - called for each ide channel once
+ */
+static void __init init_hwif_cy82c693(ide_hwif_t *hwif)
+{
+ hwif->autodma = 0;
+
+ hwif->chipset = ide_cy82c693;
+ hwif->tuneproc = &cy82c693_tune_drive;
+
+ if (!hwif->dma_base) {
+ hwif->drives[0].autotune = 1;
+ hwif->drives[1].autotune = 1;
+ return;
+ }
+
+ hwif->atapi_dma = 1;
+ hwif->mwdma_mask = 0x04;
+ hwif->swdma_mask = 0x04;
+
+ hwif->ide_dma_on = &cy82c693_ide_dma_on;
+ if (!noautodma)
+ hwif->autodma = 1;
+ hwif->drives[0].autodma = hwif->autodma;
+ hwif->drives[1].autodma = hwif->autodma;
+}
+
+static __initdata ide_hwif_t *primary;
+
+void __init init_iops_cy82c693(ide_hwif_t *hwif)
+{
+ if (PCI_FUNC(hwif->pci_dev->devfn) == 1)
+ primary = hwif;
+ else {
+ hwif->mate = primary;
+ hwif->channel = 1;
+ }
+}
+
+static ide_pci_device_t cy82c693_chipsets[] __devinitdata = {
+ { /* 0 */
+ .name = "CY82C693",
+ .init_chipset = init_chipset_cy82c693,
+ .init_iops = init_iops_cy82c693,
+ .init_hwif = init_hwif_cy82c693,
+ .channels = 1,
+ .autodma = AUTODMA,
+ .bootable = ON_BOARD,
+ }
+};
+
+static int __devinit cy82c693_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ ide_pci_device_t *d = &cy82c693_chipsets[id->driver_data];
+ 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_find_slot(dev->bus->number, dev->devfn + 1);
+ ret = ide_setup_pci_devices(dev, dev2, d);
+ }
+ return ret;
+}
+
+static struct pci_device_id cy82c693_pci_tbl[] = {
+ { PCI_VENDOR_ID_CONTAQ, PCI_DEVICE_ID_CONTAQ_82C693, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { 0, },
+};
+MODULE_DEVICE_TABLE(pci, cy82c693_pci_tbl);
+
+static struct pci_driver driver = {
+ .name = "Cypress_IDE",
+ .id_table = cy82c693_pci_tbl,
+ .probe = cy82c693_init_one,
+};
+
+static int cy82c693_ide_init(void)
+{
+ return ide_pci_register_driver(&driver);
+}
+
+module_init(cy82c693_ide_init);
+
+MODULE_AUTHOR("Andreas Krebs, Andre Hedrick");
+MODULE_DESCRIPTION("PCI driver module for the Cypress CY82C693 IDE");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/pci/generic.c b/drivers/ide/pci/generic.c
new file mode 100644
index 000000000000..4565cc311ff3
--- /dev/null
+++ b/drivers/ide/pci/generic.c
@@ -0,0 +1,232 @@
+/*
+ * linux/drivers/ide/pci/generic.c Version 0.11 December 30, 2002
+ *
+ * Copyright (C) 2001-2002 Andre Hedrick <andre@linux-ide.org>
+ * Portions (C) Copyright 2002 Red Hat Inc <alan@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * 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.
+ */
+
+#undef REALLY_SLOW_IO /* most systems can safely undef this */
+
+#include <linux/config.h> /* for CONFIG_BLK_DEV_IDEPCI */
+#include <linux/types.h>
+#include <linux/module.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/hdreg.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+static void __devinit init_hwif_generic (ide_hwif_t *hwif)
+{
+ switch(hwif->pci_dev->device) {
+ case PCI_DEVICE_ID_UMC_UM8673F:
+ case PCI_DEVICE_ID_UMC_UM8886A:
+ case PCI_DEVICE_ID_UMC_UM8886BF:
+ hwif->irq = hwif->channel ? 15 : 14;
+ break;
+ default:
+ break;
+ }
+
+ if (!(hwif->dma_base))
+ return;
+
+ hwif->atapi_dma = 1;
+ hwif->ultra_mask = 0x7f;
+ hwif->mwdma_mask = 0x07;
+ hwif->swdma_mask = 0x07;
+
+ if (!noautodma)
+ hwif->autodma = 1;
+ hwif->drives[0].autodma = hwif->autodma;
+ hwif->drives[1].autodma = hwif->autodma;
+}
+
+#if 0
+ /* Logic to add back later on */
+
+ if ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE) {
+ ide_pci_device_t *unknown = unknown_chipset;
+ init_setup_unknown(dev, unknown);
+ return 1;
+ }
+ return 0;
+#endif
+
+static ide_pci_device_t generic_chipsets[] __devinitdata = {
+ { /* 0 */
+ .name = "NS87410",
+ .init_hwif = init_hwif_generic,
+ .channels = 2,
+ .autodma = AUTODMA,
+ .enablebits = {{0x43,0x08,0x08}, {0x47,0x08,0x08}},
+ .bootable = ON_BOARD,
+ },{ /* 1 */
+ .name = "SAMURAI",
+ .init_hwif = init_hwif_generic,
+ .channels = 2,
+ .autodma = AUTODMA,
+ .bootable = ON_BOARD,
+ },{ /* 2 */
+ .name = "HT6565",
+ .init_hwif = init_hwif_generic,
+ .channels = 2,
+ .autodma = AUTODMA,
+ .bootable = ON_BOARD,
+ },{ /* 3 */
+ .name = "UM8673F",
+ .init_hwif = init_hwif_generic,
+ .channels = 2,
+ .autodma = NODMA,
+ .bootable = ON_BOARD,
+ },{ /* 4 */
+ .name = "UM8886A",
+ .init_hwif = init_hwif_generic,
+ .channels = 2,
+ .autodma = NODMA,
+ .bootable = ON_BOARD,
+ },{ /* 5 */
+ .name = "UM8886BF",
+ .init_hwif = init_hwif_generic,
+ .channels = 2,
+ .autodma = NODMA,
+ .bootable = ON_BOARD,
+ },{ /* 6 */
+ .name = "HINT_IDE",
+ .init_hwif = init_hwif_generic,
+ .channels = 2,
+ .autodma = AUTODMA,
+ .bootable = ON_BOARD,
+ },{ /* 7 */
+ .name = "VIA_IDE",
+ .init_hwif = init_hwif_generic,
+ .channels = 2,
+ .autodma = NOAUTODMA,
+ .bootable = ON_BOARD,
+ },{ /* 8 */
+ .name = "OPTI621V",
+ .init_hwif = init_hwif_generic,
+ .channels = 2,
+ .autodma = NOAUTODMA,
+ .bootable = ON_BOARD,
+ },{ /* 9 */
+ .name = "VIA8237SATA",
+ .init_hwif = init_hwif_generic,
+ .channels = 2,
+ .autodma = AUTODMA,
+ .bootable = OFF_BOARD,
+ },{ /* 10 */
+ .name = "Piccolo0102",
+ .init_hwif = init_hwif_generic,
+ .channels = 2,
+ .autodma = NOAUTODMA,
+ .bootable = ON_BOARD,
+ },{ /* 11 */
+ .name = "Piccolo0103",
+ .init_hwif = init_hwif_generic,
+ .channels = 2,
+ .autodma = NOAUTODMA,
+ .bootable = ON_BOARD,
+ },{ /* 12 */
+ .name = "Piccolo0105",
+ .init_hwif = init_hwif_generic,
+ .channels = 2,
+ .autodma = NOAUTODMA,
+ .bootable = ON_BOARD,
+ }
+};
+
+/**
+ * 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)
+{
+ ide_pci_device_t *d = &generic_chipsets[id->driver_data];
+ u16 command;
+ int ret = -ENODEV;
+
+ if (dev->vendor == PCI_VENDOR_ID_UMC &&
+ dev->device == PCI_DEVICE_ID_UMC_UM8886A &&
+ (!(PCI_FUNC(dev->devfn) & 1)))
+ goto out; /* UM8886A/BF pair */
+
+ if (dev->vendor == PCI_VENDOR_ID_OPTI &&
+ dev->device == PCI_DEVICE_ID_OPTI_82C558 &&
+ (!(PCI_FUNC(dev->devfn) & 1)))
+ goto out;
+
+ pci_read_config_word(dev, PCI_COMMAND, &command);
+ if (!(command & PCI_COMMAND_IO)) {
+ printk(KERN_INFO "Skipping disabled %s IDE controller.\n", d->name);
+ goto out;
+ }
+ ret = ide_setup_pci_device(dev, d);
+out:
+ return ret;
+}
+
+static struct pci_device_id generic_pci_tbl[] = {
+ { PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87410, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_SAMURAI_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+ { PCI_VENDOR_ID_HOLTEK, PCI_DEVICE_ID_HOLTEK_6565, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
+ { PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8673F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3},
+ { PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4},
+ { PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886BF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5},
+ { PCI_VENDOR_ID_HINT, PCI_DEVICE_ID_HINT_VXPROII_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6},
+ { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C561, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 7},
+ { PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C558, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8},
+#ifdef CONFIG_BLK_DEV_IDE_SATA
+ { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237_SATA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 9},
+#endif
+ { PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 10},
+ { PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 11},
+ { PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 12},
+ { 0, },
+};
+MODULE_DEVICE_TABLE(pci, generic_pci_tbl);
+
+static struct pci_driver driver = {
+ .name = "PCI_IDE",
+ .id_table = generic_pci_tbl,
+ .probe = generic_init_one,
+};
+
+static int generic_ide_init(void)
+{
+ return ide_pci_register_driver(&driver);
+}
+
+module_init(generic_ide_init);
+
+MODULE_AUTHOR("Andre Hedrick");
+MODULE_DESCRIPTION("PCI driver module for generic PCI IDE");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/pci/hpt34x.c b/drivers/ide/pci/hpt34x.c
new file mode 100644
index 000000000000..bbde46279984
--- /dev/null
+++ b/drivers/ide/pci/hpt34x.c
@@ -0,0 +1,278 @@
+/*
+ * linux/drivers/ide/pci/hpt34x.c Version 0.40 Sept 10, 2002
+ *
+ * Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org>
+ * May be copied or modified under the terms of the GNU General Public License
+ *
+ *
+ * 00:12.0 Unknown mass storage controller:
+ * Triones Technologies, Inc.
+ * Unknown device 0003 (rev 01)
+ *
+ * hde: UDMA 2 (0x0000 0x0002) (0x0000 0x0010)
+ * hdf: UDMA 2 (0x0002 0x0012) (0x0010 0x0030)
+ * hde: DMA 2 (0x0000 0x0002) (0x0000 0x0010)
+ * hdf: DMA 2 (0x0002 0x0012) (0x0010 0x0030)
+ * hdg: DMA 1 (0x0012 0x0052) (0x0030 0x0070)
+ * hdh: DMA 1 (0x0052 0x0252) (0x0070 0x00f0)
+ *
+ * ide-pci.c reference
+ *
+ * Since there are two cards that report almost identically,
+ * the only discernable difference is the values reported in pcicmd.
+ * Booting-BIOS card or HPT363 :: pcicmd == 0x07
+ * Non-bootable card or HPT343 :: pcicmd == 0x05
+ */
+
+#include <linux/config.h>
+#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/hdreg.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#define HPT343_DEBUG_DRIVE_INFO 0
+
+static u8 hpt34x_ratemask (ide_drive_t *drive)
+{
+ return 1;
+}
+
+static void hpt34x_clear_chipset (ide_drive_t *drive)
+{
+ struct pci_dev *dev = HWIF(drive)->pci_dev;
+ u32 reg1 = 0, tmp1 = 0, reg2 = 0, tmp2 = 0;
+
+ pci_read_config_dword(dev, 0x44, &reg1);
+ pci_read_config_dword(dev, 0x48, &reg2);
+ tmp1 = ((0x00 << (3*drive->dn)) | (reg1 & ~(7 << (3*drive->dn))));
+ tmp2 = (reg2 & ~(0x11 << drive->dn));
+ pci_write_config_dword(dev, 0x44, tmp1);
+ pci_write_config_dword(dev, 0x48, tmp2);
+}
+
+static int hpt34x_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+ struct pci_dev *dev = HWIF(drive)->pci_dev;
+ u8 speed = ide_rate_filter(hpt34x_ratemask(drive), xferspeed);
+ u32 reg1= 0, tmp1 = 0, reg2 = 0, tmp2 = 0;
+ u8 hi_speed, lo_speed;
+
+ hi_speed = speed >> 4;
+ lo_speed = speed & 0x0f;
+
+ if (hi_speed & 7) {
+ hi_speed = (hi_speed & 4) ? 0x01 : 0x10;
+ } else {
+ lo_speed <<= 5;
+ lo_speed >>= 5;
+ }
+
+ pci_read_config_dword(dev, 0x44, &reg1);
+ pci_read_config_dword(dev, 0x48, &reg2);
+ tmp1 = ((lo_speed << (3*drive->dn)) | (reg1 & ~(7 << (3*drive->dn))));
+ tmp2 = ((hi_speed << drive->dn) | reg2);
+ pci_write_config_dword(dev, 0x44, tmp1);
+ pci_write_config_dword(dev, 0x48, tmp2);
+
+#if HPT343_DEBUG_DRIVE_INFO
+ printk("%s: %s drive%d (0x%04x 0x%04x) (0x%04x 0x%04x)" \
+ " (0x%02x 0x%02x)\n",
+ drive->name, ide_xfer_verbose(speed),
+ drive->dn, reg1, tmp1, reg2, tmp2,
+ hi_speed, lo_speed);
+#endif /* HPT343_DEBUG_DRIVE_INFO */
+
+ return(ide_config_drive_speed(drive, speed));
+}
+
+static void hpt34x_tune_drive (ide_drive_t *drive, u8 pio)
+{
+ pio = ide_get_best_pio_mode(drive, pio, 5, NULL);
+ hpt34x_clear_chipset(drive);
+ (void) hpt34x_tune_chipset(drive, (XFER_PIO_0 + pio));
+}
+
+/*
+ * This allows the configuration of ide_pci chipset registers
+ * for cards that learn about the drive's UDMA, DMA, PIO capabilities
+ * after the drive is reported by the OS. Initially for designed for
+ * HPT343 UDMA chipset by HighPoint|Triones Technologies, Inc.
+ */
+
+static int config_chipset_for_dma (ide_drive_t *drive)
+{
+ u8 speed = ide_dma_speed(drive, hpt34x_ratemask(drive));
+
+ if (!(speed))
+ return 0;
+
+ hpt34x_clear_chipset(drive);
+ (void) hpt34x_tune_chipset(drive, speed);
+ return ide_dma_enable(drive);
+}
+
+static int hpt34x_config_drive_xfer_rate (ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct hd_driveid *id = drive->id;
+
+ drive->init_speed = 0;
+
+ if (id && (id->capability & 1) && drive->autodma) {
+
+ if (ide_use_dma(drive)) {
+ if (config_chipset_for_dma(drive))
+#ifndef CONFIG_HPT34X_AUTODMA
+ return hwif->ide_dma_off_quietly(drive);
+#else
+ return hwif->ide_dma_on(drive);
+#endif
+ }
+
+ goto fast_ata_pio;
+
+ } else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+ hpt34x_tune_drive(drive, 255);
+ return hwif->ide_dma_off_quietly(drive);
+ }
+ /* IORDY not supported */
+ return 0;
+}
+
+/*
+ * If the BIOS does not set the IO base addaress to XX00, 343 will fail.
+ */
+#define HPT34X_PCI_INIT_REG 0x80
+
+static unsigned int __devinit init_chipset_hpt34x(struct pci_dev *dev, const char *name)
+{
+ int i = 0;
+ unsigned long hpt34xIoBase = pci_resource_start(dev, 4);
+ unsigned long hpt_addr[4] = { 0x20, 0x34, 0x28, 0x3c };
+ unsigned long hpt_addr_len[4] = { 7, 3, 7, 3 };
+ u16 cmd;
+ unsigned long flags;
+
+ local_irq_save(flags);
+
+ pci_write_config_byte(dev, HPT34X_PCI_INIT_REG, 0x00);
+ pci_read_config_word(dev, PCI_COMMAND, &cmd);
+
+ if (cmd & PCI_COMMAND_MEMORY) {
+ if (pci_resource_start(dev, PCI_ROM_RESOURCE)) {
+ pci_write_config_byte(dev, PCI_ROM_ADDRESS,
+ dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
+ printk(KERN_INFO "HPT345: ROM enabled at 0x%08lx\n",
+ dev->resource[PCI_ROM_RESOURCE].start);
+ }
+ pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xF0);
+ } else {
+ pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x20);
+ }
+
+ /*
+ * Since 20-23 can be assigned and are R/W, we correct them.
+ */
+ pci_write_config_word(dev, PCI_COMMAND, cmd & ~PCI_COMMAND_IO);
+ for(i=0; i<4; i++) {
+ dev->resource[i].start = (hpt34xIoBase + hpt_addr[i]);
+ dev->resource[i].end = dev->resource[i].start + hpt_addr_len[i];
+ dev->resource[i].flags = IORESOURCE_IO;
+ pci_write_config_dword(dev,
+ (PCI_BASE_ADDRESS_0 + (i * 4)),
+ dev->resource[i].start);
+ }
+ pci_write_config_word(dev, PCI_COMMAND, cmd);
+
+ local_irq_restore(flags);
+
+ return dev->irq;
+}
+
+static void __devinit init_hwif_hpt34x(ide_hwif_t *hwif)
+{
+ u16 pcicmd = 0;
+
+ hwif->autodma = 0;
+
+ hwif->tuneproc = &hpt34x_tune_drive;
+ hwif->speedproc = &hpt34x_tune_chipset;
+ hwif->no_dsc = 1;
+ hwif->drives[0].autotune = 1;
+ hwif->drives[1].autotune = 1;
+
+ pci_read_config_word(hwif->pci_dev, PCI_COMMAND, &pcicmd);
+
+ if (!hwif->dma_base)
+ return;
+
+ hwif->ultra_mask = 0x07;
+ hwif->mwdma_mask = 0x07;
+ hwif->swdma_mask = 0x07;
+
+ hwif->ide_dma_check = &hpt34x_config_drive_xfer_rate;
+ if (!noautodma)
+ hwif->autodma = (pcicmd & PCI_COMMAND_MEMORY) ? 1 : 0;
+ hwif->drives[0].autodma = hwif->autodma;
+ hwif->drives[1].autodma = hwif->autodma;
+}
+
+static ide_pci_device_t hpt34x_chipset __devinitdata = {
+ .name = "HPT34X",
+ .init_chipset = init_chipset_hpt34x,
+ .init_hwif = init_hwif_hpt34x,
+ .channels = 2,
+ .autodma = NOAUTODMA,
+ .bootable = NEVER_BOARD,
+ .extra = 16
+};
+
+static int __devinit hpt34x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ ide_pci_device_t *d = &hpt34x_chipset;
+ static char *chipset_names[] = {"HPT343", "HPT345"};
+ u16 pcicmd = 0;
+
+ pci_read_config_word(dev, PCI_COMMAND, &pcicmd);
+
+ d->name = chipset_names[(pcicmd & PCI_COMMAND_MEMORY) ? 1 : 0];
+ d->bootable = (pcicmd & PCI_COMMAND_MEMORY) ? OFF_BOARD : NEVER_BOARD;
+
+ return ide_setup_pci_device(dev, d);
+}
+
+static struct pci_device_id hpt34x_pci_tbl[] = {
+ { PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT343, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { 0, },
+};
+MODULE_DEVICE_TABLE(pci, hpt34x_pci_tbl);
+
+static struct pci_driver driver = {
+ .name = "HPT34x_IDE",
+ .id_table = hpt34x_pci_tbl,
+ .probe = hpt34x_init_one,
+};
+
+static int hpt34x_ide_init(void)
+{
+ return ide_pci_register_driver(&driver);
+}
+
+module_init(hpt34x_ide_init);
+
+MODULE_AUTHOR("Andre Hedrick");
+MODULE_DESCRIPTION("PCI driver module for Highpoint 34x IDE");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/pci/hpt366.c b/drivers/ide/pci/hpt366.c
new file mode 100644
index 000000000000..c8ee0b8c0292
--- /dev/null
+++ b/drivers/ide/pci/hpt366.c
@@ -0,0 +1,1745 @@
+/*
+ * linux/drivers/ide/pci/hpt366.c Version 0.36 April 25, 2003
+ *
+ * Copyright (C) 1999-2003 Andre Hedrick <andre@linux-ide.org>
+ * Portions Copyright (C) 2001 Sun Microsystems, Inc.
+ * Portions Copyright (C) 2003 Red Hat Inc
+ *
+ * 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.
+ *
+ * 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@redhat.com>
+ *
+ */
+
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/module.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/hdreg.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>
+#include <asm/irq.h>
+
+/* various tuning parameters */
+#define HPT_RESET_STATE_ENGINE
+#undef HPT_DELAY_INTERRUPT
+#undef HPT_SERIALIZE_IO
+
+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",
+ 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
+};
+
+struct chipset_bus_clock_list_entry {
+ u8 xfer_speed;
+ unsigned int chipset_settings;
+};
+
+/* key for bus clock timings
+ * bit
+ * 0:3 data_high_time. inactive time of DIOW_/DIOR_ for PIO and MW
+ * DMA. cycles = value + 1
+ * 4:8 data_low_time. active time of DIOW_/DIOR_ for PIO and MW
+ * DMA. cycles = value + 1
+ * 9:12 cmd_high_time. inactive time of DIOW_/DIOR_ during task file
+ * register access.
+ * 13:17 cmd_low_time. active time of DIOW_/DIOR_ during task file
+ * register access.
+ * 18:21 udma_cycle_time. clock freq and clock cycles for UDMA xfer.
+ * during task file register access.
+ * 22:24 pre_high_time. time to initialize 1st cycle for PIO and MW DMA
+ * xfer.
+ * 25:27 cmd_pre_high_time. time to initialize 1st PIO cycle for task
+ * register access.
+ * 28 UDMA enable
+ * 29 DMA enable
+ * 30 PIO_MST enable. if set, the chip is in bus master mode during
+ * PIO.
+ * 31 FIFO enable.
+ */
+static struct chipset_bus_clock_list_entry forty_base_hpt366[] = {
+ { XFER_UDMA_4, 0x900fd943 },
+ { XFER_UDMA_3, 0x900ad943 },
+ { XFER_UDMA_2, 0x900bd943 },
+ { XFER_UDMA_1, 0x9008d943 },
+ { XFER_UDMA_0, 0x9008d943 },
+
+ { XFER_MW_DMA_2, 0xa008d943 },
+ { XFER_MW_DMA_1, 0xa010d955 },
+ { XFER_MW_DMA_0, 0xa010d9fc },
+
+ { XFER_PIO_4, 0xc008d963 },
+ { XFER_PIO_3, 0xc010d974 },
+ { XFER_PIO_2, 0xc010d997 },
+ { XFER_PIO_1, 0xc010d9c7 },
+ { XFER_PIO_0, 0xc018d9d9 },
+ { 0, 0x0120d9d9 }
+};
+
+static struct chipset_bus_clock_list_entry thirty_three_base_hpt366[] = {
+ { XFER_UDMA_4, 0x90c9a731 },
+ { XFER_UDMA_3, 0x90cfa731 },
+ { XFER_UDMA_2, 0x90caa731 },
+ { XFER_UDMA_1, 0x90cba731 },
+ { XFER_UDMA_0, 0x90c8a731 },
+
+ { XFER_MW_DMA_2, 0xa0c8a731 },
+ { XFER_MW_DMA_1, 0xa0c8a732 }, /* 0xa0c8a733 */
+ { XFER_MW_DMA_0, 0xa0c8a797 },
+
+ { XFER_PIO_4, 0xc0c8a731 },
+ { XFER_PIO_3, 0xc0c8a742 },
+ { XFER_PIO_2, 0xc0d0a753 },
+ { XFER_PIO_1, 0xc0d0a7a3 }, /* 0xc0d0a793 */
+ { XFER_PIO_0, 0xc0d0a7aa }, /* 0xc0d0a7a7 */
+ { 0, 0x0120a7a7 }
+};
+
+static struct chipset_bus_clock_list_entry twenty_five_base_hpt366[] = {
+ { XFER_UDMA_4, 0x90c98521 },
+ { XFER_UDMA_3, 0x90cf8521 },
+ { XFER_UDMA_2, 0x90cf8521 },
+ { XFER_UDMA_1, 0x90cb8521 },
+ { XFER_UDMA_0, 0x90cb8521 },
+
+ { XFER_MW_DMA_2, 0xa0ca8521 },
+ { XFER_MW_DMA_1, 0xa0ca8532 },
+ { XFER_MW_DMA_0, 0xa0ca8575 },
+
+ { XFER_PIO_4, 0xc0ca8521 },
+ { XFER_PIO_3, 0xc0ca8532 },
+ { XFER_PIO_2, 0xc0ca8542 },
+ { XFER_PIO_1, 0xc0d08572 },
+ { XFER_PIO_0, 0xc0d08585 },
+ { 0, 0x01208585 }
+};
+
+/* from highpoint documentation. these are old values */
+static struct chipset_bus_clock_list_entry thirty_three_base_hpt370[] = {
+/* { XFER_UDMA_5, 0x1A85F442, 0x16454e31 }, */
+ { XFER_UDMA_5, 0x16454e31 },
+ { XFER_UDMA_4, 0x16454e31 },
+ { XFER_UDMA_3, 0x166d4e31 },
+ { XFER_UDMA_2, 0x16494e31 },
+ { XFER_UDMA_1, 0x164d4e31 },
+ { XFER_UDMA_0, 0x16514e31 },
+
+ { XFER_MW_DMA_2, 0x26514e21 },
+ { XFER_MW_DMA_1, 0x26514e33 },
+ { XFER_MW_DMA_0, 0x26514e97 },
+
+ { XFER_PIO_4, 0x06514e21 },
+ { XFER_PIO_3, 0x06514e22 },
+ { XFER_PIO_2, 0x06514e33 },
+ { XFER_PIO_1, 0x06914e43 },
+ { XFER_PIO_0, 0x06914e57 },
+ { 0, 0x06514e57 }
+};
+
+static struct chipset_bus_clock_list_entry sixty_six_base_hpt370[] = {
+ { XFER_UDMA_5, 0x14846231 },
+ { XFER_UDMA_4, 0x14886231 },
+ { XFER_UDMA_3, 0x148c6231 },
+ { XFER_UDMA_2, 0x148c6231 },
+ { XFER_UDMA_1, 0x14906231 },
+ { XFER_UDMA_0, 0x14986231 },
+
+ { XFER_MW_DMA_2, 0x26514e21 },
+ { XFER_MW_DMA_1, 0x26514e33 },
+ { XFER_MW_DMA_0, 0x26514e97 },
+
+ { XFER_PIO_4, 0x06514e21 },
+ { XFER_PIO_3, 0x06514e22 },
+ { XFER_PIO_2, 0x06514e33 },
+ { XFER_PIO_1, 0x06914e43 },
+ { XFER_PIO_0, 0x06914e57 },
+ { 0, 0x06514e57 }
+};
+
+/* these are the current (4 sep 2001) timings from highpoint */
+static struct chipset_bus_clock_list_entry thirty_three_base_hpt370a[] = {
+ { XFER_UDMA_5, 0x12446231 },
+ { XFER_UDMA_4, 0x12446231 },
+ { XFER_UDMA_3, 0x126c6231 },
+ { XFER_UDMA_2, 0x12486231 },
+ { XFER_UDMA_1, 0x124c6233 },
+ { XFER_UDMA_0, 0x12506297 },
+
+ { XFER_MW_DMA_2, 0x22406c31 },
+ { XFER_MW_DMA_1, 0x22406c33 },
+ { XFER_MW_DMA_0, 0x22406c97 },
+
+ { XFER_PIO_4, 0x06414e31 },
+ { XFER_PIO_3, 0x06414e42 },
+ { XFER_PIO_2, 0x06414e53 },
+ { XFER_PIO_1, 0x06814e93 },
+ { XFER_PIO_0, 0x06814ea7 },
+ { 0, 0x06814ea7 }
+};
+
+/* 2x 33MHz timings */
+static struct chipset_bus_clock_list_entry sixty_six_base_hpt370a[] = {
+ { XFER_UDMA_5, 0x1488e673 },
+ { XFER_UDMA_4, 0x1488e673 },
+ { XFER_UDMA_3, 0x1498e673 },
+ { XFER_UDMA_2, 0x1490e673 },
+ { XFER_UDMA_1, 0x1498e677 },
+ { XFER_UDMA_0, 0x14a0e73f },
+
+ { XFER_MW_DMA_2, 0x2480fa73 },
+ { XFER_MW_DMA_1, 0x2480fa77 },
+ { XFER_MW_DMA_0, 0x2480fb3f },
+
+ { XFER_PIO_4, 0x0c82be73 },
+ { XFER_PIO_3, 0x0c82be95 },
+ { XFER_PIO_2, 0x0c82beb7 },
+ { XFER_PIO_1, 0x0d02bf37 },
+ { XFER_PIO_0, 0x0d02bf5f },
+ { 0, 0x0d02bf5f }
+};
+
+static struct chipset_bus_clock_list_entry fifty_base_hpt370a[] = {
+ { XFER_UDMA_5, 0x12848242 },
+ { XFER_UDMA_4, 0x12ac8242 },
+ { XFER_UDMA_3, 0x128c8242 },
+ { XFER_UDMA_2, 0x120c8242 },
+ { XFER_UDMA_1, 0x12148254 },
+ { XFER_UDMA_0, 0x121882ea },
+
+ { XFER_MW_DMA_2, 0x22808242 },
+ { XFER_MW_DMA_1, 0x22808254 },
+ { XFER_MW_DMA_0, 0x228082ea },
+
+ { XFER_PIO_4, 0x0a81f442 },
+ { XFER_PIO_3, 0x0a81f443 },
+ { XFER_PIO_2, 0x0a81f454 },
+ { XFER_PIO_1, 0x0ac1f465 },
+ { XFER_PIO_0, 0x0ac1f48a },
+ { 0, 0x0ac1f48a }
+};
+
+static struct chipset_bus_clock_list_entry thirty_three_base_hpt372[] = {
+ { XFER_UDMA_6, 0x1c81dc62 },
+ { XFER_UDMA_5, 0x1c6ddc62 },
+ { XFER_UDMA_4, 0x1c8ddc62 },
+ { XFER_UDMA_3, 0x1c8edc62 }, /* checkme */
+ { XFER_UDMA_2, 0x1c91dc62 },
+ { XFER_UDMA_1, 0x1c9adc62 }, /* checkme */
+ { XFER_UDMA_0, 0x1c82dc62 }, /* checkme */
+
+ { XFER_MW_DMA_2, 0x2c829262 },
+ { XFER_MW_DMA_1, 0x2c829266 }, /* checkme */
+ { XFER_MW_DMA_0, 0x2c82922e }, /* checkme */
+
+ { XFER_PIO_4, 0x0c829c62 },
+ { XFER_PIO_3, 0x0c829c84 },
+ { XFER_PIO_2, 0x0c829ca6 },
+ { XFER_PIO_1, 0x0d029d26 },
+ { XFER_PIO_0, 0x0d029d5e },
+ { 0, 0x0d029d5e }
+};
+
+static struct chipset_bus_clock_list_entry fifty_base_hpt372[] = {
+ { XFER_UDMA_5, 0x12848242 },
+ { XFER_UDMA_4, 0x12ac8242 },
+ { XFER_UDMA_3, 0x128c8242 },
+ { XFER_UDMA_2, 0x120c8242 },
+ { XFER_UDMA_1, 0x12148254 },
+ { XFER_UDMA_0, 0x121882ea },
+
+ { XFER_MW_DMA_2, 0x22808242 },
+ { XFER_MW_DMA_1, 0x22808254 },
+ { XFER_MW_DMA_0, 0x228082ea },
+
+ { XFER_PIO_4, 0x0a81f442 },
+ { XFER_PIO_3, 0x0a81f443 },
+ { XFER_PIO_2, 0x0a81f454 },
+ { XFER_PIO_1, 0x0ac1f465 },
+ { XFER_PIO_0, 0x0ac1f48a },
+ { 0, 0x0a81f443 }
+};
+
+static struct chipset_bus_clock_list_entry sixty_six_base_hpt372[] = {
+ { XFER_UDMA_6, 0x1c869c62 },
+ { XFER_UDMA_5, 0x1cae9c62 },
+ { XFER_UDMA_4, 0x1c8a9c62 },
+ { XFER_UDMA_3, 0x1c8e9c62 },
+ { XFER_UDMA_2, 0x1c929c62 },
+ { XFER_UDMA_1, 0x1c9a9c62 },
+ { XFER_UDMA_0, 0x1c829c62 },
+
+ { XFER_MW_DMA_2, 0x2c829c62 },
+ { XFER_MW_DMA_1, 0x2c829c66 },
+ { XFER_MW_DMA_0, 0x2c829d2e },
+
+ { XFER_PIO_4, 0x0c829c62 },
+ { XFER_PIO_3, 0x0c829c84 },
+ { XFER_PIO_2, 0x0c829ca6 },
+ { XFER_PIO_1, 0x0d029d26 },
+ { XFER_PIO_0, 0x0d029d5e },
+ { 0, 0x0d029d26 }
+};
+
+static struct chipset_bus_clock_list_entry thirty_three_base_hpt374[] = {
+ { XFER_UDMA_6, 0x12808242 },
+ { XFER_UDMA_5, 0x12848242 },
+ { XFER_UDMA_4, 0x12ac8242 },
+ { XFER_UDMA_3, 0x128c8242 },
+ { XFER_UDMA_2, 0x120c8242 },
+ { XFER_UDMA_1, 0x12148254 },
+ { XFER_UDMA_0, 0x121882ea },
+
+ { XFER_MW_DMA_2, 0x22808242 },
+ { XFER_MW_DMA_1, 0x22808254 },
+ { XFER_MW_DMA_0, 0x228082ea },
+
+ { XFER_PIO_4, 0x0a81f442 },
+ { XFER_PIO_3, 0x0a81f443 },
+ { XFER_PIO_2, 0x0a81f454 },
+ { XFER_PIO_1, 0x0ac1f465 },
+ { XFER_PIO_0, 0x0ac1f48a },
+ { 0, 0x06814e93 }
+};
+
+/* FIXME: 50MHz timings for HPT374 */
+
+#if 0
+static struct chipset_bus_clock_list_entry sixty_six_base_hpt374[] = {
+ { XFER_UDMA_6, 0x12406231 }, /* checkme */
+ { XFER_UDMA_5, 0x12446231 }, /* 0x14846231 */
+ { XFER_UDMA_4, 0x16814ea7 }, /* 0x14886231 */
+ { XFER_UDMA_3, 0x16814ea7 }, /* 0x148c6231 */
+ { XFER_UDMA_2, 0x16814ea7 }, /* 0x148c6231 */
+ { XFER_UDMA_1, 0x16814ea7 }, /* 0x14906231 */
+ { XFER_UDMA_0, 0x16814ea7 }, /* 0x14986231 */
+ { XFER_MW_DMA_2, 0x16814ea7 }, /* 0x26514e21 */
+ { XFER_MW_DMA_1, 0x16814ea7 }, /* 0x26514e97 */
+ { XFER_MW_DMA_0, 0x16814ea7 }, /* 0x26514e97 */
+ { XFER_PIO_4, 0x06814ea7 }, /* 0x06514e21 */
+ { XFER_PIO_3, 0x06814ea7 }, /* 0x06514e22 */
+ { XFER_PIO_2, 0x06814ea7 }, /* 0x06514e33 */
+ { XFER_PIO_1, 0x06814ea7 }, /* 0x06914e43 */
+ { XFER_PIO_0, 0x06814ea7 }, /* 0x06914e57 */
+ { 0, 0x06814ea7 }
+};
+#endif
+
+#define HPT366_DEBUG_DRIVE_INFO 0
+#define HPT374_ALLOW_ATA133_6 0
+#define HPT371_ALLOW_ATA133_6 0
+#define HPT302_ALLOW_ATA133_6 0
+#define HPT372_ALLOW_ATA133_6 1
+#define HPT370_ALLOW_ATA100_5 1
+#define HPT366_ALLOW_ATA66_4 1
+#define HPT366_ALLOW_ATA66_3 1
+#define HPT366_MAX_DEVS 8
+
+#define F_LOW_PCI_33 0x23
+#define F_LOW_PCI_40 0x29
+#define F_LOW_PCI_50 0x2d
+#define F_LOW_PCI_66 0x42
+
+/* FIXME: compare with driver's code before removing */
+#if 0
+ if (hpt_minimum_revision(dev, 3)) {
+ u8 cbl;
+ cbl = inb(iobase + 0x7b);
+ outb(cbl | 1, iobase + 0x7b);
+ outb(cbl & ~1, iobase + 0x7b);
+ cbl = inb(iobase + 0x7a);
+ p += sprintf(p, "Cable: ATA-%d"
+ " ATA-%d\n",
+ (cbl & 0x02) ? 33 : 66,
+ (cbl & 0x01) ? 33 : 66);
+ p += sprintf(p, "\n");
+ }
+ {
+ u8 c2, c3;
+ /* older revs don't have these registers mapped
+ * into io space */
+ pci_read_config_byte(dev, 0x43, &c0);
+ pci_read_config_byte(dev, 0x47, &c1);
+ pci_read_config_byte(dev, 0x4b, &c2);
+ pci_read_config_byte(dev, 0x4f, &c3);
+
+ p += sprintf(p, "Mode: %s %s"
+ " %s %s\n",
+ (c0 & 0x10) ? "UDMA" : (c0 & 0x20) ? "DMA " :
+ (c0 & 0x80) ? "PIO " : "off ",
+ (c1 & 0x10) ? "UDMA" : (c1 & 0x20) ? "DMA " :
+ (c1 & 0x80) ? "PIO " : "off ",
+ (c2 & 0x10) ? "UDMA" : (c2 & 0x20) ? "DMA " :
+ (c2 & 0x80) ? "PIO " : "off ",
+ (c3 & 0x10) ? "UDMA" : (c3 & 0x20) ? "DMA " :
+ (c3 & 0x80) ? "PIO " : "off ");
+ }
+ }
+#endif
+
+static u32 hpt_revision (struct pci_dev *dev)
+{
+ u32 class_rev;
+ pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
+ class_rev &= 0xff;
+
+ switch(dev->device) {
+ /* Remap new 372N onto 372 */
+ case PCI_DEVICE_ID_TTI_HPT372N:
+ class_rev = PCI_DEVICE_ID_TTI_HPT372; break;
+ case PCI_DEVICE_ID_TTI_HPT374:
+ class_rev = PCI_DEVICE_ID_TTI_HPT374; break;
+ case PCI_DEVICE_ID_TTI_HPT371:
+ class_rev = PCI_DEVICE_ID_TTI_HPT371; break;
+ case PCI_DEVICE_ID_TTI_HPT302:
+ class_rev = PCI_DEVICE_ID_TTI_HPT302; break;
+ case PCI_DEVICE_ID_TTI_HPT372:
+ class_rev = PCI_DEVICE_ID_TTI_HPT372; break;
+ default:
+ break;
+ }
+ return class_rev;
+}
+
+static u32 hpt_minimum_revision (struct pci_dev *dev, int revision)
+{
+ unsigned int class_rev = hpt_revision(dev);
+ revision--;
+ return ((int) (class_rev > revision) ? 1 : 0);
+}
+
+static int check_in_drive_lists(ide_drive_t *drive, const char **list);
+
+static u8 hpt3xx_ratemask (ide_drive_t *drive)
+{
+ struct pci_dev *dev = HWIF(drive)->pci_dev;
+ u8 mode = 0;
+
+ if (hpt_minimum_revision(dev, 8)) { /* HPT374 */
+ mode = (HPT374_ALLOW_ATA133_6) ? 4 : 3;
+ } else if (hpt_minimum_revision(dev, 7)) { /* HPT371 */
+ mode = (HPT371_ALLOW_ATA133_6) ? 4 : 3;
+ } else if (hpt_minimum_revision(dev, 6)) { /* HPT302 */
+ mode = (HPT302_ALLOW_ATA133_6) ? 4 : 3;
+ } else if (hpt_minimum_revision(dev, 5)) { /* HPT372 */
+ mode = (HPT372_ALLOW_ATA133_6) ? 4 : 3;
+ } else if (hpt_minimum_revision(dev, 4)) { /* HPT370A */
+ mode = (HPT370_ALLOW_ATA100_5) ? 3 : 2;
+ } else if (hpt_minimum_revision(dev, 3)) { /* HPT370 */
+ mode = (HPT370_ALLOW_ATA100_5) ? 3 : 2;
+ mode = (check_in_drive_lists(drive, bad_ata33)) ? 0 : mode;
+ } else { /* HPT366 and HPT368 */
+ mode = (check_in_drive_lists(drive, bad_ata33)) ? 0 : 2;
+ }
+ if (!eighty_ninty_three(drive) && (mode))
+ mode = min(mode, (u8)1);
+ return mode;
+}
+
+/*
+ * Note for the future; the SATA hpt37x we must set
+ * either PIO or UDMA modes 0,4,5
+ */
+
+static u8 hpt3xx_ratefilter (ide_drive_t *drive, u8 speed)
+{
+ struct pci_dev *dev = HWIF(drive)->pci_dev;
+ u8 mode = hpt3xx_ratemask(drive);
+
+ if (drive->media != ide_disk)
+ return min(speed, (u8)XFER_PIO_4);
+
+ switch(mode) {
+ case 0x04:
+ speed = min(speed, (u8)XFER_UDMA_6);
+ break;
+ case 0x03:
+ speed = min(speed, (u8)XFER_UDMA_5);
+ if (hpt_minimum_revision(dev, 5))
+ break;
+ if (check_in_drive_lists(drive, bad_ata100_5))
+ speed = min(speed, (u8)XFER_UDMA_4);
+ break;
+ case 0x02:
+ speed = min(speed, (u8)XFER_UDMA_4);
+ /*
+ * CHECK ME, Does this need to be set to 5 ??
+ */
+ if (hpt_minimum_revision(dev, 3))
+ break;
+ if ((check_in_drive_lists(drive, bad_ata66_4)) ||
+ (!(HPT366_ALLOW_ATA66_4)))
+ speed = min(speed, (u8)XFER_UDMA_3);
+ if ((check_in_drive_lists(drive, bad_ata66_3)) ||
+ (!(HPT366_ALLOW_ATA66_3)))
+ speed = min(speed, (u8)XFER_UDMA_2);
+ break;
+ case 0x01:
+ speed = min(speed, (u8)XFER_UDMA_2);
+ /*
+ * CHECK ME, Does this need to be set to 5 ??
+ */
+ if (hpt_minimum_revision(dev, 3))
+ break;
+ if (check_in_drive_lists(drive, bad_ata33))
+ speed = min(speed, (u8)XFER_MW_DMA_2);
+ break;
+ case 0x00:
+ default:
+ speed = min(speed, (u8)XFER_MW_DMA_2);
+ break;
+ }
+ return speed;
+}
+
+static int check_in_drive_lists (ide_drive_t *drive, const char **list)
+{
+ struct hd_driveid *id = drive->id;
+
+ if (quirk_drives == list) {
+ while (*list)
+ if (strstr(id->model, *list++))
+ return 1;
+ } else {
+ while (*list)
+ if (!strcmp(*list++,id->model))
+ return 1;
+ }
+ return 0;
+}
+
+static unsigned int 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 int hpt36x_tune_chipset(ide_drive_t *drive, u8 xferspeed)
+{
+ struct pci_dev *dev = HWIF(drive)->pci_dev;
+ u8 speed = hpt3xx_ratefilter(drive, xferspeed);
+// u8 speed = ide_rate_filter(hpt3xx_ratemask(drive), xferspeed);
+ u8 regtime = (drive->select.b.unit & 0x01) ? 0x44 : 0x40;
+ u8 regfast = (HWIF(drive)->channel) ? 0x55 : 0x51;
+ u8 drive_fast = 0;
+ u32 reg1 = 0, reg2 = 0;
+
+ /*
+ * Disable the "fast interrupt" prediction.
+ */
+ pci_read_config_byte(dev, regfast, &drive_fast);
+#if 0
+ if (drive_fast & 0x02)
+ pci_write_config_byte(dev, regfast, drive_fast & ~0x20);
+#else
+ if (drive_fast & 0x80)
+ pci_write_config_byte(dev, regfast, drive_fast & ~0x80);
+#endif
+
+ reg2 = pci_bus_clock_list(speed,
+ (struct chipset_bus_clock_list_entry *) pci_get_drvdata(dev));
+ /*
+ * Disable on-chip PIO FIFO/buffer
+ * (to avoid problems handling I/O errors later)
+ */
+ pci_read_config_dword(dev, regtime, &reg1);
+ if (speed >= XFER_MW_DMA_0) {
+ reg2 = (reg2 & ~0xc0000000) | (reg1 & 0xc0000000);
+ } else {
+ reg2 = (reg2 & ~0x30070000) | (reg1 & 0x30070000);
+ }
+ reg2 &= ~0x80000000;
+
+ pci_write_config_dword(dev, regtime, reg2);
+
+ return ide_config_drive_speed(drive, speed);
+}
+
+static int hpt370_tune_chipset(ide_drive_t *drive, u8 xferspeed)
+{
+ struct pci_dev *dev = HWIF(drive)->pci_dev;
+ u8 speed = hpt3xx_ratefilter(drive, xferspeed);
+// u8 speed = ide_rate_filter(hpt3xx_ratemask(drive), xferspeed);
+ u8 regfast = (HWIF(drive)->channel) ? 0x55 : 0x51;
+ u8 drive_pci = 0x40 + (drive->dn * 4);
+ u8 new_fast = 0, drive_fast = 0;
+ u32 list_conf = 0, drive_conf = 0;
+ u32 conf_mask = (speed >= XFER_MW_DMA_0) ? 0xc0000000 : 0x30070000;
+
+ /*
+ * Disable the "fast interrupt" prediction.
+ * don't holdoff on interrupts. (== 0x01 despite what the docs say)
+ */
+ pci_read_config_byte(dev, regfast, &drive_fast);
+ new_fast = drive_fast;
+ if (new_fast & 0x02)
+ new_fast &= ~0x02;
+
+#ifdef HPT_DELAY_INTERRUPT
+ if (new_fast & 0x01)
+ new_fast &= ~0x01;
+#else
+ if ((new_fast & 0x01) == 0)
+ new_fast |= 0x01;
+#endif
+ if (new_fast != drive_fast)
+ pci_write_config_byte(dev, regfast, new_fast);
+
+ list_conf = pci_bus_clock_list(speed,
+ (struct chipset_bus_clock_list_entry *)
+ pci_get_drvdata(dev));
+
+ pci_read_config_dword(dev, drive_pci, &drive_conf);
+ list_conf = (list_conf & ~conf_mask) | (drive_conf & conf_mask);
+
+ if (speed < XFER_MW_DMA_0) {
+ list_conf &= ~0x80000000; /* Disable on-chip PIO FIFO/buffer */
+ }
+
+ pci_write_config_dword(dev, drive_pci, list_conf);
+
+ return ide_config_drive_speed(drive, speed);
+}
+
+static int hpt372_tune_chipset(ide_drive_t *drive, u8 xferspeed)
+{
+ struct pci_dev *dev = HWIF(drive)->pci_dev;
+ u8 speed = hpt3xx_ratefilter(drive, xferspeed);
+// u8 speed = ide_rate_filter(hpt3xx_ratemask(drive), xferspeed);
+ u8 regfast = (HWIF(drive)->channel) ? 0x55 : 0x51;
+ u8 drive_fast = 0, drive_pci = 0x40 + (drive->dn * 4);
+ u32 list_conf = 0, drive_conf = 0;
+ u32 conf_mask = (speed >= XFER_MW_DMA_0) ? 0xc0000000 : 0x30070000;
+
+ /*
+ * Disable the "fast interrupt" prediction.
+ * don't holdoff on interrupts. (== 0x01 despite what the docs say)
+ */
+ pci_read_config_byte(dev, regfast, &drive_fast);
+ drive_fast &= ~0x07;
+ pci_write_config_byte(dev, regfast, drive_fast);
+
+ list_conf = pci_bus_clock_list(speed,
+ (struct chipset_bus_clock_list_entry *)
+ pci_get_drvdata(dev));
+ pci_read_config_dword(dev, drive_pci, &drive_conf);
+ list_conf = (list_conf & ~conf_mask) | (drive_conf & conf_mask);
+ if (speed < XFER_MW_DMA_0)
+ list_conf &= ~0x80000000; /* Disable on-chip PIO FIFO/buffer */
+ pci_write_config_dword(dev, drive_pci, list_conf);
+
+ return ide_config_drive_speed(drive, speed);
+}
+
+static int hpt3xx_tune_chipset (ide_drive_t *drive, u8 speed)
+{
+ struct pci_dev *dev = HWIF(drive)->pci_dev;
+
+ if (hpt_minimum_revision(dev, 8))
+ return hpt372_tune_chipset(drive, speed); /* not a typo */
+#if 0
+ else if (hpt_minimum_revision(dev, 7))
+ hpt371_tune_chipset(drive, speed);
+ else if (hpt_minimum_revision(dev, 6))
+ hpt302_tune_chipset(drive, speed);
+#endif
+ else if (hpt_minimum_revision(dev, 5))
+ return hpt372_tune_chipset(drive, speed);
+ else if (hpt_minimum_revision(dev, 3))
+ return hpt370_tune_chipset(drive, speed);
+ else /* hpt368: hpt_minimum_revision(dev, 2) */
+ return hpt36x_tune_chipset(drive, speed);
+}
+
+static void hpt3xx_tune_drive (ide_drive_t *drive, u8 pio)
+{
+ pio = ide_get_best_pio_mode(drive, 255, pio, NULL);
+ (void) hpt3xx_tune_chipset(drive, (XFER_PIO_0 + pio));
+}
+
+/*
+ * This allows the configuration of ide_pci chipset registers
+ * for cards that learn about the drive's UDMA, DMA, PIO capabilities
+ * after the drive is reported by the OS. Initially for designed for
+ * HPT366 UDMA chipset by HighPoint|Triones Technologies, Inc.
+ *
+ * check_in_drive_lists(drive, bad_ata66_4)
+ * check_in_drive_lists(drive, bad_ata66_3)
+ * check_in_drive_lists(drive, bad_ata33)
+ *
+ */
+static int config_chipset_for_dma (ide_drive_t *drive)
+{
+ u8 speed = ide_dma_speed(drive, hpt3xx_ratemask(drive));
+
+ if (!(speed))
+ return 0;
+
+ (void) hpt3xx_tune_chipset(drive, speed);
+ return ide_dma_enable(drive);
+}
+
+static int hpt3xx_quirkproc (ide_drive_t *drive)
+{
+ return ((int) check_in_drive_lists(drive, quirk_drives));
+}
+
+static void hpt3xx_intrproc (ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+
+ if (drive->quirk_list)
+ return;
+ /* drives in the quirk_list may not like intr setups/cleanups */
+ hwif->OUTB(drive->ctl|2, IDE_CONTROL_REG);
+}
+
+static void hpt3xx_maskproc (ide_drive_t *drive, int mask)
+{
+ struct pci_dev *dev = HWIF(drive)->pci_dev;
+
+ if (drive->quirk_list) {
+ if (hpt_minimum_revision(dev,3)) {
+ u8 reg5a = 0;
+ pci_read_config_byte(dev, 0x5a, &reg5a);
+ if (((reg5a & 0x10) >> 4) != mask)
+ pci_write_config_byte(dev, 0x5a, mask ? (reg5a | 0x10) : (reg5a & ~0x10));
+ } else {
+ if (mask) {
+ disable_irq(HWIF(drive)->irq);
+ } else {
+ enable_irq(HWIF(drive)->irq);
+ }
+ }
+ } else {
+ if (IDE_CONTROL_REG)
+ HWIF(drive)->OUTB(mask ? (drive->ctl | 2) :
+ (drive->ctl & ~2),
+ IDE_CONTROL_REG);
+ }
+}
+
+static int hpt366_config_drive_xfer_rate (ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct hd_driveid *id = drive->id;
+
+ drive->init_speed = 0;
+
+ if (id && (id->capability & 1) && drive->autodma) {
+
+ if (ide_use_dma(drive)) {
+ if (config_chipset_for_dma(drive))
+ return hwif->ide_dma_on(drive);
+ }
+
+ goto fast_ata_pio;
+
+ } else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+ hpt3xx_tune_drive(drive, 5);
+ return hwif->ide_dma_off_quietly(drive);
+ }
+ /* IORDY not supported */
+ return 0;
+}
+
+/*
+ * This is specific to the HPT366 UDMA bios chipset
+ * by HighPoint|Triones Technologies, Inc.
+ */
+static int hpt366_ide_dma_lostirq (ide_drive_t *drive)
+{
+ struct pci_dev *dev = HWIF(drive)->pci_dev;
+ u8 reg50h = 0, reg52h = 0, reg5ah = 0;
+
+ pci_read_config_byte(dev, 0x50, &reg50h);
+ pci_read_config_byte(dev, 0x52, &reg52h);
+ pci_read_config_byte(dev, 0x5a, &reg5ah);
+ printk("%s: (%s) reg50h=0x%02x, reg52h=0x%02x, reg5ah=0x%02x\n",
+ drive->name, __FUNCTION__, reg50h, reg52h, reg5ah);
+ if (reg5ah & 0x10)
+ pci_write_config_byte(dev, 0x5a, reg5ah & ~0x10);
+#if 0
+ /* how about we flush and reset, mmmkay? */
+ pci_write_config_byte(dev, 0x51, 0x1F);
+ /* fall through to a reset */
+ case dma_start:
+ case ide_dma_end:
+ /* reset the chips state over and over.. */
+ pci_write_config_byte(dev, 0x51, 0x13);
+#endif
+ return __ide_dma_lostirq(drive);
+}
+
+static void hpt370_clear_engine (ide_drive_t *drive)
+{
+ u8 regstate = HWIF(drive)->channel ? 0x54 : 0x50;
+ pci_write_config_byte(HWIF(drive)->pci_dev, regstate, 0x37);
+ udelay(10);
+}
+
+static void hpt370_ide_dma_start(ide_drive_t *drive)
+{
+#ifdef HPT_RESET_STATE_ENGINE
+ hpt370_clear_engine(drive);
+#endif
+ ide_dma_start(drive);
+}
+
+static int hpt370_ide_dma_end (ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ u8 dma_stat = hwif->INB(hwif->dma_status);
+
+ if (dma_stat & 0x01) {
+ /* wait a little */
+ udelay(20);
+ dma_stat = hwif->INB(hwif->dma_status);
+ }
+ if ((dma_stat & 0x01) != 0)
+ /* fallthrough */
+ (void) HWIF(drive)->ide_dma_timeout(drive);
+
+ return __ide_dma_end(drive);
+}
+
+static void hpt370_lostirq_timeout (ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ u8 bfifo = 0, reginfo = hwif->channel ? 0x56 : 0x52;
+ u8 dma_stat = 0, dma_cmd = 0;
+
+ pci_read_config_byte(HWIF(drive)->pci_dev, reginfo, &bfifo);
+ printk("%s: %d bytes in FIFO\n", drive->name, bfifo);
+ hpt370_clear_engine(drive);
+ /* get dma command mode */
+ dma_cmd = hwif->INB(hwif->dma_command);
+ /* stop dma */
+ hwif->OUTB(dma_cmd & ~0x1, hwif->dma_command);
+ dma_stat = hwif->INB(hwif->dma_status);
+ /* clear errors */
+ hwif->OUTB(dma_stat | 0x6, hwif->dma_status);
+}
+
+static int hpt370_ide_dma_timeout (ide_drive_t *drive)
+{
+ hpt370_lostirq_timeout(drive);
+ hpt370_clear_engine(drive);
+ return __ide_dma_timeout(drive);
+}
+
+static int hpt370_ide_dma_lostirq (ide_drive_t *drive)
+{
+ hpt370_lostirq_timeout(drive);
+ hpt370_clear_engine(drive);
+ return __ide_dma_lostirq(drive);
+}
+
+/* returns 1 if DMA IRQ issued, 0 otherwise */
+static int hpt374_ide_dma_test_irq(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ u16 bfifo = 0;
+ u8 reginfo = hwif->channel ? 0x56 : 0x52;
+ u8 dma_stat;
+
+ pci_read_config_word(hwif->pci_dev, reginfo, &bfifo);
+ if (bfifo & 0x1FF) {
+// printk("%s: %d bytes in FIFO\n", drive->name, bfifo);
+ return 0;
+ }
+
+ dma_stat = hwif->INB(hwif->dma_status);
+ /* return 1 if INTR asserted */
+ if ((dma_stat & 4) == 4)
+ return 1;
+
+ if (!drive->waiting_for_dma)
+ printk(KERN_WARNING "%s: (%s) called while not waiting\n",
+ drive->name, __FUNCTION__);
+ return 0;
+}
+
+static int hpt374_ide_dma_end (ide_drive_t *drive)
+{
+ struct pci_dev *dev = HWIF(drive)->pci_dev;
+ ide_hwif_t *hwif = HWIF(drive);
+ u8 msc_stat = 0, mscreg = hwif->channel ? 0x54 : 0x50;
+ u8 bwsr_stat = 0, bwsr_mask = hwif->channel ? 0x02 : 0x01;
+
+ pci_read_config_byte(dev, 0x6a, &bwsr_stat);
+ pci_read_config_byte(dev, mscreg, &msc_stat);
+ if ((bwsr_stat & bwsr_mask) == bwsr_mask)
+ pci_write_config_byte(dev, mscreg, msc_stat|0x30);
+ return __ide_dma_end(drive);
+}
+
+/**
+ * hpt372n_set_clock - perform clock switching dance
+ * @drive: Drive to switch
+ * @mode: Switching mode (0x21 for write, 0x23 otherwise)
+ *
+ * Switch the DPLL clock on the HPT372N devices. This is a
+ * right mess.
+ */
+
+static void hpt372n_set_clock(ide_drive_t *drive, int mode)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+
+ /* FIXME: should we check for DMA active and BUG() */
+ /* Tristate the bus */
+ outb(0x80, hwif->dma_base+0x73);
+ outb(0x80, hwif->dma_base+0x77);
+
+ /* Switch clock and reset channels */
+ outb(mode, hwif->dma_base+0x7B);
+ outb(0xC0, hwif->dma_base+0x79);
+
+ /* Reset state machines */
+ outb(0x37, hwif->dma_base+0x70);
+ outb(0x37, hwif->dma_base+0x74);
+
+ /* Complete reset */
+ outb(0x00, hwif->dma_base+0x79);
+
+ /* Reconnect channels to bus */
+ outb(0x00, hwif->dma_base+0x73);
+ outb(0x00, hwif->dma_base+0x77);
+}
+
+/**
+ * hpt372n_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 the 372N.
+ * We need it because of the clock switching.
+ */
+
+static void hpt372n_rw_disk(ide_drive_t *drive, struct request *rq)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ int wantclock;
+
+ wantclock = rq_data_dir(rq) ? 0x23 : 0x21;
+
+ if (hwif->config_data != wantclock) {
+ hpt372n_set_clock(drive, wantclock);
+ hwif->config_data = wantclock;
+ }
+}
+
+/*
+ * Since SUN Cobalt is attempting to do this operation, I should disclose
+ * this has been a long time ago Thu Jul 27 16:40:57 2000 was the patch date
+ * HOTSWAP ATA Infrastructure.
+ */
+
+static void hpt3xx_reset (ide_drive_t *drive)
+{
+#if 0
+ unsigned long high_16 = pci_resource_start(HWIF(drive)->pci_dev, 4);
+ u8 reset = (HWIF(drive)->channel) ? 0x80 : 0x40;
+ u8 reg59h = 0;
+
+ pci_read_config_byte(HWIF(drive)->pci_dev, 0x59, &reg59h);
+ pci_write_config_byte(HWIF(drive)->pci_dev, 0x59, reg59h|reset);
+ pci_write_config_byte(HWIF(drive)->pci_dev, 0x59, reg59h);
+#endif
+}
+
+static int hpt3xx_tristate (ide_drive_t * drive, int state)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = hwif->pci_dev;
+ u8 reg59h = 0, reset = (hwif->channel) ? 0x80 : 0x40;
+ u8 regXXh = 0, state_reg= (hwif->channel) ? 0x57 : 0x53;
+
+// hwif->bus_state = state;
+
+ pci_read_config_byte(dev, 0x59, &reg59h);
+ pci_read_config_byte(dev, state_reg, &regXXh);
+
+ if (state) {
+ (void) ide_do_reset(drive);
+ pci_write_config_byte(dev, state_reg, regXXh|0x80);
+ pci_write_config_byte(dev, 0x59, reg59h|reset);
+ } else {
+ pci_write_config_byte(dev, 0x59, reg59h & ~(reset));
+ pci_write_config_byte(dev, state_reg, regXXh & ~(0x80));
+ (void) ide_do_reset(drive);
+ }
+ return 0;
+}
+
+/*
+ * set/get power state for a drive.
+ * turning the power off does the following things:
+ * 1) soft-reset the drive
+ * 2) tri-states the ide bus
+ *
+ * when we turn things back on, we need to re-initialize things.
+ */
+#define TRISTATE_BIT 0x8000
+static int hpt370_busproc(ide_drive_t * drive, int state)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = hwif->pci_dev;
+ u8 tristate = 0, resetmask = 0, bus_reg = 0;
+ u16 tri_reg;
+
+ hwif->bus_state = state;
+
+ if (hwif->channel) {
+ /* secondary channel */
+ tristate = 0x56;
+ resetmask = 0x80;
+ } else {
+ /* primary channel */
+ tristate = 0x52;
+ resetmask = 0x40;
+ }
+
+ /* grab status */
+ pci_read_config_word(dev, tristate, &tri_reg);
+ pci_read_config_byte(dev, 0x59, &bus_reg);
+
+ /* set the state. we don't set it if we don't need to do so.
+ * make sure that the drive knows that it has failed if it's off */
+ switch (state) {
+ case BUSSTATE_ON:
+ hwif->drives[0].failures = 0;
+ hwif->drives[1].failures = 0;
+ if ((bus_reg & resetmask) == 0)
+ return 0;
+ tri_reg &= ~TRISTATE_BIT;
+ bus_reg &= ~resetmask;
+ break;
+ case BUSSTATE_OFF:
+ hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
+ hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
+ if ((tri_reg & TRISTATE_BIT) == 0 && (bus_reg & resetmask))
+ return 0;
+ tri_reg &= ~TRISTATE_BIT;
+ bus_reg |= resetmask;
+ break;
+ case BUSSTATE_TRISTATE:
+ hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
+ hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
+ if ((tri_reg & TRISTATE_BIT) && (bus_reg & resetmask))
+ return 0;
+ tri_reg |= TRISTATE_BIT;
+ bus_reg |= resetmask;
+ break;
+ }
+ pci_write_config_byte(dev, 0x59, bus_reg);
+ pci_write_config_word(dev, tristate, tri_reg);
+
+ return 0;
+}
+
+static int __devinit init_hpt37x(struct pci_dev *dev)
+{
+ int adjust, i;
+ u16 freq;
+ u32 pll;
+ u8 reg5bh;
+ u8 reg5ah = 0;
+ unsigned long dmabase = pci_resource_start(dev, 4);
+ u8 did, rid;
+ int is_372n = 0;
+
+ pci_read_config_byte(dev, 0x5a, &reg5ah);
+ /* interrupt force enable */
+ pci_write_config_byte(dev, 0x5a, (reg5ah & ~0x10));
+
+ if(dmabase)
+ {
+ did = inb(dmabase + 0x22);
+ rid = inb(dmabase + 0x28);
+
+ if((did == 4 && rid == 6) || (did == 5 && rid > 1))
+ is_372n = 1;
+ }
+
+ /*
+ * 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);
+
+ /*
+ * set up the PLL. we need to adjust it so that it's stable.
+ * freq = Tpll * 192 / Tpci
+ *
+ * Todo. For non x86 should probably check the dword is
+ * set to 0xABCDExxx indicating the BIOS saved f_CNT
+ */
+ pci_read_config_word(dev, 0x78, &freq);
+ freq &= 0x1FF;
+
+ /*
+ * The 372N uses different PCI clock information and has
+ * some other complications
+ * On PCI33 timing we must clock switch
+ * On PCI66 timing we must NOT use the PCI clock
+ *
+ * Currently we always set up the PLL for the 372N
+ */
+
+ pci_set_drvdata(dev, NULL);
+
+ if(is_372n)
+ {
+ printk(KERN_INFO "hpt: HPT372N detected, using 372N timing.\n");
+ if(freq < 0x55)
+ pll = F_LOW_PCI_33;
+ else if(freq < 0x70)
+ pll = F_LOW_PCI_40;
+ else if(freq < 0x7F)
+ pll = F_LOW_PCI_50;
+ else
+ pll = F_LOW_PCI_66;
+
+ printk(KERN_INFO "FREQ: %d PLL: %d\n", freq, pll);
+
+ /* We always use the pll not the PCI clock on 372N */
+ }
+ else
+ {
+ if(freq < 0x9C)
+ pll = F_LOW_PCI_33;
+ else if(freq < 0xb0)
+ pll = F_LOW_PCI_40;
+ else if(freq <0xc8)
+ pll = F_LOW_PCI_50;
+ else
+ pll = F_LOW_PCI_66;
+
+ if (pll == F_LOW_PCI_33) {
+ if (hpt_minimum_revision(dev,8))
+ pci_set_drvdata(dev, (void *) thirty_three_base_hpt374);
+ else if (hpt_minimum_revision(dev,5))
+ pci_set_drvdata(dev, (void *) thirty_three_base_hpt372);
+ else if (hpt_minimum_revision(dev,4))
+ pci_set_drvdata(dev, (void *) thirty_three_base_hpt370a);
+ else
+ pci_set_drvdata(dev, (void *) thirty_three_base_hpt370);
+ printk("HPT37X: using 33MHz PCI clock\n");
+ } else if (pll == F_LOW_PCI_40) {
+ /* Unsupported */
+ } else if (pll == F_LOW_PCI_50) {
+ if (hpt_minimum_revision(dev,8))
+ pci_set_drvdata(dev, (void *) fifty_base_hpt370a);
+ else if (hpt_minimum_revision(dev,5))
+ pci_set_drvdata(dev, (void *) fifty_base_hpt372);
+ else if (hpt_minimum_revision(dev,4))
+ pci_set_drvdata(dev, (void *) fifty_base_hpt370a);
+ else
+ pci_set_drvdata(dev, (void *) fifty_base_hpt370a);
+ printk("HPT37X: using 50MHz PCI clock\n");
+ } else {
+ if (hpt_minimum_revision(dev,8))
+ {
+ printk(KERN_ERR "HPT37x: 66MHz timings are not supported.\n");
+ }
+ else if (hpt_minimum_revision(dev,5))
+ pci_set_drvdata(dev, (void *) sixty_six_base_hpt372);
+ else if (hpt_minimum_revision(dev,4))
+ pci_set_drvdata(dev, (void *) sixty_six_base_hpt370a);
+ else
+ pci_set_drvdata(dev, (void *) sixty_six_base_hpt370);
+ printk("HPT37X: using 66MHz PCI clock\n");
+ }
+ }
+
+ /*
+ * only try the pll if we don't have a table for the clock
+ * speed that we're running at. NOTE: the internal PLL will
+ * result in slow reads when using a 33MHz PCI clock. we also
+ * don't like to use the PLL because it will cause glitches
+ * on PRST/SRST when the HPT state engine gets reset.
+ */
+ if (pci_get_drvdata(dev))
+ goto init_hpt37X_done;
+
+ /*
+ * adjust PLL based upon PCI clock, enable it, and wait for
+ * stabilization.
+ */
+ adjust = 0;
+ freq = (pll < F_LOW_PCI_50) ? 2 : 4;
+ while (adjust++ < 6) {
+ pci_write_config_dword(dev, 0x5c, (freq + pll) << 16 |
+ pll | 0x100);
+
+ /* wait for clock stabilization */
+ for (i = 0; i < 0x50000; i++) {
+ pci_read_config_byte(dev, 0x5b, &reg5bh);
+ if (reg5bh & 0x80) {
+ /* spin looking for the clock to destabilize */
+ for (i = 0; i < 0x1000; ++i) {
+ pci_read_config_byte(dev, 0x5b,
+ &reg5bh);
+ if ((reg5bh & 0x80) == 0)
+ goto pll_recal;
+ }
+ pci_read_config_dword(dev, 0x5c, &pll);
+ pci_write_config_dword(dev, 0x5c,
+ pll & ~0x100);
+ pci_write_config_byte(dev, 0x5b, 0x21);
+ if (hpt_minimum_revision(dev,8))
+ pci_set_drvdata(dev, (void *) fifty_base_hpt370a);
+ else if (hpt_minimum_revision(dev,5))
+ pci_set_drvdata(dev, (void *) fifty_base_hpt372);
+ else if (hpt_minimum_revision(dev,4))
+ pci_set_drvdata(dev, (void *) fifty_base_hpt370a);
+ else
+ pci_set_drvdata(dev, (void *) fifty_base_hpt370a);
+ printk("HPT37X: using 50MHz internal PLL\n");
+ goto init_hpt37X_done;
+ }
+ }
+pll_recal:
+ if (adjust & 1)
+ pll -= (adjust >> 1);
+ else
+ pll += (adjust >> 1);
+ }
+
+init_hpt37X_done:
+ /* reset state engine */
+ pci_write_config_byte(dev, 0x50, 0x37);
+ pci_write_config_byte(dev, 0x54, 0x37);
+ udelay(100);
+ return 0;
+}
+
+static int __devinit init_hpt366(struct pci_dev *dev)
+{
+ u32 reg1 = 0;
+ u8 drive_fast = 0;
+
+ /*
+ * Disable the "fast interrupt" prediction.
+ */
+ pci_read_config_byte(dev, 0x51, &drive_fast);
+ if (drive_fast & 0x80)
+ pci_write_config_byte(dev, 0x51, drive_fast & ~0x80);
+ pci_read_config_dword(dev, 0x40, &reg1);
+
+ /* detect bus speed by looking at control reg timing: */
+ switch((reg1 >> 8) & 7) {
+ case 5:
+ pci_set_drvdata(dev, (void *) forty_base_hpt366);
+ break;
+ case 9:
+ pci_set_drvdata(dev, (void *) twenty_five_base_hpt366);
+ break;
+ case 7:
+ default:
+ pci_set_drvdata(dev, (void *) thirty_three_base_hpt366);
+ break;
+ }
+
+ if (!pci_get_drvdata(dev))
+ {
+ printk(KERN_ERR "hpt366: unknown bus timing.\n");
+ pci_set_drvdata(dev, NULL);
+ }
+ return 0;
+}
+
+static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const char *name)
+{
+ int ret = 0;
+ u8 test = 0;
+
+ if (dev->resource[PCI_ROM_RESOURCE].start)
+ pci_write_config_byte(dev, PCI_ROM_ADDRESS,
+ dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
+
+ pci_read_config_byte(dev, PCI_CACHE_LINE_SIZE, &test);
+ if (test != (L1_CACHE_BYTES / 4))
+ pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE,
+ (L1_CACHE_BYTES / 4));
+
+ pci_read_config_byte(dev, PCI_LATENCY_TIMER, &test);
+ if (test != 0x78)
+ pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x78);
+
+ pci_read_config_byte(dev, PCI_MIN_GNT, &test);
+ if (test != 0x08)
+ pci_write_config_byte(dev, PCI_MIN_GNT, 0x08);
+
+ pci_read_config_byte(dev, PCI_MAX_LAT, &test);
+ if (test != 0x08)
+ pci_write_config_byte(dev, PCI_MAX_LAT, 0x08);
+
+ if (hpt_minimum_revision(dev, 3)) {
+ ret = init_hpt37x(dev);
+ } else {
+ ret =init_hpt366(dev);
+ }
+ if (ret)
+ return ret;
+
+ return dev->irq;
+}
+
+static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
+{
+ struct pci_dev *dev = hwif->pci_dev;
+ u8 ata66 = 0, regmask = (hwif->channel) ? 0x01 : 0x02;
+ u8 did, rid;
+ unsigned long dmabase = hwif->dma_base;
+ int is_372n = 0;
+
+ if(dmabase)
+ {
+ did = inb(dmabase + 0x22);
+ rid = inb(dmabase + 0x28);
+
+ if((did == 4 && rid == 6) || (did == 5 && rid > 1))
+ is_372n = 1;
+ }
+
+ hwif->tuneproc = &hpt3xx_tune_drive;
+ hwif->speedproc = &hpt3xx_tune_chipset;
+ hwif->quirkproc = &hpt3xx_quirkproc;
+ hwif->intrproc = &hpt3xx_intrproc;
+ hwif->maskproc = &hpt3xx_maskproc;
+
+ if(is_372n)
+ hwif->rw_disk = &hpt372n_rw_disk;
+
+ /*
+ * 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 (hpt_minimum_revision(dev, 8) && 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
+ */
+ u16 mcr3, mcr6;
+ pci_read_config_word(dev, 0x52, &mcr3);
+ pci_read_config_word(dev, 0x56, &mcr6);
+ pci_write_config_word(dev, 0x52, mcr3 | 0x8000);
+ pci_write_config_word(dev, 0x56, mcr6 | 0x8000);
+ /* now read cable id register */
+ pci_read_config_byte(dev, 0x5a, &ata66);
+ pci_write_config_word(dev, 0x52, mcr3);
+ pci_write_config_word(dev, 0x56, mcr6);
+ } else if (hpt_minimum_revision(dev, 3)) {
+ /*
+ * HPT370/372 and 374 pcifn 0
+ * - clear bit 0 of 0x5b to enable P/SCBLID as inputs
+ */
+ u8 scr2;
+ 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, &ata66);
+ pci_write_config_byte(dev, 0x5b, scr2);
+ } else {
+ pci_read_config_byte(dev, 0x5a, &ata66);
+ }
+
+#ifdef DEBUG
+ printk("HPT366: reg5ah=0x%02x ATA-%s Cable Port%d\n",
+ ata66, (ata66 & regmask) ? "33" : "66",
+ PCI_FUNC(hwif->pci_dev->devfn));
+#endif /* DEBUG */
+
+#ifdef HPT_SERIALIZE_IO
+ /* serialize access to this device */
+ if (hwif->mate)
+ hwif->serialized = hwif->mate->serialized = 1;
+#endif
+
+ if (hpt_minimum_revision(dev,3)) {
+ u8 reg5ah = 0;
+ pci_write_config_byte(dev, 0x5a, reg5ah & ~0x10);
+ /*
+ * set up ioctl for power status.
+ * note: power affects both
+ * drives on each channel
+ */
+ hwif->resetproc = &hpt3xx_reset;
+ hwif->busproc = &hpt370_busproc;
+// hwif->drives[0].autotune = hwif->drives[1].autotune = 1;
+ } else if (hpt_minimum_revision(dev,2)) {
+ hwif->resetproc = &hpt3xx_reset;
+ hwif->busproc = &hpt3xx_tristate;
+ } else {
+ hwif->resetproc = &hpt3xx_reset;
+ hwif->busproc = &hpt3xx_tristate;
+ }
+
+ if (!hwif->dma_base) {
+ hwif->drives[0].autotune = 1;
+ hwif->drives[1].autotune = 1;
+ return;
+ }
+
+ hwif->ultra_mask = 0x7f;
+ hwif->mwdma_mask = 0x07;
+
+ if (!(hwif->udma_four))
+ hwif->udma_four = ((ata66 & regmask) ? 0 : 1);
+ hwif->ide_dma_check = &hpt366_config_drive_xfer_rate;
+
+ if (hpt_minimum_revision(dev,8)) {
+ hwif->ide_dma_test_irq = &hpt374_ide_dma_test_irq;
+ hwif->ide_dma_end = &hpt374_ide_dma_end;
+ } else if (hpt_minimum_revision(dev,5)) {
+ hwif->ide_dma_test_irq = &hpt374_ide_dma_test_irq;
+ hwif->ide_dma_end = &hpt374_ide_dma_end;
+ } else if (hpt_minimum_revision(dev,3)) {
+ hwif->dma_start = &hpt370_ide_dma_start;
+ hwif->ide_dma_end = &hpt370_ide_dma_end;
+ hwif->ide_dma_timeout = &hpt370_ide_dma_timeout;
+ hwif->ide_dma_lostirq = &hpt370_ide_dma_lostirq;
+ } else if (hpt_minimum_revision(dev,2))
+ hwif->ide_dma_lostirq = &hpt366_ide_dma_lostirq;
+ else
+ hwif->ide_dma_lostirq = &hpt366_ide_dma_lostirq;
+
+ if (!noautodma)
+ hwif->autodma = 1;
+ hwif->drives[0].autodma = hwif->autodma;
+ hwif->drives[1].autodma = hwif->autodma;
+}
+
+static void __devinit init_dma_hpt366(ide_hwif_t *hwif, unsigned long dmabase)
+{
+ u8 masterdma = 0, slavedma = 0;
+ u8 dma_new = 0, dma_old = 0;
+ u8 primary = hwif->channel ? 0x4b : 0x43;
+ u8 secondary = hwif->channel ? 0x4f : 0x47;
+ unsigned long flags;
+
+ if (!dmabase)
+ return;
+
+ if(pci_get_drvdata(hwif->pci_dev) == NULL)
+ {
+ printk(KERN_WARNING "hpt: no known IDE timings, disabling DMA.\n");
+ return;
+ }
+
+ dma_old = hwif->INB(dmabase+2);
+
+ local_irq_save(flags);
+
+ dma_new = dma_old;
+ pci_read_config_byte(hwif->pci_dev, primary, &masterdma);
+ pci_read_config_byte(hwif->pci_dev, secondary, &slavedma);
+
+ if (masterdma & 0x30) dma_new |= 0x20;
+ if (slavedma & 0x30) dma_new |= 0x40;
+ if (dma_new != dma_old)
+ hwif->OUTB(dma_new, dmabase+2);
+
+ local_irq_restore(flags);
+
+ ide_setup_dma(hwif, dmabase, 8);
+}
+
+static int __devinit init_setup_hpt374(struct pci_dev *dev, ide_pci_device_t *d)
+{
+ struct pci_dev *findev = NULL;
+
+ if (PCI_FUNC(dev->devfn) & 1)
+ return -ENODEV;
+
+ while ((findev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, findev)) != NULL) {
+ if ((findev->vendor == dev->vendor) &&
+ (findev->device == dev->device) &&
+ ((findev->devfn - dev->devfn) == 1) &&
+ (PCI_FUNC(findev->devfn) & 1)) {
+ if (findev->irq != dev->irq) {
+ /* FIXME: we need a core pci_set_interrupt() */
+ findev->irq = dev->irq;
+ printk(KERN_WARNING "%s: pci-config space interrupt "
+ "fixed.\n", d->name);
+ }
+ return ide_setup_pci_devices(dev, findev, d);
+ }
+ }
+ return ide_setup_pci_device(dev, d);
+}
+
+static int __devinit init_setup_hpt37x(struct pci_dev *dev, ide_pci_device_t *d)
+{
+ return ide_setup_pci_device(dev, d);
+}
+
+static int __devinit init_setup_hpt366(struct pci_dev *dev, ide_pci_device_t *d)
+{
+ struct pci_dev *findev = NULL;
+ u8 pin1 = 0, pin2 = 0;
+ unsigned int class_rev;
+ char *chipset_names[] = {"HPT366", "HPT366", "HPT368",
+ "HPT370", "HPT370A", "HPT372",
+ "HPT372N" };
+
+ if (PCI_FUNC(dev->devfn) & 1)
+ return -ENODEV;
+
+ pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
+ class_rev &= 0xff;
+
+ if(dev->device == PCI_DEVICE_ID_TTI_HPT372N)
+ class_rev = 6;
+
+ if(class_rev <= 6)
+ d->name = chipset_names[class_rev];
+
+ switch(class_rev) {
+ case 6:
+ case 5:
+ case 4:
+ case 3:
+ goto init_single;
+ default:
+ break;
+ }
+
+ d->channels = 1;
+
+ pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin1);
+ while ((findev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, findev)) != NULL) {
+ if ((findev->vendor == dev->vendor) &&
+ (findev->device == dev->device) &&
+ ((findev->devfn - dev->devfn) == 1) &&
+ (PCI_FUNC(findev->devfn) & 1)) {
+ pci_read_config_byte(findev, PCI_INTERRUPT_PIN, &pin2);
+ if ((pin1 != pin2) && (dev->irq == findev->irq)) {
+ d->bootable = ON_BOARD;
+ printk("%s: onboard version of chipset, "
+ "pin1=%d pin2=%d\n", d->name,
+ pin1, pin2);
+ }
+ return ide_setup_pci_devices(dev, findev, d);
+ }
+ }
+init_single:
+ return ide_setup_pci_device(dev, d);
+}
+
+static ide_pci_device_t hpt366_chipsets[] __devinitdata = {
+ { /* 0 */
+ .name = "HPT366",
+ .init_setup = init_setup_hpt366,
+ .init_chipset = init_chipset_hpt366,
+ .init_hwif = init_hwif_hpt366,
+ .init_dma = init_dma_hpt366,
+ .channels = 2,
+ .autodma = AUTODMA,
+ .bootable = OFF_BOARD,
+ .extra = 240
+ },{ /* 1 */
+ .name = "HPT372A",
+ .init_setup = init_setup_hpt37x,
+ .init_chipset = init_chipset_hpt366,
+ .init_hwif = init_hwif_hpt366,
+ .init_dma = init_dma_hpt366,
+ .channels = 2,
+ .autodma = AUTODMA,
+ .bootable = OFF_BOARD,
+ },{ /* 2 */
+ .name = "HPT302",
+ .init_setup = init_setup_hpt37x,
+ .init_chipset = init_chipset_hpt366,
+ .init_hwif = init_hwif_hpt366,
+ .init_dma = init_dma_hpt366,
+ .channels = 2,
+ .autodma = AUTODMA,
+ .bootable = OFF_BOARD,
+ },{ /* 3 */
+ .name = "HPT371",
+ .init_setup = init_setup_hpt37x,
+ .init_chipset = init_chipset_hpt366,
+ .init_hwif = init_hwif_hpt366,
+ .init_dma = init_dma_hpt366,
+ .channels = 2,
+ .autodma = AUTODMA,
+ .bootable = OFF_BOARD,
+ },{ /* 4 */
+ .name = "HPT374",
+ .init_setup = init_setup_hpt374,
+ .init_chipset = init_chipset_hpt366,
+ .init_hwif = init_hwif_hpt366,
+ .init_dma = init_dma_hpt366,
+ .channels = 2, /* 4 */
+ .autodma = AUTODMA,
+ .bootable = OFF_BOARD,
+ },{ /* 5 */
+ .name = "HPT372N",
+ .init_setup = init_setup_hpt37x,
+ .init_chipset = init_chipset_hpt366,
+ .init_hwif = init_hwif_hpt366,
+ .init_dma = init_dma_hpt366,
+ .channels = 2, /* 4 */
+ .autodma = AUTODMA,
+ .bootable = OFF_BOARD,
+ }
+};
+
+/**
+ * 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)
+{
+ ide_pci_device_t *d = &hpt366_chipsets[id->driver_data];
+
+ return d->init_setup(dev, d);
+}
+
+static struct pci_device_id hpt366_pci_tbl[] = {
+ { PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT366, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT372, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+ { PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT302, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
+ { PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT371, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3},
+ { PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT374, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4},
+ { PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT372N, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5},
+ { 0, },
+};
+MODULE_DEVICE_TABLE(pci, hpt366_pci_tbl);
+
+static struct pci_driver driver = {
+ .name = "HPT366_IDE",
+ .id_table = hpt366_pci_tbl,
+ .probe = hpt366_init_one,
+};
+
+static int hpt366_ide_init(void)
+{
+ return ide_pci_register_driver(&driver);
+}
+
+module_init(hpt366_ide_init);
+
+MODULE_AUTHOR("Andre Hedrick");
+MODULE_DESCRIPTION("PCI driver module for Highpoint HPT366 IDE");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/pci/it8172.c b/drivers/ide/pci/it8172.c
new file mode 100644
index 000000000000..631927cf17d4
--- /dev/null
+++ b/drivers/ide/pci/it8172.c
@@ -0,0 +1,308 @@
+/*
+ *
+ * BRIEF MODULE DESCRIPTION
+ * IT8172 IDE controller support
+ *
+ * Copyright 2000 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ * stevel@mvista.com or 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 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.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+#include <asm/it8172/it8172_int.h>
+
+/*
+ * Prototypes
+ */
+static u8 it8172_ratemask (ide_drive_t *drive)
+{
+ return 1;
+}
+
+static void it8172_tune_drive (ide_drive_t *drive, u8 pio)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = hwif->pci_dev;
+ int is_slave = (&hwif->drives[1] == drive);
+ unsigned long flags;
+ u16 drive_enables;
+ u32 drive_timing;
+
+ pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+ spin_lock_irqsave(&ide_lock, flags);
+ pci_read_config_word(dev, 0x40, &drive_enables);
+ pci_read_config_dword(dev, 0x44, &drive_timing);
+
+ /*
+ * FIX! The DIOR/DIOW pulse width and recovery times in port 0x44
+ * are being left at the default values of 8 PCI clocks (242 nsec
+ * for a 33 MHz clock). These can be safely shortened at higher
+ * PIO modes. The DIOR/DIOW pulse width and recovery times only
+ * apply to PIO modes, not to the DMA modes.
+ */
+
+ /*
+ * Enable port 0x44. The IT8172G spec is confused; it calls
+ * this register the "Slave IDE Timing Register", but in fact,
+ * it controls timing for both master and slave drives.
+ */
+ drive_enables |= 0x4000;
+
+ if (is_slave) {
+ drive_enables &= 0xc006;
+ if (pio > 1)
+ /* enable prefetch and IORDY sample-point */
+ drive_enables |= 0x0060;
+ } else {
+ drive_enables &= 0xc060;
+ if (pio > 1)
+ /* enable prefetch and IORDY sample-point */
+ drive_enables |= 0x0006;
+ }
+
+ pci_write_config_word(dev, 0x40, drive_enables);
+ spin_unlock_irqrestore(&ide_lock, flags);
+}
+
+static u8 it8172_dma_2_pio (u8 xfer_rate)
+{
+ switch(xfer_rate) {
+ case XFER_UDMA_5:
+ case XFER_UDMA_4:
+ case XFER_UDMA_3:
+ case XFER_UDMA_2:
+ case XFER_UDMA_1:
+ case XFER_UDMA_0:
+ case XFER_MW_DMA_2:
+ case XFER_PIO_4:
+ return 4;
+ case XFER_MW_DMA_1:
+ case XFER_PIO_3:
+ return 3;
+ case XFER_SW_DMA_2:
+ case XFER_PIO_2:
+ return 2;
+ case XFER_MW_DMA_0:
+ case XFER_SW_DMA_1:
+ case XFER_SW_DMA_0:
+ case XFER_PIO_1:
+ case XFER_PIO_0:
+ case XFER_PIO_SLOW:
+ default:
+ return 0;
+ }
+}
+
+static int it8172_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = hwif->pci_dev;
+ u8 speed = ide_rate_filter(it8172_ratemask(drive), xferspeed);
+ int a_speed = 3 << (drive->dn * 4);
+ int u_flag = 1 << drive->dn;
+ int u_speed = 0;
+ u8 reg48, reg4a;
+
+ pci_read_config_byte(dev, 0x48, &reg48);
+ pci_read_config_byte(dev, 0x4a, &reg4a);
+
+ /*
+ * Setting the DMA cycle time to 2 or 3 PCI clocks (60 and 91 nsec
+ * at 33 MHz PCI clock) seems to cause BadCRC errors during DMA
+ * transfers on some drives, even though both numbers meet the minimum
+ * ATAPI-4 spec of 73 and 54 nsec for UDMA 1 and 2 respectively.
+ * So the faster times are just commented out here. The good news is
+ * that the slower cycle time has very little affect on transfer
+ * performance.
+ */
+
+ switch(speed) {
+ case XFER_UDMA_4:
+ case XFER_UDMA_2: //u_speed = 2 << (drive->dn * 4); break;
+ case XFER_UDMA_5:
+ case XFER_UDMA_3:
+ case XFER_UDMA_1: //u_speed = 1 << (drive->dn * 4); break;
+ case XFER_UDMA_0: u_speed = 0 << (drive->dn * 4); break;
+ case XFER_MW_DMA_2:
+ case XFER_MW_DMA_1:
+ case XFER_MW_DMA_0:
+ case XFER_SW_DMA_2: break;
+ case XFER_PIO_4:
+ case XFER_PIO_3:
+ case XFER_PIO_2:
+ case XFER_PIO_0: break;
+ default: return -1;
+ }
+
+ if (speed >= XFER_UDMA_0) {
+ pci_write_config_byte(dev, 0x48, reg48 | u_flag);
+ reg4a &= ~a_speed;
+ pci_write_config_byte(dev, 0x4a, reg4a | u_speed);
+ } else {
+ pci_write_config_byte(dev, 0x48, reg48 & ~u_flag);
+ pci_write_config_byte(dev, 0x4a, reg4a & ~a_speed);
+ }
+
+ it8172_tune_drive(drive, it8172_dma_2_pio(speed));
+ return (ide_config_drive_speed(drive, speed));
+}
+
+static int it8172_config_chipset_for_dma (ide_drive_t *drive)
+{
+ u8 speed = ide_dma_speed(drive, it8172_ratemask(drive));
+
+ if (!(speed)) {
+ u8 tspeed = ide_get_best_pio_mode(drive, 255, 4, NULL);
+ speed = it8172_dma_2_pio(XFER_PIO_0 + tspeed);
+ }
+
+ (void) it8172_tune_chipset(drive, speed);
+ return ide_dma_enable(drive);
+}
+
+static int it8172_config_drive_xfer_rate (ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct hd_driveid *id = drive->id;
+
+ drive->init_speed = 0;
+
+ if (id && (id->capability & 1) && drive->autodma) {
+
+ if (ide_use_dma(drive)) {
+ if (it8172_config_chipset_for_dma(drive))
+ return hwif->ide_dma_on(drive);
+ }
+
+ goto fast_ata_pio;
+
+ } else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+ it8172_tune_drive(drive, 5);
+ return hwif->ide_dma_off_quietly(drive);
+ }
+ /* IORDY not supported */
+ return 0;
+}
+
+static unsigned int __init init_chipset_it8172 (struct pci_dev *dev, const char *name)
+{
+ unsigned char progif;
+
+ /*
+ * Place both IDE interfaces into PCI "native" mode
+ */
+ pci_read_config_byte(dev, PCI_CLASS_PROG, &progif);
+ pci_write_config_byte(dev, PCI_CLASS_PROG, progif | 0x05);
+
+ return IT8172_IDE_IRQ;
+}
+
+
+static void __init init_hwif_it8172 (ide_hwif_t *hwif)
+{
+ struct pci_dev* dev = hwif->pci_dev;
+ unsigned long cmdBase, ctrlBase;
+
+ hwif->autodma = 0;
+ hwif->tuneproc = &it8172_tune_drive;
+ hwif->speedproc = &it8172_tune_chipset;
+
+ cmdBase = dev->resource[0].start;
+ ctrlBase = dev->resource[1].start;
+
+ ide_init_hwif_ports(&hwif->hw, cmdBase, ctrlBase | 2, NULL);
+ memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
+ hwif->noprobe = 0;
+
+ if (!hwif->dma_base) {
+ hwif->drives[0].autotune = 1;
+ hwif->drives[1].autotune = 1;
+ return;
+ }
+
+ hwif->atapi_dma = 1;
+ hwif->ultra_mask = 0x07;
+ hwif->mwdma_mask = 0x06;
+ hwif->swdma_mask = 0x04;
+
+ hwif->ide_dma_check = &it8172_config_drive_xfer_rate;
+ if (!noautodma)
+ hwif->autodma = 1;
+ hwif->drives[0].autodma = hwif->autodma;
+ hwif->drives[1].autodma = hwif->autodma;
+}
+
+static ide_pci_device_t it8172_chipsets[] __devinitdata = {
+ { /* 0 */
+ .name = "IT8172G",
+ .init_chipset = init_chipset_it8172,
+ .init_hwif = init_hwif_it8172,
+ .channels = 2,
+ .autodma = AUTODMA,
+ .enablebits = {{0x00,0x00,0x00}, {0x40,0x00,0x01}},
+ .bootable = ON_BOARD,
+ }
+};
+
+static int __devinit it8172_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ if ((!(PCI_FUNC(dev->devfn) & 1) ||
+ (!((dev->class >> 8) == PCI_CLASS_STORAGE_IDE))))
+ return -ENODEV; /* IT8172 is more than an IDE controller */
+ return ide_setup_pci_device(dev, &it8172_chipsets[id->driver_data]);
+}
+
+static struct pci_device_id it8172_pci_tbl[] = {
+ { PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_IT8172G, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { 0, },
+};
+MODULE_DEVICE_TABLE(pci, it8172_pci_tbl);
+
+static struct pci_driver driver = {
+ .name = "IT8172_IDE",
+ .id_table = it8172_pci_tbl,
+ .probe = it8172_init_one,
+};
+
+static int it8172_ide_init(void)
+{
+ return ide_pci_register_driver(&driver);
+}
+
+module_init(it8172_ide_init);
+
+MODULE_AUTHOR("SteveL@mvista.com");
+MODULE_DESCRIPTION("PCI driver module for ITE 8172 IDE");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/pci/ns87415.c b/drivers/ide/pci/ns87415.c
new file mode 100644
index 000000000000..205a32fbc2f0
--- /dev/null
+++ b/drivers/ide/pci/ns87415.c
@@ -0,0 +1,315 @@
+/*
+ * linux/drivers/ide/pci/ns87415.c Version 2.00 Sep. 10, 2002
+ *
+ * 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/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#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>
+
+static unsigned long superio_ide_status[2];
+static unsigned long superio_ide_select[2];
+static unsigned long superio_ide_dma_status[2];
+
+#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)
+{
+ if (port == superio_ide_status[0] ||
+ port == superio_ide_status[1] ||
+ port == superio_ide_select[0] ||
+ port == superio_ide_select[1] ||
+ port == superio_ide_dma_status[0] ||
+ port == superio_ide_dma_status[1]) {
+ 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;
+ }
+
+ return inb(port);
+}
+
+static void __devinit superio_ide_init_iops (struct hwif_s *hwif)
+{
+ u32 base, dmabase;
+ u8 tmp;
+ struct pci_dev *pdev = hwif->pci_dev;
+ u8 port = hwif->channel;
+
+ base = pci_resource_start(pdev, port * 2) & ~3;
+ dmabase = pci_resource_start(pdev, 4) & ~3;
+
+ superio_ide_status[port] = base + IDE_STATUS_OFFSET;
+ superio_ide_select[port] = base + IDE_SELECT_OFFSET;
+ superio_ide_dma_status[port] = dmabase + (!port ? 2 : 0xa);
+
+ /* Clear error/interrupt, enable dma */
+ tmp = superio_ide_inb(superio_ide_dma_status[port]);
+ outb(tmp | 0x66, superio_ide_dma_status[port]);
+
+ /* We need to override inb to workaround a SuperIO errata */
+ hwif->INB = superio_ide_inb;
+}
+
+static void __devinit init_iops_ns87415(ide_hwif_t *hwif)
+{
+ if (PCI_SLOT(hwif->pci_dev->devfn) == 0xE) {
+ /* Built-in - assume it's under superio. */
+ superio_ide_init_iops(hwif);
+ }
+}
+#endif
+
+static unsigned int ns87415_count = 0, ns87415_control[MAX_HWIFS] = { 0 };
+
+/*
+ * This routine either enables/disables (according to drive->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);
+ unsigned int bit, other, new, *old = (unsigned int *) hwif->select_data;
+ struct pci_dev *dev = hwif->pci_dev;
+ unsigned long flags;
+
+ local_irq_save(flags);
+ new = *old;
+
+ /* Adjust IRQ enable bit */
+ bit = 1 << (8 + hwif->channel);
+ new = drive->present ? (new & ~bit) : (new | bit);
+
+ /* Select PIO or DMA, DMA may only be selected for one drive/channel. */
+ bit = 1 << (20 + drive->select.b.unit + (hwif->channel << 1));
+ other = 1 << (20 + (1 - drive->select.b.unit) + (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->using_dma);
+}
+
+static int ns87415_ide_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->INB(hwif->dma_status);
+ /* get dma command mode */
+ dma_cmd = hwif->INB(hwif->dma_command);
+ /* stop DMA */
+ hwif->OUTB(dma_cmd & ~1, hwif->dma_command);
+ /* from ERRATA: clear the INTR & ERROR bits */
+ dma_cmd = hwif->INB(hwif->dma_command);
+ hwif->OUTB(dma_cmd|6, hwif->dma_command);
+ /* and free any DMA resources */
+ ide_destroy_dmatable(drive);
+ /* verify good DMA status */
+ return (dma_stat & 7) != 4;
+}
+
+static int ns87415_ide_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 int ns87415_ide_dma_check (ide_drive_t *drive)
+{
+ if (drive->media != ide_disk)
+ return HWIF(drive)->ide_dma_off_quietly(drive);
+ return __ide_dma_check(drive);
+}
+
+static void __init init_hwif_ns87415 (ide_hwif_t *hwif)
+{
+ struct pci_dev *dev = hwif->pci_dev;
+ unsigned int ctrl, using_inta;
+ u8 progif;
+#ifdef __sparc_v9__
+ int timeout;
+ u8 stat;
+#endif
+
+ hwif->autodma = 0;
+ hwif->selectproc = &ns87415_selectproc;
+
+ /*
+ * 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 probe_hwif().
+ */
+ timeout = 10000;
+ hwif->OUTB(12, hwif->io_ports[IDE_CONTROL_OFFSET]);
+ udelay(10);
+ hwif->OUTB(8, hwif->io_ports[IDE_CONTROL_OFFSET]);
+ do {
+ udelay(50);
+ stat = hwif->INB(hwif->io_ports[IDE_STATUS_OFFSET]);
+ if (stat == 0xff)
+ break;
+ } while ((stat & BUSY_STAT) && --timeout);
+#endif
+ }
+
+ if (!using_inta)
+ hwif->irq = ide_default_irq(hwif->io_ports[IDE_DATA_OFFSET]);
+ else if (!hwif->irq && hwif->mate && hwif->mate->irq)
+ hwif->irq = hwif->mate->irq; /* share IRQ with mate */
+
+ if (!hwif->dma_base)
+ return;
+
+ hwif->OUTB(0x60, hwif->dma_status);
+ hwif->dma_setup = &ns87415_ide_dma_setup;
+ hwif->ide_dma_check = &ns87415_ide_dma_check;
+ hwif->ide_dma_end = &ns87415_ide_dma_end;
+
+ if (!noautodma)
+ hwif->autodma = 1;
+ hwif->drives[0].autodma = hwif->autodma;
+ hwif->drives[1].autodma = hwif->autodma;
+}
+
+static ide_pci_device_t ns87415_chipset __devinitdata = {
+ .name = "NS87415",
+#ifdef CONFIG_SUPERIO
+ .init_iops = init_iops_ns87415,
+#endif
+ .init_hwif = init_hwif_ns87415,
+ .channels = 2,
+ .autodma = AUTODMA,
+ .bootable = ON_BOARD,
+};
+
+static int __devinit ns87415_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ return ide_setup_pci_device(dev, &ns87415_chipset);
+}
+
+static struct pci_device_id ns87415_pci_tbl[] = {
+ { PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87415, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { 0, },
+};
+MODULE_DEVICE_TABLE(pci, ns87415_pci_tbl);
+
+static struct pci_driver driver = {
+ .name = "NS87415_IDE",
+ .id_table = ns87415_pci_tbl,
+ .probe = ns87415_init_one,
+};
+
+static int ns87415_ide_init(void)
+{
+ return ide_pci_register_driver(&driver);
+}
+
+module_init(ns87415_ide_init);
+
+MODULE_AUTHOR("Mark Lord, Eddie Dost, Andre Hedrick");
+MODULE_DESCRIPTION("PCI driver module for NS87415 IDE");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/pci/opti621.c b/drivers/ide/pci/opti621.c
new file mode 100644
index 000000000000..cf4fd91d396a
--- /dev/null
+++ b/drivers/ide/pci/opti621.c
@@ -0,0 +1,394 @@
+/*
+ * linux/drivers/ide/pci/opti621.c Version 0.7 Sept 10, 2002
+ *
+ * Copyright (C) 1996-1998 Linus Torvalds & authors (see below)
+ */
+
+/*
+ * Authors:
+ * Jaromir Koutek <miri@punknet.cz>,
+ * Jan Harkes <jaharkes@cwi.nl>,
+ * Mark Lord <mlord@pobox.com>
+ * Some parts of code are from ali14xx.c and from rz1000.c.
+ *
+ * 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_tune_drive
+ * 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 which get
+ * (use idebus=xx to select PCI bus speed).
+ * Use ide0=autotune for automatical tune of the PIO modes.
+ * If you get strange results, do not use this and set PIO manually
+ * by hdparm.
+ *
+ * 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.
+ */
+
+#undef REALLY_SLOW_IO /* most systems can safely undef this */
+#define OPTI621_DEBUG /* define for debug messages */
+
+#include <linux/types.h>
+#include <linux/module.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/pci.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+
+#define OPTI621_MAX_PIO 3
+/* In fact, I do not have any PIO 4 drive
+ * (address: 25 ns, data: 70 ns, recovery: 35 ns),
+ * but OPTi 82C621 is programmable and it can do (minimal values):
+ * on 40MHz PCI bus (pulse 25 ns):
+ * address: 25 ns, data: 25 ns, recovery: 50 ns;
+ * on 20MHz PCI bus (pulse 50 ns):
+ * address: 50 ns, data: 50 ns, recovery: 100 ns.
+ */
+
+/* #define READ_PREFETCH 0 */
+/* Uncomment for disable read prefetch.
+ * There is some readprefetch capatibility in hdparm,
+ * but when I type hdparm -P 1 /dev/hda, I got errors
+ * and till reset drive is inaccessible.
+ * This (hw) read prefetch is safe on my drive.
+ */
+
+#ifndef READ_PREFETCH
+#define READ_PREFETCH 0x40 /* read prefetch is enabled */
+#endif /* else read prefetch is disabled */
+
+#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;
+
+#define PIO_NOT_EXIST 254
+#define PIO_DONT_KNOW 255
+
+/* there are stored pio numbers from other calls of opti621_tune_drive */
+static void compute_pios(ide_drive_t *drive, u8 pio)
+/* Store values into drive->drive_data
+ * second_contr - 0 for primary controller, 1 for secondary
+ * slave_drive - 0 -> pio is for master, 1 -> pio is for slave
+ * pio - PIO mode for selected drive (for other we don't know)
+ */
+{
+ int d;
+ ide_hwif_t *hwif = HWIF(drive);
+
+ drive->drive_data = ide_get_best_pio_mode(drive, pio, OPTI621_MAX_PIO, NULL);
+ for (d = 0; d < 2; ++d) {
+ drive = &hwif->drives[d];
+ if (drive->present) {
+ if (drive->drive_data == PIO_DONT_KNOW)
+ drive->drive_data = ide_get_best_pio_mode(drive, 255, OPTI621_MAX_PIO, NULL);
+#ifdef OPTI621_DEBUG
+ printk("%s: Selected PIO mode %d\n",
+ drive->name, drive->drive_data);
+#endif
+ } else {
+ drive->drive_data = PIO_NOT_EXIST;
+ }
+ }
+}
+
+static int cmpt_clk(int time, int bus_speed)
+/* Returns (rounded up) time in clocks for time in ns,
+ * with bus_speed in MHz.
+ * Example: bus_speed = 40 MHz, time = 80 ns
+ * 1000/40 = 25 ns (clk value),
+ * 80/25 = 3.2, rounded up to 4 (I hope ;-)).
+ * Use idebus=xx to select right frequency.
+ */
+{
+ return ((time*bus_speed+999)/1000);
+}
+
+static void write_reg(ide_hwif_t *hwif, u8 value, int reg)
+/* 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.
+ */
+{
+ hwif->INW(reg_base+1);
+ hwif->INW(reg_base+1);
+ hwif->OUTB(3, reg_base+2);
+ hwif->OUTB(value, reg_base+reg);
+ hwif->OUTB(0x83, reg_base+2);
+}
+
+static u8 read_reg(ide_hwif_t *hwif, int reg)
+/* 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.
+ */
+{
+ u8 ret = 0;
+
+ hwif->INW(reg_base+1);
+ hwif->INW(reg_base+1);
+ hwif->OUTB(3, reg_base+2);
+ ret = hwif->INB(reg_base+reg);
+ hwif->OUTB(0x83, reg_base+2);
+ return ret;
+}
+
+typedef struct pio_clocks_s {
+ int address_time; /* Address setup (clocks) */
+ int data_time; /* Active/data pulse (clocks) */
+ int recovery_time; /* Recovery time (clocks) */
+} pio_clocks_t;
+
+static void compute_clocks(int pio, pio_clocks_t *clks)
+{
+ if (pio != PIO_NOT_EXIST) {
+ int adr_setup, data_pls;
+ int bus_speed = system_bus_clock();
+
+ adr_setup = ide_pio_timings[pio].setup_time;
+ data_pls = ide_pio_timings[pio].active_time;
+ clks->address_time = cmpt_clk(adr_setup, bus_speed);
+ clks->data_time = cmpt_clk(data_pls, bus_speed);
+ clks->recovery_time = cmpt_clk(ide_pio_timings[pio].cycle_time
+ - adr_setup-data_pls, bus_speed);
+ if (clks->address_time<1) clks->address_time = 1;
+ if (clks->address_time>4) clks->address_time = 4;
+ if (clks->data_time<1) clks->data_time = 1;
+ if (clks->data_time>16) clks->data_time = 16;
+ if (clks->recovery_time<2) clks->recovery_time = 2;
+ if (clks->recovery_time>17) clks->recovery_time = 17;
+ } else {
+ clks->address_time = 1;
+ clks->data_time = 1;
+ clks->recovery_time = 2;
+ /* minimal values */
+ }
+
+}
+
+/* Main tune procedure, called from tuneproc. */
+static void opti621_tune_drive (ide_drive_t *drive, u8 pio)
+{
+ /* primary and secondary drives share some registers,
+ * so we have to program both drives
+ */
+ unsigned long flags;
+ u8 pio1 = 0, pio2 = 0;
+ pio_clocks_t first, second;
+ int ax, drdy;
+ u8 cycle1, cycle2, misc;
+ ide_hwif_t *hwif = HWIF(drive);
+
+ /* sets drive->drive_data for both drives */
+ compute_pios(drive, pio);
+ pio1 = hwif->drives[0].drive_data;
+ pio2 = hwif->drives[1].drive_data;
+
+ compute_clocks(pio1, &first);
+ compute_clocks(pio2, &second);
+
+ /* ax = max(a1,a2) */
+ ax = (first.address_time < second.address_time) ? second.address_time : first.address_time;
+
+ drdy = 2; /* DRDY is default 2 (by OPTi Databook) */
+
+ cycle1 = ((first.data_time-1)<<4) | (first.recovery_time-2);
+ cycle2 = ((second.data_time-1)<<4) | (second.recovery_time-2);
+ misc = READ_PREFETCH | ((ax-1)<<4) | ((drdy-2)<<1);
+
+#ifdef OPTI621_DEBUG
+ printk("%s: master: address: %d, data: %d, "
+ "recovery: %d, drdy: %d [clk]\n",
+ hwif->name, ax, first.data_time,
+ first.recovery_time, drdy);
+ printk("%s: slave: address: %d, data: %d, "
+ "recovery: %d, drdy: %d [clk]\n",
+ hwif->name, ax, second.data_time,
+ second.recovery_time, drdy);
+#endif
+
+ spin_lock_irqsave(&ide_lock, flags);
+
+ reg_base = hwif->io_ports[IDE_DATA_OFFSET];
+
+ /* allow Register-B */
+ hwif->OUTB(0xc0, reg_base+CNTRL_REG);
+ /* hmm, setupvic.exe does this ;-) */
+ hwif->OUTB(0xff, reg_base+5);
+ /* if reads 0xff, adapter not exist? */
+ (void) hwif->INB(reg_base+CNTRL_REG);
+ /* if reads 0xc0, no interface exist? */
+ read_reg(hwif, CNTRL_REG);
+ /* read version, probably 0 */
+ read_reg(hwif, STRAP_REG);
+
+ /* program primary drive */
+ /* select Index-0 for Register-A */
+ write_reg(hwif, 0, MISC_REG);
+ /* set read cycle timings */
+ write_reg(hwif, cycle1, READ_REG);
+ /* set write cycle timings */
+ write_reg(hwif, cycle1, WRITE_REG);
+
+ /* program secondary drive */
+ /* select Index-1 for Register-B */
+ write_reg(hwif, 1, MISC_REG);
+ /* set read cycle timings */
+ write_reg(hwif, cycle2, READ_REG);
+ /* set write cycle timings */
+ write_reg(hwif, cycle2, WRITE_REG);
+
+ /* use Register-A for drive 0 */
+ /* use Register-B for drive 1 */
+ write_reg(hwif, 0x85, CNTRL_REG);
+
+ /* set address setup, DRDY timings, */
+ /* and read prefetch for both drives */
+ write_reg(hwif, misc, MISC_REG);
+
+ spin_unlock_irqrestore(&ide_lock, flags);
+}
+
+/*
+ * init_hwif_opti621() is called once for each hwif found at boot.
+ */
+static void __init init_hwif_opti621 (ide_hwif_t *hwif)
+{
+ hwif->autodma = 0;
+ hwif->drives[0].drive_data = PIO_DONT_KNOW;
+ hwif->drives[1].drive_data = PIO_DONT_KNOW;
+ hwif->tuneproc = &opti621_tune_drive;
+
+ if (!(hwif->dma_base))
+ return;
+
+ hwif->atapi_dma = 1;
+ hwif->mwdma_mask = 0x07;
+ hwif->swdma_mask = 0x07;
+
+ if (!noautodma)
+ hwif->autodma = 1;
+ hwif->drives[0].autodma = hwif->autodma;
+ hwif->drives[1].autodma = hwif->autodma;
+}
+
+static ide_pci_device_t opti621_chipsets[] __devinitdata = {
+ { /* 0 */
+ .name = "OPTI621",
+ .init_hwif = init_hwif_opti621,
+ .channels = 2,
+ .autodma = AUTODMA,
+ .enablebits = {{0x45,0x80,0x00}, {0x40,0x08,0x00}},
+ .bootable = ON_BOARD,
+ },{ /* 1 */
+ .name = "OPTI621X",
+ .init_hwif = init_hwif_opti621,
+ .channels = 2,
+ .autodma = AUTODMA,
+ .enablebits = {{0x45,0x80,0x00}, {0x40,0x08,0x00}},
+ .bootable = ON_BOARD,
+ }
+};
+
+static int __devinit opti621_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ return ide_setup_pci_device(dev, &opti621_chipsets[id->driver_data]);
+}
+
+static struct pci_device_id opti621_pci_tbl[] = {
+ { PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C621, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C825, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+ { 0, },
+};
+MODULE_DEVICE_TABLE(pci, opti621_pci_tbl);
+
+static struct pci_driver driver = {
+ .name = "Opti621_IDE",
+ .id_table = opti621_pci_tbl,
+ .probe = opti621_init_one,
+};
+
+static int opti621_ide_init(void)
+{
+ return ide_pci_register_driver(&driver);
+}
+
+module_init(opti621_ide_init);
+
+MODULE_AUTHOR("Jaromir Koutek, Jan Harkes, Mark Lord");
+MODULE_DESCRIPTION("PCI driver module for Opti621 IDE");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/pci/pdc202xx_new.c b/drivers/ide/pci/pdc202xx_new.c
new file mode 100644
index 000000000000..211641a54398
--- /dev/null
+++ b/drivers/ide/pci/pdc202xx_new.c
@@ -0,0 +1,508 @@
+/*
+ * 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>
+ * Portions Copyright (C) 1999 Promise Technology, Inc.
+ * Author: Frank Tiernan (frankt@promise.com)
+ * Released under terms of General Public License
+ */
+
+#include <linux/config.h>
+#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/hdreg.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#ifdef CONFIG_PPC_PMAC
+#include <asm/prom.h>
+#include <asm/pci-bridge.h>
+#endif
+
+#define PDC202_DEBUG_CABLE 0
+
+const static 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
+};
+
+#define set_2regs(a, b) \
+ do { \
+ hwif->OUTB((a + adj), indexreg); \
+ hwif->OUTB(b, datareg); \
+ } while(0)
+
+#define set_ultra(a, b, c) \
+ do { \
+ set_2regs(0x10,(a)); \
+ set_2regs(0x11,(b)); \
+ set_2regs(0x12,(c)); \
+ } while(0)
+
+#define set_ata2(a, b) \
+ do { \
+ set_2regs(0x0e,(a)); \
+ set_2regs(0x0f,(b)); \
+ } while(0)
+
+#define set_pio(a, b, c) \
+ do { \
+ set_2regs(0x0c,(a)); \
+ set_2regs(0x0d,(b)); \
+ set_2regs(0x13,(c)); \
+ } while(0)
+
+static u8 pdcnew_ratemask (ide_drive_t *drive)
+{
+ u8 mode;
+
+ switch(HWIF(drive)->pci_dev->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;
+ }
+ if (!eighty_ninty_three(drive))
+ mode = min(mode, (u8)1);
+ return mode;
+}
+
+static int check_in_drive_lists (ide_drive_t *drive, const char **list)
+{
+ struct hd_driveid *id = drive->id;
+
+ if (pdc_quirk_drives == list) {
+ while (*list) {
+ if (strstr(id->model, *list++)) {
+ return 2;
+ }
+ }
+ } else {
+ while (*list) {
+ if (!strcmp(*list++,id->model)) {
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+static int pdcnew_new_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ unsigned long indexreg = hwif->dma_vendor1;
+ unsigned long datareg = hwif->dma_vendor3;
+ u8 thold = 0x10;
+ u8 adj = (drive->dn%2) ? 0x08 : 0x00;
+ u8 speed = ide_rate_filter(pdcnew_ratemask(drive), xferspeed);
+
+ if (speed == XFER_UDMA_2) {
+ hwif->OUTB((thold + adj), indexreg);
+ hwif->OUTB((hwif->INB(datareg) & 0x7f), datareg);
+ }
+
+ switch (speed) {
+ case XFER_UDMA_7:
+ speed = XFER_UDMA_6;
+ case XFER_UDMA_6: set_ultra(0x1a, 0x01, 0xcb); break;
+ case XFER_UDMA_5: set_ultra(0x1a, 0x02, 0xcb); break;
+ case XFER_UDMA_4: set_ultra(0x1a, 0x03, 0xcd); break;
+ case XFER_UDMA_3: set_ultra(0x1a, 0x05, 0xcd); break;
+ case XFER_UDMA_2: set_ultra(0x2a, 0x07, 0xcd); break;
+ case XFER_UDMA_1: set_ultra(0x3a, 0x0a, 0xd0); break;
+ case XFER_UDMA_0: set_ultra(0x4a, 0x0f, 0xd5); break;
+ case XFER_MW_DMA_2: set_ata2(0x69, 0x25); break;
+ case XFER_MW_DMA_1: set_ata2(0x6b, 0x27); break;
+ case XFER_MW_DMA_0: set_ata2(0xdf, 0x5f); break;
+ case XFER_PIO_4: set_pio(0x23, 0x09, 0x25); break;
+ case XFER_PIO_3: set_pio(0x27, 0x0d, 0x35); break;
+ case XFER_PIO_2: set_pio(0x23, 0x26, 0x64); break;
+ case XFER_PIO_1: set_pio(0x46, 0x29, 0xa4); break;
+ case XFER_PIO_0: set_pio(0xfb, 0x2b, 0xac); break;
+ default:
+ ;
+ }
+
+ return (ide_config_drive_speed(drive, speed));
+}
+
+/* 0 1 2 3 4 5 6 7 8
+ * 960, 480, 390, 300, 240, 180, 120, 90, 60
+ * 180, 150, 120, 90, 60
+ * DMA_Speed
+ * 180, 120, 90, 90, 90, 60, 30
+ * 11, 5, 4, 3, 2, 1, 0
+ */
+static void pdcnew_tune_drive(ide_drive_t *drive, u8 pio)
+{
+ u8 speed;
+
+ if (pio == 5) pio = 4;
+ speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, pio, NULL);
+
+ (void)pdcnew_new_tune_chipset(drive, speed);
+}
+
+static u8 pdcnew_new_cable_detect (ide_hwif_t *hwif)
+{
+ hwif->OUTB(0x0b, hwif->dma_vendor1);
+ return ((u8)((hwif->INB(hwif->dma_vendor3) & 0x04)));
+}
+static int config_chipset_for_dma (ide_drive_t *drive)
+{
+ struct hd_driveid *id = drive->id;
+ ide_hwif_t *hwif = HWIF(drive);
+ u8 speed = -1;
+ u8 cable;
+
+ u8 ultra_66 = ((id->dma_ultra & 0x0010) ||
+ (id->dma_ultra & 0x0008)) ? 1 : 0;
+
+ cable = pdcnew_new_cable_detect(hwif);
+
+ if (ultra_66 && cable) {
+ printk(KERN_WARNING "Warning: %s channel requires an 80-pin cable for operation.\n", hwif->channel ? "Secondary":"Primary");
+ printk(KERN_WARNING "%s reduced to Ultra33 mode.\n", drive->name);
+ }
+
+ if (drive->media != ide_disk)
+ return 0;
+ if (id->capability & 4) { /* IORDY_EN & PREFETCH_EN */
+ hwif->OUTB((0x13 + ((drive->dn%2) ? 0x08 : 0x00)), hwif->dma_vendor1);
+ hwif->OUTB((hwif->INB(hwif->dma_vendor3)|0x03), hwif->dma_vendor3);
+ }
+
+ speed = ide_dma_speed(drive, pdcnew_ratemask(drive));
+
+ if (!(speed)) {
+ hwif->tuneproc(drive, 5);
+ return 0;
+ }
+
+ (void) hwif->speedproc(drive, speed);
+ return ide_dma_enable(drive);
+}
+
+static int pdcnew_config_drive_xfer_rate (ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct hd_driveid *id = drive->id;
+
+ drive->init_speed = 0;
+
+ if (id && (id->capability & 1) && drive->autodma) {
+
+ if (ide_use_dma(drive)) {
+ if (config_chipset_for_dma(drive))
+ return hwif->ide_dma_on(drive);
+ }
+
+ goto fast_ata_pio;
+
+ } else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+ hwif->tuneproc(drive, 5);
+ return hwif->ide_dma_off_quietly(drive);
+ }
+ /* IORDY not supported */
+ return 0;
+}
+
+static int pdcnew_quirkproc (ide_drive_t *drive)
+{
+ return ((int) check_in_drive_lists(drive, pdc_quirk_drives));
+}
+
+static int pdcnew_ide_dma_lostirq(ide_drive_t *drive)
+{
+ if (HWIF(drive)->resetproc != NULL)
+ HWIF(drive)->resetproc(drive);
+ return __ide_dma_lostirq(drive);
+}
+
+static int pdcnew_ide_dma_timeout(ide_drive_t *drive)
+{
+ if (HWIF(drive)->resetproc != NULL)
+ HWIF(drive)->resetproc(drive);
+ return __ide_dma_timeout(drive);
+}
+
+static void pdcnew_new_reset (ide_drive_t *drive)
+{
+ /*
+ * Deleted this because it is redundant from the caller.
+ */
+ printk(KERN_WARNING "PDC202XX: %s channel reset.\n",
+ HWIF(drive)->channel ? "Secondary" : "Primary");
+}
+
+#ifdef CONFIG_PPC_PMAC
+static void __devinit apple_kiwi_init(struct pci_dev *pdev)
+{
+ struct device_node *np = pci_device_to_OF_node(pdev);
+ unsigned int class_rev = 0;
+ void __iomem *mmio;
+ u8 conf;
+
+ if (np == NULL || !device_is_compatible(np, "kiwi-root"))
+ return;
+
+ pci_read_config_dword(pdev, PCI_CLASS_REVISION, &class_rev);
+ class_rev &= 0xff;
+
+ if (class_rev >= 0x03) {
+ /* Setup chip magic config stuff (from darwin) */
+ pci_read_config_byte(pdev, 0x40, &conf);
+ pci_write_config_byte(pdev, 0x40, conf | 0x01);
+ }
+ mmio = ioremap(pci_resource_start(pdev, 5),
+ pci_resource_len(pdev, 5));
+
+ /* Setup some PLL stuffs */
+ switch (pdev->device) {
+ case PCI_DEVICE_ID_PROMISE_20270:
+ writew(0x0d2b, mmio + 0x1202);
+ mdelay(30);
+ break;
+ case PCI_DEVICE_ID_PROMISE_20271:
+ writew(0x0826, mmio + 0x1202);
+ mdelay(30);
+ break;
+ }
+
+ iounmap(mmio);
+}
+#endif /* CONFIG_PPC_PMAC */
+
+static unsigned int __devinit init_chipset_pdcnew(struct pci_dev *dev, const char *name)
+{
+ if (dev->resource[PCI_ROM_RESOURCE].start) {
+ pci_write_config_dword(dev, PCI_ROM_ADDRESS,
+ dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
+ printk(KERN_INFO "%s: ROM enabled at 0x%08lx\n",
+ name, dev->resource[PCI_ROM_RESOURCE].start);
+ }
+
+#ifdef CONFIG_PPC_PMAC
+ apple_kiwi_init(dev);
+#endif
+
+ return dev->irq;
+}
+
+static void __devinit init_hwif_pdc202new(ide_hwif_t *hwif)
+{
+ hwif->autodma = 0;
+
+ hwif->tuneproc = &pdcnew_tune_drive;
+ hwif->quirkproc = &pdcnew_quirkproc;
+ hwif->speedproc = &pdcnew_new_tune_chipset;
+ hwif->resetproc = &pdcnew_new_reset;
+
+ hwif->drives[0].autotune = hwif->drives[1].autotune = 1;
+
+ hwif->ultra_mask = 0x7f;
+ hwif->mwdma_mask = 0x07;
+
+ hwif->ide_dma_check = &pdcnew_config_drive_xfer_rate;
+ hwif->ide_dma_lostirq = &pdcnew_ide_dma_lostirq;
+ hwif->ide_dma_timeout = &pdcnew_ide_dma_timeout;
+ if (!(hwif->udma_four))
+ hwif->udma_four = (pdcnew_new_cable_detect(hwif)) ? 0 : 1;
+ if (!noautodma)
+ hwif->autodma = 1;
+ hwif->drives[0].autodma = hwif->drives[1].autodma = hwif->autodma;
+#if PDC202_DEBUG_CABLE
+ printk(KERN_DEBUG "%s: %s-pin cable\n",
+ hwif->name, hwif->udma_four ? "80" : "40");
+#endif /* PDC202_DEBUG_CABLE */
+}
+
+static int __devinit init_setup_pdcnew(struct pci_dev *dev, ide_pci_device_t *d)
+{
+ return ide_setup_pci_device(dev, d);
+}
+
+static int __devinit init_setup_pdc20270(struct pci_dev *dev,
+ ide_pci_device_t *d)
+{
+ struct pci_dev *findev = NULL;
+
+ if ((dev->bus->self &&
+ dev->bus->self->vendor == PCI_VENDOR_ID_DEC) &&
+ (dev->bus->self->device == PCI_DEVICE_ID_DEC_21150)) {
+ if (PCI_SLOT(dev->devfn) & 2)
+ return -ENODEV;
+ d->extra = 0;
+ while ((findev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, findev)) != NULL) {
+ if ((findev->vendor == dev->vendor) &&
+ (findev->device == dev->device) &&
+ (PCI_SLOT(findev->devfn) & 2)) {
+ if (findev->irq != dev->irq) {
+ findev->irq = dev->irq;
+ }
+ return ide_setup_pci_devices(dev, findev, d);
+ }
+ }
+ }
+ return ide_setup_pci_device(dev, d);
+}
+
+static int __devinit init_setup_pdc20276(struct pci_dev *dev,
+ ide_pci_device_t *d)
+{
+ if ((dev->bus->self) &&
+ (dev->bus->self->vendor == PCI_VENDOR_ID_INTEL) &&
+ ((dev->bus->self->device == PCI_DEVICE_ID_INTEL_I960) ||
+ (dev->bus->self->device == PCI_DEVICE_ID_INTEL_I960RM))) {
+ printk(KERN_INFO "ide: Skipping Promise PDC20276 "
+ "attached to I2O RAID controller.\n");
+ return -ENODEV;
+ }
+ return ide_setup_pci_device(dev, d);
+}
+
+static ide_pci_device_t pdcnew_chipsets[] __devinitdata = {
+ { /* 0 */
+ .name = "PDC20268",
+ .init_setup = init_setup_pdcnew,
+ .init_chipset = init_chipset_pdcnew,
+ .init_hwif = init_hwif_pdc202new,
+ .channels = 2,
+ .autodma = AUTODMA,
+ .bootable = OFF_BOARD,
+ },{ /* 1 */
+ .name = "PDC20269",
+ .init_setup = init_setup_pdcnew,
+ .init_chipset = init_chipset_pdcnew,
+ .init_hwif = init_hwif_pdc202new,
+ .channels = 2,
+ .autodma = AUTODMA,
+ .bootable = OFF_BOARD,
+ },{ /* 2 */
+ .name = "PDC20270",
+ .init_setup = init_setup_pdc20270,
+ .init_chipset = init_chipset_pdcnew,
+ .init_hwif = init_hwif_pdc202new,
+ .channels = 2,
+ .autodma = AUTODMA,
+#ifndef CONFIG_PDC202XX_FORCE
+ .enablebits = {{0x50,0x02,0x02}, {0x50,0x04,0x04}},
+#endif
+ .bootable = OFF_BOARD,
+ },{ /* 3 */
+ .name = "PDC20271",
+ .init_setup = init_setup_pdcnew,
+ .init_chipset = init_chipset_pdcnew,
+ .init_hwif = init_hwif_pdc202new,
+ .channels = 2,
+ .autodma = AUTODMA,
+ .bootable = OFF_BOARD,
+ },{ /* 4 */
+ .name = "PDC20275",
+ .init_setup = init_setup_pdcnew,
+ .init_chipset = init_chipset_pdcnew,
+ .init_hwif = init_hwif_pdc202new,
+ .channels = 2,
+ .autodma = AUTODMA,
+ .bootable = OFF_BOARD,
+ },{ /* 5 */
+ .name = "PDC20276",
+ .init_setup = init_setup_pdc20276,
+ .init_chipset = init_chipset_pdcnew,
+ .init_hwif = init_hwif_pdc202new,
+ .channels = 2,
+ .autodma = AUTODMA,
+#ifndef CONFIG_PDC202XX_FORCE
+ .enablebits = {{0x50,0x02,0x02}, {0x50,0x04,0x04}},
+#endif
+ .bootable = OFF_BOARD,
+ },{ /* 6 */
+ .name = "PDC20277",
+ .init_setup = init_setup_pdcnew,
+ .init_chipset = init_chipset_pdcnew,
+ .init_hwif = init_hwif_pdc202new,
+ .channels = 2,
+ .autodma = AUTODMA,
+ .bootable = OFF_BOARD,
+ }
+};
+
+/**
+ * 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)
+{
+ ide_pci_device_t *d = &pdcnew_chipsets[id->driver_data];
+
+ return d->init_setup(dev, d);
+}
+
+static struct pci_device_id pdc202new_pci_tbl[] = {
+ { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20268, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20269, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+ { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20270, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
+ { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20271, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3},
+ { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20275, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4},
+ { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20276, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5},
+ { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20277, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6},
+ { 0, },
+};
+MODULE_DEVICE_TABLE(pci, pdc202new_pci_tbl);
+
+static struct pci_driver driver = {
+ .name = "Promise_IDE",
+ .id_table = pdc202new_pci_tbl,
+ .probe = pdc202new_init_one,
+};
+
+static int pdc202new_ide_init(void)
+{
+ return ide_pci_register_driver(&driver);
+}
+
+module_init(pdc202new_ide_init);
+
+MODULE_AUTHOR("Andre Hedrick, Frank Tiernan");
+MODULE_DESCRIPTION("PCI driver module for Promise PDC20268 and higher");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/pci/pdc202xx_old.c b/drivers/ide/pci/pdc202xx_old.c
new file mode 100644
index 000000000000..ad9d95817f95
--- /dev/null
+++ b/drivers/ide/pci/pdc202xx_old.c
@@ -0,0 +1,892 @@
+/*
+ * linux/drivers/ide/pci/pdc202xx_old.c Version 0.36 Sept 11, 2002
+ *
+ * Copyright (C) 1998-2002 Andre Hedrick <andre@linux-ide.org>
+ *
+ * Promise Ultra33 cards with BIOS v1.20 through 1.28 will need this
+ * compiled into the kernel if you have more than one card installed.
+ * Note that BIOS v1.29 is reported to fix the problem. Since this is
+ * safe chipset tuning, including this support is harmless
+ *
+ * Promise Ultra66 cards with BIOS v1.11 this
+ * compiled into the kernel if you have more than one card installed.
+ *
+ * Promise Ultra100 cards.
+ *
+ * The latest chipset code will support the following ::
+ * Three Ultra33 controllers and 12 drives.
+ * 8 are UDMA supported and 4 are limited to DMA mode 2 multi-word.
+ * The 8/4 ratio is a BIOS code limit by promise.
+ *
+ * UNLESS you enable "CONFIG_PDC202XX_BURST"
+ *
+ */
+
+/*
+ * Portions Copyright (C) 1999 Promise Technology, Inc.
+ * Author: Frank Tiernan (frankt@promise.com)
+ * Released under terms of General Public License
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/module.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/hdreg.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#define PDC202_DEBUG_CABLE 0
+#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
+};
+
+/* A Register */
+#define SYNC_ERRDY_EN 0xC0
+
+#define SYNC_IN 0x80 /* control bit, different for master vs. slave drives */
+#define ERRDY_EN 0x40 /* control bit, different for master vs. slave drives */
+#define IORDY_EN 0x20 /* PIO: IOREADY */
+#define PREFETCH_EN 0x10 /* PIO: PREFETCH */
+
+#define PA3 0x08 /* PIO"A" timing */
+#define PA2 0x04 /* PIO"A" timing */
+#define PA1 0x02 /* PIO"A" timing */
+#define PA0 0x01 /* PIO"A" timing */
+
+/* B Register */
+
+#define MB2 0x80 /* DMA"B" timing */
+#define MB1 0x40 /* DMA"B" timing */
+#define MB0 0x20 /* DMA"B" timing */
+
+#define PB4 0x10 /* PIO_FORCE 1:0 */
+
+#define PB3 0x08 /* PIO"B" timing */ /* PIO flow Control mode */
+#define PB2 0x04 /* PIO"B" timing */ /* PIO 4 */
+#define PB1 0x02 /* PIO"B" timing */ /* PIO 3 half */
+#define PB0 0x01 /* PIO"B" timing */ /* PIO 3 other half */
+
+/* C Register */
+#define IORDYp_NO_SPEED 0x4F
+#define SPEED_DIS 0x0F
+
+#define DMARQp 0x80
+#define IORDYp 0x40
+#define DMAR_EN 0x20
+#define DMAW_EN 0x10
+
+#define MC3 0x08 /* DMA"C" timing */
+#define MC2 0x04 /* DMA"C" timing */
+#define MC1 0x02 /* DMA"C" timing */
+#define MC0 0x01 /* DMA"C" timing */
+
+#if 0
+ unsigned long bibma = pci_resource_start(dev, 4);
+ u8 hi = 0, lo = 0;
+
+ u8 sc1c = inb_p((u16)bibma + 0x1c);
+ u8 sc1e = inb_p((u16)bibma + 0x1e);
+ u8 sc1f = inb_p((u16)bibma + 0x1f);
+
+ p += sprintf(p, "Host Mode : %s\n",
+ (sc1f & 0x08) ? "Tri-Stated" : "Normal");
+ p += sprintf(p, "Bus Clocking : %s\n",
+ ((sc1f & 0xC0) == 0xC0) ? "100 External" :
+ ((sc1f & 0x80) == 0x80) ? "66 External" :
+ ((sc1f & 0x40) == 0x40) ? "33 External" : "33 PCI Internal");
+ p += sprintf(p, "IO pad select : %s mA\n",
+ ((sc1c & 0x03) == 0x03) ? "10" :
+ ((sc1c & 0x02) == 0x02) ? "8" :
+ ((sc1c & 0x01) == 0x01) ? "6" :
+ ((sc1c & 0x00) == 0x00) ? "4" : "??");
+ hi = sc1e >> 4;
+ lo = sc1e & 0xf;
+ p += sprintf(p, "Status Polling Period : %d\n", hi);
+ p += sprintf(p, "Interrupt Check Status Polling Delay : %d\n", lo);
+#endif
+
+static u8 pdc202xx_ratemask (ide_drive_t *drive)
+{
+ u8 mode;
+
+ switch(HWIF(drive)->pci_dev->device) {
+ case PCI_DEVICE_ID_PROMISE_20267:
+ case PCI_DEVICE_ID_PROMISE_20265:
+ mode = 3;
+ break;
+ case PCI_DEVICE_ID_PROMISE_20263:
+ case PCI_DEVICE_ID_PROMISE_20262:
+ mode = 2;
+ break;
+ case PCI_DEVICE_ID_PROMISE_20246:
+ return 1;
+ default:
+ return 0;
+ }
+ if (!eighty_ninty_three(drive))
+ mode = min(mode, (u8)1);
+ return mode;
+}
+
+static int check_in_drive_lists (ide_drive_t *drive, const char **list)
+{
+ struct hd_driveid *id = drive->id;
+
+ if (pdc_quirk_drives == list) {
+ while (*list) {
+ if (strstr(id->model, *list++)) {
+ return 2;
+ }
+ }
+ } else {
+ while (*list) {
+ if (!strcmp(*list++,id->model)) {
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+static int pdc202xx_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = hwif->pci_dev;
+ u8 drive_pci = 0x60 + (drive->dn << 2);
+ u8 speed = ide_rate_filter(pdc202xx_ratemask(drive), xferspeed);
+
+ u32 drive_conf;
+ u8 AP, BP, CP, DP;
+ u8 TA = 0, TB = 0, TC = 0;
+
+ if ((drive->media != ide_disk) && (speed < XFER_SW_DMA_0))
+ return -1;
+
+ pci_read_config_dword(dev, drive_pci, &drive_conf);
+ pci_read_config_byte(dev, (drive_pci), &AP);
+ pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+ pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
+ pci_read_config_byte(dev, (drive_pci)|0x03, &DP);
+
+ if (speed < XFER_SW_DMA_0) {
+ if ((AP & 0x0F) || (BP & 0x07)) {
+ /* clear PIO modes of lower 8421 bits of A Register */
+ pci_write_config_byte(dev, (drive_pci), AP &~0x0F);
+ pci_read_config_byte(dev, (drive_pci), &AP);
+
+ /* clear PIO modes of lower 421 bits of B Register */
+ pci_write_config_byte(dev, (drive_pci)|0x01, BP &~0x07);
+ pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+
+ pci_read_config_byte(dev, (drive_pci), &AP);
+ pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+ }
+ } else {
+ if ((BP & 0xF0) && (CP & 0x0F)) {
+ /* clear DMA modes of upper 842 bits of B Register */
+ /* clear PIO forced mode upper 1 bit of B Register */
+ pci_write_config_byte(dev, (drive_pci)|0x01, BP &~0xF0);
+ pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+
+ /* clear DMA modes of lower 8421 bits of C Register */
+ pci_write_config_byte(dev, (drive_pci)|0x02, CP &~0x0F);
+ pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
+ }
+ }
+
+ pci_read_config_byte(dev, (drive_pci), &AP);
+ pci_read_config_byte(dev, (drive_pci)|0x01, &BP);
+ pci_read_config_byte(dev, (drive_pci)|0x02, &CP);
+
+ switch(speed) {
+ case XFER_UDMA_6: speed = XFER_UDMA_5;
+ 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:
+ case XFER_SW_DMA_2: TB = 0x60; TC = 0x05; break;
+ case XFER_SW_DMA_1: TB = 0x80; TC = 0x06; break;
+ case XFER_SW_DMA_0: TB = 0xC0; TC = 0x0B; 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) {
+ pci_write_config_byte(dev, (drive_pci), AP|TA);
+ pci_write_config_byte(dev, (drive_pci)|0x01, BP|TB);
+ } else {
+ pci_write_config_byte(dev, (drive_pci)|0x01, BP|TB);
+ pci_write_config_byte(dev, (drive_pci)|0x02, 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 /* PDC202XX_DEBUG_DRIVE_INFO */
+
+ return (ide_config_drive_speed(drive, speed));
+}
+
+
+/* 0 1 2 3 4 5 6 7 8
+ * 960, 480, 390, 300, 240, 180, 120, 90, 60
+ * 180, 150, 120, 90, 60
+ * DMA_Speed
+ * 180, 120, 90, 90, 90, 60, 30
+ * 11, 5, 4, 3, 2, 1, 0
+ */
+static void config_chipset_for_pio (ide_drive_t *drive, u8 pio)
+{
+ u8 speed = 0;
+
+ if (pio == 5) pio = 4;
+ speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, pio, NULL);
+
+ pdc202xx_tune_chipset(drive, speed);
+}
+
+static u8 pdc202xx_old_cable_detect (ide_hwif_t *hwif)
+{
+ u16 CIS = 0, mask = (hwif->channel) ? (1<<11) : (1<<10);
+ pci_read_config_word(hwif->pci_dev, 0x50, &CIS);
+ return (CIS & mask) ? 1 : 0;
+}
+
+/*
+ * Set the control register to use the 66MHz system
+ * clock for UDMA 3/4/5 mode operation when necessary.
+ *
+ * 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->dma_master + 0x11;
+ u8 clock = hwif->INB(clock_reg);
+
+ hwif->OUTB(clock | (hwif->channel ? 0x08 : 0x02), clock_reg);
+}
+
+static void pdc_old_disable_66MHz_clock(ide_hwif_t *hwif)
+{
+ unsigned long clock_reg = hwif->dma_master + 0x11;
+ u8 clock = hwif->INB(clock_reg);
+
+ hwif->OUTB(clock & ~(hwif->channel ? 0x08 : 0x02), clock_reg);
+}
+
+static int config_chipset_for_dma (ide_drive_t *drive)
+{
+ struct hd_driveid *id = drive->id;
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = hwif->pci_dev;
+ u32 drive_conf = 0;
+ u8 drive_pci = 0x60 + (drive->dn << 2);
+ u8 test1 = 0, test2 = 0, speed = -1;
+ u8 AP = 0, cable = 0;
+
+ u8 ultra_66 = ((id->dma_ultra & 0x0010) ||
+ (id->dma_ultra & 0x0008)) ? 1 : 0;
+
+ if (dev->device != PCI_DEVICE_ID_PROMISE_20246)
+ cable = pdc202xx_old_cable_detect(hwif);
+ else
+ ultra_66 = 0;
+
+ if (ultra_66 && cable) {
+ printk(KERN_WARNING "Warning: %s channel requires an 80-pin cable for operation.\n", hwif->channel ? "Secondary":"Primary");
+ printk(KERN_WARNING "%s reduced to Ultra33 mode.\n", drive->name);
+ }
+
+ if (dev->device != PCI_DEVICE_ID_PROMISE_20246)
+ pdc_old_disable_66MHz_clock(drive->hwif);
+
+ drive_pci = 0x60 + (drive->dn << 2);
+ pci_read_config_dword(dev, drive_pci, &drive_conf);
+ if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4))
+ goto chipset_is_set;
+
+ pci_read_config_byte(dev, drive_pci, &test1);
+ if (!(test1 & SYNC_ERRDY_EN)) {
+ if (drive->select.b.unit & 0x01) {
+ pci_read_config_byte(dev, drive_pci - 4, &test2);
+ if ((test2 & SYNC_ERRDY_EN) &&
+ !(test1 & SYNC_ERRDY_EN)) {
+ pci_write_config_byte(dev, drive_pci,
+ test1|SYNC_ERRDY_EN);
+ }
+ } else {
+ pci_write_config_byte(dev, drive_pci,
+ test1|SYNC_ERRDY_EN);
+ }
+ }
+
+chipset_is_set:
+
+ if (drive->media == ide_disk) {
+ pci_read_config_byte(dev, (drive_pci), &AP);
+ if (id->capability & 4) /* IORDY_EN */
+ pci_write_config_byte(dev, (drive_pci), AP|IORDY_EN);
+ pci_read_config_byte(dev, (drive_pci), &AP);
+ if (drive->media == ide_disk) /* PREFETCH_EN */
+ pci_write_config_byte(dev, (drive_pci), AP|PREFETCH_EN);
+ }
+
+ speed = ide_dma_speed(drive, pdc202xx_ratemask(drive));
+
+ if (!(speed)) {
+ /* restore original pci-config space */
+ pci_write_config_dword(dev, drive_pci, drive_conf);
+ hwif->tuneproc(drive, 5);
+ return 0;
+ }
+
+ (void) hwif->speedproc(drive, speed);
+ return ide_dma_enable(drive);
+}
+
+static int pdc202xx_config_drive_xfer_rate (ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct hd_driveid *id = drive->id;
+
+ drive->init_speed = 0;
+
+ if (id && (id->capability & 1) && drive->autodma) {
+
+ if (ide_use_dma(drive)) {
+ if (config_chipset_for_dma(drive))
+ return hwif->ide_dma_on(drive);
+ }
+
+ goto fast_ata_pio;
+
+ } else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+ hwif->tuneproc(drive, 5);
+ return hwif->ide_dma_off_quietly(drive);
+ }
+ /* IORDY not supported */
+ return 0;
+}
+
+static int pdc202xx_quirkproc (ide_drive_t *drive)
+{
+ return ((int) check_in_drive_lists(drive, pdc_quirk_drives));
+}
+
+static void pdc202xx_old_ide_dma_start(ide_drive_t *drive)
+{
+ if (drive->current_speed > XFER_UDMA_2)
+ pdc_old_enable_66MHz_clock(drive->hwif);
+ if (drive->addressing == 1) {
+ struct request *rq = HWGROUP(drive)->rq;
+ ide_hwif_t *hwif = HWIF(drive);
+// struct pci_dev *dev = hwif->pci_dev;
+// unsgned long high_16 = pci_resource_start(dev, 4);
+ unsigned long high_16 = hwif->dma_master;
+ unsigned long atapi_reg = high_16 + (hwif->channel ? 0x24 : 0x20);
+ u32 word_count = 0;
+ u8 clock = hwif->INB(high_16 + 0x11);
+
+ hwif->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;
+ hwif->OUTL(word_count, atapi_reg);
+ }
+ ide_dma_start(drive);
+}
+
+static int pdc202xx_old_ide_dma_end(ide_drive_t *drive)
+{
+ if (drive->addressing == 1) {
+ ide_hwif_t *hwif = HWIF(drive);
+// unsigned long high_16 = pci_resource_start(hwif->pci_dev, 4);
+ unsigned long high_16 = hwif->dma_master;
+ unsigned long atapi_reg = high_16 + (hwif->channel ? 0x24 : 0x20);
+ u8 clock = 0;
+
+ hwif->OUTL(0, atapi_reg); /* zero out extra */
+ clock = hwif->INB(high_16 + 0x11);
+ hwif->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_old_ide_dma_test_irq(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+// struct pci_dev *dev = hwif->pci_dev;
+// unsigned long high_16 = pci_resource_start(dev, 4);
+ unsigned long high_16 = hwif->dma_master;
+ u8 dma_stat = hwif->INB(hwif->dma_status);
+ u8 sc1d = hwif->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 int pdc202xx_ide_dma_lostirq(ide_drive_t *drive)
+{
+ if (HWIF(drive)->resetproc != NULL)
+ HWIF(drive)->resetproc(drive);
+ return __ide_dma_lostirq(drive);
+}
+
+static int pdc202xx_ide_dma_timeout(ide_drive_t *drive)
+{
+ if (HWIF(drive)->resetproc != NULL)
+ HWIF(drive)->resetproc(drive);
+ return __ide_dma_timeout(drive);
+}
+
+static void pdc202xx_reset_host (ide_hwif_t *hwif)
+{
+#ifdef CONFIG_BLK_DEV_IDEDMA
+// unsigned long high_16 = hwif->dma_base - (8*(hwif->channel));
+ unsigned long high_16 = hwif->dma_master;
+#else /* !CONFIG_BLK_DEV_IDEDMA */
+ unsigned long high_16 = pci_resource_start(hwif->pci_dev, 4);
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+ u8 udma_speed_flag = hwif->INB(high_16|0x001f);
+
+ hwif->OUTB((udma_speed_flag | 0x10), (high_16|0x001f));
+ mdelay(100);
+ hwif->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);
+#if 0
+ /*
+ * FIXME: Have to kick all the drives again :-/
+ * What a pain in the ACE!
+ */
+ if (hwif->present) {
+ u16 hunit = 0;
+ for (hunit = 0; hunit < MAX_DRIVES; ++hunit) {
+ ide_drive_t *hdrive = &hwif->drives[hunit];
+ if (hdrive->present) {
+ if (hwif->ide_dma_check)
+ hwif->ide_dma_check(hdrive);
+ else
+ hwif->tuneproc(hdrive, 5);
+ }
+ }
+ }
+ if (mate->present) {
+ u16 munit = 0;
+ for (munit = 0; munit < MAX_DRIVES; ++munit) {
+ ide_drive_t *mdrive = &mate->drives[munit];
+ if (mdrive->present) {
+ if (mate->ide_dma_check)
+ mate->ide_dma_check(mdrive);
+ else
+ mate->tuneproc(mdrive, 5);
+ }
+ }
+ }
+#else
+ hwif->tuneproc(drive, 5);
+#endif
+}
+
+/*
+ * Since SUN Cobalt is attempting to do this operation, I should disclose
+ * this has been a long time ago Thu Jul 27 16:40:57 2000 was the patch date
+ * HOTSWAP ATA Infrastructure.
+ */
+static int pdc202xx_tristate (ide_drive_t * drive, int state)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+// unsigned long high_16 = hwif->dma_base - (8*(hwif->channel));
+ unsigned long high_16 = hwif->dma_master;
+ u8 sc1f = hwif->INB(high_16|0x001f);
+
+ if (!hwif)
+ return -EINVAL;
+
+// hwif->bus_state = state;
+
+ if (state) {
+ hwif->OUTB(sc1f | 0x08, (high_16|0x001f));
+ } else {
+ hwif->OUTB(sc1f & ~0x08, (high_16|0x001f));
+ }
+ return 0;
+}
+
+static unsigned int __devinit init_chipset_pdc202xx(struct pci_dev *dev, const char *name)
+{
+ if (dev->resource[PCI_ROM_RESOURCE].start) {
+ pci_write_config_dword(dev, PCI_ROM_ADDRESS,
+ dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
+ printk(KERN_INFO "%s: ROM enabled at 0x%08lx\n",
+ name, dev->resource[PCI_ROM_RESOURCE].start);
+ }
+
+ /*
+ * software reset - this is required because the bios
+ * will set UDMA timing on if the hdd supports it. The
+ * user may want to turn udma off. A bug in the pdc20262
+ * is that it cannot handle a downgrade in timing from
+ * UDMA to DMA. Disk accesses after issuing a set
+ * feature command will result in errors. A software
+ * reset leaves the timing registers intact,
+ * but resets the drives.
+ */
+#if 0
+ if ((dev->device == PCI_DEVICE_ID_PROMISE_20267) ||
+ (dev->device == PCI_DEVICE_ID_PROMISE_20265) ||
+ (dev->device == PCI_DEVICE_ID_PROMISE_20263) ||
+ (dev->device == PCI_DEVICE_ID_PROMISE_20262)) {
+ unsigned long high_16 = pci_resource_start(dev, 4);
+ byte 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 ?! */
+ }
+
+#endif
+ return dev->irq;
+}
+
+static void __devinit init_hwif_pdc202xx(ide_hwif_t *hwif)
+{
+ struct pci_dev *dev = hwif->pci_dev;
+
+ /* PDC20265 has problems with large LBA48 requests */
+ if ((dev->device == PCI_DEVICE_ID_PROMISE_20267) ||
+ (dev->device == PCI_DEVICE_ID_PROMISE_20265))
+ hwif->rqsize = 256;
+
+ hwif->autodma = 0;
+ hwif->tuneproc = &config_chipset_for_pio;
+ hwif->quirkproc = &pdc202xx_quirkproc;
+
+ if (hwif->pci_dev->device != PCI_DEVICE_ID_PROMISE_20246) {
+ hwif->busproc = &pdc202xx_tristate;
+ hwif->resetproc = &pdc202xx_reset;
+ }
+
+ hwif->speedproc = &pdc202xx_tune_chipset;
+
+ hwif->drives[0].autotune = hwif->drives[1].autotune = 1;
+
+ hwif->ultra_mask = 0x3f;
+ hwif->mwdma_mask = 0x07;
+ hwif->swdma_mask = 0x07;
+
+ hwif->ide_dma_check = &pdc202xx_config_drive_xfer_rate;
+ hwif->ide_dma_lostirq = &pdc202xx_ide_dma_lostirq;
+ hwif->ide_dma_timeout = &pdc202xx_ide_dma_timeout;
+
+ if (hwif->pci_dev->device != PCI_DEVICE_ID_PROMISE_20246) {
+ if (!(hwif->udma_four))
+ hwif->udma_four = (pdc202xx_old_cable_detect(hwif)) ? 0 : 1;
+ hwif->dma_start = &pdc202xx_old_ide_dma_start;
+ hwif->ide_dma_end = &pdc202xx_old_ide_dma_end;
+ }
+ hwif->ide_dma_test_irq = &pdc202xx_old_ide_dma_test_irq;
+
+ if (!noautodma)
+ hwif->autodma = 1;
+ hwif->drives[0].autodma = hwif->drives[1].autodma = hwif->autodma;
+#if PDC202_DEBUG_CABLE
+ printk(KERN_DEBUG "%s: %s-pin cable\n",
+ hwif->name, hwif->udma_four ? "80" : "40");
+#endif /* PDC202_DEBUG_CABLE */
+}
+
+static void __devinit init_dma_pdc202xx(ide_hwif_t *hwif, unsigned long dmabase)
+{
+ u8 udma_speed_flag = 0, primary_mode = 0, secondary_mode = 0;
+
+ if (hwif->channel) {
+ ide_setup_dma(hwif, dmabase, 8);
+ return;
+ }
+
+ udma_speed_flag = hwif->INB((dmabase|0x1f));
+ primary_mode = hwif->INB((dmabase|0x1a));
+ secondary_mode = hwif->INB((dmabase|0x1b));
+ printk(KERN_INFO "%s: (U)DMA Burst Bit %sABLED " \
+ "Primary %s Mode " \
+ "Secondary %s Mode.\n", hwif->cds->name,
+ (udma_speed_flag & 1) ? "EN" : "DIS",
+ (primary_mode & 1) ? "MASTER" : "PCI",
+ (secondary_mode & 1) ? "MASTER" : "PCI" );
+
+#ifdef CONFIG_PDC202XX_BURST
+ if (!(udma_speed_flag & 1)) {
+ printk(KERN_INFO "%s: FORCING BURST BIT 0x%02x->0x%02x ",
+ hwif->cds->name, udma_speed_flag,
+ (udma_speed_flag|1));
+ hwif->OUTB(udma_speed_flag|1,(dmabase|0x1f));
+ printk("%sACTIVE\n",
+ (hwif->INB(dmabase|0x1f)&1) ? "":"IN");
+ }
+#endif /* CONFIG_PDC202XX_BURST */
+#ifdef CONFIG_PDC202XX_MASTER
+ if (!(primary_mode & 1)) {
+ printk(KERN_INFO "%s: FORCING PRIMARY MODE BIT "
+ "0x%02x -> 0x%02x ", hwif->cds->name,
+ primary_mode, (primary_mode|1));
+ hwif->OUTB(primary_mode|1, (dmabase|0x1a));
+ printk("%s\n",
+ (hwif->INB((dmabase|0x1a)) & 1) ? "MASTER" : "PCI");
+ }
+
+ if (!(secondary_mode & 1)) {
+ printk(KERN_INFO "%s: FORCING SECONDARY MODE BIT "
+ "0x%02x -> 0x%02x ", hwif->cds->name,
+ secondary_mode, (secondary_mode|1));
+ hwif->OUTB(secondary_mode|1, (dmabase|0x1b));
+ printk("%s\n",
+ (hwif->INB((dmabase|0x1b)) & 1) ? "MASTER" : "PCI");
+ }
+#endif /* CONFIG_PDC202XX_MASTER */
+
+ ide_setup_dma(hwif, dmabase, 8);
+}
+
+static int __devinit init_setup_pdc202ata4(struct pci_dev *dev,
+ ide_pci_device_t *d)
+{
+ 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: pci-config space interrupt "
+ "mirror fixed.\n", d->name);
+ }
+ }
+
+#if 0
+ if (dev->device == PCI_DEVICE_ID_PROMISE_20262)
+ if (e->reg && (pci_read_config_byte(dev, e->reg, &tmp) ||
+ (tmp & e->mask) != e->val))
+
+ if (d->enablebits[0].reg != d->enablebits[1].reg) {
+ d->enablebits[0].reg = d->enablebits[1].reg;
+ d->enablebits[0].mask = d->enablebits[1].mask;
+ d->enablebits[0].val = d->enablebits[1].val;
+ }
+#endif
+
+ return ide_setup_pci_device(dev, d);
+}
+
+static int __devinit init_setup_pdc20265(struct pci_dev *dev,
+ ide_pci_device_t *d)
+{
+ if ((dev->bus->self) &&
+ (dev->bus->self->vendor == PCI_VENDOR_ID_INTEL) &&
+ ((dev->bus->self->device == PCI_DEVICE_ID_INTEL_I960) ||
+ (dev->bus->self->device == PCI_DEVICE_ID_INTEL_I960RM))) {
+ printk(KERN_INFO "ide: Skipping Promise PDC20265 "
+ "attached to I2O RAID controller.\n");
+ return -ENODEV;
+ }
+
+#if 0
+ {
+ u8 pri = 0, sec = 0;
+
+ if (e->reg && (pci_read_config_byte(dev, e->reg, &tmp) ||
+ (tmp & e->mask) != e->val))
+
+ if (d->enablebits[0].reg != d->enablebits[1].reg) {
+ d->enablebits[0].reg = d->enablebits[1].reg;
+ d->enablebits[0].mask = d->enablebits[1].mask;
+ d->enablebits[0].val = d->enablebits[1].val;
+ }
+ }
+#endif
+
+ return ide_setup_pci_device(dev, d);
+}
+
+static int __devinit init_setup_pdc202xx(struct pci_dev *dev,
+ ide_pci_device_t *d)
+{
+ return ide_setup_pci_device(dev, d);
+}
+
+static ide_pci_device_t pdc202xx_chipsets[] __devinitdata = {
+ { /* 0 */
+ .name = "PDC20246",
+ .init_setup = init_setup_pdc202ata4,
+ .init_chipset = init_chipset_pdc202xx,
+ .init_hwif = init_hwif_pdc202xx,
+ .init_dma = init_dma_pdc202xx,
+ .channels = 2,
+ .autodma = AUTODMA,
+#ifndef CONFIG_PDC202XX_FORCE
+ .enablebits = {{0x50,0x02,0x02}, {0x50,0x04,0x04}},
+#endif
+ .bootable = OFF_BOARD,
+ .extra = 16,
+ },{ /* 1 */
+ .name = "PDC20262",
+ .init_setup = init_setup_pdc202ata4,
+ .init_chipset = init_chipset_pdc202xx,
+ .init_hwif = init_hwif_pdc202xx,
+ .init_dma = init_dma_pdc202xx,
+ .channels = 2,
+ .autodma = AUTODMA,
+#ifndef CONFIG_PDC202XX_FORCE
+ .enablebits = {{0x50,0x02,0x02}, {0x50,0x04,0x04}},
+#endif
+ .bootable = OFF_BOARD,
+ .extra = 48,
+ .flags = IDEPCI_FLAG_FORCE_PDC,
+ },{ /* 2 */
+ .name = "PDC20263",
+ .init_setup = init_setup_pdc202ata4,
+ .init_chipset = init_chipset_pdc202xx,
+ .init_hwif = init_hwif_pdc202xx,
+ .init_dma = init_dma_pdc202xx,
+ .channels = 2,
+ .autodma = AUTODMA,
+#ifndef CONFIG_PDC202XX_FORCE
+ .enablebits = {{0x50,0x02,0x02}, {0x50,0x04,0x04}},
+#endif
+ .bootable = OFF_BOARD,
+ .extra = 48,
+ },{ /* 3 */
+ .name = "PDC20265",
+ .init_setup = init_setup_pdc20265,
+ .init_chipset = init_chipset_pdc202xx,
+ .init_hwif = init_hwif_pdc202xx,
+ .init_dma = init_dma_pdc202xx,
+ .channels = 2,
+ .autodma = AUTODMA,
+#ifndef CONFIG_PDC202XX_FORCE
+ .enablebits = {{0x50,0x02,0x02}, {0x50,0x04,0x04}},
+#endif
+ .bootable = OFF_BOARD,
+ .extra = 48,
+ .flags = IDEPCI_FLAG_FORCE_PDC,
+ },{ /* 4 */
+ .name = "PDC20267",
+ .init_setup = init_setup_pdc202xx,
+ .init_chipset = init_chipset_pdc202xx,
+ .init_hwif = init_hwif_pdc202xx,
+ .init_dma = init_dma_pdc202xx,
+ .channels = 2,
+ .autodma = AUTODMA,
+#ifndef CONFIG_PDC202XX_FORCE
+ .enablebits = {{0x50,0x02,0x02}, {0x50,0x04,0x04}},
+#endif
+ .bootable = OFF_BOARD,
+ .extra = 48,
+ }
+};
+
+/**
+ * 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)
+{
+ ide_pci_device_t *d = &pdc202xx_chipsets[id->driver_data];
+
+ return d->init_setup(dev, d);
+}
+
+static struct pci_device_id pdc202xx_pci_tbl[] = {
+ { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20246, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20262, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+ { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20263, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
+ { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20265, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3},
+ { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20267, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4},
+ { 0, },
+};
+MODULE_DEVICE_TABLE(pci, pdc202xx_pci_tbl);
+
+static struct pci_driver driver = {
+ .name = "Promise_Old_IDE",
+ .id_table = pdc202xx_pci_tbl,
+ .probe = pdc202xx_init_one,
+};
+
+static int pdc202xx_ide_init(void)
+{
+ return ide_pci_register_driver(&driver);
+}
+
+module_init(pdc202xx_ide_init);
+
+MODULE_AUTHOR("Andre Hedrick, Frank Tiernan");
+MODULE_DESCRIPTION("PCI driver module for older Promise IDE");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/pci/piix.c b/drivers/ide/pci/piix.c
new file mode 100644
index 000000000000..b5a20ae1ef3e
--- /dev/null
+++ b/drivers/ide/pci/piix.c
@@ -0,0 +1,670 @@
+/*
+ * linux/drivers/ide/pci/piix.c Version 0.44 March 20, 2003
+ *
+ * Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer
+ * Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org>
+ * Copyright (C) 2003 Red Hat Inc <alan@redhat.com>
+ *
+ * May be copied or modified under the terms of the GNU General Public License
+ *
+ * PIO mode setting function for Intel chipsets.
+ * For use instead of BIOS settings.
+ *
+ * 40-41
+ * 42-43
+ *
+ * 41
+ * 43
+ *
+ * | PIO 0 | c0 | 80 | 0 | piix_tune_drive(drive, 0);
+ * | PIO 2 | SW2 | d0 | 90 | 4 | piix_tune_drive(drive, 2);
+ * | PIO 3 | MW1 | e1 | a1 | 9 | piix_tune_drive(drive, 3);
+ * | PIO 4 | MW2 | e3 | a3 | b | piix_tune_drive(drive, 4);
+ *
+ * sitre = word40 & 0x4000; primary
+ * sitre = word42 & 0x4000; secondary
+ *
+ * 44 8421|8421 hdd|hdb
+ *
+ * 48 8421 hdd|hdc|hdb|hda udma enabled
+ *
+ * 0001 hda
+ * 0010 hdb
+ * 0100 hdc
+ * 1000 hdd
+ *
+ * 4a 84|21 hdb|hda
+ * 4b 84|21 hdd|hdc
+ *
+ * ata-33/82371AB
+ * ata-33/82371EB
+ * ata-33/82801AB ata-66/82801AA
+ * 00|00 udma 0 00|00 reserved
+ * 01|01 udma 1 01|01 udma 3
+ * 10|10 udma 2 10|10 udma 4
+ * 11|11 reserved 11|11 reserved
+ *
+ * 54 8421|8421 ata66 drive|ata66 enable
+ *
+ * pci_read_config_word(HWIF(drive)->pci_dev, 0x40, &reg40);
+ * pci_read_config_word(HWIF(drive)->pci_dev, 0x42, &reg42);
+ * pci_read_config_word(HWIF(drive)->pci_dev, 0x44, &reg44);
+ * pci_read_config_byte(HWIF(drive)->pci_dev, 0x48, &reg48);
+ * pci_read_config_word(HWIF(drive)->pci_dev, 0x4a, &reg4a);
+ * pci_read_config_byte(HWIF(drive)->pci_dev, 0x54, &reg54);
+ *
+ * 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/config.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+static int no_piix_dma;
+
+/**
+ * piix_ratemask - compute rate mask for PIIX IDE
+ * @drive: IDE drive to compute for
+ *
+ * Returns the available modes for the PIIX IDE controller.
+ */
+
+static u8 piix_ratemask (ide_drive_t *drive)
+{
+ struct pci_dev *dev = HWIF(drive)->pci_dev;
+ u8 mode;
+
+ switch(dev->device) {
+ case PCI_DEVICE_ID_INTEL_82801EB_1:
+ mode = 3;
+ break;
+ /* UDMA 100 capable */
+ case PCI_DEVICE_ID_INTEL_82801BA_8:
+ case PCI_DEVICE_ID_INTEL_82801BA_9:
+ case PCI_DEVICE_ID_INTEL_82801CA_10:
+ case PCI_DEVICE_ID_INTEL_82801CA_11:
+ case PCI_DEVICE_ID_INTEL_82801E_11:
+ case PCI_DEVICE_ID_INTEL_82801DB_1:
+ case PCI_DEVICE_ID_INTEL_82801DB_10:
+ case PCI_DEVICE_ID_INTEL_82801DB_11:
+ case PCI_DEVICE_ID_INTEL_82801EB_11:
+ case PCI_DEVICE_ID_INTEL_ESB_2:
+ case PCI_DEVICE_ID_INTEL_ICH6_19:
+ case PCI_DEVICE_ID_INTEL_ICH7_21:
+ mode = 3;
+ break;
+ /* UDMA 66 capable */
+ case PCI_DEVICE_ID_INTEL_82801AA_1:
+ case PCI_DEVICE_ID_INTEL_82372FB_1:
+ mode = 2;
+ break;
+ /* UDMA 33 capable */
+ case PCI_DEVICE_ID_INTEL_82371AB:
+ case PCI_DEVICE_ID_INTEL_82443MX_1:
+ case PCI_DEVICE_ID_INTEL_82451NX:
+ case PCI_DEVICE_ID_INTEL_82801AB_1:
+ return 1;
+ /* Non UDMA capable (MWDMA2) */
+ case PCI_DEVICE_ID_INTEL_82371SB_1:
+ case PCI_DEVICE_ID_INTEL_82371FB_1:
+ case PCI_DEVICE_ID_INTEL_82371FB_0:
+ case PCI_DEVICE_ID_INTEL_82371MX:
+ default:
+ return 0;
+ }
+
+ /*
+ * If we are UDMA66 capable fall back to UDMA33
+ * if the drive cannot see an 80pin cable.
+ */
+ if (!eighty_ninty_three(drive))
+ mode = min(mode, (u8)1);
+ return mode;
+}
+
+/**
+ * piix_dma_2_pio - return the PIO mode matching DMA
+ * @xfer_rate: transfer speed
+ *
+ * Returns the nearest equivalent PIO timing for the PIO or DMA
+ * mode requested by the controller.
+ */
+
+static u8 piix_dma_2_pio (u8 xfer_rate) {
+ switch(xfer_rate) {
+ case XFER_UDMA_6:
+ case XFER_UDMA_5:
+ case XFER_UDMA_4:
+ case XFER_UDMA_3:
+ case XFER_UDMA_2:
+ case XFER_UDMA_1:
+ case XFER_UDMA_0:
+ case XFER_MW_DMA_2:
+ case XFER_PIO_4:
+ return 4;
+ case XFER_MW_DMA_1:
+ case XFER_PIO_3:
+ return 3;
+ case XFER_SW_DMA_2:
+ case XFER_PIO_2:
+ return 2;
+ case XFER_MW_DMA_0:
+ case XFER_SW_DMA_1:
+ case XFER_SW_DMA_0:
+ case XFER_PIO_1:
+ case XFER_PIO_0:
+ case XFER_PIO_SLOW:
+ default:
+ return 0;
+ }
+}
+
+/**
+ * piix_tune_drive - tune a drive attached to a PIIX
+ * @drive: drive to tune
+ * @pio: desired PIO mode
+ *
+ * Set the interface PIO mode based upon the settings done by AMI BIOS
+ * (might be useful if drive is not registered in CMOS for any reason).
+ */
+static void piix_tune_drive (ide_drive_t *drive, u8 pio)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = hwif->pci_dev;
+ int is_slave = (&hwif->drives[1] == drive);
+ int master_port = hwif->channel ? 0x42 : 0x40;
+ int slave_port = 0x44;
+ unsigned long flags;
+ u16 master_data;
+ u8 slave_data;
+ /* ISP RTC */
+ u8 timings[][2] = { { 0, 0 },
+ { 0, 0 },
+ { 1, 0 },
+ { 2, 1 },
+ { 2, 3 }, };
+
+ pio = ide_get_best_pio_mode(drive, pio, 5, NULL);
+ spin_lock_irqsave(&ide_lock, flags);
+ pci_read_config_word(dev, master_port, &master_data);
+ if (is_slave) {
+ master_data = master_data | 0x4000;
+ if (pio > 1)
+ /* enable PPE, IE and TIME */
+ master_data = master_data | 0x0070;
+ pci_read_config_byte(dev, slave_port, &slave_data);
+ slave_data = slave_data & (hwif->channel ? 0x0f : 0xf0);
+ slave_data = slave_data | (((timings[pio][0] << 2) | timings[pio][1]) << (hwif->channel ? 4 : 0));
+ } else {
+ master_data = master_data & 0xccf8;
+ if (pio > 1)
+ /* enable PPE, IE and TIME */
+ master_data = master_data | 0x0007;
+ 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(&ide_lock, flags);
+}
+
+/**
+ * piix_tune_chipset - tune a PIIX interface
+ * @drive: IDE drive to tune
+ * @xferspeed: speed to configure
+ *
+ * Set a PIIX interface channel to the desired speeds. This involves
+ * requires the right timing data into the PIIX configuration space
+ * then setting the drive parameters appropriately
+ */
+
+static int piix_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = hwif->pci_dev;
+ u8 maslave = hwif->channel ? 0x42 : 0x40;
+ u8 speed = ide_rate_filter(piix_ratemask(drive), xferspeed);
+ 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);
+
+ switch(speed) {
+ case XFER_UDMA_4:
+ case XFER_UDMA_2: u_speed = 2 << (drive->dn * 4); break;
+ case XFER_UDMA_5:
+ case XFER_UDMA_3:
+ case XFER_UDMA_1: u_speed = 1 << (drive->dn * 4); break;
+ case XFER_UDMA_0: u_speed = 0 << (drive->dn * 4); break;
+ case XFER_MW_DMA_2:
+ case XFER_MW_DMA_1:
+ case XFER_SW_DMA_2: break;
+ case XFER_PIO_4:
+ case XFER_PIO_3:
+ case XFER_PIO_2:
+ case XFER_PIO_0: break;
+ default: return -1;
+ }
+
+ if (speed >= XFER_UDMA_0) {
+ 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 {
+ 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);
+ }
+
+ piix_tune_drive(drive, piix_dma_2_pio(speed));
+ return (ide_config_drive_speed(drive, speed));
+}
+
+/**
+ * piix_faulty_dma0 - check for DMA0 errata
+ * @hwif: IDE interface to check
+ *
+ * If an ICH/ICH0/ICH2 interface is is operating in multi-word
+ * DMA mode with 600nS cycle time the IDE PIO prefetch buffer will
+ * inadvertently provide an extra piece of secondary data to the primary
+ * device resulting in data corruption.
+ *
+ * With such a device this test function returns true. This allows
+ * our tuning code to follow Intel recommendations and use PIO on
+ * such devices.
+ */
+
+static int piix_faulty_dma0(ide_hwif_t *hwif)
+{
+ switch(hwif->pci_dev->device)
+ {
+ case PCI_DEVICE_ID_INTEL_82801AA_1: /* ICH */
+ case PCI_DEVICE_ID_INTEL_82801AB_1: /* ICH0 */
+ case PCI_DEVICE_ID_INTEL_82801BA_8: /* ICH2 */
+ case PCI_DEVICE_ID_INTEL_82801BA_9: /* ICH2 */
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * piix_config_drive_for_dma - configure drive for DMA
+ * @drive: IDE drive to configure
+ *
+ * Set up a PIIX interface channel for the best available speed.
+ * We prefer UDMA if it is available and then MWDMA. If DMA is
+ * not available we switch to PIO and return 0.
+ */
+
+static int piix_config_drive_for_dma (ide_drive_t *drive)
+{
+ u8 speed = ide_dma_speed(drive, piix_ratemask(drive));
+
+ /* Some ICH devices cannot support DMA mode 0 */
+ if(speed == XFER_MW_DMA_0 && piix_faulty_dma0(HWIF(drive)))
+ speed = 0;
+
+ /* If no DMA speed was available or the chipset has DMA bugs
+ then disable DMA and use PIO */
+
+ if (!speed || no_piix_dma) {
+ u8 tspeed = ide_get_best_pio_mode(drive, 255, 5, NULL);
+ speed = piix_dma_2_pio(XFER_PIO_0 + tspeed);
+ }
+
+ (void) piix_tune_chipset(drive, speed);
+ return ide_dma_enable(drive);
+}
+
+/**
+ * piix_config_drive_xfer_rate - set up an IDE device
+ * @drive: IDE drive to configure
+ *
+ * Set up the PIIX interface for the best available speed on this
+ * interface, preferring DMA to PIO.
+ */
+
+static int piix_config_drive_xfer_rate (ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct hd_driveid *id = drive->id;
+
+ drive->init_speed = 0;
+
+ if ((id->capability & 1) && drive->autodma) {
+
+ if (ide_use_dma(drive)) {
+ if (piix_config_drive_for_dma(drive))
+ return hwif->ide_dma_on(drive);
+ }
+
+ goto fast_ata_pio;
+
+ } else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+ /* Find best PIO mode. */
+ hwif->tuneproc(drive, 255);
+ return hwif->ide_dma_off_quietly(drive);
+ }
+ /* IORDY not supported */
+ return 0;
+}
+
+/**
+ * init_chipset_piix - set up the PIIX chipset
+ * @dev: PCI device to set up
+ * @name: Name of the device
+ *
+ * Initialize the PCI device as required. For the PIIX this turns
+ * out to be nice and simple
+ */
+
+static unsigned int __devinit init_chipset_piix (struct pci_dev *dev, const char *name)
+{
+ switch(dev->device) {
+ case PCI_DEVICE_ID_INTEL_82801EB_1:
+ case PCI_DEVICE_ID_INTEL_82801AA_1:
+ case PCI_DEVICE_ID_INTEL_82801AB_1:
+ case PCI_DEVICE_ID_INTEL_82801BA_8:
+ case PCI_DEVICE_ID_INTEL_82801BA_9:
+ case PCI_DEVICE_ID_INTEL_82801CA_10:
+ case PCI_DEVICE_ID_INTEL_82801CA_11:
+ case PCI_DEVICE_ID_INTEL_82801DB_1:
+ case PCI_DEVICE_ID_INTEL_82801DB_10:
+ case PCI_DEVICE_ID_INTEL_82801DB_11:
+ case PCI_DEVICE_ID_INTEL_82801EB_11:
+ case PCI_DEVICE_ID_INTEL_82801E_11:
+ case PCI_DEVICE_ID_INTEL_ESB_2:
+ case PCI_DEVICE_ID_INTEL_ICH6_19:
+ case PCI_DEVICE_ID_INTEL_ICH7_21:
+ {
+ unsigned int extra = 0;
+ pci_read_config_dword(dev, 0x54, &extra);
+ pci_write_config_dword(dev, 0x54, extra|0x400);
+ }
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+/**
+ * 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)
+{
+ u8 reg54h = 0, reg55h = 0, ata66 = 0;
+ u8 mask = hwif->channel ? 0xc0 : 0x30;
+
+#ifndef CONFIG_IA64
+ if (!hwif->irq)
+ hwif->irq = hwif->channel ? 15 : 14;
+#endif /* CONFIG_IA64 */
+
+ if (hwif->pci_dev->device == PCI_DEVICE_ID_INTEL_82371MX) {
+ /* This is a painful system best to let it self tune for now */
+ return;
+ }
+
+ hwif->autodma = 0;
+ hwif->tuneproc = &piix_tune_drive;
+ hwif->speedproc = &piix_tune_chipset;
+ hwif->drives[0].autotune = 1;
+ hwif->drives[1].autotune = 1;
+
+ if (!hwif->dma_base)
+ return;
+
+ hwif->atapi_dma = 1;
+ hwif->ultra_mask = 0x3f;
+ hwif->mwdma_mask = 0x06;
+ hwif->swdma_mask = 0x04;
+
+ switch(hwif->pci_dev->device) {
+ case PCI_DEVICE_ID_INTEL_82371MX:
+ hwif->mwdma_mask = 0x80;
+ hwif->swdma_mask = 0x80;
+ case PCI_DEVICE_ID_INTEL_82371FB_0:
+ case PCI_DEVICE_ID_INTEL_82371FB_1:
+ case PCI_DEVICE_ID_INTEL_82371SB_1:
+ hwif->ultra_mask = 0x80;
+ break;
+ case PCI_DEVICE_ID_INTEL_82371AB:
+ case PCI_DEVICE_ID_INTEL_82443MX_1:
+ case PCI_DEVICE_ID_INTEL_82451NX:
+ case PCI_DEVICE_ID_INTEL_82801AB_1:
+ hwif->ultra_mask = 0x07;
+ break;
+ default:
+ pci_read_config_byte(hwif->pci_dev, 0x54, &reg54h);
+ pci_read_config_byte(hwif->pci_dev, 0x55, &reg55h);
+ ata66 = (reg54h & mask) ? 1 : 0;
+ break;
+ }
+
+ if (!(hwif->udma_four))
+ hwif->udma_four = ata66;
+ hwif->ide_dma_check = &piix_config_drive_xfer_rate;
+ if (!noautodma)
+ hwif->autodma = 1;
+
+ hwif->drives[1].autodma = hwif->autodma;
+ hwif->drives[0].autodma = hwif->autodma;
+}
+
+#define DECLARE_PIIX_DEV(name_str) \
+ { \
+ .name = name_str, \
+ .init_chipset = init_chipset_piix, \
+ .init_hwif = init_hwif_piix, \
+ .channels = 2, \
+ .autodma = AUTODMA, \
+ .enablebits = {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, \
+ .bootable = ON_BOARD, \
+ }
+
+static ide_pci_device_t piix_pci_info[] __devinitdata = {
+ /* 0 */ DECLARE_PIIX_DEV("PIIXa"),
+ /* 1 */ DECLARE_PIIX_DEV("PIIXb"),
+
+ { /* 2 */
+ .name = "MPIIX",
+ .init_hwif = init_hwif_piix,
+ .channels = 2,
+ .autodma = NODMA,
+ .enablebits = {{0x6D,0x80,0x80}, {0x6F,0x80,0x80}},
+ .bootable = ON_BOARD,
+ },
+
+ /* 3 */ DECLARE_PIIX_DEV("PIIX3"),
+ /* 4 */ DECLARE_PIIX_DEV("PIIX4"),
+ /* 5 */ DECLARE_PIIX_DEV("ICH0"),
+ /* 6 */ DECLARE_PIIX_DEV("PIIX4"),
+ /* 7 */ DECLARE_PIIX_DEV("ICH"),
+ /* 8 */ DECLARE_PIIX_DEV("PIIX4"),
+ /* 9 */ DECLARE_PIIX_DEV("PIIX4"),
+ /* 10 */ DECLARE_PIIX_DEV("ICH2"),
+ /* 11 */ DECLARE_PIIX_DEV("ICH2M"),
+ /* 12 */ DECLARE_PIIX_DEV("ICH3M"),
+ /* 13 */ DECLARE_PIIX_DEV("ICH3"),
+ /* 14 */ DECLARE_PIIX_DEV("ICH4"),
+ /* 15 */ DECLARE_PIIX_DEV("ICH5"),
+ /* 16 */ DECLARE_PIIX_DEV("C-ICH"),
+ /* 17 */ DECLARE_PIIX_DEV("ICH4"),
+ /* 18 */ DECLARE_PIIX_DEV("ICH5-SATA"),
+ /* 19 */ DECLARE_PIIX_DEV("ICH5"),
+ /* 20 */ DECLARE_PIIX_DEV("ICH6"),
+ /* 21 */ DECLARE_PIIX_DEV("ICH7"),
+ /* 22 */ DECLARE_PIIX_DEV("ICH4"),
+};
+
+/**
+ * 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)
+{
+ ide_pci_device_t *d = &piix_pci_info[id->driver_data];
+
+ return ide_setup_pci_device(dev, d);
+}
+
+/**
+ * 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;
+ u8 rev;
+ while((pdev=pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454NX, pdev))!=NULL)
+ {
+ /* Look for 450NX PXB. Check for problem configurations
+ A PCI quirk checks bit 6 already */
+ pci_read_config_byte(pdev, PCI_REVISION_ID, &rev);
+ pci_read_config_word(pdev, 0x41, &cfg);
+ /* Only on the original revision: IDE DMA can hang */
+ if(rev == 0x00)
+ no_piix_dma = 1;
+ /* On all revisions below 5 PXB bus lock must be disabled for IDE */
+ else if(cfg & (1<<14) && rev < 5)
+ no_piix_dma = 2;
+ }
+ if(no_piix_dma)
+ printk(KERN_WARNING "piix: 450NX errata present, disabling IDE DMA.\n");
+ if(no_piix_dma == 2)
+ printk(KERN_WARNING "piix: A BIOS update may resolve this.\n");
+}
+
+static struct pci_device_id piix_pci_tbl[] = {
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371FB_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371FB_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371MX, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3},
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4},
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5},
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6},
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 7},
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82372FB_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8},
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82451NX, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 9},
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 10},
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 11},
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_10,PCI_ANY_ID, PCI_ANY_ID, 0, 0, 12},
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_11,PCI_ANY_ID, PCI_ANY_ID, 0, 0, 13},
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_11,PCI_ANY_ID, PCI_ANY_ID, 0, 0, 14},
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_11,PCI_ANY_ID, PCI_ANY_ID, 0, 0, 15},
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801E_11, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 16},
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_10,PCI_ANY_ID, PCI_ANY_ID, 0, 0, 17},
+#ifdef CONFIG_BLK_DEV_IDE_SATA
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 18},
+#endif
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 19},
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_19, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 20},
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_21, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 21},
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 22},
+ { 0, },
+};
+MODULE_DEVICE_TABLE(pci, piix_pci_tbl);
+
+static struct pci_driver driver = {
+ .name = "PIIX_IDE",
+ .id_table = piix_pci_tbl,
+ .probe = piix_init_one,
+};
+
+static int __init piix_ide_init(void)
+{
+ piix_check_450nx();
+ return ide_pci_register_driver(&driver);
+}
+
+module_init(piix_ide_init);
+
+MODULE_AUTHOR("Andre Hedrick, Andrzej Krzysztofowicz");
+MODULE_DESCRIPTION("PCI driver module for Intel PIIX IDE");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/pci/rz1000.c b/drivers/ide/pci/rz1000.c
new file mode 100644
index 000000000000..608cd7609072
--- /dev/null
+++ b/drivers/ide/pci/rz1000.c
@@ -0,0 +1,91 @@
+/*
+ * linux/drivers/ide/pci/rz1000.c Version 0.06 January 12, 2003
+ *
+ * Copyright (C) 1995-1998 Linus Torvalds & author (see below)
+ */
+
+/*
+ * Principal Author: mlord@pobox.com (Mark Lord)
+ *
+ * See linux/MAINTAINERS for address of current maintainer.
+ *
+ * This file provides support for disabling the buggy read-ahead
+ * mode of the RZ1000 IDE chipset, commonly used on Intel motherboards.
+ *
+ * Dunno if this fixes both ports, or only the primary port (?).
+ */
+
+#undef REALLY_SLOW_IO /* most systems can safely undef this */
+
+#include <linux/config.h> /* for CONFIG_BLK_DEV_IDEPCI */
+#include <linux/types.h>
+#include <linux/module.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/hdreg.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+static void __devinit init_hwif_rz1000 (ide_hwif_t *hwif)
+{
+ u16 reg;
+ struct pci_dev *dev = hwif->pci_dev;
+
+ hwif->chipset = ide_rz1000;
+ 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 {
+ hwif->serialized = 1;
+ hwif->drives[0].no_unmask = 1;
+ hwif->drives[1].no_unmask = 1;
+ printk(KERN_INFO "%s: serialized, disabled unmasking "
+ "(buggy RZ1000/RZ1001)\n", hwif->name);
+ }
+}
+
+static ide_pci_device_t rz1000_chipset __devinitdata = {
+ .name = "RZ100x",
+ .init_hwif = init_hwif_rz1000,
+ .channels = 2,
+ .autodma = NODMA,
+ .bootable = ON_BOARD,
+};
+
+static int __devinit rz1000_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ return ide_setup_pci_device(dev, &rz1000_chipset);
+}
+
+static struct pci_device_id rz1000_pci_tbl[] = {
+ { PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { 0, },
+};
+MODULE_DEVICE_TABLE(pci, rz1000_pci_tbl);
+
+static struct pci_driver driver = {
+ .name = "RZ1000_IDE",
+ .id_table = rz1000_pci_tbl,
+ .probe = rz1000_init_one,
+};
+
+static int rz1000_ide_init(void)
+{
+ return ide_pci_register_driver(&driver);
+}
+
+module_init(rz1000_ide_init);
+
+MODULE_AUTHOR("Andre Hedrick");
+MODULE_DESCRIPTION("PCI driver module for RZ1000 IDE");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/ide/pci/sc1200.c b/drivers/ide/pci/sc1200.c
new file mode 100644
index 000000000000..84fda21e4dbd
--- /dev/null
+++ b/drivers/ide/pci/sc1200.c
@@ -0,0 +1,518 @@
+/*
+ * linux/drivers/ide/pci/sc1200.c Version 0.91 28-Jan-2003
+ *
+ * Copyright (C) 2000-2002 Mark Lord <mlord@pobox.com>
+ * May be copied or modified under the terms of the GNU General Public License
+ *
+ * Development of this chipset driver was funded
+ * by the nice folks at National Semiconductor.
+ *
+ * Documentation:
+ * Available from National Semiconductor
+ */
+
+#include <linux/config.h>
+#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/hdreg.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/ide.h>
+#include <linux/pm.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#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;
+}
+
+extern char *ide_xfer_verbose (byte xfer_rate);
+
+/*
+ * Set a new transfer mode at the drive
+ */
+static int sc1200_set_xfer_mode (ide_drive_t *drive, byte mode)
+{
+ printk("%s: sc1200_set_xfer_mode(%s)\n", drive->name, ide_xfer_verbose(mode));
+ return ide_config_drive_speed(drive, mode);
+}
+
+/*
+ * 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 int sc1200_autoselect_dma_mode (ide_drive_t *drive)
+{
+ int udma_ok = 1, mode = 0;
+ ide_hwif_t *hwif = HWIF(drive);
+ int unit = drive->select.b.unit;
+ ide_drive_t *mate = &hwif->drives[unit^1];
+ struct hd_driveid *id = drive->id;
+
+ /*
+ * 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.
+ */
+ if (mate->present) {
+ struct hd_driveid *mateid = mate->id;
+ if (mateid && (mateid->capability & 1) && !__ide_dma_bad_drive(mate)) {
+ if ((mateid->field_valid & 4) && (mateid->dma_ultra & 7))
+ udma_ok = 1;
+ else if ((mateid->field_valid & 2) && (mateid->dma_mword & 7))
+ udma_ok = 0;
+ else
+ udma_ok = 1;
+ }
+ }
+ /*
+ * Now see what the current drive is capable of,
+ * selecting UDMA only if the mate said it was ok.
+ */
+ if (id && (id->capability & 1) && hwif->autodma && !__ide_dma_bad_drive(drive)) {
+ if (udma_ok && (id->field_valid & 4) && (id->dma_ultra & 7)) {
+ if (id->dma_ultra & 4)
+ mode = XFER_UDMA_2;
+ else if (id->dma_ultra & 2)
+ mode = XFER_UDMA_1;
+ else if (id->dma_ultra & 1)
+ mode = XFER_UDMA_0;
+ }
+ if (!mode && (id->field_valid & 2) && (id->dma_mword & 7)) {
+ if (id->dma_mword & 4)
+ mode = XFER_MW_DMA_2;
+ else if (id->dma_mword & 2)
+ mode = XFER_MW_DMA_1;
+ else if (id->dma_mword & 1)
+ mode = XFER_MW_DMA_0;
+ }
+ }
+ return mode;
+}
+
+/*
+ * sc1200_config_dma2() handles selection/setting of DMA/UDMA modes
+ * for both the chipset and drive.
+ */
+static int sc1200_config_dma2 (ide_drive_t *drive, int mode)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ int unit = drive->select.b.unit;
+ unsigned int reg, timings;
+ unsigned short pci_clock;
+ unsigned int basereg = hwif->channel ? 0x50 : 0x40;
+
+ /*
+ * Default to DMA-off in case we run into trouble here.
+ */
+ hwif->ide_dma_off_quietly(drive); /* turn off DMA while we fiddle */
+ outb(inb(hwif->dma_base+2)&~(unit?0x40:0x20), hwif->dma_base+2); /* clear DMA_capable bit */
+
+ /*
+ * Tell the drive to switch to the new mode; abort on failure.
+ */
+ if (!mode || sc1200_set_xfer_mode(drive, mode)) {
+ printk("SC1200: set xfer mode failure\n");
+ return 1; /* failure */
+ }
+
+ pci_clock = sc1200_get_pci_clock();
+
+ /*
+ * Now tune the chipset to match the drive:
+ *
+ * Note that each DMA mode has several timings associated with it.
+ * The correct timing depends on the fast PCI clock freq.
+ */
+ timings = 0;
+ switch (mode) {
+ case XFER_UDMA_0:
+ switch (pci_clock) {
+ case PCI_CLK_33: timings = 0x00921250; break;
+ case PCI_CLK_48: timings = 0x00932470; break;
+ case PCI_CLK_66: timings = 0x009436a1; break;
+ }
+ break;
+ case XFER_UDMA_1:
+ switch (pci_clock) {
+ case PCI_CLK_33: timings = 0x00911140; break;
+ case PCI_CLK_48: timings = 0x00922260; break;
+ case PCI_CLK_66: timings = 0x00933481; break;
+ }
+ break;
+ case XFER_UDMA_2:
+ switch (pci_clock) {
+ case PCI_CLK_33: timings = 0x00911030; break;
+ case PCI_CLK_48: timings = 0x00922140; break;
+ case PCI_CLK_66: timings = 0x00923261; break;
+ }
+ break;
+ case XFER_MW_DMA_0:
+ switch (pci_clock) {
+ case PCI_CLK_33: timings = 0x00077771; break;
+ case PCI_CLK_48: timings = 0x000bbbb2; break;
+ case PCI_CLK_66: timings = 0x000ffff3; break;
+ }
+ break;
+ case XFER_MW_DMA_1:
+ switch (pci_clock) {
+ case PCI_CLK_33: timings = 0x00012121; break;
+ case PCI_CLK_48: timings = 0x00024241; break;
+ case PCI_CLK_66: timings = 0x00035352; break;
+ }
+ break;
+ case XFER_MW_DMA_2:
+ switch (pci_clock) {
+ case PCI_CLK_33: timings = 0x00002020; break;
+ case PCI_CLK_48: timings = 0x00013131; break;
+ case PCI_CLK_66: timings = 0x00015151; break;
+ }
+ break;
+ }
+
+ if (timings == 0) {
+ printk("%s: sc1200_config_dma: huh? mode=%02x clk=%x \n", drive->name, mode, pci_clock);
+ return 1; /* failure */
+ }
+
+ if (unit == 0) { /* are we configuring drive0? */
+ pci_read_config_dword(hwif->pci_dev, basereg+4, &reg);
+ timings |= reg & 0x80000000; /* preserve PIO format bit */
+ pci_write_config_dword(hwif->pci_dev, basereg+4, timings);
+ } else {
+ pci_write_config_dword(hwif->pci_dev, basereg+12, timings);
+ }
+
+ outb(inb(hwif->dma_base+2)|(unit?0x40:0x20), hwif->dma_base+2); /* set DMA_capable bit */
+
+ /*
+ * Finally, turn DMA on in software, and exit.
+ */
+ return hwif->ide_dma_on(drive); /* success */
+}
+
+/*
+ * sc1200_config_dma() handles selection/setting of DMA/UDMA modes
+ * for both the chipset and drive.
+ */
+static int sc1200_config_dma (ide_drive_t *drive)
+{
+ return sc1200_config_dma2(drive, sc1200_autoselect_dma_mode(drive));
+}
+
+
+/* Replacement for the standard ide_dma_end action in
+ * dma_proc.
+ *
+ * returns 1 on error, 0 otherwise
+ */
+static int sc1200_ide_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_tuneproc() handles selection/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_tuneproc (ide_drive_t *drive, byte pio) /* mode=255 means "autotune" */
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ unsigned int format;
+ static byte modes[5] = {XFER_PIO_0, XFER_PIO_1, XFER_PIO_2, XFER_PIO_3, XFER_PIO_4};
+ int mode = -1;
+
+ 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);
+ (void)sc1200_config_dma2(drive, mode);
+ return;
+ }
+
+ pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+ printk("SC1200: %s: setting PIO mode%d\n", drive->name, pio);
+ if (!sc1200_set_xfer_mode(drive, modes[pio])) {
+ unsigned int basereg = hwif->channel ? 0x50 : 0x40;
+ pci_read_config_dword (hwif->pci_dev, basereg+4, &format);
+ format = (format >> 31) & 1;
+ if (format)
+ format += sc1200_get_pci_clock();
+ pci_write_config_dword(hwif->pci_dev, basereg + (drive->select.b.unit << 3), sc1200_pio_timings[format][pio]);
+ }
+}
+
+static ide_hwif_t *lookup_pci_dev (ide_hwif_t *prev, struct pci_dev *dev)
+{
+ int h;
+
+ for (h = 0; h < MAX_HWIFS; h++) {
+ ide_hwif_t *hwif = &ide_hwifs[h];
+ if (prev) {
+ if (hwif == prev)
+ prev = NULL; // found previous, now look for next match
+ } else {
+ if (hwif && hwif->pci_dev == dev)
+ return hwif; // found next match
+ }
+ }
+ return NULL; // not found
+}
+
+typedef struct sc1200_saved_state_s {
+ __u32 regs[4];
+} sc1200_saved_state_t;
+
+
+static int sc1200_suspend (struct pci_dev *dev, u32 state)
+{
+ ide_hwif_t *hwif = NULL;
+
+ printk("SC1200: suspend(%u)\n", state);
+
+ if (state == 0) {
+ // we only save state when going from full power to less
+
+ //
+ // Loop over all interfaces that are part of this PCI device:
+ //
+ while ((hwif = lookup_pci_dev(hwif, dev)) != NULL) {
+ sc1200_saved_state_t *ss;
+ unsigned int basereg, r;
+ //
+ // allocate a permanent save area, if not already allocated
+ //
+ ss = (sc1200_saved_state_t *)hwif->config_data;
+ if (ss == NULL) {
+ ss = kmalloc(sizeof(sc1200_saved_state_t), GFP_KERNEL);
+ if (ss == NULL)
+ return -ENOMEM;
+ hwif->config_data = (unsigned long)ss;
+ }
+ ss = (sc1200_saved_state_t *)hwif->config_data;
+ //
+ // Save timing registers: this may be unnecessary if
+ // BIOS also does it
+ //
+ basereg = hwif->channel ? 0x50 : 0x40;
+ for (r = 0; r < 4; ++r) {
+ pci_read_config_dword (hwif->pci_dev, basereg + (r<<2), &ss->regs[r]);
+ }
+ }
+ }
+
+ /* You don't need to iterate over disks -- sysfs should have done that for you already */
+
+ pci_disable_device(dev);
+ pci_set_power_state(dev,state);
+ dev->current_state = state;
+ return 0;
+}
+
+static int sc1200_resume (struct pci_dev *dev)
+{
+ ide_hwif_t *hwif = NULL;
+
+printk("SC1200: resume\n");
+ pci_set_power_state(dev,0); // bring chip back from sleep state
+ dev->current_state = 0;
+ pci_enable_device(dev);
+ //
+ // loop over all interfaces that are part of this pci device:
+ //
+ while ((hwif = lookup_pci_dev(hwif, dev)) != NULL) {
+ unsigned int basereg, r, d, format;
+ sc1200_saved_state_t *ss = (sc1200_saved_state_t *)hwif->config_data;
+printk("%s: SC1200: resume\n", hwif->name);
+
+ //
+ // Restore timing registers: this may be unnecessary if BIOS also does it
+ //
+ basereg = hwif->channel ? 0x50 : 0x40;
+ if (ss != NULL) {
+ for (r = 0; r < 4; ++r) {
+ pci_write_config_dword(hwif->pci_dev, basereg + (r<<2), ss->regs[r]);
+ }
+ }
+ //
+ // Re-program drive PIO modes
+ //
+ pci_read_config_dword(hwif->pci_dev, basereg+4, &format);
+ format = (format >> 31) & 1;
+ if (format)
+ format += sc1200_get_pci_clock();
+ for (d = 0; d < 2; ++d) {
+ ide_drive_t *drive = &(hwif->drives[d]);
+ if (drive->present) {
+ unsigned int pio, timings;
+ pci_read_config_dword(hwif->pci_dev, basereg+(drive->select.b.unit << 3), &timings);
+ for (pio = 0; pio <= 4; ++pio) {
+ if (sc1200_pio_timings[format][pio] == timings)
+ break;
+ }
+ if (pio > 4)
+ pio = 255; /* autotune */
+ (void)sc1200_tuneproc(drive, pio);
+ }
+ }
+ //
+ // Re-program drive DMA modes
+ //
+ for (d = 0; d < MAX_DRIVES; ++d) {
+ ide_drive_t *drive = &(hwif->drives[d]);
+ if (drive->present && !__ide_dma_bad_drive(drive)) {
+ int was_using_dma = drive->using_dma;
+ hwif->ide_dma_off_quietly(drive);
+ sc1200_config_dma(drive);
+ if (!was_using_dma && drive->using_dma) {
+ hwif->ide_dma_off_quietly(drive);
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+/*
+ * This gets invoked by the IDE driver once for each channel,
+ * and performs channel-specific pre-initialization before drive probing.
+ */
+static void __init init_hwif_sc1200 (ide_hwif_t *hwif)
+{
+ if (hwif->mate)
+ hwif->serialized = hwif->mate->serialized = 1;
+ hwif->autodma = 0;
+ if (hwif->dma_base) {
+ hwif->ide_dma_check = &sc1200_config_dma;
+ hwif->ide_dma_end = &sc1200_ide_dma_end;
+ if (!noautodma)
+ hwif->autodma = 1;
+ hwif->tuneproc = &sc1200_tuneproc;
+ }
+ hwif->atapi_dma = 1;
+ hwif->ultra_mask = 0x07;
+ hwif->mwdma_mask = 0x07;
+
+ hwif->drives[0].autodma = hwif->autodma;
+ hwif->drives[1].autodma = hwif->autodma;
+}
+
+static ide_pci_device_t sc1200_chipset __devinitdata = {
+ .name = "SC1200",
+ .init_hwif = init_hwif_sc1200,
+ .channels = 2,
+ .autodma = AUTODMA,
+ .bootable = ON_BOARD,
+};
+
+static int __devinit sc1200_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ return ide_setup_pci_device(dev, &sc1200_chipset);
+}
+
+static struct pci_device_id sc1200_pci_tbl[] = {
+ { PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { 0, },
+};
+MODULE_DEVICE_TABLE(pci, sc1200_pci_tbl);
+
+static struct pci_driver driver = {
+ .name = "SC1200_IDE",
+ .id_table = sc1200_pci_tbl,
+ .probe = sc1200_init_one,
+ .suspend = sc1200_suspend,
+ .resume = sc1200_resume,
+};
+
+static int sc1200_ide_init(void)
+{
+ return ide_pci_register_driver(&driver);
+}
+
+module_init(sc1200_ide_init);
+
+MODULE_AUTHOR("Mark Lord");
+MODULE_DESCRIPTION("PCI driver module for NS SC1200 IDE");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/pci/serverworks.c b/drivers/ide/pci/serverworks.c
new file mode 100644
index 000000000000..82a1103b2413
--- /dev/null
+++ b/drivers/ide/pci/serverworks.c
@@ -0,0 +1,675 @@
+/*
+ * linux/drivers/ide/pci/serverworks.c Version 0.8 25 Ebr 2003
+ *
+ * Copyright (C) 1998-2000 Michel Aubry
+ * Copyright (C) 1998-2000 Andrzej Krzysztofowicz
+ * Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org>
+ * Portions copyright (c) 2001 Sun Microsystems
+ *
+ *
+ * RCC/ServerWorks IDE driver for Linux
+ *
+ * OSB4: `Open South Bridge' IDE Interface (fn 1)
+ * supports UDMA mode 2 (33 MB/s)
+ *
+ * CSB5: `Champion South Bridge' IDE Interface (fn 1)
+ * all revisions support UDMA mode 4 (66 MB/s)
+ * revision A2.0 and up support UDMA mode 5 (100 MB/s)
+ *
+ * *** The CSB5 does not provide ANY register ***
+ * *** to detect 80-conductor cable presence. ***
+ *
+ * CSB6: `Champion South Bridge' IDE Interface (optional: third channel)
+ *
+ * Documentation:
+ * Available under NDA only. Errata info very hard to get.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+
+#include <asm/io.h>
+
+#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 u8 svwks_revision = 0;
+static struct pci_dev *isa_dev;
+
+static int check_in_drive_lists (ide_drive_t *drive, const char **list)
+{
+ while (*list)
+ if (!strcmp(*list++, drive->id->model))
+ return 1;
+ return 0;
+}
+
+static u8 svwks_ratemask (ide_drive_t *drive)
+{
+ struct pci_dev *dev = HWIF(drive)->pci_dev;
+ u8 mode;
+
+ if (!svwks_revision)
+ pci_read_config_byte(dev, PCI_REVISION_ID, &svwks_revision);
+
+ 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) ? 1 : 0;
+ } else if (svwks_revision < SVWKS_CSB5_REVISION_NEW) {
+ return 1;
+ } else if (svwks_revision >= SVWKS_CSB5_REVISION_NEW) {
+ u8 btr = 0;
+ pci_read_config_byte(dev, 0x5A, &btr);
+ mode = btr & 0x3;
+ if (!eighty_ninty_three(drive))
+ mode = min(mode, (u8)1);
+ /* 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;
+ }
+ if (((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) ||
+ (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2)) &&
+ (!(PCI_FUNC(dev->devfn) & 1)))
+ mode = 2;
+ return mode;
+}
+
+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:
+ return 1;
+ default:
+ break;
+ }
+ return 0;
+}
+static int svwks_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+ u8 udma_modes[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 };
+ u8 dma_modes[] = { 0x77, 0x21, 0x20 };
+ u8 pio_modes[] = { 0x5d, 0x47, 0x34, 0x22, 0x20 };
+ u8 drive_pci[] = { 0x41, 0x40, 0x43, 0x42 };
+ u8 drive_pci2[] = { 0x45, 0x44, 0x47, 0x46 };
+
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = hwif->pci_dev;
+ u8 speed;
+ u8 pio = ide_get_best_pio_mode(drive, 255, 5, NULL);
+ u8 unit = (drive->select.b.unit & 0x01);
+ u8 csb5 = svwks_csb_check(dev);
+ u8 ultra_enable = 0, ultra_timing = 0;
+ u8 dma_timing = 0, pio_timing = 0;
+ u16 csb5_pio = 0;
+
+ if (xferspeed == 255) /* PIO auto-tuning */
+ speed = XFER_PIO_0 + pio;
+ else
+ speed = ide_rate_filter(svwks_ratemask(drive), xferspeed);
+
+ /* If we are about to put a disk into UDMA mode we screwed up.
+ Our code assumes we never _ever_ do this on an OSB4 */
+
+ if(dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4 &&
+ drive->media == ide_disk && speed >= XFER_UDMA_0)
+ BUG();
+
+ pci_read_config_byte(dev, drive_pci[drive->dn], &pio_timing);
+ pci_read_config_byte(dev, drive_pci2[drive->dn], &dma_timing);
+ pci_read_config_byte(dev, (0x56|hwif->channel), &ultra_timing);
+ pci_read_config_word(dev, 0x4A, &csb5_pio);
+ pci_read_config_byte(dev, 0x54, &ultra_enable);
+
+ /* Per Specified Design by OEM, and ASIC Architect */
+ if ((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) ||
+ (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2)) {
+ if (!drive->init_speed) {
+ u8 dma_stat = hwif->INB(hwif->dma_status);
+
+dma_pio:
+ if (((ultra_enable << (7-drive->dn) & 0x80) == 0x80) &&
+ ((dma_stat & (1<<(5+unit))) == (1<<(5+unit)))) {
+ drive->current_speed = drive->init_speed = XFER_UDMA_0 + udma_modes[(ultra_timing >> (4*unit)) & ~(0xF0)];
+ return 0;
+ } else if ((dma_timing) &&
+ ((dma_stat&(1<<(5+unit)))==(1<<(5+unit)))) {
+ u8 dmaspeed = dma_timing;
+
+ dma_timing &= ~0xFF;
+ if ((dmaspeed & 0x20) == 0x20)
+ dmaspeed = XFER_MW_DMA_2;
+ else if ((dmaspeed & 0x21) == 0x21)
+ dmaspeed = XFER_MW_DMA_1;
+ else if ((dmaspeed & 0x77) == 0x77)
+ dmaspeed = XFER_MW_DMA_0;
+ else
+ goto dma_pio;
+ drive->current_speed = drive->init_speed = dmaspeed;
+ return 0;
+ } else if (pio_timing) {
+ u8 piospeed = pio_timing;
+
+ pio_timing &= ~0xFF;
+ if ((piospeed & 0x20) == 0x20)
+ piospeed = XFER_PIO_4;
+ else if ((piospeed & 0x22) == 0x22)
+ piospeed = XFER_PIO_3;
+ else if ((piospeed & 0x34) == 0x34)
+ piospeed = XFER_PIO_2;
+ else if ((piospeed & 0x47) == 0x47)
+ piospeed = XFER_PIO_1;
+ else if ((piospeed & 0x5d) == 0x5d)
+ piospeed = XFER_PIO_0;
+ else
+ goto oem_setup_failed;
+ drive->current_speed = drive->init_speed = piospeed;
+ return 0;
+ }
+ }
+ }
+
+oem_setup_failed:
+
+ pio_timing &= ~0xFF;
+ dma_timing &= ~0xFF;
+ ultra_timing &= ~(0x0F << (4*unit));
+ ultra_enable &= ~(0x01 << drive->dn);
+ csb5_pio &= ~(0x0F << (4*drive->dn));
+
+ switch(speed) {
+ case XFER_PIO_4:
+ case XFER_PIO_3:
+ case XFER_PIO_2:
+ case XFER_PIO_1:
+ case XFER_PIO_0:
+ pio_timing |= pio_modes[speed - XFER_PIO_0];
+ csb5_pio |= ((speed - XFER_PIO_0) << (4*drive->dn));
+ break;
+
+ case XFER_MW_DMA_2:
+ case XFER_MW_DMA_1:
+ case XFER_MW_DMA_0:
+ pio_timing |= pio_modes[pio];
+ csb5_pio |= (pio << (4*drive->dn));
+ dma_timing |= dma_modes[speed - XFER_MW_DMA_0];
+ break;
+
+ case XFER_UDMA_5:
+ case XFER_UDMA_4:
+ case XFER_UDMA_3:
+ case XFER_UDMA_2:
+ case XFER_UDMA_1:
+ case XFER_UDMA_0:
+ pio_timing |= pio_modes[pio];
+ csb5_pio |= (pio << (4*drive->dn));
+ dma_timing |= dma_modes[2];
+ ultra_timing |= ((udma_modes[speed - XFER_UDMA_0]) << (4*unit));
+ ultra_enable |= (0x01 << drive->dn);
+ default:
+ break;
+ }
+
+ pci_write_config_byte(dev, drive_pci[drive->dn], pio_timing);
+ if (csb5)
+ pci_write_config_word(dev, 0x4A, csb5_pio);
+
+ 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);
+
+ return (ide_config_drive_speed(drive, speed));
+}
+
+static void config_chipset_for_pio (ide_drive_t *drive)
+{
+ u16 eide_pio_timing[6] = {960, 480, 240, 180, 120, 90};
+ u16 xfer_pio = drive->id->eide_pio_modes;
+ u8 timing, speed, pio;
+
+ pio = ide_get_best_pio_mode(drive, 255, 5, NULL);
+
+ if (xfer_pio > 4)
+ xfer_pio = 0;
+
+ if (drive->id->eide_pio_iordy > 0)
+ for (xfer_pio = 5;
+ xfer_pio>0 &&
+ drive->id->eide_pio_iordy>eide_pio_timing[xfer_pio];
+ xfer_pio--);
+ else
+ xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 :
+ (drive->id->eide_pio_modes & 2) ? 0x04 :
+ (drive->id->eide_pio_modes & 1) ? 0x03 :
+ (drive->id->tPIO & 2) ? 0x02 :
+ (drive->id->tPIO & 1) ? 0x01 : xfer_pio;
+
+ timing = (xfer_pio >= pio) ? xfer_pio : pio;
+
+ switch(timing) {
+ case 4: speed = XFER_PIO_4;break;
+ case 3: speed = XFER_PIO_3;break;
+ case 2: speed = XFER_PIO_2;break;
+ case 1: speed = XFER_PIO_1;break;
+ default:
+ speed = (!drive->id->tPIO) ? XFER_PIO_0 : XFER_PIO_SLOW;
+ break;
+ }
+ (void) svwks_tune_chipset(drive, speed);
+ drive->current_speed = speed;
+}
+
+static void svwks_tune_drive (ide_drive_t *drive, u8 pio)
+{
+ if(pio == 255)
+ (void) svwks_tune_chipset(drive, 255);
+ else
+ (void) svwks_tune_chipset(drive, (XFER_PIO_0 + pio));
+}
+
+static int config_chipset_for_dma (ide_drive_t *drive)
+{
+ u8 speed = ide_dma_speed(drive, svwks_ratemask(drive));
+
+ if (!(speed))
+ speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL);
+
+ (void) svwks_tune_chipset(drive, speed);
+ return ide_dma_enable(drive);
+}
+
+static int svwks_config_drive_xfer_rate (ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct hd_driveid *id = drive->id;
+
+ drive->init_speed = 0;
+
+ if ((id->capability & 1) && drive->autodma) {
+
+ if (ide_use_dma(drive)) {
+ if (config_chipset_for_dma(drive))
+ return hwif->ide_dma_on(drive);
+ }
+
+ goto fast_ata_pio;
+
+ } else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+ config_chipset_for_pio(drive);
+ // hwif->tuneproc(drive, 5);
+ return hwif->ide_dma_off_quietly(drive);
+ }
+ /* IORDY not supported */
+ return 0;
+}
+
+/* This can go soon */
+
+static int svwks_ide_dma_end (ide_drive_t *drive)
+{
+ return __ide_dma_end(drive);
+}
+
+static unsigned int __devinit init_chipset_svwks (struct pci_dev *dev, const char *name)
+{
+ unsigned int reg;
+ u8 btr;
+
+ /* save revision id to determine DMA capability */
+ pci_read_config_byte(dev, PCI_REVISION_ID, &svwks_revision);
+
+ /* 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_find_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 "%s: UDMA not BIOS enabled.\n", name);
+ 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_find_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);
+ }
+ outb_p(0x06, 0x0c00);
+ dev->irq = inb_p(0x0c01);
+#if 0
+ printk("%s: device class (0x%04x)\n",
+ name, dev->class);
+ if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE) {
+ dev->class &= ~0x000F0F00;
+ // dev->class |= ~0x00000400;
+ dev->class |= ~0x00010100;
+ /**/
+ }
+#endif
+ } else {
+ struct pci_dev * findev = NULL;
+ u8 reg41 = 0;
+
+ findev = pci_find_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);
+ }
+ /*
+ * 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 |= (svwks_revision >= SVWKS_CSB5_REVISION_NEW) ? 0x3 : 0x2;
+ pci_write_config_byte(dev, 0x5A, btr);
+ }
+
+ return (dev->irq) ? dev->irq : 0;
+}
+
+static unsigned int __init ata66_svwks_svwks (ide_hwif_t *hwif)
+{
+ return 1;
+}
+
+/* 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 unsigned int __init ata66_svwks_dell (ide_hwif_t *hwif)
+{
+ struct pci_dev *dev = hwif->pci_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) ? 1 : 0;
+ return 0;
+}
+
+/* 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 unsigned int __init ata66_svwks_cobalt (ide_hwif_t *hwif)
+{
+ struct pci_dev *dev = hwif->pci_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) ? 1 : 0;
+ return 0;
+}
+
+static unsigned int __init ata66_svwks (ide_hwif_t *hwif)
+{
+ struct pci_dev *dev = hwif->pci_dev;
+
+ /* Per Specified Design by OEM, and ASIC Architect */
+ if ((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) ||
+ (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2))
+ return 1;
+
+ /* 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);
+
+ return 0;
+}
+
+#undef CAN_SW_DMA
+static void __devinit init_hwif_svwks (ide_hwif_t *hwif)
+{
+ u8 dma_stat = 0;
+
+ if (!hwif->irq)
+ hwif->irq = hwif->channel ? 15 : 14;
+
+ hwif->tuneproc = &svwks_tune_drive;
+ hwif->speedproc = &svwks_tune_chipset;
+
+ hwif->atapi_dma = 1;
+
+ if (hwif->pci_dev->device != PCI_DEVICE_ID_SERVERWORKS_OSB4IDE)
+ hwif->ultra_mask = 0x3f;
+
+ hwif->mwdma_mask = 0x07;
+#ifdef CAN_SW_DMA
+ hwif->swdma_mask = 0x07;
+#endif /* CAN_SW_DMA */
+
+ hwif->autodma = 0;
+
+ if (!hwif->dma_base) {
+ hwif->drives[0].autotune = 1;
+ hwif->drives[1].autotune = 1;
+ return;
+ }
+
+ hwif->ide_dma_check = &svwks_config_drive_xfer_rate;
+ if (hwif->pci_dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4IDE)
+ hwif->ide_dma_end = &svwks_ide_dma_end;
+ else if (!(hwif->udma_four))
+ hwif->udma_four = ata66_svwks(hwif);
+ if (!noautodma)
+ hwif->autodma = 1;
+
+ dma_stat = hwif->INB(hwif->dma_status);
+ hwif->drives[0].autodma = (dma_stat & 0x20);
+ hwif->drives[1].autodma = (dma_stat & 0x40);
+ hwif->drives[0].autotune = (!(dma_stat & 0x20));
+ hwif->drives[1].autotune = (!(dma_stat & 0x40));
+// hwif->drives[0].autodma = hwif->autodma;
+// hwif->drives[1].autodma = hwif->autodma;
+}
+
+/*
+ * We allow the BM-DMA driver to only work on enabled interfaces.
+ */
+static void __devinit init_dma_svwks (ide_hwif_t *hwif, unsigned long dmabase)
+{
+ struct pci_dev *dev = hwif->pci_dev;
+
+ if (((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) ||
+ (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2)) &&
+ (!(PCI_FUNC(dev->devfn) & 1)) && (hwif->channel))
+ return;
+
+ ide_setup_dma(hwif, dmabase, 8);
+}
+
+static int __devinit init_setup_svwks (struct pci_dev *dev, ide_pci_device_t *d)
+{
+ return ide_setup_pci_device(dev, d);
+}
+
+static int __init init_setup_csb6 (struct pci_dev *dev, ide_pci_device_t *d)
+{
+ if (!(PCI_FUNC(dev->devfn) & 1)) {
+ d->bootable = NEVER_BOARD;
+ if (dev->resource[0].start == 0x01f1)
+ d->bootable = ON_BOARD;
+ }
+#if 0
+ if ((IDE_PCI_DEVID_EQ(d->devid, DEVID_CSB6) &&
+ (!(PCI_FUNC(dev->devfn) & 1)))
+ d->autodma = AUTODMA;
+#endif
+
+ d->channels = ((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE ||
+ dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2) &&
+ (!(PCI_FUNC(dev->devfn) & 1))) ? 1 : 2;
+
+ return ide_setup_pci_device(dev, d);
+}
+
+static ide_pci_device_t serverworks_chipsets[] __devinitdata = {
+ { /* 0 */
+ .name = "SvrWks OSB4",
+ .init_setup = init_setup_svwks,
+ .init_chipset = init_chipset_svwks,
+ .init_hwif = init_hwif_svwks,
+ .channels = 2,
+ .autodma = AUTODMA,
+ .bootable = ON_BOARD,
+ },{ /* 1 */
+ .name = "SvrWks CSB5",
+ .init_setup = init_setup_svwks,
+ .init_chipset = init_chipset_svwks,
+ .init_hwif = init_hwif_svwks,
+ .init_dma = init_dma_svwks,
+ .channels = 2,
+ .autodma = AUTODMA,
+ .bootable = ON_BOARD,
+ },{ /* 2 */
+ .name = "SvrWks CSB6",
+ .init_setup = init_setup_csb6,
+ .init_chipset = init_chipset_svwks,
+ .init_hwif = init_hwif_svwks,
+ .init_dma = init_dma_svwks,
+ .channels = 2,
+ .autodma = AUTODMA,
+ .bootable = ON_BOARD,
+ },{ /* 3 */
+ .name = "SvrWks CSB6",
+ .init_setup = init_setup_csb6,
+ .init_chipset = init_chipset_svwks,
+ .init_hwif = init_hwif_svwks,
+ .init_dma = init_dma_svwks,
+ .channels = 1, /* 2 */
+ .autodma = AUTODMA,
+ .bootable = ON_BOARD,
+ }
+};
+
+/**
+ * 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)
+{
+ ide_pci_device_t *d = &serverworks_chipsets[id->driver_data];
+
+ return d->init_setup(dev, d);
+}
+
+static struct pci_device_id svwks_pci_tbl[] = {
+ { PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+ { PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
+ { PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3},
+ { 0, },
+};
+MODULE_DEVICE_TABLE(pci, svwks_pci_tbl);
+
+static struct pci_driver driver = {
+ .name = "Serverworks_IDE",
+ .id_table = svwks_pci_tbl,
+ .probe = svwks_init_one,
+};
+
+static int svwks_ide_init(void)
+{
+ return ide_pci_register_driver(&driver);
+}
+
+module_init(svwks_ide_init);
+
+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/pci/sgiioc4.c b/drivers/ide/pci/sgiioc4.c
new file mode 100644
index 000000000000..4651a22bf12e
--- /dev/null
+++ b/drivers/ide/pci/sgiioc4.c
@@ -0,0 +1,728 @@
+/*
+ * Copyright (c) 2003 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * 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.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA 94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * 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/hdreg.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/ioc4_common.h>
+#include <asm/io.h>
+
+#include <linux/ide.h>
+
+/* 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 = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++)
+ hw->io_ports[i] = reg + i * 4;
+
+ if (ctrl_port)
+ hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port;
+
+ if (irq_port)
+ hw->io_ports[IDE_IRQ_OFFSET] = irq_port;
+}
+
+static void
+sgiioc4_maskproc(ide_drive_t * drive, int mask)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ hwif->OUTB(mask ? (drive->ctl | 2) : (drive->ctl & ~2),
+ IDE_CONTROL_REG);
+}
+
+
+static int
+sgiioc4_checkirq(ide_hwif_t * hwif)
+{
+ u8 intr_reg =
+ hwif->INL(hwif->io_ports[IDE_IRQ_OFFSET] + IOC4_INTR_REG * 4);
+
+ if (intr_reg & 0x03)
+ return 1;
+
+ return 0;
+}
+
+
+static int
+sgiioc4_clearirq(ide_drive_t * drive)
+{
+ u32 intr_reg;
+ ide_hwif_t *hwif = HWIF(drive);
+ unsigned long other_ir =
+ hwif->io_ports[IDE_IRQ_OFFSET] + (IOC4_INTR_REG << 2);
+
+ /* Code to check for PCI error conditions */
+ intr_reg = hwif->INL(other_ir);
+ if (intr_reg & 0x03) { /* Valid IOC4-IDE interrupt */
+ /*
+ * Using hwif->INB to read the IDE_STATUS_REG 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 = hwif->INB(IDE_STATUS_REG);
+ int count = 0;
+ stat = hwif->INB(IDE_STATUS_REG);
+ while ((stat & 0x80) && (count++ < 100)) {
+ udelay(1);
+ stat = hwif->INB(IDE_STATUS_REG);
+ }
+
+ if (intr_reg & 0x02) {
+ /* 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 =
+ hwif->INL(hwif->io_ports[IDE_IRQ_OFFSET]);
+ pci_err_addr_high =
+ hwif->INL(hwif->io_ports[IDE_IRQ_OFFSET] + 4);
+ pci_read_config_dword(hwif->pci_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",
+ __FUNCTION__, drive->name, pci_stat_cmd_reg);
+ printk(KERN_ERR
+ "%s(%s) : PCI Error Address is 0x%x%x\n",
+ __FUNCTION__, drive->name,
+ pci_err_addr_high, pci_err_addr_low);
+ /* Clear the PCI Error indicator */
+ pci_write_config_dword(hwif->pci_dev, PCI_COMMAND,
+ 0x00000146);
+ }
+
+ /* Clear the Interrupt, Error bits on the IOC4 */
+ hwif->OUTL(0x03, other_ir);
+
+ intr_reg = hwif->INL(other_ir);
+ }
+
+ return intr_reg & 3;
+}
+
+static void sgiioc4_ide_dma_start(ide_drive_t * drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ unsigned int reg = hwif->INL(hwif->dma_base + IOC4_DMA_CTRL * 4);
+ unsigned int temp_reg = reg | IOC4_S_DMA_START;
+
+ hwif->OUTL(temp_reg, hwif->dma_base + IOC4_DMA_CTRL * 4);
+}
+
+static u32
+sgiioc4_ide_dma_stop(ide_hwif_t *hwif, u64 dma_base)
+{
+ u32 ioc4_dma;
+ int count;
+
+ count = 0;
+ ioc4_dma = hwif->INL(dma_base + IOC4_DMA_CTRL * 4);
+ while ((ioc4_dma & IOC4_S_DMA_STOP) && (count++ < 200)) {
+ udelay(1);
+ ioc4_dma = hwif->INL(dma_base + IOC4_DMA_CTRL * 4);
+ }
+ return ioc4_dma;
+}
+
+/* Stops the IOC4 DMA Engine */
+static int
+sgiioc4_ide_dma_end(ide_drive_t * drive)
+{
+ u32 ioc4_dma, bc_dev, bc_mem, num, valid = 0, cnt = 0;
+ ide_hwif_t *hwif = HWIF(drive);
+ u64 dma_base = hwif->dma_base;
+ int dma_stat = 0;
+ unsigned long *ending_dma = (unsigned long *) hwif->dma_base2;
+
+ hwif->OUTL(IOC4_S_DMA_STOP, 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",
+ __FUNCTION__, 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", __FUNCTION__,
+ drive->name);
+ dma_stat = 1;
+ }
+
+ bc_dev = hwif->INL(dma_base + IOC4_BC_DEV * 4);
+ bc_mem = hwif->INL(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",
+ __FUNCTION__, drive->name, bc_dev, bc_mem);
+ }
+ }
+
+ drive->waiting_for_dma = 0;
+ ide_destroy_dmatable(drive);
+
+ return dma_stat;
+}
+
+static int
+sgiioc4_ide_dma_check(ide_drive_t * drive)
+{
+ if (ide_config_drive_speed(drive, XFER_MW_DMA_2) != 0) {
+ printk(KERN_INFO
+ "Couldnot set %s in Multimode-2 DMA mode | "
+ "Drive %s using PIO instead\n",
+ drive->name, drive->name);
+ drive->using_dma = 0;
+ } else
+ drive->using_dma = 1;
+
+ return 0;
+}
+
+static int
+sgiioc4_ide_dma_on(ide_drive_t * drive)
+{
+ drive->using_dma = 1;
+
+ return HWIF(drive)->ide_dma_host_on(drive);
+}
+
+static int
+sgiioc4_ide_dma_off_quietly(ide_drive_t * drive)
+{
+ drive->using_dma = 0;
+
+ return HWIF(drive)->ide_dma_host_off(drive);
+}
+
+/* returns 1 if dma irq issued, 0 otherwise */
+static int
+sgiioc4_ide_dma_test_irq(ide_drive_t * drive)
+{
+ return sgiioc4_checkirq(HWIF(drive));
+}
+
+static int
+sgiioc4_ide_dma_host_on(ide_drive_t * drive)
+{
+ if (drive->using_dma)
+ return 0;
+
+ return 1;
+}
+
+static int
+sgiioc4_ide_dma_host_off(ide_drive_t * drive)
+{
+ sgiioc4_clearirq(drive);
+
+ return 0;
+}
+
+static int
+sgiioc4_ide_dma_lostirq(ide_drive_t * drive)
+{
+ HWIF(drive)->resetproc(drive);
+
+ return __ide_dma_lostirq(drive);
+}
+
+static void
+sgiioc4_resetproc(ide_drive_t * drive)
+{
+ sgiioc4_ide_dma_end(drive);
+ sgiioc4_clearirq(drive);
+}
+
+static u8
+sgiioc4_INB(unsigned long port)
+{
+ u8 reg = (u8) inb(port);
+
+ if ((port & 0xFFF) == 0x11C) { /* Status register of IOC4 */
+ if (reg & 0x51) { /* Not busy...check for interrupt */
+ unsigned long other_ir = port - 0x110;
+ unsigned int intr_reg = (u32) inl(other_ir);
+
+ /* Clear the Interrupt, Error bits on the IOC4 */
+ if (intr_reg & 0x03) {
+ outl(0x03, other_ir);
+ intr_reg = (u32) inl(other_ir);
+ }
+ }
+ }
+
+ return reg;
+}
+
+/* Creates a dma map for the scatter-gather list entries */
+static void __devinit
+ide_dma_sgiioc4(ide_hwif_t * hwif, unsigned long dma_base)
+{
+ int num_ports = sizeof (ioc4_dma_regs_t);
+
+ printk(KERN_INFO "%s: BM-DMA at 0x%04lx-0x%04lx\n", hwif->name,
+ dma_base, dma_base + num_ports - 1);
+
+ if (!request_region(dma_base, num_ports, hwif->name)) {
+ printk(KERN_ERR
+ "%s(%s) -- ERROR, Addresses 0x%p to 0x%p "
+ "ALREADY in use\n",
+ __FUNCTION__, hwif->name, (void *) dma_base,
+ (void *) dma_base + num_ports - 1);
+ goto dma_alloc_failure;
+ }
+
+ hwif->dma_base = dma_base;
+ hwif->dmatable_cpu = pci_alloc_consistent(hwif->pci_dev,
+ IOC4_PRD_ENTRIES * IOC4_PRD_BYTES,
+ &hwif->dmatable_dma);
+
+ if (!hwif->dmatable_cpu)
+ goto dma_alloc_failure;
+
+ hwif->sg_max_nents = IOC4_PRD_ENTRIES;
+
+ hwif->dma_base2 = (unsigned long)
+ pci_alloc_consistent(hwif->pci_dev,
+ IOC4_IDE_CACHELINE_SIZE,
+ (dma_addr_t *) &(hwif->dma_status));
+
+ if (!hwif->dma_base2)
+ goto dma_base2alloc_failure;
+
+ return;
+
+dma_base2alloc_failure:
+ pci_free_consistent(hwif->pci_dev,
+ IOC4_PRD_ENTRIES * IOC4_PRD_BYTES,
+ hwif->dmatable_cpu, hwif->dmatable_dma);
+ printk(KERN_INFO
+ "%s() -- Error! Unable to allocate DMA Maps for drive %s\n",
+ __FUNCTION__, hwif->name);
+ printk(KERN_INFO
+ "Changing from DMA to PIO mode for Drive %s\n", hwif->name);
+
+dma_alloc_failure:
+ /* Disable DMA because we couldnot allocate any DMA maps */
+ hwif->autodma = 0;
+ hwif->atapi_dma = 0;
+}
+
+/* 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);
+ u64 dma_base = hwif->dma_base;
+ u32 dma_addr, ending_dma_addr;
+
+ ioc4_dma = hwif->INL(dma_base + IOC4_DMA_CTRL * 4);
+
+ if (ioc4_dma & IOC4_S_DMA_ACTIVE) {
+ printk(KERN_WARNING
+ "%s(%s):Warning!! DMA from previous transfer was still active\n",
+ __FUNCTION__, drive->name);
+ hwif->OUTL(IOC4_S_DMA_STOP, 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\n",
+ __FUNCTION__, drive->name);
+ }
+
+ ioc4_dma = hwif->INL(dma_base + IOC4_DMA_CTRL * 4);
+ if (ioc4_dma & IOC4_S_DMA_ERROR) {
+ printk(KERN_WARNING
+ "%s(%s) : Warning!! - DMA Error during Previous"
+ " transfer | status 0x%x\n",
+ __FUNCTION__, drive->name, ioc4_dma);
+ hwif->OUTL(IOC4_S_DMA_STOP, 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\n",
+ __FUNCTION__, drive->name);
+ }
+
+ /* Address of the Scatter Gather List */
+ dma_addr = cpu_to_le32(hwif->dmatable_dma);
+ hwif->OUTL(dma_addr, dma_base + IOC4_DMA_PTR_L * 4);
+
+ /* Address of the Ending DMA */
+ memset((unsigned int *) hwif->dma_base2, 0, IOC4_IDE_CACHELINE_SIZE);
+ ending_dma_addr = cpu_to_le32(hwif->dma_status);
+ hwif->OUTL(ending_dma_addr, dma_base + IOC4_DMA_END_ADDR * 4);
+
+ hwif->OUTL(dma_direction, dma_base + IOC4_DMA_CTRL * 4);
+ 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 xcount, 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++;
+
+ xcount = bcount & 0xffff;
+ *table = cpu_to_be32(xcount);
+ table++;
+
+ cur_addr += bcount;
+ cur_len -= bcount;
+ }
+ }
+
+ sg++;
+ i--;
+ }
+
+ if (count) {
+ table--;
+ *table |= cpu_to_be32(0x80000000);
+ return count;
+ }
+
+use_pio_instead:
+ pci_unmap_sg(hwif->pci_dev, hwif->sg_table, hwif->sg_nents,
+ hwif->sg_dma_direction);
+
+ return 0; /* revert to PIO for this request */
+}
+
+static int sgiioc4_ide_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 void __devinit
+ide_init_sgiioc4(ide_hwif_t * hwif)
+{
+ hwif->mmio = 2;
+ hwif->autodma = 1;
+ hwif->atapi_dma = 1;
+ hwif->ultra_mask = 0x0; /* Disable Ultra DMA */
+ hwif->mwdma_mask = 0x2; /* Multimode-2 DMA */
+ hwif->swdma_mask = 0x2;
+ hwif->tuneproc = NULL; /* Sets timing for PIO mode */
+ hwif->speedproc = NULL; /* Sets timing for DMA &/or PIO modes */
+ hwif->selectproc = NULL;/* Use the default routine to select drive */
+ hwif->reset_poll = NULL;/* No HBA specific reset_poll needed */
+ hwif->pre_reset = NULL; /* No HBA specific pre_set needed */
+ hwif->resetproc = &sgiioc4_resetproc;/* Reset DMA engine,
+ clear interrupts */
+ hwif->intrproc = NULL; /* Enable or Disable interrupt from drive */
+ hwif->maskproc = &sgiioc4_maskproc; /* Mask on/off NIEN register */
+ hwif->quirkproc = NULL;
+ hwif->busproc = NULL;
+
+ hwif->dma_setup = &sgiioc4_ide_dma_setup;
+ hwif->dma_start = &sgiioc4_ide_dma_start;
+ hwif->ide_dma_end = &sgiioc4_ide_dma_end;
+ hwif->ide_dma_check = &sgiioc4_ide_dma_check;
+ hwif->ide_dma_on = &sgiioc4_ide_dma_on;
+ hwif->ide_dma_off_quietly = &sgiioc4_ide_dma_off_quietly;
+ hwif->ide_dma_test_irq = &sgiioc4_ide_dma_test_irq;
+ hwif->ide_dma_host_on = &sgiioc4_ide_dma_host_on;
+ hwif->ide_dma_host_off = &sgiioc4_ide_dma_host_off;
+ hwif->ide_dma_lostirq = &sgiioc4_ide_dma_lostirq;
+ hwif->ide_dma_timeout = &__ide_dma_timeout;
+ hwif->INB = &sgiioc4_INB;
+}
+
+static int __devinit
+sgiioc4_ide_setup_pci_device(struct pci_dev *dev, ide_pci_device_t * d)
+{
+ unsigned long base, ctl, dma_base, irqport;
+ ide_hwif_t *hwif;
+ int h;
+
+ for (h = 0; h < MAX_HWIFS; ++h) {
+ hwif = &ide_hwifs[h];
+ /* Find an empty HWIF */
+ if (hwif->chipset == ide_unknown)
+ break;
+ }
+
+ /* Get the CmdBlk and CtrlBlk Base Registers */
+ base = pci_resource_start(dev, 0) + IOC4_CMD_OFFSET;
+ ctl = pci_resource_start(dev, 0) + IOC4_CTRL_OFFSET;
+ irqport = pci_resource_start(dev, 0) + IOC4_INTR_OFFSET;
+ dma_base = pci_resource_start(dev, 0) + IOC4_DMA_OFFSET;
+
+ if (!request_region(base, IOC4_CMD_CTL_BLK_SIZE, hwif->name)) {
+ printk(KERN_ERR
+ "%s : %s -- ERROR, Port Addresses "
+ "0x%p to 0x%p ALREADY in use\n",
+ __FUNCTION__, hwif->name, (void *) base,
+ (void *) base + IOC4_CMD_CTL_BLK_SIZE);
+ return -ENOMEM;
+ }
+
+ if (hwif->io_ports[IDE_DATA_OFFSET] != base) {
+ /* Initialize the IO registers */
+ sgiioc4_init_hwif_ports(&hwif->hw, base, ctl, irqport);
+ memcpy(hwif->io_ports, hwif->hw.io_ports,
+ sizeof (hwif->io_ports));
+ hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET];
+ }
+
+ hwif->irq = dev->irq;
+ hwif->chipset = ide_pci;
+ hwif->pci_dev = dev;
+ hwif->channel = 0; /* Single Channel chip */
+ hwif->cds = (struct ide_pci_device_s *) d;
+ hwif->gendev.parent = &dev->dev;/* setup proper ancestral information */
+
+ /* Initializing chipset IRQ Registers */
+ hwif->OUTL(0x03, irqport + IOC4_INTR_SET * 4);
+
+ ide_init_sgiioc4(hwif);
+
+ if (dma_base)
+ ide_dma_sgiioc4(hwif, dma_base);
+ else
+ printk(KERN_INFO "%s: %s Bus-Master DMA disabled\n",
+ hwif->name, d->name);
+
+ if (probe_hwif_init(hwif))
+ return -EIO;
+
+ /* Create /proc/ide entries */
+ create_proc_ide_interfaces();
+
+ return 0;
+}
+
+static unsigned int __devinit
+pci_init_sgiioc4(struct pci_dev *dev, ide_pci_device_t * d)
+{
+ unsigned int class_rev;
+ int ret;
+
+ pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
+ class_rev &= 0xff;
+ printk(KERN_INFO "%s: IDE controller at PCI slot %s, revision %d\n",
+ d->name, pci_name(dev), class_rev);
+ if (class_rev < IOC4_SUPPORTED_FIRMWARE_REV) {
+ printk(KERN_ERR "Skipping %s IDE controller in slot %s: "
+ "firmware is obsolete - please upgrade to revision"
+ "46 or higher\n", d->name, pci_name(dev));
+ ret = -EAGAIN;
+ goto out;
+ }
+ ret = sgiioc4_ide_setup_pci_device(dev, d);
+out:
+ return ret;
+}
+
+static ide_pci_device_t sgiioc4_chipsets[] __devinitdata = {
+ {
+ /* Channel 0 */
+ .name = "SGIIOC4",
+ .init_hwif = ide_init_sgiioc4,
+ .init_dma = ide_dma_sgiioc4,
+ .channels = 1,
+ .autodma = AUTODMA,
+ /* SGI IOC4 doesn't have enablebits. */
+ .bootable = ON_BOARD,
+ }
+};
+
+int
+ioc4_ide_attach_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ return pci_init_sgiioc4(dev, &sgiioc4_chipsets[id->driver_data]);
+}
+
+
+MODULE_AUTHOR("Aniket Malatpure - Silicon Graphics Inc. (SGI)");
+MODULE_DESCRIPTION("IDE PCI driver module for SGI IOC4 Base-IO Card");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(ioc4_ide_attach_one);
diff --git a/drivers/ide/pci/siimage.c b/drivers/ide/pci/siimage.c
new file mode 100644
index 000000000000..2b9961b88135
--- /dev/null
+++ b/drivers/ide/pci/siimage.c
@@ -0,0 +1,1133 @@
+/*
+ * linux/drivers/ide/pci/siimage.c Version 1.07 Nov 30, 2003
+ *
+ * Copyright (C) 2001-2002 Andre Hedrick <andre@linux-ide.org>
+ * Copyright (C) 2003 Red Hat <alan@redhat.com>
+ *
+ * May be copied or modified under the terms of the GNU General Public License
+ *
+ * Documentation available under NDA only
+ *
+ *
+ * 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 neccessary
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#undef SIIMAGE_VIRTUAL_DMAPIO
+#undef SIIMAGE_LARGE_DMA
+
+/**
+ * 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)
+{
+ 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();
+ 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(hwif->pci_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 isnt performance
+ * criticial.
+ */
+
+static unsigned long siimage_selreg(ide_hwif_t *hwif, int r)
+{
+ unsigned long base = (unsigned long)hwif->hwif_data;
+ base += 0xA0 + r;
+ if(hwif->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;
+ base += 0xA0 + r;
+ if(hwif->mmio)
+ base += (hwif->channel << 6);
+ else
+ base += (hwif->channel << 4);
+ base |= drive->select.b.unit << drive->select.b.unit;
+ return base;
+}
+
+/**
+ * siimage_ratemask - Compute available modes
+ * @drive: IDE drive
+ *
+ * Compute the available speeds for the devices on the interface.
+ * For the CMD680 this depends on the clocking mode (scsc), for the
+ * SI3312 SATA controller life is a bit simpler. Enforce UDMA33
+ * as a limit if there is no 80pin cable present.
+ */
+
+static byte siimage_ratemask (ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ u8 mode = 0, scsc = 0;
+ unsigned long base = (unsigned long) hwif->hwif_data;
+
+ if (hwif->mmio)
+ scsc = hwif->INB(base + 0x4A);
+ else
+ pci_read_config_byte(hwif->pci_dev, 0x8A, &scsc);
+
+ if(is_sata(hwif))
+ {
+ if(strstr(drive->id->model, "Maxtor"))
+ return 3;
+ return 4;
+ }
+
+ if ((scsc & 0x30) == 0x10) /* 133 */
+ mode = 4;
+ else if ((scsc & 0x30) == 0x20) /* 2xPCI */
+ mode = 4;
+ else if ((scsc & 0x30) == 0x00) /* 100 */
+ mode = 3;
+ else /* Disabled ? */
+ BUG();
+
+ if (!eighty_ninty_three(drive))
+ mode = min(mode, (u8)1);
+ return mode;
+}
+
+/**
+ * siimage_taskfile_timing - turn timing data to a mode
+ * @hwif: interface to query
+ *
+ * Read the timing data for the interface and return the
+ * mode that is being used.
+ */
+
+static byte siimage_taskfile_timing (ide_hwif_t *hwif)
+{
+ u16 timing = 0x328a;
+ unsigned long addr = siimage_selreg(hwif, 2);
+
+ if (hwif->mmio)
+ timing = hwif->INW(addr);
+ else
+ pci_read_config_word(hwif->pci_dev, addr, &timing);
+
+ switch (timing) {
+ case 0x10c1: return 4;
+ case 0x10c3: return 3;
+ case 0x1104:
+ case 0x1281: return 2;
+ case 0x2283: return 1;
+ case 0x328a:
+ default: return 0;
+ }
+}
+
+/**
+ * simmage_tuneproc - tune a drive
+ * @drive: drive to tune
+ * @mode_wanted: the target operating mode
+ *
+ * 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 siimage_tuneproc (ide_drive_t *drive, byte mode_wanted)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ u32 speedt = 0;
+ u16 speedp = 0;
+ unsigned long addr = siimage_seldev(drive, 0x04);
+ unsigned long tfaddr = siimage_selreg(hwif, 0x02);
+
+ /* cheat for now and use the docs */
+ switch(mode_wanted) {
+ case 4:
+ speedp = 0x10c1;
+ speedt = 0x10c1;
+ break;
+ case 3:
+ speedp = 0x10C3;
+ speedt = 0x10C3;
+ break;
+ case 2:
+ speedp = 0x1104;
+ speedt = 0x1281;
+ break;
+ case 1:
+ speedp = 0x2283;
+ speedt = 0x1281;
+ break;
+ case 0:
+ default:
+ speedp = 0x328A;
+ speedt = 0x328A;
+ break;
+ }
+ if (hwif->mmio)
+ {
+ hwif->OUTW(speedt, addr);
+ hwif->OUTW(speedp, tfaddr);
+ /* Now set up IORDY */
+ if(mode_wanted == 3 || mode_wanted == 4)
+ hwif->OUTW(hwif->INW(tfaddr-2)|0x200, tfaddr-2);
+ else
+ hwif->OUTW(hwif->INW(tfaddr-2)&~0x200, tfaddr-2);
+ }
+ else
+ {
+ pci_write_config_word(hwif->pci_dev, addr, speedp);
+ pci_write_config_word(hwif->pci_dev, tfaddr, speedt);
+ pci_read_config_word(hwif->pci_dev, tfaddr-2, &speedp);
+ speedp &= ~0x200;
+ /* Set IORDY for mode 3 or 4 */
+ if(mode_wanted == 3 || mode_wanted == 4)
+ speedp |= 0x200;
+ pci_write_config_word(hwif->pci_dev, tfaddr-2, speedp);
+ }
+}
+
+/**
+ * config_siimage_chipset_for_pio - set drive timings
+ * @drive: drive to tune
+ * @speed we want
+ *
+ * Compute the best pio mode we can for a given device. Also honour
+ * the timings for the driver when dealing with mixed devices. Some
+ * of this is ugly but its all wrapped up here
+ *
+ * The SI680 can also do VDMA - we need to start using that
+ *
+ * FIXME: we use the BIOS channel timings to avoid driving the task
+ * files too fast at the disk. We need to compute the master/slave
+ * drive PIO mode properly so that we can up the speed on a hotplug
+ * system.
+ */
+
+static void config_siimage_chipset_for_pio (ide_drive_t *drive, byte set_speed)
+{
+ u8 channel_timings = siimage_taskfile_timing(HWIF(drive));
+ u8 speed = 0, set_pio = ide_get_best_pio_mode(drive, 4, 5, NULL);
+
+ /* WARNING PIO timing mess is going to happen b/w devices, argh */
+ if ((channel_timings != set_pio) && (set_pio > channel_timings))
+ set_pio = channel_timings;
+
+ siimage_tuneproc(drive, set_pio);
+ speed = XFER_PIO_0 + set_pio;
+ if (set_speed)
+ (void) ide_config_drive_speed(drive, speed);
+}
+
+static void config_chipset_for_pio (ide_drive_t *drive, byte set_speed)
+{
+ config_siimage_chipset_for_pio(drive, set_speed);
+}
+
+/**
+ * siimage_tune_chipset - set controller timings
+ * @drive: Drive to set up
+ * @xferspeed: speed we want to achieve
+ *
+ * Tune the SII chipset for the desired mode. If we can't achieve
+ * the desired mode then tune for a lower one, but ultimately
+ * make the thing work.
+ */
+
+static int siimage_tune_chipset (ide_drive_t *drive, byte xferspeed)
+{
+ u8 ultra6[] = { 0x0F, 0x0B, 0x07, 0x05, 0x03, 0x02, 0x01 };
+ u8 ultra5[] = { 0x0C, 0x07, 0x05, 0x04, 0x02, 0x01 };
+ u16 dma[] = { 0x2208, 0x10C2, 0x10C1 };
+
+ ide_hwif_t *hwif = HWIF(drive);
+ u16 ultra = 0, multi = 0;
+ u8 mode = 0, unit = drive->select.b.unit;
+ u8 speed = ide_rate_filter(siimage_ratemask(drive), xferspeed);
+ unsigned long base = (unsigned long)hwif->hwif_data;
+ u8 scsc = 0, addr_mask = ((hwif->channel) ?
+ ((hwif->mmio) ? 0xF4 : 0x84) :
+ ((hwif->mmio) ? 0xB4 : 0x80));
+
+ unsigned long ma = siimage_seldev(drive, 0x08);
+ unsigned long ua = siimage_seldev(drive, 0x0C);
+
+ if (hwif->mmio) {
+ scsc = hwif->INB(base + 0x4A);
+ mode = hwif->INB(base + addr_mask);
+ multi = hwif->INW(ma);
+ ultra = hwif->INW(ua);
+ } else {
+ pci_read_config_byte(hwif->pci_dev, 0x8A, &scsc);
+ pci_read_config_byte(hwif->pci_dev, addr_mask, &mode);
+ pci_read_config_word(hwif->pci_dev, ma, &multi);
+ pci_read_config_word(hwif->pci_dev, ua, &ultra);
+ }
+
+ mode &= ~((unit) ? 0x30 : 0x03);
+ ultra &= ~0x3F;
+ scsc = ((scsc & 0x30) == 0x00) ? 0 : 1;
+
+ scsc = is_sata(hwif) ? 1 : scsc;
+
+ switch(speed) {
+ case XFER_PIO_4:
+ case XFER_PIO_3:
+ case XFER_PIO_2:
+ case XFER_PIO_1:
+ case XFER_PIO_0:
+ siimage_tuneproc(drive, (speed - XFER_PIO_0));
+ mode |= ((unit) ? 0x10 : 0x01);
+ break;
+ case XFER_MW_DMA_2:
+ case XFER_MW_DMA_1:
+ case XFER_MW_DMA_0:
+ multi = dma[speed - XFER_MW_DMA_0];
+ mode |= ((unit) ? 0x20 : 0x02);
+ config_siimage_chipset_for_pio(drive, 0);
+ break;
+ case XFER_UDMA_6:
+ case XFER_UDMA_5:
+ case XFER_UDMA_4:
+ case XFER_UDMA_3:
+ case XFER_UDMA_2:
+ case XFER_UDMA_1:
+ case XFER_UDMA_0:
+ multi = dma[2];
+ ultra |= ((scsc) ? (ultra6[speed - XFER_UDMA_0]) :
+ (ultra5[speed - XFER_UDMA_0]));
+ mode |= ((unit) ? 0x30 : 0x03);
+ config_siimage_chipset_for_pio(drive, 0);
+ break;
+ default:
+ return 1;
+ }
+
+ if (hwif->mmio) {
+ hwif->OUTB(mode, base + addr_mask);
+ hwif->OUTW(multi, ma);
+ hwif->OUTW(ultra, ua);
+ } else {
+ pci_write_config_byte(hwif->pci_dev, addr_mask, mode);
+ pci_write_config_word(hwif->pci_dev, ma, multi);
+ pci_write_config_word(hwif->pci_dev, ua, ultra);
+ }
+ return (ide_config_drive_speed(drive, speed));
+}
+
+/**
+ * config_chipset_for_dma - configure for DMA
+ * @drive: drive to configure
+ *
+ * Called by the IDE layer when it wants the timings set up.
+ * For the CMD680 we also need to set up the PIO timings and
+ * enable DMA.
+ */
+
+static int config_chipset_for_dma (ide_drive_t *drive)
+{
+ u8 speed = ide_dma_speed(drive, siimage_ratemask(drive));
+
+ config_chipset_for_pio(drive, !speed);
+
+ if (!speed)
+ return 0;
+
+ if (ide_set_xfer_rate(drive, speed))
+ return 0;
+
+ if (!drive->init_speed)
+ drive->init_speed = speed;
+
+ return ide_dma_enable(drive);
+}
+
+/**
+ * siimage_configure_drive_for_dma - set up for DMA transfers
+ * @drive: drive we are going to set up
+ *
+ * Set up the drive for DMA, tune the controller and drive as
+ * required. If the drive isn't suitable for DMA or we hit
+ * other problems then we will drop down to PIO and set up
+ * PIO appropriately
+ */
+
+static int siimage_config_drive_for_dma (ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct hd_driveid *id = drive->id;
+
+ if ((id->capability & 1) != 0 && drive->autodma) {
+
+ if (ide_use_dma(drive)) {
+ if (config_chipset_for_dma(drive))
+ return hwif->ide_dma_on(drive);
+ }
+
+ goto fast_ata_pio;
+
+ } else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+ config_chipset_for_pio(drive, 1);
+ return hwif->ide_dma_off_quietly(drive);
+ }
+ /* IORDY not supported */
+ return 0;
+}
+
+/* returns 1 if dma irq issued, 0 otherwise */
+static int siimage_io_ide_dma_test_irq (ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ u8 dma_altstat = 0;
+ unsigned long addr = siimage_selreg(hwif, 1);
+
+ /* return 1 if INTR asserted */
+ if ((hwif->INB(hwif->dma_status) & 4) == 4)
+ return 1;
+
+ /* return 1 if Device INTR asserted */
+ pci_read_config_byte(hwif->pci_dev, addr, &dma_altstat);
+ if (dma_altstat & 8)
+ return 0; //return 1;
+ return 0;
+}
+
+#if 0
+/**
+ * siimage_mmio_ide_dma_count - DMA bytes done
+ * @drive
+ *
+ * If we are doing VDMA the CMD680 requires a little bit
+ * of more careful handling and we have to read the counts
+ * off ourselves. For non VDMA life is normal.
+ */
+
+static int siimage_mmio_ide_dma_count (ide_drive_t *drive)
+{
+#ifdef SIIMAGE_VIRTUAL_DMAPIO
+ struct request *rq = HWGROUP(drive)->rq;
+ ide_hwif_t *hwif = HWIF(drive);
+ u32 count = (rq->nr_sectors * SECTOR_SIZE);
+ u32 rcount = 0;
+ unsigned long addr = siimage_selreg(hwif, 0x1C);
+
+ hwif->OUTL(count, addr);
+ rcount = hwif->INL(addr);
+
+ printk("\n%s: count = %d, rcount = %d, nr_sectors = %lu\n",
+ drive->name, count, rcount, rq->nr_sectors);
+
+#endif /* SIIMAGE_VIRTUAL_DMAPIO */
+ return __ide_dma_count(drive);
+}
+#endif
+
+/**
+ * siimage_mmio_ide_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_ide_dma_test_irq (ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ unsigned long base = (unsigned long)hwif->hwif_data;
+ unsigned long addr = siimage_selreg(hwif, 0x1);
+
+ if (SATA_ERROR_REG) {
+ u32 ext_stat = hwif->INL(base + 0x10);
+ u8 watchdog = 0;
+ if (ext_stat & ((hwif->channel) ? 0x40 : 0x10)) {
+ u32 sata_error = hwif->INL(SATA_ERROR_REG);
+ hwif->OUTL(sata_error, SATA_ERROR_REG);
+ watchdog = (sata_error & 0x00680000) ? 1 : 0;
+#if 1
+ printk(KERN_WARNING "%s: sata_error = 0x%08x, "
+ "watchdog = %d, %s\n",
+ drive->name, sata_error, watchdog,
+ __FUNCTION__);
+#endif
+
+ } else {
+ watchdog = (ext_stat & 0x8000) ? 1 : 0;
+ }
+ ext_stat >>= 16;
+
+ if (!(ext_stat & 0x0404) && !watchdog)
+ return 0;
+ }
+
+ /* return 1 if INTR asserted */
+ if ((hwif->INB(hwif->dma_status) & 0x04) == 0x04)
+ return 1;
+
+ /* return 1 if Device INTR asserted */
+ if ((hwif->INB(addr) & 8) == 8)
+ return 0; //return 1;
+
+ return 0;
+}
+
+/**
+ * siimage_busproc - bus isolation ioctl
+ * @drive: drive to isolate/restore
+ * @state: bus state to set
+ *
+ * Used by the SII3112 to handle bus isolation. As this is a
+ * SATA controller the work required is quite limited, we
+ * just have to clean up the statistics
+ */
+
+static int siimage_busproc (ide_drive_t * drive, int state)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ u32 stat_config = 0;
+ unsigned long addr = siimage_selreg(hwif, 0);
+
+ if (hwif->mmio) {
+ stat_config = hwif->INL(addr);
+ } else
+ pci_read_config_dword(hwif->pci_dev, addr, &stat_config);
+
+ switch (state) {
+ case BUSSTATE_ON:
+ hwif->drives[0].failures = 0;
+ hwif->drives[1].failures = 0;
+ break;
+ case BUSSTATE_OFF:
+ hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
+ hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
+ break;
+ case BUSSTATE_TRISTATE:
+ hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
+ hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
+ break;
+ default:
+ return -EINVAL;
+ }
+ hwif->bus_state = state;
+ return 0;
+}
+
+/**
+ * siimage_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 siimage_reset_poll (ide_drive_t *drive)
+{
+ if (SATA_STATUS_REG) {
+ ide_hwif_t *hwif = HWIF(drive);
+
+ if ((hwif->INL(SATA_STATUS_REG) & 0x03) != 0x03) {
+ printk(KERN_WARNING "%s: reset phy dead, status=0x%08x\n",
+ hwif->name, hwif->INL(SATA_STATUS_REG));
+ HWGROUP(drive)->polling = 0;
+ return ide_started;
+ }
+ return 0;
+ } else {
+ return 0;
+ }
+}
+
+/**
+ * siimage_pre_reset - reset hook
+ * @drive: IDE device being reset
+ *
+ * For the SATA devices we need to handle recalibration/geometry
+ * differently
+ */
+
+static void siimage_pre_reset (ide_drive_t *drive)
+{
+ if (drive->media != ide_disk)
+ return;
+
+ if (is_sata(HWIF(drive)))
+ {
+ drive->special.b.set_geometry = 0;
+ drive->special.b.recalibrate = 0;
+ }
+}
+
+/**
+ * siimage_reset - reset a device on an siimage controller
+ * @drive: drive to reset
+ *
+ * Perform a controller level reset fo the device. For
+ * SATA we must also check the PHY.
+ */
+
+static void siimage_reset (ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ u8 reset = 0;
+ unsigned long addr = siimage_selreg(hwif, 0);
+
+ if (hwif->mmio) {
+ reset = hwif->INB(addr);
+ hwif->OUTB((reset|0x03), addr);
+ /* FIXME:posting */
+ udelay(25);
+ hwif->OUTB(reset, addr);
+ (void) hwif->INB(addr);
+ } else {
+ pci_read_config_byte(hwif->pci_dev, addr, &reset);
+ pci_write_config_byte(hwif->pci_dev, addr, reset|0x03);
+ udelay(25);
+ pci_write_config_byte(hwif->pci_dev, addr, reset);
+ pci_read_config_byte(hwif->pci_dev, addr, &reset);
+ }
+
+ if (SATA_STATUS_REG) {
+ u32 sata_stat = hwif->INL(SATA_STATUS_REG);
+ printk(KERN_WARNING "%s: reset phy, status=0x%08x, %s\n",
+ hwif->name, sata_stat, __FUNCTION__);
+ if (!(sata_stat)) {
+ printk(KERN_WARNING "%s: reset phy dead, status=0x%08x\n",
+ hwif->name, sata_stat);
+ drive->failures++;
+ }
+ }
+
+}
+
+/**
+ * proc_reports_siimage - add siimage controller to proc
+ * @dev: PCI device
+ * @clocking: SCSC value
+ * @name: controller name
+ *
+ * Report the clocking mode of the controller and add it to
+ * the /proc interface layer
+ */
+
+static void proc_reports_siimage (struct pci_dev *dev, u8 clocking, const char *name)
+{
+ if (!pdev_is_sata(dev)) {
+ printk(KERN_INFO "%s: BASE CLOCK ", name);
+ clocking &= 0x03;
+ switch (clocking) {
+ case 0x03: printk("DISABLED!\n"); break;
+ case 0x02: printk("== 2X PCI\n"); break;
+ case 0x01: printk("== 133\n"); break;
+ case 0x00: printk("== 100\n"); break;
+ }
+ }
+}
+
+/**
+ * setup_mmio_siimage - switch an SI controller into MMIO
+ * @dev: PCI device we are configuring
+ * @name: device name
+ *
+ * Attempt to put the device into mmio mode. There are some slight
+ * complications here with certain systems where the mmio bar isnt
+ * mapped so we have to be sure we can fall back to I/O.
+ */
+
+static unsigned int setup_mmio_siimage (struct pci_dev *dev, const char *name)
+{
+ unsigned long bar5 = pci_resource_start(dev, 5);
+ unsigned long barsize = pci_resource_len(dev, 5);
+ u8 tmpbyte = 0;
+ void __iomem *ioaddr;
+
+ /*
+ * 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, name))
+ {
+ printk(KERN_WARNING "siimage: IDE controller MMIO ports not available.\n");
+ return 0;
+ }
+
+ ioaddr = ioremap(bar5, barsize);
+
+ if (ioaddr == NULL)
+ {
+ release_mem_region(bar5, barsize);
+ return 0;
+ }
+
+ pci_set_master(dev);
+ pci_set_drvdata(dev, (void *) ioaddr);
+
+ if (pdev_is_sata(dev)) {
+ writel(0, ioaddr + 0x148);
+ writel(0, ioaddr + 0x1C8);
+ }
+
+ writeb(0, ioaddr + 0xB4);
+ writeb(0, ioaddr + 0xF4);
+ tmpbyte = readb(ioaddr + 0x4A);
+
+ switch(tmpbyte & 0x30) {
+ case 0x00:
+ /* In 100 MHz clocking, try and switch to 133 */
+ writeb(tmpbyte|0x10, ioaddr + 0x4A);
+ break;
+ case 0x10:
+ /* On 133Mhz clocking */
+ break;
+ case 0x20:
+ /* On PCIx2 clocking */
+ break;
+ case 0x30:
+ /* Clocking is disabled */
+ /* 133 clock attempt to force it on */
+ writeb(tmpbyte & ~0x20, ioaddr + 0x4A);
+ break;
+ }
+
+ writeb( 0x72, ioaddr + 0xA1);
+ writew( 0x328A, ioaddr + 0xA2);
+ writel(0x62DD62DD, ioaddr + 0xA4);
+ writel(0x43924392, ioaddr + 0xA8);
+ writel(0x40094009, ioaddr + 0xAC);
+ writeb( 0x72, ioaddr + 0xE1);
+ writew( 0x328A, ioaddr + 0xE2);
+ writel(0x62DD62DD, ioaddr + 0xE4);
+ writel(0x43924392, ioaddr + 0xE8);
+ writel(0x40094009, ioaddr + 0xEC);
+
+ if (pdev_is_sata(dev)) {
+ writel(0xFFFF0000, ioaddr + 0x108);
+ writel(0xFFFF0000, ioaddr + 0x188);
+ writel(0x00680000, ioaddr + 0x148);
+ writel(0x00680000, ioaddr + 0x1C8);
+ }
+
+ tmpbyte = readb(ioaddr + 0x4A);
+
+ proc_reports_siimage(dev, (tmpbyte>>4), name);
+ return 1;
+}
+
+/**
+ * init_chipset_siimage - set up an SI device
+ * @dev: PCI device
+ * @name: device name
+ *
+ * Perform the initial PCI set up for this device. Attempt to switch
+ * to 133MHz clocking if the system isn't already set up to do it.
+ */
+
+static unsigned int __devinit init_chipset_siimage(struct pci_dev *dev, const char *name)
+{
+ u32 class_rev = 0;
+ u8 tmpbyte = 0;
+ u8 BA5_EN = 0;
+
+ pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
+ class_rev &= 0xff;
+ pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, (class_rev) ? 1 : 255);
+
+ pci_read_config_byte(dev, 0x8A, &BA5_EN);
+ if ((BA5_EN & 0x01) || (pci_resource_start(dev, 5))) {
+ if (setup_mmio_siimage(dev, name)) {
+ return 0;
+ }
+ }
+
+ pci_write_config_byte(dev, 0x80, 0x00);
+ pci_write_config_byte(dev, 0x84, 0x00);
+ pci_read_config_byte(dev, 0x8A, &tmpbyte);
+ switch(tmpbyte & 0x30) {
+ case 0x00:
+ /* 133 clock attempt to force it on */
+ pci_write_config_byte(dev, 0x8A, tmpbyte|0x10);
+ case 0x30:
+ /* if clocking is disabled */
+ /* 133 clock attempt to force it on */
+ pci_write_config_byte(dev, 0x8A, tmpbyte & ~0x20);
+ case 0x10:
+ /* 133 already */
+ break;
+ case 0x20:
+ /* BIOS set PCI x2 clocking */
+ break;
+ }
+
+ pci_read_config_byte(dev, 0x8A, &tmpbyte);
+
+ pci_write_config_byte(dev, 0xA1, 0x72);
+ pci_write_config_word(dev, 0xA2, 0x328A);
+ pci_write_config_dword(dev, 0xA4, 0x62DD62DD);
+ pci_write_config_dword(dev, 0xA8, 0x43924392);
+ pci_write_config_dword(dev, 0xAC, 0x40094009);
+ pci_write_config_byte(dev, 0xB1, 0x72);
+ pci_write_config_word(dev, 0xB2, 0x328A);
+ pci_write_config_dword(dev, 0xB4, 0x62DD62DD);
+ pci_write_config_dword(dev, 0xB8, 0x43924392);
+ pci_write_config_dword(dev, 0xBC, 0x40094009);
+
+ proc_reports_siimage(dev, (tmpbyte>>4), name);
+ 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 isnt a standard defined layout for them this
+ * time.
+ *
+ * The hardware supports buffered taskfiles and also some rather nice
+ * extended PRD tables. Unfortunately right now we don't.
+ */
+
+static void __devinit init_mmio_iops_siimage(ide_hwif_t *hwif)
+{
+ struct pci_dev *dev = hwif->pci_dev;
+ void *addr = pci_get_drvdata(dev);
+ u8 ch = hwif->channel;
+ hw_regs_t hw;
+ unsigned long base;
+
+ /*
+ * Fill in the basic HWIF bits
+ */
+
+ default_hwif_mmiops(hwif);
+ hwif->hwif_data = addr;
+
+ /*
+ * Now set up the hw. We have to do this ourselves as
+ * the MMIO layout isnt the same as the the standard port
+ * based I/O
+ */
+
+ memset(&hw, 0, sizeof(hw_regs_t));
+
+ 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.
+ */
+// base += 0x10;
+// hwif->no_lba48 = 1;
+
+ hw.io_ports[IDE_DATA_OFFSET] = base;
+ hw.io_ports[IDE_ERROR_OFFSET] = base + 1;
+ hw.io_ports[IDE_NSECTOR_OFFSET] = base + 2;
+ hw.io_ports[IDE_SECTOR_OFFSET] = base + 3;
+ hw.io_ports[IDE_LCYL_OFFSET] = base + 4;
+ hw.io_ports[IDE_HCYL_OFFSET] = base + 5;
+ hw.io_ports[IDE_SELECT_OFFSET] = base + 6;
+ hw.io_ports[IDE_STATUS_OFFSET] = base + 7;
+ hw.io_ports[IDE_CONTROL_OFFSET] = base + 10;
+
+ hw.io_ports[IDE_IRQ_OFFSET] = 0;
+
+ 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->sata_misc[SATA_MISC_OFFSET] = base + 0x140;
+ hwif->sata_misc[SATA_PHY_OFFSET] = base + 0x144;
+ hwif->sata_misc[SATA_IEN_OFFSET] = base + 0x148;
+ }
+
+ hw.irq = hwif->pci_dev->irq;
+
+ memcpy(&hwif->hw, &hw, sizeof(hw));
+ memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->hw.io_ports));
+
+ hwif->irq = hw.irq;
+
+ base = (unsigned long) addr;
+
+#ifdef SIIMAGE_LARGE_DMA
+/* Watch the brackets - even Ken and Dennis get some language design wrong */
+ hwif->dma_base = base + (ch ? 0x18 : 0x10);
+ hwif->dma_base2 = base + (ch ? 0x08 : 0x00);
+ hwif->dma_prdtable = hwif->dma_base2 + 4;
+#else /* ! SIIMAGE_LARGE_DMA */
+ hwif->dma_base = base + (ch ? 0x08 : 0x00);
+ hwif->dma_base2 = base + (ch ? 0x18 : 0x10);
+#endif /* SIIMAGE_LARGE_DMA */
+ hwif->mmio = 2;
+}
+
+static int is_dev_seagate_sata(ide_drive_t *drive)
+{
+ const char *s = &drive->id->model[0];
+ unsigned len;
+
+ if (!drive->present)
+ return 0;
+
+ len = strnlen(s, sizeof(drive->id->model));
+
+ 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;
+}
+
+/**
+ * siimage_fixup - post probe fixups
+ * @hwif: interface to fix up
+ *
+ * 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 __devinit siimage_fixup(ide_hwif_t *hwif)
+{
+ /* Try and raise the rqsize */
+ if (!is_sata(hwif) || !is_dev_seagate_sata(&hwif->drives[0]))
+ 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 = hwif->pci_dev;
+ u32 class_rev = 0;
+
+ pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
+ class_rev &= 0xff;
+
+ hwif->hwif_data = NULL;
+
+ /* Pessimal until we finish probing */
+ hwif->rqsize = 15;
+
+ if (pci_get_drvdata(dev) == NULL)
+ return;
+ init_mmio_iops_siimage(hwif);
+}
+
+/**
+ * ata66_siimage - check for 80 pin cable
+ * @hwif: interface to check
+ *
+ * Check for the presence of an ATA66 capable cable on the
+ * interface.
+ */
+
+static unsigned int __devinit ata66_siimage(ide_hwif_t *hwif)
+{
+ unsigned long addr = siimage_selreg(hwif, 0);
+ if (pci_get_drvdata(hwif->pci_dev) == NULL) {
+ u8 ata66 = 0;
+ pci_read_config_byte(hwif->pci_dev, addr, &ata66);
+ return (ata66 & 0x01) ? 1 : 0;
+ }
+
+ return (hwif->INB(addr) & 0x01) ? 1 : 0;
+}
+
+/**
+ * init_hwif_siimage - set up hwif structs
+ * @hwif: interface to set up
+ *
+ * We do the basic set up of the interface structure. The SIIMAGE
+ * requires several custom handlers so we override the default
+ * ide DMA handlers appropriately
+ */
+
+static void __devinit init_hwif_siimage(ide_hwif_t *hwif)
+{
+ hwif->autodma = 0;
+
+ hwif->resetproc = &siimage_reset;
+ hwif->speedproc = &siimage_tune_chipset;
+ hwif->tuneproc = &siimage_tuneproc;
+ hwif->reset_poll = &siimage_reset_poll;
+ hwif->pre_reset = &siimage_pre_reset;
+
+ if(is_sata(hwif))
+ hwif->busproc = &siimage_busproc;
+
+ if (!hwif->dma_base) {
+ hwif->drives[0].autotune = 1;
+ hwif->drives[1].autotune = 1;
+ return;
+ }
+
+ hwif->ultra_mask = 0x7f;
+ hwif->mwdma_mask = 0x07;
+ hwif->swdma_mask = 0x07;
+
+ if (!is_sata(hwif))
+ hwif->atapi_dma = 1;
+
+ hwif->ide_dma_check = &siimage_config_drive_for_dma;
+ if (!(hwif->udma_four))
+ hwif->udma_four = ata66_siimage(hwif);
+
+ if (hwif->mmio) {
+ hwif->ide_dma_test_irq = &siimage_mmio_ide_dma_test_irq;
+ } else {
+ hwif->ide_dma_test_irq = & siimage_io_ide_dma_test_irq;
+ }
+
+ /*
+ * The BIOS often doesn't set up DMA on this controller
+ * so we always do it.
+ */
+
+ hwif->autodma = 1;
+ hwif->drives[0].autodma = hwif->autodma;
+ hwif->drives[1].autodma = hwif->autodma;
+}
+
+#define DECLARE_SII_DEV(name_str) \
+ { \
+ .name = name_str, \
+ .init_chipset = init_chipset_siimage, \
+ .init_iops = init_iops_siimage, \
+ .init_hwif = init_hwif_siimage, \
+ .fixup = siimage_fixup, \
+ .channels = 2, \
+ .autodma = AUTODMA, \
+ .bootable = ON_BOARD, \
+ }
+
+static ide_pci_device_t siimage_chipsets[] __devinitdata = {
+ /* 0 */ DECLARE_SII_DEV("SiI680"),
+ /* 1 */ DECLARE_SII_DEV("SiI3112 Serial ATA"),
+ /* 2 */ DECLARE_SII_DEV("Adaptec AAR-1210SA")
+};
+
+/**
+ * siimage_init_one - pci layer discovery entry
+ * @dev: PCI device
+ * @id: ident table entry
+ *
+ * Called by the PCI code when it finds an SI680 or SI3112 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)
+{
+ return ide_setup_pci_device(dev, &siimage_chipsets[id->driver_data]);
+}
+
+static struct pci_device_id siimage_pci_tbl[] = {
+ { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_SII_680, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+#ifdef CONFIG_BLK_DEV_IDE_SATA
+ { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_SII_3112, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+ { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_SII_1210SA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
+#endif
+ { 0, },
+};
+MODULE_DEVICE_TABLE(pci, siimage_pci_tbl);
+
+static struct pci_driver driver = {
+ .name = "SiI_IDE",
+ .id_table = siimage_pci_tbl,
+ .probe = siimage_init_one,
+};
+
+static int siimage_ide_init(void)
+{
+ return ide_pci_register_driver(&driver);
+}
+
+module_init(siimage_ide_init);
+
+MODULE_AUTHOR("Andre Hedrick, Alan Cox");
+MODULE_DESCRIPTION("PCI driver module for SiI IDE");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/pci/sis5513.c b/drivers/ide/pci/sis5513.c
new file mode 100644
index 000000000000..9d70ba5ea59b
--- /dev/null
+++ b/drivers/ide/pci/sis5513.c
@@ -0,0 +1,984 @@
+/*
+ * linux/drivers/ide/pci/sis5513.c Version 0.16ac+vp Jun 18, 2003
+ *
+ * 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>
+ * 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/config.h>
+#include <linux/types.h>
+#include <linux/module.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/hdreg.h>
+
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/ide.h>
+
+#include <asm/irq.h>
+
+#include "ide-timing.h"
+
+#define DISPLAY_SIS_TIMINGS
+
+/* 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[] = {
+ { "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 },
+ { "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), differences are on 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)"
+};
+
+#if defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 sis_proc = 0;
+
+static struct pci_dev *bmide_dev;
+
+static char* cable_type[] = {
+ "80 pins",
+ "40 pins"
+};
+
+static char* recovery_time[] ={
+ "12 PCICLK", "1 PCICLK",
+ "2 PCICLK", "3 PCICLK",
+ "4 PCICLK", "5 PCICLCK",
+ "6 PCICLK", "7 PCICLCK",
+ "8 PCICLK", "9 PCICLCK",
+ "10 PCICLK", "11 PCICLK",
+ "13 PCICLK", "14 PCICLK",
+ "15 PCICLK", "15 PCICLK"
+};
+
+static char* active_time[] = {
+ "8 PCICLK", "1 PCICLCK",
+ "2 PCICLK", "3 PCICLK",
+ "4 PCICLK", "5 PCICLK",
+ "6 PCICLK", "12 PCICLK"
+};
+
+static char* cycle_time[] = {
+ "Reserved", "2 CLK",
+ "3 CLK", "4 CLK",
+ "5 CLK", "6 CLK",
+ "7 CLK", "8 CLK",
+ "9 CLK", "10 CLK",
+ "11 CLK", "12 CLK",
+ "13 CLK", "14 CLK",
+ "15 CLK", "16 CLK"
+};
+
+/* Generic add master or slave info function */
+static char* get_drives_info (char *buffer, u8 pos)
+{
+ u8 reg00, reg01, reg10, reg11; /* timing registers */
+ u32 regdw0, regdw1;
+ char* p = buffer;
+
+/* Postwrite/Prefetch */
+ if (chipset_family < ATA_133) {
+ pci_read_config_byte(bmide_dev, 0x4b, &reg00);
+ p += sprintf(p, "Drive %d: Postwrite %s \t \t Postwrite %s\n",
+ pos, (reg00 & (0x10 << pos)) ? "Enabled" : "Disabled",
+ (reg00 & (0x40 << pos)) ? "Enabled" : "Disabled");
+ p += sprintf(p, " Prefetch %s \t \t Prefetch %s\n",
+ (reg00 & (0x01 << pos)) ? "Enabled" : "Disabled",
+ (reg00 & (0x04 << pos)) ? "Enabled" : "Disabled");
+ pci_read_config_byte(bmide_dev, 0x40+2*pos, &reg00);
+ pci_read_config_byte(bmide_dev, 0x41+2*pos, &reg01);
+ pci_read_config_byte(bmide_dev, 0x44+2*pos, &reg10);
+ pci_read_config_byte(bmide_dev, 0x45+2*pos, &reg11);
+ } else {
+ u32 reg54h;
+ u8 drive_pci = 0x40;
+ pci_read_config_dword(bmide_dev, 0x54, &reg54h);
+ if (reg54h & 0x40000000) {
+ // Configuration space remapped to 0x70
+ drive_pci = 0x70;
+ }
+ pci_read_config_dword(bmide_dev, (unsigned long)drive_pci+4*pos, &regdw0);
+ pci_read_config_dword(bmide_dev, (unsigned long)drive_pci+4*pos+8, &regdw1);
+
+ p += sprintf(p, "Drive %d:\n", pos);
+ }
+
+
+/* UDMA */
+ if (chipset_family >= ATA_133) {
+ p += sprintf(p, " UDMA %s \t \t \t UDMA %s\n",
+ (regdw0 & 0x04) ? "Enabled" : "Disabled",
+ (regdw1 & 0x04) ? "Enabled" : "Disabled");
+ p += sprintf(p, " UDMA Cycle Time %s \t UDMA Cycle Time %s\n",
+ cycle_time[(regdw0 & 0xF0) >> 4],
+ cycle_time[(regdw1 & 0xF0) >> 4]);
+ } else if (chipset_family >= ATA_33) {
+ p += sprintf(p, " UDMA %s \t \t \t UDMA %s\n",
+ (reg01 & 0x80) ? "Enabled" : "Disabled",
+ (reg11 & 0x80) ? "Enabled" : "Disabled");
+
+ p += sprintf(p, " UDMA Cycle Time ");
+ switch(chipset_family) {
+ case ATA_33: p += sprintf(p, cycle_time[(reg01 & 0x60) >> 5]); break;
+ case ATA_66:
+ case ATA_100a: p += sprintf(p, cycle_time[(reg01 & 0x70) >> 4]); break;
+ case ATA_100:
+ case ATA_133a: p += sprintf(p, cycle_time[reg01 & 0x0F]); break;
+ default: p += sprintf(p, "?"); break;
+ }
+ p += sprintf(p, " \t UDMA Cycle Time ");
+ switch(chipset_family) {
+ case ATA_33: p += sprintf(p, cycle_time[(reg11 & 0x60) >> 5]); break;
+ case ATA_66:
+ case ATA_100a: p += sprintf(p, cycle_time[(reg11 & 0x70) >> 4]); break;
+ case ATA_100:
+ case ATA_133a: p += sprintf(p, cycle_time[reg11 & 0x0F]); break;
+ default: p += sprintf(p, "?"); break;
+ }
+ p += sprintf(p, "\n");
+ }
+
+
+ if (chipset_family < ATA_133) { /* else case TODO */
+
+/* Data Active */
+ p += sprintf(p, " Data Active Time ");
+ switch(chipset_family) {
+ case ATA_16: /* confirmed */
+ case ATA_33:
+ case ATA_66:
+ case ATA_100a: p += sprintf(p, active_time[reg01 & 0x07]); break;
+ case ATA_100:
+ case ATA_133a: p += sprintf(p, active_time[(reg00 & 0x70) >> 4]); break;
+ default: p += sprintf(p, "?"); break;
+ }
+ p += sprintf(p, " \t Data Active Time ");
+ switch(chipset_family) {
+ case ATA_16:
+ case ATA_33:
+ case ATA_66:
+ case ATA_100a: p += sprintf(p, active_time[reg11 & 0x07]); break;
+ case ATA_100:
+ case ATA_133a: p += sprintf(p, active_time[(reg10 & 0x70) >> 4]); break;
+ default: p += sprintf(p, "?"); break;
+ }
+ p += sprintf(p, "\n");
+
+/* Data Recovery */
+ /* warning: may need (reg&0x07) for pre ATA66 chips */
+ p += sprintf(p, " Data Recovery Time %s \t Data Recovery Time %s\n",
+ recovery_time[reg00 & 0x0f], recovery_time[reg10 & 0x0f]);
+ }
+
+ return p;
+}
+
+static char* get_masters_info(char* buffer)
+{
+ return get_drives_info(buffer, 0);
+}
+
+static char* get_slaves_info(char* buffer)
+{
+ return get_drives_info(buffer, 1);
+}
+
+/* Main get_info, called on /proc/ide/sis reads */
+static int sis_get_info (char *buffer, char **addr, off_t offset, int count)
+{
+ char *p = buffer;
+ int len;
+ u8 reg;
+ u16 reg2, reg3;
+
+ p += sprintf(p, "\nSiS 5513 ");
+ switch(chipset_family) {
+ case ATA_16: p += sprintf(p, "DMA 16"); break;
+ case ATA_33: p += sprintf(p, "Ultra 33"); break;
+ case ATA_66: p += sprintf(p, "Ultra 66"); break;
+ case ATA_100a:
+ case ATA_100: p += sprintf(p, "Ultra 100"); break;
+ case ATA_133a:
+ case ATA_133: p += sprintf(p, "Ultra 133"); break;
+ default: p+= sprintf(p, "Unknown???"); break;
+ }
+ p += sprintf(p, " chipset\n");
+ p += sprintf(p, "--------------- Primary Channel "
+ "---------------- Secondary Channel "
+ "-------------\n");
+
+/* Status */
+ pci_read_config_byte(bmide_dev, 0x4a, &reg);
+ if (chipset_family == ATA_133) {
+ pci_read_config_word(bmide_dev, 0x50, &reg2);
+ pci_read_config_word(bmide_dev, 0x52, &reg3);
+ }
+ p += sprintf(p, "Channel Status: ");
+ if (chipset_family < ATA_66) {
+ p += sprintf(p, "%s \t \t \t \t %s\n",
+ (reg & 0x04) ? "On" : "Off",
+ (reg & 0x02) ? "On" : "Off");
+ } else if (chipset_family < ATA_133) {
+ p += sprintf(p, "%s \t \t \t \t %s \n",
+ (reg & 0x02) ? "On" : "Off",
+ (reg & 0x04) ? "On" : "Off");
+ } else { /* ATA_133 */
+ p += sprintf(p, "%s \t \t \t \t %s \n",
+ (reg2 & 0x02) ? "On" : "Off",
+ (reg3 & 0x02) ? "On" : "Off");
+ }
+
+/* Operation Mode */
+ pci_read_config_byte(bmide_dev, 0x09, &reg);
+ p += sprintf(p, "Operation Mode: %s \t \t \t %s \n",
+ (reg & 0x01) ? "Native" : "Compatible",
+ (reg & 0x04) ? "Native" : "Compatible");
+
+/* 80-pin cable ? */
+ if (chipset_family >= ATA_133) {
+ p += sprintf(p, "Cable Type: %s \t \t \t %s\n",
+ (reg2 & 0x01) ? cable_type[1] : cable_type[0],
+ (reg3 & 0x01) ? cable_type[1] : cable_type[0]);
+ } else if (chipset_family > ATA_33) {
+ pci_read_config_byte(bmide_dev, 0x48, &reg);
+ p += sprintf(p, "Cable Type: %s \t \t \t %s\n",
+ (reg & 0x10) ? cable_type[1] : cable_type[0],
+ (reg & 0x20) ? cable_type[1] : cable_type[0]);
+ }
+
+/* Prefetch Count */
+ if (chipset_family < ATA_133) {
+ pci_read_config_word(bmide_dev, 0x4c, &reg2);
+ pci_read_config_word(bmide_dev, 0x4e, &reg3);
+ p += sprintf(p, "Prefetch Count: %d \t \t \t \t %d\n",
+ reg2, reg3);
+ }
+
+ p = get_masters_info(p);
+ p = get_slaves_info(p);
+
+ len = (p - buffer) - offset;
+ *addr = buffer + offset;
+
+ return len > count ? count : len;
+}
+#endif /* defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+static u8 sis5513_ratemask (ide_drive_t *drive)
+{
+ u8 rates[] = { 0, 0, 1, 2, 3, 3, 4, 4 };
+ u8 mode = rates[chipset_family];
+
+ if (!eighty_ninty_three(drive))
+ mode = min(mode, (u8)1);
+ return mode;
+}
+
+/*
+ * Configuration functions
+ */
+/* Enables per-drive prefetch and postwrite */
+static void config_drive_art_rwp (ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = hwif->pci_dev;
+
+ u8 reg4bh = 0;
+ u8 rw_prefetch = (0x11 << drive->dn);
+
+ if (drive->media != ide_disk)
+ return;
+ pci_read_config_byte(dev, 0x4b, &reg4bh);
+
+ if ((reg4bh & rw_prefetch) != rw_prefetch)
+ pci_write_config_byte(dev, 0x4b, reg4bh|rw_prefetch);
+}
+
+
+/* Set per-drive active and recovery time */
+static void config_art_rwp_pio (ide_drive_t *drive, u8 pio)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = hwif->pci_dev;
+
+ u8 timing, drive_pci, test1, test2;
+
+ u16 eide_pio_timing[6] = {600, 390, 240, 180, 120, 90};
+ u16 xfer_pio = drive->id->eide_pio_modes;
+
+ config_drive_art_rwp(drive);
+ pio = ide_get_best_pio_mode(drive, 255, pio, NULL);
+
+ if (xfer_pio> 4)
+ xfer_pio = 0;
+
+ if (drive->id->eide_pio_iordy > 0) {
+ for (xfer_pio = 5;
+ (xfer_pio > 0) &&
+ (drive->id->eide_pio_iordy > eide_pio_timing[xfer_pio]);
+ xfer_pio--);
+ } else {
+ xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 :
+ (drive->id->eide_pio_modes & 2) ? 0x04 :
+ (drive->id->eide_pio_modes & 1) ? 0x03 : xfer_pio;
+ }
+
+ timing = (xfer_pio >= pio) ? xfer_pio : pio;
+
+ /* In pre ATA_133 case, drives sit at 0x40 + 4*drive->dn */
+ drive_pci = 0x40;
+ /* In SiS962 case drives sit at (0x40 or 0x70) + 8*drive->dn) */
+ if (chipset_family >= ATA_133) {
+ u32 reg54h;
+ pci_read_config_dword(dev, 0x54, &reg54h);
+ if (reg54h & 0x40000000) drive_pci = 0x70;
+ drive_pci += ((drive->dn)*0x4);
+ } else {
+ drive_pci += ((drive->dn)*0x2);
+ }
+
+ /* register layout changed with newer ATA100 chips */
+ if (chipset_family < ATA_100) {
+ pci_read_config_byte(dev, drive_pci, &test1);
+ pci_read_config_byte(dev, drive_pci+1, &test2);
+
+ /* Clear active and recovery timings */
+ test1 &= ~0x0F;
+ test2 &= ~0x07;
+
+ switch(timing) {
+ case 4: test1 |= 0x01; test2 |= 0x03; break;
+ case 3: test1 |= 0x03; test2 |= 0x03; break;
+ case 2: test1 |= 0x04; test2 |= 0x04; break;
+ case 1: test1 |= 0x07; test2 |= 0x06; break;
+ default: break;
+ }
+ pci_write_config_byte(dev, drive_pci, test1);
+ pci_write_config_byte(dev, drive_pci+1, test2);
+ } else if (chipset_family < ATA_133) {
+ switch(timing) { /* active recovery
+ v v */
+ case 4: test1 = 0x30|0x01; break;
+ case 3: test1 = 0x30|0x03; break;
+ case 2: test1 = 0x40|0x04; break;
+ case 1: test1 = 0x60|0x07; break;
+ default: break;
+ }
+ pci_write_config_byte(dev, drive_pci, test1);
+ } else { /* ATA_133 */
+ u32 test3;
+ pci_read_config_dword(dev, drive_pci, &test3);
+ test3 &= 0xc0c00fff;
+ if (test3 & 0x08) {
+ test3 |= (unsigned long)ini_time_value[ATA_133][timing] << 12;
+ test3 |= (unsigned long)act_time_value[ATA_133][timing] << 16;
+ test3 |= (unsigned long)rco_time_value[ATA_133][timing] << 24;
+ } else {
+ test3 |= (unsigned long)ini_time_value[ATA_100][timing] << 12;
+ test3 |= (unsigned long)act_time_value[ATA_100][timing] << 16;
+ test3 |= (unsigned long)rco_time_value[ATA_100][timing] << 24;
+ }
+ pci_write_config_dword(dev, drive_pci, test3);
+ }
+}
+
+static int config_chipset_for_pio (ide_drive_t *drive, u8 pio)
+{
+ if (pio == 255)
+ pio = ide_find_best_mode(drive, XFER_PIO | XFER_EPIO) - XFER_PIO_0;
+ config_art_rwp_pio(drive, pio);
+ return ide_config_drive_speed(drive, XFER_PIO_0 + min_t(u8, pio, 4));
+}
+
+static int sis5513_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = hwif->pci_dev;
+
+ u8 drive_pci, reg, speed;
+ u32 regdw;
+
+ speed = ide_rate_filter(sis5513_ratemask(drive), xferspeed);
+
+ /* See config_art_rwp_pio for drive pci config registers */
+ drive_pci = 0x40;
+ if (chipset_family >= ATA_133) {
+ u32 reg54h;
+ pci_read_config_dword(dev, 0x54, &reg54h);
+ if (reg54h & 0x40000000) drive_pci = 0x70;
+ drive_pci += ((drive->dn)*0x4);
+ pci_read_config_dword(dev, (unsigned long)drive_pci, &regdw);
+ /* Disable UDMA bit for non UDMA modes on UDMA chips */
+ if (speed < XFER_UDMA_0) {
+ regdw &= 0xfffffffb;
+ pci_write_config_dword(dev, (unsigned long)drive_pci, regdw);
+ }
+
+ } else {
+ drive_pci += ((drive->dn)*0x2);
+ pci_read_config_byte(dev, drive_pci+1, &reg);
+ /* Disable UDMA bit for non UDMA modes on UDMA chips */
+ if ((speed < XFER_UDMA_0) && (chipset_family > ATA_16)) {
+ reg &= 0x7F;
+ pci_write_config_byte(dev, drive_pci+1, reg);
+ }
+ }
+
+ /* Config chip for mode */
+ switch(speed) {
+ case XFER_UDMA_6:
+ case XFER_UDMA_5:
+ case XFER_UDMA_4:
+ case XFER_UDMA_3:
+ case XFER_UDMA_2:
+ case XFER_UDMA_1:
+ case XFER_UDMA_0:
+ if (chipset_family >= ATA_133) {
+ regdw |= 0x04;
+ regdw &= 0xfffff00f;
+ /* check if ATA133 enable */
+ if (regdw & 0x08) {
+ regdw |= (unsigned long)cycle_time_value[ATA_133][speed-XFER_UDMA_0] << 4;
+ regdw |= (unsigned long)cvs_time_value[ATA_133][speed-XFER_UDMA_0] << 8;
+ } else {
+ /* if ATA133 disable, we should not set speed above UDMA5 */
+ if (speed > XFER_UDMA_5)
+ speed = XFER_UDMA_5;
+ regdw |= (unsigned long)cycle_time_value[ATA_100][speed-XFER_UDMA_0] << 4;
+ regdw |= (unsigned long)cvs_time_value[ATA_100][speed-XFER_UDMA_0] << 8;
+ }
+ pci_write_config_dword(dev, (unsigned long)drive_pci, regdw);
+ } else {
+ /* Force the UDMA bit on if we want to use UDMA */
+ reg |= 0x80;
+ /* clean reg cycle time bits */
+ reg &= ~((0xFF >> (8 - cycle_time_range[chipset_family]))
+ << cycle_time_offset[chipset_family]);
+ /* set reg cycle time bits */
+ reg |= cycle_time_value[chipset_family][speed-XFER_UDMA_0]
+ << cycle_time_offset[chipset_family];
+ pci_write_config_byte(dev, drive_pci+1, reg);
+ }
+ break;
+ case XFER_MW_DMA_2:
+ case XFER_MW_DMA_1:
+ case XFER_MW_DMA_0:
+ case XFER_SW_DMA_2:
+ case XFER_SW_DMA_1:
+ case XFER_SW_DMA_0:
+ break;
+ case XFER_PIO_4: return((int) config_chipset_for_pio(drive, 4));
+ case XFER_PIO_3: return((int) config_chipset_for_pio(drive, 3));
+ case XFER_PIO_2: return((int) config_chipset_for_pio(drive, 2));
+ case XFER_PIO_1: return((int) config_chipset_for_pio(drive, 1));
+ case XFER_PIO_0:
+ default: return((int) config_chipset_for_pio(drive, 0));
+ }
+
+ return ((int) ide_config_drive_speed(drive, speed));
+}
+
+static void sis5513_tune_drive (ide_drive_t *drive, u8 pio)
+{
+ (void) config_chipset_for_pio(drive, pio);
+}
+
+/*
+ * ((id->hw_config & 0x4000|0x2000) && (HWIF(drive)->udma_four))
+ */
+static int config_chipset_for_dma (ide_drive_t *drive)
+{
+ u8 speed = ide_dma_speed(drive, sis5513_ratemask(drive));
+
+#ifdef DEBUG
+ printk("SIS5513: config_chipset_for_dma, drive %d, ultra %x\n",
+ drive->dn, drive->id->dma_ultra);
+#endif
+
+ if (!(speed))
+ return 0;
+
+ sis5513_tune_chipset(drive, speed);
+ return ide_dma_enable(drive);
+}
+
+static int sis5513_config_drive_xfer_rate (ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct hd_driveid *id = drive->id;
+
+ drive->init_speed = 0;
+
+ if (id && (id->capability & 1) && drive->autodma) {
+
+ if (ide_use_dma(drive)) {
+ if (config_chipset_for_dma(drive))
+ return hwif->ide_dma_on(drive);
+ }
+
+ goto fast_ata_pio;
+
+ } else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+ sis5513_tune_drive(drive, 5);
+ return hwif->ide_dma_off_quietly(drive);
+ }
+ /* IORDY not supported */
+ return 0;
+}
+
+/* initiates/aborts (U)DMA read/write operations on a drive. */
+static int sis5513_config_xfer_rate (ide_drive_t *drive)
+{
+ config_drive_art_rwp(drive);
+ config_art_rwp_pio(drive, 5);
+ return sis5513_config_drive_xfer_rate(drive);
+}
+
+/*
+ Future simpler config_xfer_rate :
+ When ide_find_best_mode is made bad-drive aware
+ - remove config_drive_xfer_rate and config_chipset_for_dma,
+ - replace config_xfer_rate with the following
+
+static int sis5513_config_xfer_rate (ide_drive_t *drive)
+{
+ u16 w80 = HWIF(drive)->udma_four;
+ u16 speed;
+
+ config_drive_art_rwp(drive);
+ config_art_rwp_pio(drive, 5);
+
+ speed = ide_find_best_mode(drive,
+ XFER_PIO | XFER_EPIO | XFER_SWDMA | XFER_MWDMA |
+ (chipset_family >= ATA_33 ? XFER_UDMA : 0) |
+ (w80 && chipset_family >= ATA_66 ? XFER_UDMA_66 : 0) |
+ (w80 && chipset_family >= ATA_100a ? XFER_UDMA_100 : 0) |
+ (w80 && chipset_family >= ATA_133a ? XFER_UDMA_133 : 0));
+
+ sis5513_tune_chipset(drive, speed);
+
+ if (drive->autodma && (speed & XFER_MODE) != XFER_PIO)
+ return HWIF(drive)->ide_dma_on(drive);
+ return HWIF(drive)->ide_dma_off_quietly(drive);
+}
+*/
+
+/* Chip detection and general config */
+static unsigned int __init init_chipset_sis5513 (struct pci_dev *dev, const char *name)
+{
+ struct pci_dev *host;
+ int i = 0;
+
+ chipset_family = 0;
+
+ for (i = 0; i < ARRAY_SIZE(SiSHostChipInfo) && !chipset_family; i++) {
+
+ host = pci_find_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) {
+ u8 hostrev;
+ pci_read_config_byte(host, PCI_REVISION_ID, &hostrev);
+ if (hostrev >= 0x30)
+ chipset_family = ATA_100a;
+ }
+
+ printk(KERN_INFO "SIS5513: %s %s controller\n",
+ 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 "SIS5513: SiS 962/963 MuTIOL IDE UDMA133 controller\n");
+ 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 "SIS5513: Switching to 5513 register mapping\n");
+ }
+ }
+ }
+
+ if (!chipset_family) { /* Belongs to pci-quirks */
+
+ struct pci_dev *lpc_bridge;
+ u16 trueid;
+ u8 prefctl;
+ u8 idecfg;
+ u8 sbrev;
+
+ 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_find_slot(0x00, 0x10); /* Bus 0, Dev 2, Fn 0 */
+ pci_read_config_byte(lpc_bridge, PCI_REVISION_ID, &sbrev);
+ pci_read_config_byte(dev, 0x49, &prefctl);
+
+ if (sbrev == 0x10 && (prefctl & 0x80)) {
+ printk(KERN_INFO "SIS5513: SiS 961B MuTIOL IDE UDMA133 controller\n");
+ chipset_family = ATA_133a;
+ } else {
+ printk(KERN_INFO "SIS5513: SiS 961 MuTIOL IDE UDMA100 controller\n");
+ chipset_family = ATA_100;
+ }
+ }
+ }
+
+ if (!chipset_family)
+ return -1;
+
+ /* 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;
+ }
+
+#if defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS)
+ if (!sis_proc) {
+ sis_proc = 1;
+ bmide_dev = dev;
+ ide_pci_create_host_proc("sis", sis_get_info);
+ }
+#endif
+ }
+
+ return 0;
+}
+
+static unsigned int __init ata66_sis5513 (ide_hwif_t *hwif)
+{
+ u8 ata66 = 0;
+
+ if (chipset_family >= ATA_133) {
+ u16 regw = 0;
+ u16 reg_addr = hwif->channel ? 0x52: 0x50;
+ pci_read_config_word(hwif->pci_dev, 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(hwif->pci_dev, 0x48, &reg48h);
+ ata66 = (reg48h & mask) ? 0 : 1;
+ }
+ return ata66;
+}
+
+static void __init init_hwif_sis5513 (ide_hwif_t *hwif)
+{
+ hwif->autodma = 0;
+
+ if (!hwif->irq)
+ hwif->irq = hwif->channel ? 15 : 14;
+
+ hwif->tuneproc = &sis5513_tune_drive;
+ hwif->speedproc = &sis5513_tune_chipset;
+
+ if (!(hwif->dma_base)) {
+ hwif->drives[0].autotune = 1;
+ hwif->drives[1].autotune = 1;
+ return;
+ }
+
+ hwif->atapi_dma = 1;
+ hwif->ultra_mask = 0x7f;
+ hwif->mwdma_mask = 0x07;
+ hwif->swdma_mask = 0x07;
+
+ if (!chipset_family)
+ return;
+
+ if (!(hwif->udma_four))
+ hwif->udma_four = ata66_sis5513(hwif);
+
+ if (chipset_family > ATA_16) {
+ hwif->ide_dma_check = &sis5513_config_xfer_rate;
+ if (!noautodma)
+ hwif->autodma = 1;
+ }
+ hwif->drives[0].autodma = hwif->autodma;
+ hwif->drives[1].autodma = hwif->autodma;
+ return;
+}
+
+static ide_pci_device_t sis5513_chipset __devinitdata = {
+ .name = "SIS5513",
+ .init_chipset = init_chipset_sis5513,
+ .init_hwif = init_hwif_sis5513,
+ .channels = 2,
+ .autodma = NOAUTODMA,
+ .enablebits = {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
+ .bootable = ON_BOARD,
+};
+
+static int __devinit sis5513_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ return ide_setup_pci_device(dev, &sis5513_chipset);
+}
+
+static struct pci_device_id sis5513_pci_tbl[] = {
+ { PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5513, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5518, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { 0, },
+};
+MODULE_DEVICE_TABLE(pci, sis5513_pci_tbl);
+
+static struct pci_driver driver = {
+ .name = "SIS_IDE",
+ .id_table = sis5513_pci_tbl,
+ .probe = sis5513_init_one,
+};
+
+static int sis5513_ide_init(void)
+{
+ return ide_pci_register_driver(&driver);
+}
+
+module_init(sis5513_ide_init);
+
+MODULE_AUTHOR("Lionel Bouton, L C Chang, Andre Hedrick, Vojtech Pavlik");
+MODULE_DESCRIPTION("PCI driver module for SIS IDE");
+MODULE_LICENSE("GPL");
+
+/*
+ * TODO:
+ * - CLEANUP
+ * - Use drivers/ide/ide-timing.h !
+ * - 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/pci/sl82c105.c b/drivers/ide/pci/sl82c105.c
new file mode 100644
index 000000000000..1d970a0de21a
--- /dev/null
+++ b/drivers/ide/pci/sl82c105.c
@@ -0,0 +1,516 @@
+/*
+ * linux/drivers/ide/pci/sl82c105.c
+ *
+ * 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
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+#include <asm/dma.h>
+
+#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 run-away
+ * timings.
+ */
+static unsigned int get_timing_sl82c105(ide_pio_data_t *p)
+{
+ unsigned int cmd_on;
+ unsigned int cmd_off;
+
+ cmd_on = (ide_pio_timings[p->pio_mode].active_time + 29) / 30;
+ cmd_off = (p->cycle_time - 30 * cmd_on + 29) / 30;
+
+ if (cmd_on > 32)
+ cmd_on = 32;
+ if (cmd_on == 0)
+ cmd_on = 1;
+
+ if (cmd_off > 32)
+ cmd_off = 32;
+ if (cmd_off == 0)
+ cmd_off = 1;
+
+ return (cmd_on - 1) << 8 | (cmd_off - 1) | (p->use_iordy ? 0x40 : 0x00);
+}
+
+/*
+ * Configure the drive and chipset for PIO
+ */
+static void config_for_pio(ide_drive_t *drive, int pio, int report, int chipset_only)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = hwif->pci_dev;
+ ide_pio_data_t p;
+ u16 drv_ctrl = 0x909;
+ unsigned int xfer_mode, reg;
+
+ DBG(("config_for_pio(drive:%s, pio:%d, report:%d, chipset_only:%d)\n",
+ drive->name, pio, report, chipset_only));
+
+ reg = (hwif->channel ? 0x4c : 0x44) + (drive->select.b.unit ? 4 : 0);
+
+ pio = ide_get_best_pio_mode(drive, pio, 5, &p);
+
+ xfer_mode = XFER_PIO_0 + pio;
+
+ if (chipset_only || ide_config_drive_speed(drive, xfer_mode) == 0) {
+ drv_ctrl = get_timing_sl82c105(&p);
+ drive->pio_speed = xfer_mode;
+ } else
+ drive->pio_speed = XFER_PIO_0;
+
+ if (drive->using_dma == 0) {
+ /*
+ * If we are actually using MW DMA, then we can not
+ * reprogram the interface drive control register.
+ */
+ pci_write_config_word(dev, reg, drv_ctrl);
+ pci_read_config_word(dev, reg, &drv_ctrl);
+
+ if (report) {
+ printk("%s: selected %s (%dns) (%04X)\n", drive->name,
+ ide_xfer_verbose(xfer_mode), p.cycle_time, drv_ctrl);
+ }
+ }
+}
+
+/*
+ * Configure the drive and the chipset for DMA
+ */
+static int config_for_dma (ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = hwif->pci_dev;
+ unsigned int reg;
+
+ DBG(("config_for_dma(drive:%s)\n", drive->name));
+
+ reg = (hwif->channel ? 0x4c : 0x44) + (drive->select.b.unit ? 4 : 0);
+
+ if (ide_config_drive_speed(drive, XFER_MW_DMA_2) != 0)
+ return 1;
+
+ pci_write_config_word(dev, reg, 0x0240);
+
+ return 0;
+}
+
+/*
+ * Check to see if the drive and
+ * chipset is capable of DMA mode
+ */
+
+static int sl82c105_check_drive (ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+
+ DBG(("sl82c105_check_drive(drive:%s)\n", drive->name));
+
+ do {
+ struct hd_driveid *id = drive->id;
+
+ if (!drive->autodma)
+ break;
+
+ if (!id || !(id->capability & 1))
+ break;
+
+ /* Consult the list of known "bad" drives */
+ if (__ide_dma_bad_drive(drive))
+ break;
+
+ if (id->field_valid & 2) {
+ if ((id->dma_mword & hwif->mwdma_mask) ||
+ (id->dma_1word & hwif->swdma_mask))
+ return hwif->ide_dma_on(drive);
+ }
+
+ if (__ide_dma_good_drive(drive))
+ return hwif->ide_dma_on(drive);
+ } while (0);
+
+ return hwif->ide_dma_off_quietly(drive);
+}
+
+/*
+ * 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 int sl82c105_ide_dma_lost_irq(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = hwif->pci_dev;
+ u32 val, mask = hwif->channel ? CTRL_IDE_IRQB : CTRL_IDE_IRQA;
+ unsigned long dma_base = hwif->dma_base;
+
+ 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.
+ */
+ val = hwif->INB(dma_base);
+ if (val & 1) {
+ outb(val & ~1, dma_base);
+ printk("sl82c105: DMA was enabled\n");
+ }
+
+ sl82c105_reset_host(dev);
+
+ /* ide_dmaproc would return 1, so we do as well */
+ return 1;
+}
+
+/*
+ * 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_ide_dma_start(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = hwif->pci_dev;
+
+ sl82c105_reset_host(dev);
+ ide_dma_start(drive);
+}
+
+static int sl82c105_ide_dma_timeout(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = hwif->pci_dev;
+
+ DBG(("sl82c105_ide_dma_timeout(drive:%s)\n", drive->name));
+
+ sl82c105_reset_host(dev);
+ return __ide_dma_timeout(drive);
+}
+
+static int sl82c105_ide_dma_on (ide_drive_t *drive)
+{
+ DBG(("sl82c105_ide_dma_on(drive:%s)\n", drive->name));
+
+ if (config_for_dma(drive)) {
+ config_for_pio(drive, 4, 0, 0);
+ return HWIF(drive)->ide_dma_off_quietly(drive);
+ }
+ printk(KERN_INFO "%s: DMA enabled\n", drive->name);
+ return __ide_dma_on(drive);
+}
+
+static int sl82c105_ide_dma_off_quietly (ide_drive_t *drive)
+{
+ u8 speed = XFER_PIO_0;
+ int rc;
+
+ DBG(("sl82c105_ide_dma_off_quietly(drive:%s)\n", drive->name));
+
+ rc = __ide_dma_off_quietly(drive);
+ if (drive->pio_speed)
+ speed = drive->pio_speed - XFER_PIO_0;
+ config_for_pio(drive, speed, 0, 1);
+ drive->current_speed = drive->pio_speed;
+
+ return rc;
+}
+
+/*
+ * Ok, that is nasty, but we must make sure the DMA timings
+ * won't be used for a PIO access. The solution here is
+ * to make sure the 16 bits mode is diabled on the channel
+ * when DMA is enabled, thus causing the chip to use PIO0
+ * timings for those operations.
+ */
+static void sl82c105_selectproc(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = hwif->pci_dev;
+ u32 val, old, mask;
+
+ //DBG(("sl82c105_selectproc(drive:%s)\n", drive->name));
+
+ mask = hwif->channel ? CTRL_P1F16 : CTRL_P0F16;
+ old = val = *((u32 *)&hwif->hwif_data);
+ if (drive->using_dma)
+ val &= ~mask;
+ else
+ val |= mask;
+ if (old != val) {
+ pci_write_config_dword(dev, 0x40, val);
+ *((u32 *)&hwif->hwif_data) = val;
+ }
+}
+
+/*
+ * ATA reset will clear the 16 bits mode in the control
+ * register, we need to update our cache
+ */
+static void sl82c105_resetproc(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = hwif->pci_dev;
+ u32 val;
+
+ DBG(("sl82c105_resetproc(drive:%s)\n", drive->name));
+
+ pci_read_config_dword(dev, 0x40, &val);
+ *((u32 *)&hwif->hwif_data) = val;
+}
+
+/*
+ * We only deal with PIO mode here - DMA mode 'using_dma' is not
+ * initialised at the point that this function is called.
+ */
+static void tune_sl82c105(ide_drive_t *drive, u8 pio)
+{
+ DBG(("tune_sl82c105(drive:%s)\n", drive->name));
+
+ config_for_pio(drive, pio, 1, 0);
+
+ /*
+ * We support 32-bit I/O on this interface, and it
+ * doesn't have problems with interrupts.
+ */
+ drive->io_32bit = 1;
+ drive->unmask = 1;
+}
+
+/*
+ * Return the revision of the Winbond bridge
+ * which this function is part of.
+ */
+static unsigned int sl82c105_bridge_revision(struct pci_dev *dev)
+{
+ struct pci_dev *bridge;
+ u8 rev;
+
+ /*
+ * The bridge should be part of the same device, but function 0.
+ */
+ bridge = pci_find_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)
+ return -1;
+
+ /*
+ * We need to find function 0's revision, not function 1
+ */
+ pci_read_config_byte(bridge, PCI_REVISION_ID, &rev);
+
+ return rev;
+}
+
+/*
+ * 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 init_chipset_sl82c105(struct pci_dev *dev, const char *msg)
+{
+ 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 void __init init_dma_sl82c105(ide_hwif_t *hwif, unsigned long dma_base)
+{
+ unsigned int rev;
+ u8 dma_state;
+
+ DBG(("init_dma_sl82c105(hwif: ide%d, dma_base: 0x%08x)\n", hwif->index, dma_base));
+
+ hwif->autodma = 0;
+
+ if (!dma_base)
+ return;
+
+ dma_state = hwif->INB(dma_base + 2);
+ rev = sl82c105_bridge_revision(hwif->pci_dev);
+ if (rev <= 5) {
+ printk(" %s: Winbond 553 bridge revision %d, BM-DMA disabled\n",
+ hwif->name, rev);
+ dma_state &= ~0x60;
+ } else {
+ dma_state |= 0x60;
+ if (!noautodma)
+ hwif->autodma = 1;
+ }
+ hwif->OUTB(dma_state, dma_base + 2);
+
+ ide_setup_dma(hwif, dma_base, 8);
+}
+
+/*
+ * Initialise the chip
+ */
+
+static void __init init_hwif_sl82c105(ide_hwif_t *hwif)
+{
+ struct pci_dev *dev = hwif->pci_dev;
+ u32 val;
+
+ DBG(("init_hwif_sl82c105(hwif: ide%d)\n", hwif->index));
+
+ hwif->tuneproc = tune_sl82c105;
+ hwif->selectproc = sl82c105_selectproc;
+ hwif->resetproc = sl82c105_resetproc;
+
+ /* Default to PIO 0 for fallback unless tuned otherwise,
+ * we always autotune PIO, this is done before DMA is
+ * checked, so there is no risk of accidentally disabling
+ * DMA
+ */
+ hwif->drives[0].pio_speed = XFER_PIO_0;
+ hwif->drives[0].autotune = 1;
+ hwif->drives[1].pio_speed = XFER_PIO_1;
+ hwif->drives[1].autotune = 1;
+
+ pci_read_config_dword(dev, 0x40, &val);
+ *((u32 *)&hwif->hwif_data) = val;
+
+ if (!hwif->dma_base)
+ return;
+
+ hwif->atapi_dma = 1;
+ hwif->mwdma_mask = 0x07;
+ hwif->swdma_mask = 0x07;
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+ hwif->ide_dma_check = &sl82c105_check_drive;
+ hwif->ide_dma_on = &sl82c105_ide_dma_on;
+ hwif->ide_dma_off_quietly = &sl82c105_ide_dma_off_quietly;
+ hwif->ide_dma_lostirq = &sl82c105_ide_dma_lost_irq;
+ hwif->dma_start = &sl82c105_ide_dma_start;
+ hwif->ide_dma_timeout = &sl82c105_ide_dma_timeout;
+
+ if (!noautodma)
+ hwif->autodma = 1;
+ hwif->drives[0].autodma = hwif->autodma;
+ hwif->drives[1].autodma = hwif->autodma;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+}
+
+static ide_pci_device_t sl82c105_chipset __devinitdata = {
+ .name = "W82C105",
+ .init_chipset = init_chipset_sl82c105,
+ .init_hwif = init_hwif_sl82c105,
+ .init_dma = init_dma_sl82c105,
+ .channels = 2,
+ .autodma = NOAUTODMA,
+ .enablebits = {{0x40,0x01,0x01}, {0x40,0x10,0x10}},
+ .bootable = ON_BOARD,
+};
+
+static int __devinit sl82c105_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ return ide_setup_pci_device(dev, &sl82c105_chipset);
+}
+
+static struct pci_device_id sl82c105_pci_tbl[] = {
+ { PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { 0, },
+};
+MODULE_DEVICE_TABLE(pci, sl82c105_pci_tbl);
+
+static struct pci_driver driver = {
+ .name = "W82C105_IDE",
+ .id_table = sl82c105_pci_tbl,
+ .probe = sl82c105_init_one,
+};
+
+static int sl82c105_ide_init(void)
+{
+ return ide_pci_register_driver(&driver);
+}
+
+module_init(sl82c105_ide_init);
+
+MODULE_DESCRIPTION("PCI driver module for W82C105 IDE");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/pci/slc90e66.c b/drivers/ide/pci/slc90e66.c
new file mode 100644
index 000000000000..7fbf36342f73
--- /dev/null
+++ b/drivers/ide/pci/slc90e66.c
@@ -0,0 +1,273 @@
+/*
+ * linux/drivers/ide/pci/slc90e66.c Version 0.11 September 11, 2002
+ *
+ * Copyright (C) 2000-2002 Andre Hedrick <andre@linux-ide.org>
+ *
+ * This a look-a-like variation of the ICH0 PIIX4 Ultra-66,
+ * but this keeps the ISA-Bridge and slots alive.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+static u8 slc90e66_ratemask (ide_drive_t *drive)
+{
+ u8 mode = 2;
+
+ if (!eighty_ninty_three(drive))
+ mode = min(mode, (u8)1);
+ return mode;
+}
+
+static u8 slc90e66_dma_2_pio (u8 xfer_rate) {
+ switch(xfer_rate) {
+ case XFER_UDMA_4:
+ case XFER_UDMA_3:
+ case XFER_UDMA_2:
+ case XFER_UDMA_1:
+ case XFER_UDMA_0:
+ case XFER_MW_DMA_2:
+ case XFER_PIO_4:
+ return 4;
+ case XFER_MW_DMA_1:
+ case XFER_PIO_3:
+ return 3;
+ case XFER_SW_DMA_2:
+ case XFER_PIO_2:
+ return 2;
+ case XFER_MW_DMA_0:
+ case XFER_SW_DMA_1:
+ case XFER_SW_DMA_0:
+ case XFER_PIO_1:
+ case XFER_PIO_0:
+ case XFER_PIO_SLOW:
+ default:
+ return 0;
+ }
+}
+
+/*
+ * Based on settings done by AMI BIOS
+ * (might be useful if drive is not registered in CMOS for any reason).
+ */
+static void slc90e66_tune_drive (ide_drive_t *drive, u8 pio)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = hwif->pci_dev;
+ int is_slave = (&hwif->drives[1] == drive);
+ int master_port = hwif->channel ? 0x42 : 0x40;
+ int slave_port = 0x44;
+ unsigned long flags;
+ u16 master_data;
+ u8 slave_data;
+ /* ISP RTC */
+ u8 timings[][2] = { { 0, 0 },
+ { 0, 0 },
+ { 1, 0 },
+ { 2, 1 },
+ { 2, 3 }, };
+
+ pio = ide_get_best_pio_mode(drive, pio, 5, NULL);
+ spin_lock_irqsave(&ide_lock, flags);
+ pci_read_config_word(dev, master_port, &master_data);
+ if (is_slave) {
+ master_data = master_data | 0x4000;
+ if (pio > 1)
+ /* enable PPE, IE and TIME */
+ master_data = master_data | 0x0070;
+ pci_read_config_byte(dev, slave_port, &slave_data);
+ slave_data = slave_data & (hwif->channel ? 0x0f : 0xf0);
+ slave_data = slave_data | (((timings[pio][0] << 2) | timings[pio][1]) << (hwif->channel ? 4 : 0));
+ } else {
+ master_data = master_data & 0xccf8;
+ if (pio > 1)
+ /* enable PPE, IE and TIME */
+ master_data = master_data | 0x0007;
+ 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(&ide_lock, flags);
+}
+
+static int slc90e66_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = hwif->pci_dev;
+ u8 maslave = hwif->channel ? 0x42 : 0x40;
+ u8 speed = ide_rate_filter(slc90e66_ratemask(drive), xferspeed);
+ 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);
+
+ switch(speed) {
+#ifdef CONFIG_BLK_DEV_IDEDMA
+ case XFER_UDMA_4: u_speed = 4 << (drive->dn * 4); break;
+ case XFER_UDMA_3: u_speed = 3 << (drive->dn * 4); break;
+ case XFER_UDMA_2: u_speed = 2 << (drive->dn * 4); break;
+ case XFER_UDMA_1: u_speed = 1 << (drive->dn * 4); break;
+ case XFER_UDMA_0: u_speed = 0 << (drive->dn * 4); break;
+ case XFER_MW_DMA_2:
+ case XFER_MW_DMA_1:
+ case XFER_SW_DMA_2: break;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+ case XFER_PIO_4:
+ case XFER_PIO_3:
+ case XFER_PIO_2:
+ case XFER_PIO_0: break;
+ default: return -1;
+ }
+
+ if (speed >= XFER_UDMA_0) {
+ 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 {
+ 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);
+ }
+
+ slc90e66_tune_drive(drive, slc90e66_dma_2_pio(speed));
+ return (ide_config_drive_speed(drive, speed));
+}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+static int slc90e66_config_drive_for_dma (ide_drive_t *drive)
+{
+ u8 speed = ide_dma_speed(drive, slc90e66_ratemask(drive));
+
+ if (!(speed)) {
+ u8 tspeed = ide_get_best_pio_mode(drive, 255, 5, NULL);
+ speed = slc90e66_dma_2_pio(XFER_PIO_0 + tspeed);
+ }
+
+ (void) slc90e66_tune_chipset(drive, speed);
+ return ide_dma_enable(drive);
+}
+
+static int slc90e66_config_drive_xfer_rate (ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct hd_driveid *id = drive->id;
+
+ drive->init_speed = 0;
+
+ if (id && (id->capability & 1) && drive->autodma) {
+
+ if (ide_use_dma(drive)) {
+ if (slc90e66_config_drive_for_dma(drive))
+ return hwif->ide_dma_on(drive);
+ }
+
+ goto fast_ata_pio;
+
+ } else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+ hwif->tuneproc(drive, 5);
+ return hwif->ide_dma_off_quietly(drive);
+ }
+ /* IORDY not supported */
+ return 0;
+}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
+static void __init init_hwif_slc90e66 (ide_hwif_t *hwif)
+{
+ u8 reg47 = 0;
+ u8 mask = hwif->channel ? 0x01 : 0x02; /* bit0:Primary */
+
+ hwif->autodma = 0;
+
+ if (!hwif->irq)
+ hwif->irq = hwif->channel ? 15 : 14;
+
+ hwif->speedproc = &slc90e66_tune_chipset;
+ hwif->tuneproc = &slc90e66_tune_drive;
+
+ pci_read_config_byte(hwif->pci_dev, 0x47, &reg47);
+
+ if (!hwif->dma_base) {
+ hwif->drives[0].autotune = 1;
+ hwif->drives[1].autotune = 1;
+ return;
+ }
+
+ hwif->atapi_dma = 1;
+ hwif->ultra_mask = 0x1f;
+ hwif->mwdma_mask = 0x07;
+ hwif->swdma_mask = 0x07;
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+ if (!(hwif->udma_four))
+ /* bit[0(1)]: 0:80, 1:40 */
+ hwif->udma_four = (reg47 & mask) ? 0 : 1;
+
+ hwif->ide_dma_check = &slc90e66_config_drive_xfer_rate;
+ if (!noautodma)
+ hwif->autodma = 1;
+ hwif->drives[0].autodma = hwif->autodma;
+ hwif->drives[1].autodma = hwif->autodma;
+#endif /* !CONFIG_BLK_DEV_IDEDMA */
+}
+
+static ide_pci_device_t slc90e66_chipset __devinitdata = {
+ .name = "SLC90E66",
+ .init_hwif = init_hwif_slc90e66,
+ .channels = 2,
+ .autodma = AUTODMA,
+ .enablebits = {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
+ .bootable = ON_BOARD,
+};
+
+static int __devinit slc90e66_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ return ide_setup_pci_device(dev, &slc90e66_chipset);
+}
+
+static struct pci_device_id slc90e66_pci_tbl[] = {
+ { PCI_VENDOR_ID_EFAR, PCI_DEVICE_ID_EFAR_SLC90E66_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { 0, },
+};
+MODULE_DEVICE_TABLE(pci, slc90e66_pci_tbl);
+
+static struct pci_driver driver = {
+ .name = "SLC90e66_IDE",
+ .id_table = slc90e66_pci_tbl,
+ .probe = slc90e66_init_one,
+};
+
+static int slc90e66_ide_init(void)
+{
+ return ide_pci_register_driver(&driver);
+}
+
+module_init(slc90e66_ide_init);
+
+MODULE_AUTHOR("Andre Hedrick");
+MODULE_DESCRIPTION("PCI driver module for SLC90E66 IDE");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/pci/triflex.c b/drivers/ide/pci/triflex.c
new file mode 100644
index 000000000000..a1df2bfe3631
--- /dev/null
+++ b/drivers/ide/pci/triflex.c
@@ -0,0 +1,188 @@
+/*
+ * triflex.c
+ *
+ * IDE Chipset driver for the Compaq TriFlex IDE controller.
+ *
+ * Known to work with the Compaq Workstation 5x00 series.
+ *
+ * Copyright (C) 2002 Hewlett-Packard Development Group, L.P.
+ * Author: Torben Mathiasen <torben.mathiasen@hp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Loosely based on the piix & svwks drivers.
+ *
+ * Documentation:
+ * Not publically available.
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/module.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/hdreg.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+static int triflex_tune_chipset(ide_drive_t *drive, u8 xferspeed)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = hwif->pci_dev;
+ u8 channel_offset = hwif->channel ? 0x74 : 0x70;
+ u16 timing = 0;
+ u32 triflex_timings = 0;
+ u8 unit = (drive->select.b.unit & 0x01);
+ u8 speed = ide_rate_filter(0, xferspeed);
+
+ 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;
+ default:
+ return -1;
+ }
+
+ triflex_timings &= ~(0xFFFF << (16 * unit));
+ triflex_timings |= (timing << (16 * unit));
+
+ pci_write_config_dword(dev, channel_offset, triflex_timings);
+
+ return (ide_config_drive_speed(drive, speed));
+}
+
+static void triflex_tune_drive(ide_drive_t *drive, u8 pio)
+{
+ int use_pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+ (void) triflex_tune_chipset(drive, (XFER_PIO_0 + use_pio));
+}
+
+static int triflex_config_drive_for_dma(ide_drive_t *drive)
+{
+ int speed = ide_dma_speed(drive, 0); /* No ultra speeds */
+
+ if (!speed) {
+ u8 pspeed = ide_get_best_pio_mode(drive, 255, 4, NULL);
+ speed = XFER_PIO_0 + pspeed;
+ }
+
+ (void) triflex_tune_chipset(drive, speed);
+ return ide_dma_enable(drive);
+}
+
+static int triflex_config_drive_xfer_rate(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct hd_driveid *id = drive->id;
+
+ if ((id->capability & 1) && drive->autodma) {
+ if (ide_use_dma(drive)) {
+ if (triflex_config_drive_for_dma(drive))
+ return hwif->ide_dma_on(drive);
+ }
+ }
+
+ hwif->tuneproc(drive, 255);
+ return hwif->ide_dma_off_quietly(drive);
+}
+
+static void __init init_hwif_triflex(ide_hwif_t *hwif)
+{
+ hwif->tuneproc = &triflex_tune_drive;
+ hwif->speedproc = &triflex_tune_chipset;
+
+ hwif->atapi_dma = 1;
+ hwif->mwdma_mask = 0x07;
+ hwif->swdma_mask = 0x07;
+ hwif->ide_dma_check = &triflex_config_drive_xfer_rate;
+
+ if (!noautodma)
+ hwif->autodma = 1;
+ hwif->drives[0].autodma = hwif->autodma;
+ hwif->drives[1].autodma = hwif->autodma;
+}
+
+static ide_pci_device_t triflex_device __devinitdata = {
+ .name = "TRIFLEX",
+ .init_hwif = init_hwif_triflex,
+ .channels = 2,
+ .autodma = AUTODMA,
+ .enablebits = {{0x80, 0x01, 0x01}, {0x80, 0x02, 0x02}},
+ .bootable = ON_BOARD,
+};
+
+static int __devinit triflex_init_one(struct pci_dev *dev,
+ const struct pci_device_id *id)
+{
+ return ide_setup_pci_device(dev, &triflex_device);
+}
+
+static struct pci_device_id triflex_pci_tbl[] = {
+ { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_TRIFLEX_IDE,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { 0, },
+};
+MODULE_DEVICE_TABLE(pci, triflex_pci_tbl);
+
+static struct pci_driver driver = {
+ .name = "TRIFLEX_IDE",
+ .id_table = triflex_pci_tbl,
+ .probe = triflex_init_one,
+};
+
+static int triflex_ide_init(void)
+{
+ return ide_pci_register_driver(&driver);
+}
+
+module_init(triflex_ide_init);
+
+MODULE_AUTHOR("Torben Mathiasen");
+MODULE_DESCRIPTION("PCI driver module for Compaq Triflex IDE");
+MODULE_LICENSE("GPL");
+
+
diff --git a/drivers/ide/pci/trm290.c b/drivers/ide/pci/trm290.c
new file mode 100644
index 000000000000..8b5eea5405ef
--- /dev/null
+++ b/drivers/ide/pci/trm290.c
@@ -0,0 +1,369 @@
+/*
+ * linux/drivers/ide/pci/trm290.c Version 1.02 Mar. 18, 2000
+ *
+ * Copyright (c) 1997-1998 Mark Lord
+ * May be copied or modified under the terms of the GNU General Public License
+ *
+ * June 22, 2004 - get rid of check_region
+ * Jesper Juhl <juhl-lkml@dif.dk>
+ *
+ */
+
+/*
+ * 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/config.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/init.h>
+#include <linux/hdreg.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/ide.h>
+
+#include <asm/io.h>
+
+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 */
+ hwif->OUTB(0x51|(hwif->channel<<3), hwif->config_data+1);
+ hwif->OUTW(reg & 0xff, hwif->config_data);
+ }
+
+ /* enable IRQ if not probing */
+ if (drive->present) {
+ reg = hwif->INW(hwif->config_data + 3);
+ reg &= 0x13;
+ reg &= ~(1 << hwif->channel);
+ hwif->OUTW(reg, hwif->config_data+3);
+ }
+
+ local_irq_restore(flags);
+}
+
+static void trm290_selectproc (ide_drive_t *drive)
+{
+ trm290_prepare_drive(drive, drive->using_dma);
+}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+static void trm290_ide_dma_exec_cmd(ide_drive_t *drive, u8 command)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+
+ if (HWGROUP(drive)->handler != NULL) /* paranoia check */
+ BUG();
+ ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL);
+ /* issue cmd to drive */
+ hwif->OUTB(command, IDE_COMMAND_REG);
+}
+
+static int trm290_ide_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);
+ hwif->OUTL(hwif->dmatable_dma|rw, hwif->dma_command);
+ drive->waiting_for_dma = 1;
+ /* start DMA */
+ hwif->OUTW((count * 2) - 1, hwif->dma_status);
+ return 0;
+}
+
+static void trm290_ide_dma_start(ide_drive_t *drive)
+{
+}
+
+static int trm290_ide_dma_end (ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ u16 status = 0;
+
+ drive->waiting_for_dma = 0;
+ /* purge DMA mappings */
+ ide_destroy_dmatable(drive);
+ status = hwif->INW(hwif->dma_status);
+ return (status != 0x00ff);
+}
+
+static int trm290_ide_dma_test_irq (ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ u16 status = 0;
+
+ status = hwif->INW(hwif->dma_status);
+ return (status == 0x00ff);
+}
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
+/*
+ * Invoked from ide-dma.c at boot time.
+ */
+static void __devinit init_hwif_trm290(ide_hwif_t *hwif)
+{
+ unsigned int cfgbase = 0;
+ unsigned long flags;
+ u8 reg = 0;
+ struct pci_dev *dev = hwif->pci_dev;
+
+ hwif->no_lba48 = 1;
+ hwif->chipset = ide_trm290;
+ cfgbase = pci_resource_start(dev, 4);
+ if ((dev->class & 5) && cfgbase) {
+ hwif->config_data = cfgbase;
+ printk(KERN_INFO "TRM290: chip config base at 0x%04lx\n",
+ hwif->config_data);
+ } else {
+ hwif->config_data = 0x3df0;
+ printk(KERN_INFO "TRM290: using default config base at 0x%04lx\n",
+ hwif->config_data);
+ }
+
+ local_irq_save(flags);
+ /* put config reg into first byte of hwif->select_data */
+ hwif->OUTB(0x51|(hwif->channel<<3), hwif->config_data+1);
+ /* select PIO as default */
+ hwif->select_data = 0x21;
+ hwif->OUTB(hwif->select_data, hwif->config_data);
+ /* get IRQ info */
+ reg = hwif->INB(hwif->config_data+3);
+ /* mask IRQs for both ports */
+ reg = (reg & 0x10) | 0x03;
+ hwif->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;
+
+ ide_setup_dma(hwif, (hwif->config_data + 4) ^ (hwif->channel ? 0x0080 : 0x0000), 3);
+
+#ifdef CONFIG_BLK_DEV_IDEDMA
+ hwif->dma_setup = &trm290_ide_dma_setup;
+ hwif->dma_exec_cmd = &trm290_ide_dma_exec_cmd;
+ hwif->dma_start = &trm290_ide_dma_start;
+ hwif->ide_dma_end = &trm290_ide_dma_end;
+ hwif->ide_dma_test_irq = &trm290_ide_dma_test_irq;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+
+ hwif->selectproc = &trm290_selectproc;
+ hwif->autodma = 0; /* play it safe for now */
+ hwif->drives[0].autodma = hwif->autodma;
+ hwif->drives[1].autodma = hwif->autodma;
+#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;
+
+ hwif->OUTB(0x54|(hwif->channel<<3), hwif->config_data+1);
+ old = hwif->INW(hwif->config_data);
+ old &= ~1;
+ old_mask = hwif->INB(old+2);
+ if (old != compat && old_mask == 0xff) {
+ /* leave lower 10 bits untouched */
+ compat += (next_offset += 0x400);
+ hwif->io_ports[IDE_CONTROL_OFFSET] = compat + 2;
+ hwif->OUTW(compat|1, hwif->config_data);
+ new = hwif->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 ide_pci_device_t trm290_chipset __devinitdata = {
+ .name = "TRM290",
+ .init_hwif = init_hwif_trm290,
+ .channels = 2,
+ .autodma = NOAUTODMA,
+ .bootable = ON_BOARD,
+};
+
+static int __devinit trm290_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ return ide_setup_pci_device(dev, &trm290_chipset);
+}
+
+static struct pci_device_id trm290_pci_tbl[] = {
+ { PCI_VENDOR_ID_TEKRAM, PCI_DEVICE_ID_TEKRAM_DC290, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { 0, },
+};
+MODULE_DEVICE_TABLE(pci, trm290_pci_tbl);
+
+static struct pci_driver driver = {
+ .name = "TRM290_IDE",
+ .id_table = trm290_pci_tbl,
+ .probe = trm290_init_one,
+};
+
+static int trm290_ide_init(void)
+{
+ return ide_pci_register_driver(&driver);
+}
+
+module_init(trm290_ide_init);
+
+MODULE_AUTHOR("Mark Lord");
+MODULE_DESCRIPTION("PCI driver module for Tekram TRM290 IDE");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/pci/via82cxxx.c b/drivers/ide/pci/via82cxxx.c
new file mode 100644
index 000000000000..069dbffe2116
--- /dev/null
+++ b/drivers/ide/pci/via82cxxx.c
@@ -0,0 +1,656 @@
+/*
+ *
+ * Version 3.38
+ *
+ * VIA IDE driver for Linux. Supported southbridges:
+ *
+ * vt82c576, vt82c586, vt82c586a, vt82c586b, vt82c596a, vt82c596b,
+ * vt82c686, vt82c686a, vt82c686b, vt8231, vt8233, vt8233c, vt8233a,
+ * vt8235, vt8237
+ *
+ * Copyright (c) 2000-2002 Vojtech Pavlik
+ *
+ * Based on the work of:
+ * Michel Aubry
+ * Jeff Garzik
+ * Andre Hedrick
+ *
+ * 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/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/ide.h>
+#include <asm/io.h>
+
+#ifdef CONFIG_PPC_MULTIPLATFORM
+#include <asm/processor.h>
+#endif
+
+#include "ide-timing.h"
+
+#define DISPLAY_VIA_TIMINGS
+
+#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_UDMA 0x007
+#define VIA_UDMA_NONE 0x000
+#define VIA_UDMA_33 0x001
+#define VIA_UDMA_66 0x002
+#define VIA_UDMA_100 0x003
+#define VIA_UDMA_133 0x004
+#define VIA_BAD_PREQ 0x010 /* Crashes if PREQ# till DDACK# set */
+#define VIA_BAD_CLK66 0x020 /* 66 MHz clock doesn't work correctly */
+#define VIA_SET_FIFO 0x040 /* Needs to have FIFO split set */
+#define VIA_NO_UNMASK 0x080 /* Doesn't work with IRQ unmasking on */
+#define VIA_BAD_ID 0x100 /* Has wrong vendor ID (0x1107) */
+#define VIA_BAD_AST 0x200 /* Don't touch Address Setup Timing */
+
+/*
+ * VIA SouthBridge chips.
+ */
+
+static struct via_isa_bridge {
+ char *name;
+ u16 id;
+ u8 rev_min;
+ u8 rev_max;
+ u16 flags;
+} via_isa_bridges[] = {
+ { "vt8237", PCI_DEVICE_ID_VIA_8237, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
+ { "vt8235", PCI_DEVICE_ID_VIA_8235, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
+ { "vt8233a", PCI_DEVICE_ID_VIA_8233A, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
+ { "vt8233c", PCI_DEVICE_ID_VIA_8233C_0, 0x00, 0x2f, VIA_UDMA_100 },
+ { "vt8233", PCI_DEVICE_ID_VIA_8233_0, 0x00, 0x2f, VIA_UDMA_100 },
+ { "vt8231", PCI_DEVICE_ID_VIA_8231, 0x00, 0x2f, VIA_UDMA_100 },
+ { "vt82c686b", PCI_DEVICE_ID_VIA_82C686, 0x40, 0x4f, VIA_UDMA_100 },
+ { "vt82c686a", PCI_DEVICE_ID_VIA_82C686, 0x10, 0x2f, VIA_UDMA_66 },
+ { "vt82c686", PCI_DEVICE_ID_VIA_82C686, 0x00, 0x0f, VIA_UDMA_33 | VIA_BAD_CLK66 },
+ { "vt82c596b", PCI_DEVICE_ID_VIA_82C596, 0x10, 0x2f, VIA_UDMA_66 },
+ { "vt82c596a", PCI_DEVICE_ID_VIA_82C596, 0x00, 0x0f, VIA_UDMA_33 | VIA_BAD_CLK66 },
+ { "vt82c586b", PCI_DEVICE_ID_VIA_82C586_0, 0x47, 0x4f, VIA_UDMA_33 | VIA_SET_FIFO },
+ { "vt82c586b", PCI_DEVICE_ID_VIA_82C586_0, 0x40, 0x46, VIA_UDMA_33 | VIA_SET_FIFO | VIA_BAD_PREQ },
+ { "vt82c586b", PCI_DEVICE_ID_VIA_82C586_0, 0x30, 0x3f, VIA_UDMA_33 | VIA_SET_FIFO },
+ { "vt82c586a", PCI_DEVICE_ID_VIA_82C586_0, 0x20, 0x2f, VIA_UDMA_33 | VIA_SET_FIFO },
+ { "vt82c586", PCI_DEVICE_ID_VIA_82C586_0, 0x00, 0x0f, VIA_UDMA_NONE | VIA_SET_FIFO },
+ { "vt82c576", PCI_DEVICE_ID_VIA_82C576, 0x00, 0x2f, VIA_UDMA_NONE | VIA_SET_FIFO | VIA_NO_UNMASK },
+ { "vt82c576", PCI_DEVICE_ID_VIA_82C576, 0x00, 0x2f, VIA_UDMA_NONE | VIA_SET_FIFO | VIA_NO_UNMASK | VIA_BAD_ID },
+ { NULL }
+};
+
+static struct via_isa_bridge *via_config;
+static unsigned int via_80w;
+static unsigned int via_clock;
+static char *via_dma[] = { "MWDMA16", "UDMA33", "UDMA66", "UDMA100", "UDMA133" };
+
+/*
+ * VIA /proc entry.
+ */
+
+#if defined(DISPLAY_VIA_TIMINGS) && defined(CONFIG_PROC_FS)
+
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static u8 via_proc = 0;
+static unsigned long via_base;
+static struct pci_dev *bmide_dev, *isa_dev;
+
+static char *via_control3[] = { "No limit", "64", "128", "192" };
+
+#define via_print(format, arg...) p += sprintf(p, format "\n" , ## arg)
+#define via_print_drive(name, format, arg...)\
+ p += sprintf(p, name); for (i = 0; i < 4; i++) p += sprintf(p, format, ## arg); p += sprintf(p, "\n");
+
+
+/**
+ * via_get_info - generate via /proc file
+ * @buffer: buffer for data
+ * @addr: set to start of data to use
+ * @offset: current file offset
+ * @count: size of read
+ *
+ * Fills in buffer with the debugging/configuration information for
+ * the VIA chipset tuning and attached drives
+ */
+
+static int via_get_info(char *buffer, char **addr, off_t offset, int count)
+{
+ int speed[4], cycle[4], setup[4], active[4], recover[4], den[4],
+ uen[4], udma[4], umul[4], active8b[4], recover8b[4];
+ struct pci_dev *dev = bmide_dev;
+ unsigned int v, u, i;
+ int len;
+ u16 c, w;
+ u8 t, x;
+ char *p = buffer;
+
+ via_print("----------VIA BusMastering IDE Configuration"
+ "----------------");
+
+ via_print("Driver Version: 3.38");
+ via_print("South Bridge: VIA %s",
+ via_config->name);
+
+ pci_read_config_byte(isa_dev, PCI_REVISION_ID, &t);
+ pci_read_config_byte(dev, PCI_REVISION_ID, &x);
+ via_print("Revision: ISA %#x IDE %#x", t, x);
+ via_print("Highest DMA rate: %s",
+ via_dma[via_config->flags & VIA_UDMA]);
+
+ via_print("BM-DMA base: %#lx", via_base);
+ via_print("PCI clock: %d.%dMHz",
+ via_clock / 1000, via_clock / 100 % 10);
+
+ pci_read_config_byte(dev, VIA_MISC_1, &t);
+ via_print("Master Read Cycle IRDY: %dws",
+ (t & 64) >> 6);
+ via_print("Master Write Cycle IRDY: %dws",
+ (t & 32) >> 5);
+ via_print("BM IDE Status Register Read Retry: %s",
+ (t & 8) ? "yes" : "no");
+
+ pci_read_config_byte(dev, VIA_MISC_3, &t);
+ via_print("Max DRDY Pulse Width: %s%s",
+ via_control3[(t & 0x03)], (t & 0x03) ? " PCI clocks" : "");
+
+ via_print("-----------------------Primary IDE"
+ "-------Secondary IDE------");
+ via_print("Read DMA FIFO flush: %10s%20s",
+ (t & 0x80) ? "yes" : "no", (t & 0x40) ? "yes" : "no");
+ via_print("End Sector FIFO flush: %10s%20s",
+ (t & 0x20) ? "yes" : "no", (t & 0x10) ? "yes" : "no");
+
+ pci_read_config_byte(dev, VIA_IDE_CONFIG, &t);
+ via_print("Prefetch Buffer: %10s%20s",
+ (t & 0x80) ? "yes" : "no", (t & 0x20) ? "yes" : "no");
+ via_print("Post Write Buffer: %10s%20s",
+ (t & 0x40) ? "yes" : "no", (t & 0x10) ? "yes" : "no");
+
+ pci_read_config_byte(dev, VIA_IDE_ENABLE, &t);
+ via_print("Enabled: %10s%20s",
+ (t & 0x02) ? "yes" : "no", (t & 0x01) ? "yes" : "no");
+
+ c = inb(via_base + 0x02) | (inb(via_base + 0x0a) << 8);
+ via_print("Simplex only: %10s%20s",
+ (c & 0x80) ? "yes" : "no", (c & 0x8000) ? "yes" : "no");
+
+ via_print("Cable Type: %10s%20s",
+ (via_80w & 1) ? "80w" : "40w", (via_80w & 2) ? "80w" : "40w");
+
+ via_print("-------------------drive0----drive1"
+ "----drive2----drive3-----");
+
+ pci_read_config_byte(dev, VIA_ADDRESS_SETUP, &t);
+ pci_read_config_dword(dev, VIA_DRIVE_TIMING, &v);
+ pci_read_config_word(dev, VIA_8BIT_TIMING, &w);
+
+ if (via_config->flags & VIA_UDMA)
+ pci_read_config_dword(dev, VIA_UDMA_TIMING, &u);
+ else u = 0;
+
+ for (i = 0; i < 4; i++) {
+
+ setup[i] = ((t >> ((3 - i) << 1)) & 0x3) + 1;
+ recover8b[i] = ((w >> ((1 - (i >> 1)) << 3)) & 0xf) + 1;
+ active8b[i] = ((w >> (((1 - (i >> 1)) << 3) + 4)) & 0xf) + 1;
+ active[i] = ((v >> (((3 - i) << 3) + 4)) & 0xf) + 1;
+ recover[i] = ((v >> ((3 - i) << 3)) & 0xf) + 1;
+ udma[i] = ((u >> ((3 - i) << 3)) & 0x7) + 2;
+ umul[i] = ((u >> (((3 - i) & 2) << 3)) & 0x8) ? 1 : 2;
+ uen[i] = ((u >> ((3 - i) << 3)) & 0x20);
+ den[i] = (c & ((i & 1) ? 0x40 : 0x20) << ((i & 2) << 2));
+
+ speed[i] = 2 * via_clock / (active[i] + recover[i]);
+ cycle[i] = 1000000 * (active[i] + recover[i]) / via_clock;
+
+ if (!uen[i] || !den[i])
+ continue;
+
+ switch (via_config->flags & VIA_UDMA) {
+
+ case VIA_UDMA_33:
+ speed[i] = 2 * via_clock / udma[i];
+ cycle[i] = 1000000 * udma[i] / via_clock;
+ break;
+
+ case VIA_UDMA_66:
+ speed[i] = 4 * via_clock / (udma[i] * umul[i]);
+ cycle[i] = 500000 * (udma[i] * umul[i]) / via_clock;
+ break;
+
+ case VIA_UDMA_100:
+ speed[i] = 6 * via_clock / udma[i];
+ cycle[i] = 333333 * udma[i] / via_clock;
+ break;
+
+ case VIA_UDMA_133:
+ speed[i] = 8 * via_clock / udma[i];
+ cycle[i] = 250000 * udma[i] / via_clock;
+ break;
+ }
+ }
+
+ via_print_drive("Transfer Mode: ", "%10s",
+ den[i] ? (uen[i] ? "UDMA" : "DMA") : "PIO");
+
+ via_print_drive("Address Setup: ", "%8dns",
+ 1000000 * setup[i] / via_clock);
+ via_print_drive("Cmd Active: ", "%8dns",
+ 1000000 * active8b[i] / via_clock);
+ via_print_drive("Cmd Recovery: ", "%8dns",
+ 1000000 * recover8b[i] / via_clock);
+ via_print_drive("Data Active: ", "%8dns",
+ 1000000 * active[i] / via_clock);
+ via_print_drive("Data Recovery: ", "%8dns",
+ 1000000 * recover[i] / via_clock);
+ via_print_drive("Cycle Time: ", "%8dns",
+ cycle[i]);
+ via_print_drive("Transfer Rate: ", "%4d.%dMB/s",
+ speed[i] / 1000, speed[i] / 100 % 10);
+
+ /* hoping it is less than 4K... */
+ len = (p - buffer) - offset;
+ *addr = buffer + offset;
+
+ return len > count ? count : len;
+}
+
+#endif /* DISPLAY_VIA_TIMINGS && CONFIG_PROC_FS */
+
+/**
+ * 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(struct pci_dev *dev, u8 dn, struct ide_timing *timing)
+{
+ u8 t;
+
+ if (~via_config->flags & VIA_BAD_AST) {
+ pci_read_config_byte(dev, VIA_ADDRESS_SETUP, &t);
+ t = (t & ~(3 << ((3 - dn) << 1))) | ((FIT(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)),
+ ((FIT(timing->act8b, 1, 16) - 1) << 4) | (FIT(timing->rec8b, 1, 16) - 1));
+
+ pci_write_config_byte(dev, VIA_DRIVE_TIMING + (3 - dn),
+ ((FIT(timing->active, 1, 16) - 1) << 4) | (FIT(timing->recover, 1, 16) - 1));
+
+ switch (via_config->flags & VIA_UDMA) {
+ case VIA_UDMA_33: t = timing->udma ? (0xe0 | (FIT(timing->udma, 2, 5) - 2)) : 0x03; break;
+ case VIA_UDMA_66: t = timing->udma ? (0xe8 | (FIT(timing->udma, 2, 9) - 2)) : 0x0f; break;
+ case VIA_UDMA_100: t = timing->udma ? (0xe0 | (FIT(timing->udma, 2, 9) - 2)) : 0x07; break;
+ case VIA_UDMA_133: t = timing->udma ? (0xe0 | (FIT(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 drive and
+ * the chipset to a desired transfer mode. It also can be called
+ * by upper layers.
+ */
+
+static int via_set_drive(ide_drive_t *drive, u8 speed)
+{
+ ide_drive_t *peer = HWIF(drive)->drives + (~drive->dn & 1);
+ struct ide_timing t, p;
+ unsigned int T, UT;
+
+ if (speed != XFER_PIO_SLOW)
+ ide_config_drive_speed(drive, speed);
+
+ T = 1000000000 / via_clock;
+
+ switch (via_config->flags & VIA_UDMA) {
+ case VIA_UDMA_33: UT = T; break;
+ case VIA_UDMA_66: UT = T/2; break;
+ case VIA_UDMA_100: UT = T/3; break;
+ case VIA_UDMA_133: UT = T/4; break;
+ default: UT = T;
+ }
+
+ ide_timing_compute(drive, speed, &t, T, UT);
+
+ if (peer->present) {
+ ide_timing_compute(peer, peer->current_speed, &p, T, UT);
+ ide_timing_merge(&p, &t, &t, IDE_TIMING_8BIT);
+ }
+
+ via_set_speed(HWIF(drive)->pci_dev, drive->dn, &t);
+
+ if (!drive->init_speed)
+ drive->init_speed = speed;
+ drive->current_speed = speed;
+
+ return 0;
+}
+
+/**
+ * via82cxxx_tune_drive - PIO setup
+ * @drive: drive to set up
+ * @pio: mode to use (255 for 'best possible')
+ *
+ * A callback from the upper layers for PIO-only tuning.
+ */
+
+static void via82cxxx_tune_drive(ide_drive_t *drive, u8 pio)
+{
+ if (pio == 255) {
+ via_set_drive(drive,
+ ide_find_best_mode(drive, XFER_PIO | XFER_EPIO));
+ return;
+ }
+
+ via_set_drive(drive, XFER_PIO_0 + min_t(u8, pio, 5));
+}
+
+/**
+ * via82cxxx_ide_dma_check - set up for DMA if possible
+ * @drive: IDE drive to set up
+ *
+ * Set up the drive for the highest supported speed considering the
+ * driver, controller and cable
+ */
+
+static int via82cxxx_ide_dma_check (ide_drive_t *drive)
+{
+ u16 w80 = HWIF(drive)->udma_four;
+
+ u16 speed = ide_find_best_mode(drive,
+ XFER_PIO | XFER_EPIO | XFER_SWDMA | XFER_MWDMA |
+ (via_config->flags & VIA_UDMA ? XFER_UDMA : 0) |
+ (w80 && (via_config->flags & VIA_UDMA) >= VIA_UDMA_66 ? XFER_UDMA_66 : 0) |
+ (w80 && (via_config->flags & VIA_UDMA) >= VIA_UDMA_100 ? XFER_UDMA_100 : 0) |
+ (w80 && (via_config->flags & VIA_UDMA) >= VIA_UDMA_133 ? XFER_UDMA_133 : 0));
+
+ via_set_drive(drive, speed);
+
+ if (drive->autodma && (speed & XFER_MODE) != XFER_PIO)
+ return HWIF(drive)->ide_dma_on(drive);
+ return HWIF(drive)->ide_dma_off_quietly(drive);
+}
+
+/**
+ * init_chipset_via82cxxx - initialization handler
+ * @dev: PCI device
+ * @name: Name of interface
+ *
+ * The initialization callback. Here we determine the IDE chip type
+ * and initialize its drive independent registers.
+ */
+
+static unsigned int __init init_chipset_via82cxxx(struct pci_dev *dev, const char *name)
+{
+ struct pci_dev *isa = NULL;
+ u8 t, v;
+ unsigned int u;
+ int i;
+
+ /*
+ * Find the ISA bridge to see how good the IDE is.
+ */
+
+ for (via_config = via_isa_bridges; via_config->id; via_config++)
+ if ((isa = pci_find_device(PCI_VENDOR_ID_VIA +
+ !!(via_config->flags & VIA_BAD_ID),
+ via_config->id, NULL))) {
+
+ pci_read_config_byte(isa, PCI_REVISION_ID, &t);
+ if (t >= via_config->rev_min &&
+ t <= via_config->rev_max)
+ break;
+ }
+
+ if (!via_config->id) {
+ printk(KERN_WARNING "VP_IDE: Unknown VIA SouthBridge, disabling DMA.\n");
+ return -ENODEV;
+ }
+
+ /*
+ * Check 80-wire cable presence and setup Clk66.
+ */
+
+ switch (via_config->flags & VIA_UDMA) {
+
+ case VIA_UDMA_66:
+ /* Enable Clk66 */
+ pci_read_config_dword(dev, VIA_UDMA_TIMING, &u);
+ pci_write_config_dword(dev, VIA_UDMA_TIMING, u|0x80008);
+ 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
+ */
+ via_80w |= (1 << (1 - (i >> 4)));
+ }
+ break;
+
+ case VIA_UDMA_100:
+ pci_read_config_dword(dev, VIA_UDMA_TIMING, &u);
+ 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
+ */
+ via_80w |= (1 << (1 - (i >> 4)));
+ }
+ break;
+
+ case VIA_UDMA_133:
+ pci_read_config_dword(dev, VIA_UDMA_TIMING, &u);
+ 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
+ */
+ via_80w |= (1 << (1 - (i >> 4)));
+ }
+ break;
+
+ }
+
+ /* Disable Clk66 */
+ if (via_config->flags & VIA_BAD_CLK66) {
+ /* Would cause trouble on 596a and 686 */
+ pci_read_config_dword(dev, VIA_UDMA_TIMING, &u);
+ 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);
+
+ /*
+ * Determine system bus clock.
+ */
+
+ via_clock = system_bus_clock() * 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 "VP_IDE: User given PCI clock speed "
+ "impossible (%d), using 33 MHz instead.\n", via_clock);
+ printk(KERN_WARNING "VP_IDE: Use ide0=ata66 if you want "
+ "to assume 80-wire cable.\n");
+ via_clock = 33333;
+ }
+
+ /*
+ * Print the boot message.
+ */
+
+ pci_read_config_byte(isa, PCI_REVISION_ID, &t);
+ printk(KERN_INFO "VP_IDE: VIA %s (rev %02x) IDE %s "
+ "controller on pci%s\n",
+ via_config->name, t,
+ via_dma[via_config->flags & VIA_UDMA],
+ pci_name(dev));
+
+ /*
+ * Setup /proc/ide/via entry.
+ */
+
+#if defined(DISPLAY_VIA_TIMINGS) && defined(CONFIG_PROC_FS)
+ if (!via_proc) {
+ via_base = pci_resource_start(dev, 4);
+ bmide_dev = dev;
+ isa_dev = isa;
+ ide_pci_create_host_proc("via", via_get_info);
+ via_proc = 1;
+ }
+#endif /* DISPLAY_VIA_TIMINGS && CONFIG_PROC_FS */
+ return 0;
+}
+
+static void __init init_hwif_via82cxxx(ide_hwif_t *hwif)
+{
+ int i;
+
+ hwif->autodma = 0;
+
+ hwif->tuneproc = &via82cxxx_tune_drive;
+ hwif->speedproc = &via_set_drive;
+
+
+#if defined(CONFIG_PPC_MULTIPLATFORM) && defined(CONFIG_PPC32)
+ if(_machine == _MACH_chrp && _chrp_type == _CHRP_Pegasos) {
+ hwif->irq = hwif->channel ? 15 : 14;
+ }
+#endif
+
+ for (i = 0; i < 2; i++) {
+ hwif->drives[i].io_32bit = 1;
+ hwif->drives[i].unmask = (via_config->flags & VIA_NO_UNMASK) ? 0 : 1;
+ hwif->drives[i].autotune = 1;
+ hwif->drives[i].dn = hwif->channel * 2 + i;
+ }
+
+ if (!hwif->dma_base)
+ return;
+
+ hwif->atapi_dma = 1;
+ hwif->ultra_mask = 0x7f;
+ hwif->mwdma_mask = 0x07;
+ hwif->swdma_mask = 0x07;
+
+ if (!hwif->udma_four)
+ hwif->udma_four = (via_80w >> hwif->channel) & 1;
+ hwif->ide_dma_check = &via82cxxx_ide_dma_check;
+ if (!noautodma)
+ hwif->autodma = 1;
+ hwif->drives[0].autodma = hwif->autodma;
+ hwif->drives[1].autodma = hwif->autodma;
+}
+
+static ide_pci_device_t via82cxxx_chipset __devinitdata = {
+ .name = "VP_IDE",
+ .init_chipset = init_chipset_via82cxxx,
+ .init_hwif = init_hwif_via82cxxx,
+ .channels = 2,
+ .autodma = NOAUTODMA,
+ .enablebits = {{0x40,0x02,0x02}, {0x40,0x01,0x01}},
+ .bootable = ON_BOARD,
+};
+
+static int __devinit via_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ return ide_setup_pci_device(dev, &via82cxxx_chipset);
+}
+
+static struct pci_device_id via_pci_tbl[] = {
+ { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C576_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { 0, },
+};
+MODULE_DEVICE_TABLE(pci, via_pci_tbl);
+
+static struct pci_driver driver = {
+ .name = "VIA_IDE",
+ .id_table = via_pci_tbl,
+ .probe = via_init_one,
+};
+
+static int via_ide_init(void)
+{
+ return ide_pci_register_driver(&driver);
+}
+
+module_init(via_ide_init);
+
+MODULE_AUTHOR("Vojtech Pavlik, Michel Aubry, Jeff Garzik, Andre Hedrick");
+MODULE_DESCRIPTION("PCI driver module for VIA IDE");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/ppc/mpc8xx.c b/drivers/ide/ppc/mpc8xx.c
new file mode 100644
index 000000000000..b80c6135ae93
--- /dev/null
+++ b/drivers/ide/ppc/mpc8xx.c
@@ -0,0 +1,855 @@
+/*
+ * linux/drivers/ide/ppc/ide-m8xx.c
+ *
+ * Copyright (C) 2000, 2001 Wolfgang Denk, wd@denx.de
+ * Modified for direct IDE interface
+ * by Thomas Lange, thomas@corelatus.com
+ * Modified for direct IDE interface on 8xx without using the PCMCIA
+ * controller
+ * by Steven.Scholz@imc-berlin.de
+ * Moved out of arch/ppc/kernel/m8xx_setup.c, other minor cleanups
+ * by Mathew Locke <mattl@mvista.com>
+ */
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+#include <linux/tty.h>
+#include <linux/major.h>
+#include <linux/interrupt.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/ide.h>
+#include <linux/bootmem.h>
+
+#include <asm/mpc8xx.h>
+#include <asm/mmu.h>
+#include <asm/processor.h>
+#include <asm/residual.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/ide.h>
+#include <asm/8xx_immap.h>
+#include <asm/machdep.h>
+#include <asm/irq.h>
+
+static int identify (volatile u8 *p);
+static void print_fixed (volatile u8 *p);
+static void print_funcid (int func);
+static int check_ide_device (unsigned long base);
+
+static void ide_interrupt_ack (void *dev);
+static void m8xx_ide_tuneproc(ide_drive_t *drive, u8 pio);
+
+typedef struct ide_ioport_desc {
+ unsigned long base_off; /* Offset to PCMCIA memory */
+ unsigned long reg_off[IDE_NR_PORTS]; /* controller register offsets */
+ int irq; /* IRQ */
+} ide_ioport_desc_t;
+
+ide_ioport_desc_t ioport_dsc[MAX_HWIFS] = {
+#ifdef IDE0_BASE_OFFSET
+ { IDE0_BASE_OFFSET,
+ {
+ IDE0_DATA_REG_OFFSET,
+ IDE0_ERROR_REG_OFFSET,
+ IDE0_NSECTOR_REG_OFFSET,
+ IDE0_SECTOR_REG_OFFSET,
+ IDE0_LCYL_REG_OFFSET,
+ IDE0_HCYL_REG_OFFSET,
+ IDE0_SELECT_REG_OFFSET,
+ IDE0_STATUS_REG_OFFSET,
+ IDE0_CONTROL_REG_OFFSET,
+ IDE0_IRQ_REG_OFFSET,
+ },
+ IDE0_INTERRUPT,
+ },
+#ifdef IDE1_BASE_OFFSET
+ { IDE1_BASE_OFFSET,
+ {
+ IDE1_DATA_REG_OFFSET,
+ IDE1_ERROR_REG_OFFSET,
+ IDE1_NSECTOR_REG_OFFSET,
+ IDE1_SECTOR_REG_OFFSET,
+ IDE1_LCYL_REG_OFFSET,
+ IDE1_HCYL_REG_OFFSET,
+ IDE1_SELECT_REG_OFFSET,
+ IDE1_STATUS_REG_OFFSET,
+ IDE1_CONTROL_REG_OFFSET,
+ IDE1_IRQ_REG_OFFSET,
+ },
+ IDE1_INTERRUPT,
+ },
+#endif /* IDE1_BASE_OFFSET */
+#endif /* IDE0_BASE_OFFSET */
+};
+
+ide_pio_timings_t ide_pio_clocks[6];
+int hold_time[6] = {30, 20, 15, 10, 10, 10 }; /* PIO Mode 5 with IORDY (nonstandard) */
+
+/*
+ * Warning: only 1 (ONE) PCMCIA slot supported here,
+ * which must be correctly initialized by the firmware (PPCBoot).
+ */
+static int _slot_ = -1; /* will be read from PCMCIA registers */
+
+/* Make clock cycles and always round up */
+#define PCMCIA_MK_CLKS( t, T ) (( (t) * ((T)/1000000) + 999U ) / 1000U )
+
+
+
+/*
+ * IDE stuff.
+ */
+static int
+m8xx_ide_default_irq(unsigned long base)
+{
+#ifdef CONFIG_BLK_DEV_MPC8xx_IDE
+ if (base >= MAX_HWIFS)
+ return 0;
+
+ printk("[%d] m8xx_ide_default_irq %d\n",__LINE__,ioport_dsc[base].irq);
+
+ return (ioport_dsc[base].irq);
+#else
+ return 9;
+#endif
+}
+
+static unsigned long
+m8xx_ide_default_io_base(int index)
+{
+ return index;
+}
+
+#define M8XX_PCMCIA_CD2(slot) (0x10000000 >> (slot << 4))
+#define M8XX_PCMCIA_CD1(slot) (0x08000000 >> (slot << 4))
+
+/*
+ * The TQM850L hardware has two pins swapped! Grrrrgh!
+ */
+#ifdef CONFIG_TQM850L
+#define __MY_PCMCIA_GCRX_CXRESET PCMCIA_GCRX_CXOE
+#define __MY_PCMCIA_GCRX_CXOE PCMCIA_GCRX_CXRESET
+#else
+#define __MY_PCMCIA_GCRX_CXRESET PCMCIA_GCRX_CXRESET
+#define __MY_PCMCIA_GCRX_CXOE PCMCIA_GCRX_CXOE
+#endif
+
+#if defined(CONFIG_BLK_DEV_MPC8xx_IDE) && defined(CONFIG_IDE_8xx_PCCARD)
+#define PCMCIA_SCHLVL IDE0_INTERRUPT /* Status Change Interrupt Level */
+static int pcmcia_schlvl = PCMCIA_SCHLVL;
+#endif
+
+/*
+ * See include/linux/ide.h for definition of hw_regs_t (p, base)
+ */
+
+/*
+ * m8xx_ide_init_hwif_ports for a direct IDE interface _using_
+ */
+#if defined(CONFIG_IDE_8xx_PCCARD) || defined(CONFIG_IDE_8xx_DIRECT)
+static void
+m8xx_ide_init_hwif_ports(hw_regs_t *hw, unsigned long data_port,
+ unsigned long ctrl_port, int *irq)
+{
+ unsigned long *p = hw->io_ports;
+ int i;
+
+ typedef struct {
+ ulong br;
+ ulong or;
+ } pcmcia_win_t;
+ volatile pcmcia_win_t *win;
+ volatile pcmconf8xx_t *pcmp;
+
+ uint *pgcrx;
+ u32 pcmcia_phy_base;
+ u32 pcmcia_phy_end;
+ static unsigned long pcmcia_base = 0;
+ unsigned long base;
+
+ *p = 0;
+ if (irq)
+ *irq = 0;
+
+ pcmp = (pcmconf8xx_t *)(&(((immap_t *)IMAP_ADDR)->im_pcmcia));
+
+ if (!pcmcia_base) {
+ /*
+ * Read out PCMCIA registers. Since the reset values
+ * are undefined, we sure hope that they have been
+ * set up by firmware
+ */
+
+ /* Scan all registers for valid settings */
+ pcmcia_phy_base = 0xFFFFFFFF;
+ pcmcia_phy_end = 0;
+ /* br0 is start of brX and orX regs */
+ win = (pcmcia_win_t *) \
+ (&(((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pbr0));
+ for (i = 0; i < 8; i++) {
+ if (win->or & 1) { /* This bank is marked as valid */
+ if (win->br < pcmcia_phy_base) {
+ pcmcia_phy_base = win->br;
+ }
+ if ((win->br + PCMCIA_MEM_SIZE) > pcmcia_phy_end) {
+ pcmcia_phy_end = win->br + PCMCIA_MEM_SIZE;
+ }
+ /* Check which slot that has been defined */
+ _slot_ = (win->or >> 2) & 1;
+
+ } /* Valid bank */
+ win++;
+ } /* for */
+
+ printk ("PCMCIA slot %c: phys mem %08x...%08x (size %08x)\n",
+ 'A' + _slot_,
+ pcmcia_phy_base, pcmcia_phy_end,
+ pcmcia_phy_end - pcmcia_phy_base);
+
+ pcmcia_base=(unsigned long)ioremap(pcmcia_phy_base,
+ pcmcia_phy_end-pcmcia_phy_base);
+
+#ifdef DEBUG
+ printk ("PCMCIA virt base: %08lx\n", pcmcia_base);
+#endif
+ /* Compute clock cycles for PIO timings */
+ for (i=0; i<6; ++i) {
+ bd_t *binfo = (bd_t *)__res;
+
+ hold_time[i] =
+ PCMCIA_MK_CLKS (hold_time[i],
+ binfo->bi_busfreq);
+ ide_pio_clocks[i].setup_time =
+ PCMCIA_MK_CLKS (ide_pio_timings[i].setup_time,
+ binfo->bi_busfreq);
+ ide_pio_clocks[i].active_time =
+ PCMCIA_MK_CLKS (ide_pio_timings[i].active_time,
+ binfo->bi_busfreq);
+ ide_pio_clocks[i].cycle_time =
+ PCMCIA_MK_CLKS (ide_pio_timings[i].cycle_time,
+ binfo->bi_busfreq);
+#if 0
+ printk ("PIO mode %d timings: %d/%d/%d => %d/%d/%d\n",
+ i,
+ ide_pio_clocks[i].setup_time,
+ ide_pio_clocks[i].active_time,
+ ide_pio_clocks[i].hold_time,
+ ide_pio_clocks[i].cycle_time,
+ ide_pio_timings[i].setup_time,
+ ide_pio_timings[i].active_time,
+ ide_pio_timings[i].hold_time,
+ ide_pio_timings[i].cycle_time);
+#endif
+ }
+ }
+
+ if (data_port >= MAX_HWIFS)
+ return;
+
+ if (_slot_ == -1) {
+ printk ("PCMCIA slot has not been defined! Using A as default\n");
+ _slot_ = 0;
+ }
+
+#ifdef CONFIG_IDE_8xx_PCCARD
+
+#ifdef DEBUG
+ printk ("PIPR = 0x%08X slot %c ==> mask = 0x%X\n",
+ pcmp->pcmc_pipr,
+ 'A' + _slot_,
+ M8XX_PCMCIA_CD1(_slot_) | M8XX_PCMCIA_CD2(_slot_) );
+#endif /* DEBUG */
+
+ if (pcmp->pcmc_pipr & (M8XX_PCMCIA_CD1(_slot_)|M8XX_PCMCIA_CD2(_slot_))) {
+ printk ("No card in slot %c: PIPR=%08x\n",
+ 'A' + _slot_, (u32) pcmp->pcmc_pipr);
+ return; /* No card in slot */
+ }
+
+ check_ide_device (pcmcia_base);
+
+#endif /* CONFIG_IDE_8xx_PCCARD */
+
+ base = pcmcia_base + ioport_dsc[data_port].base_off;
+#ifdef DEBUG
+ printk ("base: %08x + %08x = %08x\n",
+ pcmcia_base, ioport_dsc[data_port].base_off, base);
+#endif
+
+ for (i = 0; i < IDE_NR_PORTS; ++i) {
+#ifdef DEBUG
+ printk ("port[%d]: %08x + %08x = %08x\n",
+ i,
+ base,
+ ioport_dsc[data_port].reg_off[i],
+ i, base + ioport_dsc[data_port].reg_off[i]);
+#endif
+ *p++ = base + ioport_dsc[data_port].reg_off[i];
+ }
+
+ if (irq) {
+#ifdef CONFIG_IDE_8xx_PCCARD
+ unsigned int reg;
+
+ *irq = ioport_dsc[data_port].irq;
+ if (_slot_)
+ pgcrx = &((immap_t *) IMAP_ADDR)->im_pcmcia.pcmc_pgcrb;
+ else
+ pgcrx = &((immap_t *) IMAP_ADDR)->im_pcmcia.pcmc_pgcra;
+
+ reg = *pgcrx;
+ reg |= mk_int_int_mask (pcmcia_schlvl) << 24;
+ reg |= mk_int_int_mask (pcmcia_schlvl) << 16;
+ *pgcrx = reg;
+#else /* direct connected IDE drive, i.e. external IRQ, not the PCMCIA irq */
+ *irq = ioport_dsc[data_port].irq;
+#endif /* CONFIG_IDE_8xx_PCCARD */
+ }
+
+ /* register routine to tune PIO mode */
+ ide_hwifs[data_port].tuneproc = m8xx_ide_tuneproc;
+
+ hw->ack_intr = (ide_ack_intr_t *) ide_interrupt_ack;
+ /* Enable Harddisk Interrupt,
+ * and make it edge sensitive
+ */
+ /* (11-18) Set edge detect for irq, no wakeup from low power mode */
+ ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_siel |=
+ (0x80000000 >> ioport_dsc[data_port].irq);
+
+#ifdef CONFIG_IDE_8xx_PCCARD
+ /* Make sure we don't get garbage irq */
+ ((immap_t *) IMAP_ADDR)->im_pcmcia.pcmc_pscr = 0xFFFF;
+
+ /* Enable falling edge irq */
+ pcmp->pcmc_per = 0x100000 >> (16 * _slot_);
+#endif /* CONFIG_IDE_8xx_PCCARD */
+} /* m8xx_ide_init_hwif_ports() using 8xx internal PCMCIA interface */
+#endif /* CONFIG_IDE_8xx_PCCARD || CONFIG_IDE_8xx_DIRECT */
+
+/*
+ * m8xx_ide_init_hwif_ports for a direct IDE interface _not_ using
+ * MPC8xx's internal PCMCIA interface
+ */
+#if defined(CONFIG_IDE_EXT_DIRECT)
+void m8xx_ide_init_hwif_ports (hw_regs_t *hw,
+ unsigned long data_port, unsigned long ctrl_port, int *irq)
+{
+ unsigned long *p = hw->io_ports;
+ int i;
+
+ u32 ide_phy_base;
+ u32 ide_phy_end;
+ static unsigned long ide_base = 0;
+ unsigned long base;
+
+ *p = 0;
+ if (irq)
+ *irq = 0;
+
+ if (!ide_base) {
+
+ /* TODO:
+ * - add code to read ORx, BRx
+ */
+ ide_phy_base = CFG_ATA_BASE_ADDR;
+ ide_phy_end = CFG_ATA_BASE_ADDR + 0x200;
+
+ printk ("IDE phys mem : %08x...%08x (size %08x)\n",
+ ide_phy_base, ide_phy_end,
+ ide_phy_end - ide_phy_base);
+
+ ide_base=(unsigned long)ioremap(ide_phy_base,
+ ide_phy_end-ide_phy_base);
+
+#ifdef DEBUG
+ printk ("IDE virt base: %08lx\n", ide_base);
+#endif
+ }
+
+ if (data_port >= MAX_HWIFS)
+ return;
+
+ base = ide_base + ioport_dsc[data_port].base_off;
+#ifdef DEBUG
+ printk ("base: %08x + %08x = %08x\n",
+ ide_base, ioport_dsc[data_port].base_off, base);
+#endif
+
+ for (i = 0; i < IDE_NR_PORTS; ++i) {
+#ifdef DEBUG
+ printk ("port[%d]: %08x + %08x = %08x\n",
+ i,
+ base,
+ ioport_dsc[data_port].reg_off[i],
+ i, base + ioport_dsc[data_port].reg_off[i]);
+#endif
+ *p++ = base + ioport_dsc[data_port].reg_off[i];
+ }
+
+ if (irq) {
+ /* direct connected IDE drive, i.e. external IRQ */
+ *irq = ioport_dsc[data_port].irq;
+ }
+
+ /* register routine to tune PIO mode */
+ ide_hwifs[data_port].tuneproc = m8xx_ide_tuneproc;
+
+ hw->ack_intr = (ide_ack_intr_t *) ide_interrupt_ack;
+ /* Enable Harddisk Interrupt,
+ * and make it edge sensitive
+ */
+ /* (11-18) Set edge detect for irq, no wakeup from low power mode */
+ ((immap_t *) IMAP_ADDR)->im_siu_conf.sc_siel |=
+ (0x80000000 >> ioport_dsc[data_port].irq);
+} /* m8xx_ide_init_hwif_ports() for CONFIG_IDE_8xx_DIRECT */
+
+#endif /* CONFIG_IDE_8xx_DIRECT */
+
+
+/* -------------------------------------------------------------------- */
+
+
+/* PCMCIA Timing */
+#ifndef PCMCIA_SHT
+#define PCMCIA_SHT(t) ((t & 0x0F)<<16) /* Strobe Hold Time */
+#define PCMCIA_SST(t) ((t & 0x0F)<<12) /* Strobe Setup Time */
+#define PCMCIA_SL(t) ((t==32) ? 0 : ((t & 0x1F)<<7)) /* Strobe Length */
+#endif
+
+
+/* Calculate PIO timings */
+static void
+m8xx_ide_tuneproc(ide_drive_t *drive, u8 pio)
+{
+ ide_pio_data_t d;
+#if defined(CONFIG_IDE_8xx_PCCARD) || defined(CONFIG_IDE_8xx_DIRECT)
+ volatile pcmconf8xx_t *pcmp;
+ ulong timing, mask, reg;
+#endif
+
+ pio = ide_get_best_pio_mode(drive, pio, 4, &d);
+
+#if 1
+ printk("%s[%d] %s: best PIO mode: %d\n",
+ __FILE__,__LINE__,__FUNCTION__, pio);
+#endif
+
+#if defined(CONFIG_IDE_8xx_PCCARD) || defined(CONFIG_IDE_8xx_DIRECT)
+ pcmp = (pcmconf8xx_t *)(&(((immap_t *)IMAP_ADDR)->im_pcmcia));
+
+ mask = ~(PCMCIA_SHT(0xFF) | PCMCIA_SST(0xFF) | PCMCIA_SL(0xFF));
+
+ timing = PCMCIA_SHT(hold_time[pio] )
+ | PCMCIA_SST(ide_pio_clocks[pio].setup_time )
+ | PCMCIA_SL (ide_pio_clocks[pio].active_time)
+ ;
+
+#if 1
+ printk ("Setting timing bits 0x%08lx in PCMCIA controller\n", timing);
+#endif
+ if ((reg = pcmp->pcmc_por0 & mask) != 0)
+ pcmp->pcmc_por0 = reg | timing;
+
+ if ((reg = pcmp->pcmc_por1 & mask) != 0)
+ pcmp->pcmc_por1 = reg | timing;
+
+ if ((reg = pcmp->pcmc_por2 & mask) != 0)
+ pcmp->pcmc_por2 = reg | timing;
+
+ if ((reg = pcmp->pcmc_por3 & mask) != 0)
+ pcmp->pcmc_por3 = reg | timing;
+
+ if ((reg = pcmp->pcmc_por4 & mask) != 0)
+ pcmp->pcmc_por4 = reg | timing;
+
+ if ((reg = pcmp->pcmc_por5 & mask) != 0)
+ pcmp->pcmc_por5 = reg | timing;
+
+ if ((reg = pcmp->pcmc_por6 & mask) != 0)
+ pcmp->pcmc_por6 = reg | timing;
+
+ if ((reg = pcmp->pcmc_por7 & mask) != 0)
+ pcmp->pcmc_por7 = reg | timing;
+
+#elif defined(CONFIG_IDE_EXT_DIRECT)
+
+ printk("%s[%d] %s: not implemented yet!\n",
+ __FILE__,__LINE__,__FUNCTION__);
+#endif /* defined(CONFIG_IDE_8xx_PCCARD) || defined(CONFIG_IDE_8xx_PCMCIA */
+}
+
+static void
+ide_interrupt_ack (void *dev)
+{
+#ifdef CONFIG_IDE_8xx_PCCARD
+ u_int pscr, pipr;
+
+#if (PCMCIA_SOCKETS_NO == 2)
+ u_int _slot_;
+#endif
+
+ /* get interrupt sources */
+
+ pscr = ((volatile immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pscr;
+ pipr = ((volatile immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pipr;
+
+ /*
+ * report only if both card detect signals are the same
+ * not too nice done,
+ * we depend on that CD2 is the bit to the left of CD1...
+ */
+
+ if(_slot_==-1){
+ printk("PCMCIA slot has not been defined! Using A as default\n");
+ _slot_=0;
+ }
+
+ if(((pipr & M8XX_PCMCIA_CD2(_slot_)) >> 1) ^
+ (pipr & M8XX_PCMCIA_CD1(_slot_)) ) {
+ printk ("card detect interrupt\n");
+ }
+ /* clear the interrupt sources */
+ ((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pscr = pscr;
+
+#else /* ! CONFIG_IDE_8xx_PCCARD */
+ /*
+ * Only CONFIG_IDE_8xx_PCCARD is using the interrupt of the
+ * MPC8xx's PCMCIA controller, so there is nothing to be done here
+ * for CONFIG_IDE_8xx_DIRECT and CONFIG_IDE_EXT_DIRECT.
+ * The interrupt is handled somewhere else. -- Steven
+ */
+#endif /* CONFIG_IDE_8xx_PCCARD */
+}
+
+
+
+/*
+ * CIS Tupel codes
+ */
+#define CISTPL_NULL 0x00
+#define CISTPL_DEVICE 0x01
+#define CISTPL_LONGLINK_CB 0x02
+#define CISTPL_INDIRECT 0x03
+#define CISTPL_CONFIG_CB 0x04
+#define CISTPL_CFTABLE_ENTRY_CB 0x05
+#define CISTPL_LONGLINK_MFC 0x06
+#define CISTPL_BAR 0x07
+#define CISTPL_PWR_MGMNT 0x08
+#define CISTPL_EXTDEVICE 0x09
+#define CISTPL_CHECKSUM 0x10
+#define CISTPL_LONGLINK_A 0x11
+#define CISTPL_LONGLINK_C 0x12
+#define CISTPL_LINKTARGET 0x13
+#define CISTPL_NO_LINK 0x14
+#define CISTPL_VERS_1 0x15
+#define CISTPL_ALTSTR 0x16
+#define CISTPL_DEVICE_A 0x17
+#define CISTPL_JEDEC_C 0x18
+#define CISTPL_JEDEC_A 0x19
+#define CISTPL_CONFIG 0x1a
+#define CISTPL_CFTABLE_ENTRY 0x1b
+#define CISTPL_DEVICE_OC 0x1c
+#define CISTPL_DEVICE_OA 0x1d
+#define CISTPL_DEVICE_GEO 0x1e
+#define CISTPL_DEVICE_GEO_A 0x1f
+#define CISTPL_MANFID 0x20
+#define CISTPL_FUNCID 0x21
+#define CISTPL_FUNCE 0x22
+#define CISTPL_SWIL 0x23
+#define CISTPL_END 0xff
+
+/*
+ * CIS Function ID codes
+ */
+#define CISTPL_FUNCID_MULTI 0x00
+#define CISTPL_FUNCID_MEMORY 0x01
+#define CISTPL_FUNCID_SERIAL 0x02
+#define CISTPL_FUNCID_PARALLEL 0x03
+#define CISTPL_FUNCID_FIXED 0x04
+#define CISTPL_FUNCID_VIDEO 0x05
+#define CISTPL_FUNCID_NETWORK 0x06
+#define CISTPL_FUNCID_AIMS 0x07
+#define CISTPL_FUNCID_SCSI 0x08
+
+/*
+ * Fixed Disk FUNCE codes
+ */
+#define CISTPL_IDE_INTERFACE 0x01
+
+#define CISTPL_FUNCE_IDE_IFACE 0x01
+#define CISTPL_FUNCE_IDE_MASTER 0x02
+#define CISTPL_FUNCE_IDE_SLAVE 0x03
+
+/* First feature byte */
+#define CISTPL_IDE_SILICON 0x04
+#define CISTPL_IDE_UNIQUE 0x08
+#define CISTPL_IDE_DUAL 0x10
+
+/* Second feature byte */
+#define CISTPL_IDE_HAS_SLEEP 0x01
+#define CISTPL_IDE_HAS_STANDBY 0x02
+#define CISTPL_IDE_HAS_IDLE 0x04
+#define CISTPL_IDE_LOW_POWER 0x08
+#define CISTPL_IDE_REG_INHIBIT 0x10
+#define CISTPL_IDE_HAS_INDEX 0x20
+#define CISTPL_IDE_IOIS16 0x40
+
+
+/* -------------------------------------------------------------------- */
+
+
+#define MAX_TUPEL_SZ 512
+#define MAX_FEATURES 4
+
+static int check_ide_device (unsigned long base)
+{
+ volatile u8 *ident = NULL;
+ volatile u8 *feature_p[MAX_FEATURES];
+ volatile u8 *p, *start;
+ int n_features = 0;
+ u8 func_id = ~0;
+ u8 code, len;
+ unsigned short config_base = 0;
+ int found = 0;
+ int i;
+
+#ifdef DEBUG
+ printk ("PCMCIA MEM: %08lX\n", base);
+#endif
+ start = p = (volatile u8 *) base;
+
+ while ((p - start) < MAX_TUPEL_SZ) {
+
+ code = *p; p += 2;
+
+ if (code == 0xFF) { /* End of chain */
+ break;
+ }
+
+ len = *p; p += 2;
+#ifdef DEBUG_PCMCIA
+ { volatile u8 *q = p;
+ printk ("\nTuple code %02x length %d\n\tData:",
+ code, len);
+
+ for (i = 0; i < len; ++i) {
+ printk (" %02x", *q);
+ q+= 2;
+ }
+ }
+#endif /* DEBUG_PCMCIA */
+ switch (code) {
+ case CISTPL_VERS_1:
+ ident = p + 4;
+ break;
+ case CISTPL_FUNCID:
+ func_id = *p;
+ break;
+ case CISTPL_FUNCE:
+ if (n_features < MAX_FEATURES)
+ feature_p[n_features++] = p;
+ break;
+ case CISTPL_CONFIG:
+ config_base = (*(p+6) << 8) + (*(p+4));
+ default:
+ break;
+ }
+ p += 2 * len;
+ }
+
+ found = identify (ident);
+
+ if (func_id != ((u8)~0)) {
+ print_funcid (func_id);
+
+ if (func_id == CISTPL_FUNCID_FIXED)
+ found = 1;
+ else
+ return (1); /* no disk drive */
+ }
+
+ for (i=0; i<n_features; ++i) {
+ print_fixed (feature_p[i]);
+ }
+
+ if (!found) {
+ printk ("unknown card type\n");
+ return (1);
+ }
+
+ /* set level mode irq and I/O mapped device in config reg*/
+ *((u8 *)(base + config_base)) = 0x41;
+
+ return (0);
+}
+
+/* ------------------------------------------------------------------------- */
+
+static void print_funcid (int func)
+{
+ switch (func) {
+ case CISTPL_FUNCID_MULTI:
+ printk (" Multi-Function");
+ break;
+ case CISTPL_FUNCID_MEMORY:
+ printk (" Memory");
+ break;
+ case CISTPL_FUNCID_SERIAL:
+ printk (" Serial Port");
+ break;
+ case CISTPL_FUNCID_PARALLEL:
+ printk (" Parallel Port");
+ break;
+ case CISTPL_FUNCID_FIXED:
+ printk (" Fixed Disk");
+ break;
+ case CISTPL_FUNCID_VIDEO:
+ printk (" Video Adapter");
+ break;
+ case CISTPL_FUNCID_NETWORK:
+ printk (" Network Adapter");
+ break;
+ case CISTPL_FUNCID_AIMS:
+ printk (" AIMS Card");
+ break;
+ case CISTPL_FUNCID_SCSI:
+ printk (" SCSI Adapter");
+ break;
+ default:
+ printk (" Unknown");
+ break;
+ }
+ printk (" Card\n");
+}
+
+/* ------------------------------------------------------------------------- */
+
+static void print_fixed (volatile u8 *p)
+{
+ if (p == NULL)
+ return;
+
+ switch (*p) {
+ case CISTPL_FUNCE_IDE_IFACE:
+ { u8 iface = *(p+2);
+
+ printk ((iface == CISTPL_IDE_INTERFACE) ? " IDE" : " unknown");
+ printk (" interface ");
+ break;
+ }
+ case CISTPL_FUNCE_IDE_MASTER:
+ case CISTPL_FUNCE_IDE_SLAVE:
+ { u8 f1 = *(p+2);
+ u8 f2 = *(p+4);
+
+ printk ((f1 & CISTPL_IDE_SILICON) ? " [silicon]" : " [rotating]");
+
+ if (f1 & CISTPL_IDE_UNIQUE)
+ printk (" [unique]");
+
+ printk ((f1 & CISTPL_IDE_DUAL) ? " [dual]" : " [single]");
+
+ if (f2 & CISTPL_IDE_HAS_SLEEP)
+ printk (" [sleep]");
+
+ if (f2 & CISTPL_IDE_HAS_STANDBY)
+ printk (" [standby]");
+
+ if (f2 & CISTPL_IDE_HAS_IDLE)
+ printk (" [idle]");
+
+ if (f2 & CISTPL_IDE_LOW_POWER)
+ printk (" [low power]");
+
+ if (f2 & CISTPL_IDE_REG_INHIBIT)
+ printk (" [reg inhibit]");
+
+ if (f2 & CISTPL_IDE_HAS_INDEX)
+ printk (" [index]");
+
+ if (f2 & CISTPL_IDE_IOIS16)
+ printk (" [IOis16]");
+
+ break;
+ }
+ }
+ printk ("\n");
+}
+
+/* ------------------------------------------------------------------------- */
+
+
+#define MAX_IDENT_CHARS 64
+#define MAX_IDENT_FIELDS 4
+
+static u8 *known_cards[] = {
+ "ARGOSY PnPIDE D5",
+ NULL
+};
+
+static int identify (volatile u8 *p)
+{
+ u8 id_str[MAX_IDENT_CHARS];
+ u8 data;
+ u8 *t;
+ u8 **card;
+ int i, done;
+
+ if (p == NULL)
+ return (0); /* Don't know */
+
+ t = id_str;
+ done =0;
+
+ for (i=0; i<=4 && !done; ++i, p+=2) {
+ while ((data = *p) != '\0') {
+ if (data == 0xFF) {
+ done = 1;
+ break;
+ }
+ *t++ = data;
+ if (t == &id_str[MAX_IDENT_CHARS-1]) {
+ done = 1;
+ break;
+ }
+ p += 2;
+ }
+ if (!done)
+ *t++ = ' ';
+ }
+ *t = '\0';
+ while (--t > id_str) {
+ if (*t == ' ')
+ *t = '\0';
+ else
+ break;
+ }
+ printk ("Card ID: %s\n", id_str);
+
+ for (card=known_cards; *card; ++card) {
+ if (strcmp(*card, id_str) == 0) { /* found! */
+ return (1);
+ }
+ }
+
+ return (0); /* don't know */
+}
+
+void m8xx_ide_init(void)
+{
+ ppc_ide_md.default_irq = m8xx_ide_default_irq;
+ ppc_ide_md.default_io_base = m8xx_ide_default_io_base;
+ ppc_ide_md.ide_init_hwif = m8xx_ide_init_hwif_ports;
+}
diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c
new file mode 100644
index 000000000000..6dc273a81327
--- /dev/null
+++ b/drivers/ide/ppc/pmac.c
@@ -0,0 +1,2208 @@
+/*
+ * linux/drivers/ide/ide-pmac.c
+ *
+ * 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
+ *
+ * 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/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.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
+
+#include "ide-timing.h"
+
+#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 cable_80 : 1;
+ 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;
+#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
+ /* 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;
+#endif
+
+} pmac_ide_hwif_t;
+
+static pmac_ide_hwif_t pmac_ide[MAX_HWIFS] __pmacdata;
+static int pmac_ide_count;
+
+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
+
+#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
+
+/* 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[] __pmacdata =
+{
+ { 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[] __pmacdata =
+{
+ { 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[] __pmacdata =
+{
+ { 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[] __pmacdata =
+{
+ { 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[] __pmacdata =
+{
+ { 930 , 0x08000fff },
+ { 600 , 0x08000a92 },
+ { 383 , 0x0800060f },
+ { 360 , 0x08000492 },
+ { 330 , 0x0800048f },
+ { 300 , 0x080003cf },
+ { 270 , 0x080003cc },
+ { 240 , 0x0800038b },
+ { 239 , 0x0800030c },
+ { 180 , 0x05000249 },
+ { 120 , 0x04000148 }
+};
+
+static struct kauai_timing kauai_mdma_timings[] __pmacdata =
+{
+ { 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[] __pmacdata =
+{
+ { 120 , 0x000070c0 },
+ { 90 , 0x00005d80 },
+ { 60 , 0x00004a60 },
+ { 45 , 0x00003a50 },
+ { 30 , 0x00002a30 },
+ { 20 , 0x00002921 },
+ { 0 , 0 },
+};
+
+static struct kauai_timing shasta_pio_timings[] __pmacdata =
+{
+ { 930 , 0x08000fff },
+ { 600 , 0x0A000c97 },
+ { 383 , 0x07000712 },
+ { 360 , 0x040003cd },
+ { 330 , 0x040003cd },
+ { 300 , 0x040003cd },
+ { 270 , 0x040003cd },
+ { 240 , 0x040003cd },
+ { 239 , 0x040003cd },
+ { 180 , 0x0400028b },
+ { 120 , 0x0400010a }
+};
+
+static struct kauai_timing shasta_mdma_timings[] __pmacdata =
+{
+ { 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[] __pmacdata =
+{
+ { 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;
+ 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 void pmac_ide_setup_dma(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif);
+static int pmac_ide_build_dmatable(ide_drive_t *drive, struct request *rq);
+static int pmac_ide_tune_chipset(ide_drive_t *drive, u8 speed);
+static void pmac_ide_tuneproc(ide_drive_t *drive, u8 pio);
+static void pmac_ide_selectproc(ide_drive_t *drive);
+static void pmac_ide_kauai_selectproc(ide_drive_t *drive);
+
+#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
+
+/*
+ * Below is the code for blinking the laptop LED along with hard
+ * disk activity.
+ */
+
+#ifdef CONFIG_BLK_DEV_IDE_PMAC_BLINK
+
+/* Set to 50ms minimum led-on time (also used to limit frequency
+ * of requests sent to the PMU
+ */
+#define PMU_HD_BLINK_TIME (HZ/50)
+
+static struct adb_request pmu_blink_on, pmu_blink_off;
+static spinlock_t pmu_blink_lock;
+static unsigned long pmu_blink_stoptime;
+static int pmu_blink_ledstate;
+static struct timer_list pmu_blink_timer;
+static int pmu_ide_blink_enabled;
+
+
+static void
+pmu_hd_blink_timeout(unsigned long data)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&pmu_blink_lock, flags);
+
+ /* We may have been triggered again in a racy way, check
+ * that we really want to switch it off
+ */
+ if (time_after(pmu_blink_stoptime, jiffies))
+ goto done;
+
+ /* Previous req. not complete, try 100ms more */
+ if (pmu_blink_off.complete == 0)
+ mod_timer(&pmu_blink_timer, jiffies + PMU_HD_BLINK_TIME);
+ else if (pmu_blink_ledstate) {
+ pmu_request(&pmu_blink_off, NULL, 4, 0xee, 4, 0, 0);
+ pmu_blink_ledstate = 0;
+ }
+done:
+ spin_unlock_irqrestore(&pmu_blink_lock, flags);
+}
+
+static void
+pmu_hd_kick_blink(void *data, int rw)
+{
+ unsigned long flags;
+
+ pmu_blink_stoptime = jiffies + PMU_HD_BLINK_TIME;
+ wmb();
+ mod_timer(&pmu_blink_timer, pmu_blink_stoptime);
+ /* Fast path when LED is already ON */
+ if (pmu_blink_ledstate == 1)
+ return;
+ spin_lock_irqsave(&pmu_blink_lock, flags);
+ if (pmu_blink_on.complete && !pmu_blink_ledstate) {
+ pmu_request(&pmu_blink_on, NULL, 4, 0xee, 4, 0, 1);
+ pmu_blink_ledstate = 1;
+ }
+ spin_unlock_irqrestore(&pmu_blink_lock, flags);
+}
+
+static int
+pmu_hd_blink_init(void)
+{
+ struct device_node *dt;
+ const char *model;
+
+ /* Currently, I only enable this feature on KeyLargo based laptops,
+ * older laptops may support it (at least heathrow/paddington) but
+ * I don't feel like loading those venerable old machines with so
+ * much additional interrupt & PMU activity...
+ */
+ if (pmu_get_model() != PMU_KEYLARGO_BASED)
+ return 0;
+
+ dt = find_devices("device-tree");
+ if (dt == NULL)
+ return 0;
+ model = (const char *)get_property(dt, "model", NULL);
+ if (model == NULL)
+ return 0;
+ if (strncmp(model, "PowerBook", strlen("PowerBook")) != 0 &&
+ strncmp(model, "iBook", strlen("iBook")) != 0)
+ return 0;
+
+ pmu_blink_on.complete = 1;
+ pmu_blink_off.complete = 1;
+ spin_lock_init(&pmu_blink_lock);
+ init_timer(&pmu_blink_timer);
+ pmu_blink_timer.function = pmu_hd_blink_timeout;
+
+ return 1;
+}
+
+#endif /* CONFIG_BLK_DEV_IDE_PMAC_BLINK */
+
+/*
+ * N.B. this can't be an initfunc, because the media-bay task can
+ * call ide_[un]register at any time.
+ */
+void __pmac
+pmac_ide_init_hwif_ports(hw_regs_t *hw,
+ unsigned long data_port, unsigned long ctrl_port,
+ int *irq)
+{
+ int i, ix;
+
+ if (data_port == 0)
+ return;
+
+ for (ix = 0; ix < MAX_HWIFS; ++ix)
+ if (data_port == pmac_ide[ix].regbase)
+ break;
+
+ if (ix >= MAX_HWIFS) {
+ /* Probably a PCI interface... */
+ for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; ++i)
+ hw->io_ports[i] = data_port + i - IDE_DATA_OFFSET;
+ hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port;
+ return;
+ }
+
+ for (i = 0; i < 8; ++i)
+ hw->io_ports[i] = data_port + i * 0x10;
+ hw->io_ports[8] = data_port + 0x160;
+
+ if (irq != NULL)
+ *irq = pmac_ide[ix].irq;
+}
+
+#define PMAC_IDE_REG(x) ((void __iomem *)(IDE_DATA_REG+(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
+pmac_ide_selectproc(ide_drive_t *drive)
+{
+ pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data;
+
+ if (pmif == NULL)
+ return;
+
+ if (drive->select.b.unit & 0x01)
+ 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
+pmac_ide_kauai_selectproc(ide_drive_t *drive)
+{
+ pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data;
+
+ if (pmif == NULL)
+ return;
+
+ if (drive->select.b.unit & 0x01) {
+ 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
+pmac_ide_do_update_timings(ide_drive_t *drive)
+{
+ pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data;
+
+ if (pmif == NULL)
+ return;
+
+ 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_outbsync(ide_drive_t *drive, u8 value, unsigned long port)
+{
+ u32 tmp;
+
+ writeb(value, (void __iomem *) port);
+ tmp = readl(PMAC_IDE_REG(IDE_TIMING_CONFIG));
+}
+
+/*
+ * Send the SET_FEATURE IDE command to the drive and update drive->id with
+ * the new state. We currently don't use the generic routine as it used to
+ * cause various trouble, especially with older mediabays.
+ * This code is sometimes triggering a spurrious interrupt though, I need
+ * to sort that out sooner or later and see if I can finally get the
+ * common version to work properly in all cases
+ */
+static int __pmac
+pmac_ide_do_setfeature(ide_drive_t *drive, u8 command)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ int result = 1;
+
+ disable_irq_nosync(hwif->irq);
+ udelay(1);
+ SELECT_DRIVE(drive);
+ SELECT_MASK(drive, 0);
+ udelay(1);
+ /* Get rid of pending error state */
+ (void) hwif->INB(IDE_STATUS_REG);
+ /* Timeout bumped for some powerbooks */
+ if (wait_for_ready(drive, 2000)) {
+ /* Timeout bumped for some powerbooks */
+ printk(KERN_ERR "%s: pmac_ide_do_setfeature disk not ready "
+ "before SET_FEATURE!\n", drive->name);
+ goto out;
+ }
+ udelay(10);
+ hwif->OUTB(drive->ctl | 2, IDE_CONTROL_REG);
+ hwif->OUTB(command, IDE_NSECTOR_REG);
+ hwif->OUTB(SETFEATURES_XFER, IDE_FEATURE_REG);
+ hwif->OUTBSYNC(drive, WIN_SETFEATURES, IDE_COMMAND_REG);
+ udelay(1);
+ /* Timeout bumped for some powerbooks */
+ result = wait_for_ready(drive, 2000);
+ hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
+ if (result)
+ printk(KERN_ERR "%s: pmac_ide_do_setfeature disk not ready "
+ "after SET_FEATURE !\n", drive->name);
+out:
+ SELECT_MASK(drive, 0);
+ if (result == 0) {
+ drive->id->dma_ultra &= ~0xFF00;
+ drive->id->dma_mword &= ~0x0F00;
+ drive->id->dma_1word &= ~0x0F00;
+ switch(command) {
+ case XFER_UDMA_7:
+ drive->id->dma_ultra |= 0x8080; break;
+ case XFER_UDMA_6:
+ drive->id->dma_ultra |= 0x4040; break;
+ case XFER_UDMA_5:
+ drive->id->dma_ultra |= 0x2020; break;
+ case XFER_UDMA_4:
+ drive->id->dma_ultra |= 0x1010; break;
+ case XFER_UDMA_3:
+ drive->id->dma_ultra |= 0x0808; break;
+ case XFER_UDMA_2:
+ drive->id->dma_ultra |= 0x0404; break;
+ case XFER_UDMA_1:
+ drive->id->dma_ultra |= 0x0202; break;
+ case XFER_UDMA_0:
+ drive->id->dma_ultra |= 0x0101; break;
+ case XFER_MW_DMA_2:
+ drive->id->dma_mword |= 0x0404; break;
+ case XFER_MW_DMA_1:
+ drive->id->dma_mword |= 0x0202; break;
+ case XFER_MW_DMA_0:
+ drive->id->dma_mword |= 0x0101; break;
+ case XFER_SW_DMA_2:
+ drive->id->dma_1word |= 0x0404; break;
+ case XFER_SW_DMA_1:
+ drive->id->dma_1word |= 0x0202; break;
+ case XFER_SW_DMA_0:
+ drive->id->dma_1word |= 0x0101; break;
+ default: break;
+ }
+ }
+ enable_irq(hwif->irq);
+ return result;
+}
+
+/*
+ * Old tuning functions (called on hdparm -p), sets up drive PIO timings
+ */
+static void __pmac
+pmac_ide_tuneproc(ide_drive_t *drive, u8 pio)
+{
+ ide_pio_data_t d;
+ u32 *timings;
+ unsigned accessTicks, recTicks;
+ unsigned accessTime, recTime;
+ pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data;
+
+ if (pmif == NULL)
+ return;
+
+ /* which drive is it ? */
+ timings = &pmif->timings[drive->select.b.unit & 0x01];
+
+ pio = ide_get_best_pio_mode(drive, pio, 4, &d);
+
+ switch (pmif->kind) {
+ case controller_sh_ata6: {
+ /* 133Mhz cell */
+ u32 tr = kauai_lookup_timing(shasta_pio_timings, d.cycle_time);
+ if (tr == 0)
+ return;
+ *timings = ((*timings) & ~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, d.cycle_time);
+ if (tr == 0)
+ return;
+ *timings = ((*timings) & ~TR_100_PIOREG_PIO_MASK) | tr;
+ break;
+ }
+ case controller_kl_ata4:
+ /* 66Mhz cell */
+ recTime = d.cycle_time - ide_pio_timings[pio].active_time
+ - ide_pio_timings[pio].setup_time;
+ recTime = max(recTime, 150U);
+ accessTime = ide_pio_timings[pio].active_time;
+ accessTime = max(accessTime, 150U);
+ accessTicks = SYSCLK_TICKS_66(accessTime);
+ accessTicks = min(accessTicks, 0x1fU);
+ recTicks = SYSCLK_TICKS_66(recTime);
+ recTicks = min(recTicks, 0x1fU);
+ *timings = ((*timings) & ~TR_66_PIO_MASK) |
+ (accessTicks << TR_66_PIO_ACCESS_SHIFT) |
+ (recTicks << TR_66_PIO_RECOVERY_SHIFT);
+ break;
+ default: {
+ /* 33Mhz cell */
+ int ebit = 0;
+ recTime = d.cycle_time - ide_pio_timings[pio].active_time
+ - ide_pio_timings[pio].setup_time;
+ recTime = max(recTime, 150U);
+ accessTime = ide_pio_timings[pio].active_time;
+ 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;
+ }
+ *timings = ((*timings) & ~TR_33_PIO_MASK) |
+ (accessTicks << TR_33_PIO_ACCESS_SHIFT) |
+ (recTicks << TR_33_PIO_RECOVERY_SHIFT);
+ if (ebit)
+ *timings |= 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
+
+ if (drive->select.all == HWIF(drive)->INB(IDE_SELECT_REG))
+ pmac_ide_do_update_timings(drive);
+}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
+
+/*
+ * Calculate KeyLargo ATA/66 UDMA timings
+ */
+static int __pmac
+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 __pmac
+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);
+ if (tr == 0)
+ return 1;
+ *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 __pmac
+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);
+ if (tr == 0)
+ return 1;
+ *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 int __pmac
+set_timings_mdma(ide_drive_t *drive, int intf_type, u32 *timings, u32 *timings2,
+ u8 speed, int drive_cycle_time)
+{
+ 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:
+ return 1;
+ }
+ /* Adjust for drive */
+ if (drive_cycle_time && drive_cycle_time > cycleTime)
+ cycleTime = drive_cycle_time;
+ /* 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++;
+ }
+ if (i < 0)
+ return 1;
+ 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);
+ if (tr == 0)
+ return 1;
+ *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);
+ if (tr == 0)
+ return 1;
+ *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
+ return 0;
+}
+#endif /* #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC */
+
+/*
+ * Speedproc. This function is called by the core to set any of the standard
+ * timing (PIO, MDMA or UDMA) to both the drive and the controller.
+ * You may notice we don't use this function on normal "dma check" operation,
+ * our dedicated function is more precise as it uses the drive provided
+ * cycle time value. We should probably fix this one to deal with that too...
+ */
+static int __pmac
+pmac_ide_tune_chipset (ide_drive_t *drive, byte speed)
+{
+ int unit = (drive->select.b.unit & 0x01);
+ int ret = 0;
+ pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data;
+ u32 *timings, *timings2;
+
+ if (pmif == NULL)
+ return 1;
+
+ timings = &pmif->timings[unit];
+ timings2 = &pmif->timings[unit+2];
+
+ switch(speed) {
+#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
+ case XFER_UDMA_6:
+ if (pmif->kind != controller_sh_ata6)
+ return 1;
+ case XFER_UDMA_5:
+ if (pmif->kind != controller_un_ata6 &&
+ pmif->kind != controller_k2_ata6 &&
+ pmif->kind != controller_sh_ata6)
+ return 1;
+ case XFER_UDMA_4:
+ case XFER_UDMA_3:
+ if (HWIF(drive)->udma_four == 0)
+ return 1;
+ case XFER_UDMA_2:
+ case XFER_UDMA_1:
+ case XFER_UDMA_0:
+ if (pmif->kind == controller_kl_ata4)
+ ret = set_timings_udma_ata4(timings, speed);
+ else if (pmif->kind == controller_un_ata6
+ || pmif->kind == controller_k2_ata6)
+ ret = set_timings_udma_ata6(timings, timings2, speed);
+ else if (pmif->kind == controller_sh_ata6)
+ ret = set_timings_udma_shasta(timings, timings2, speed);
+ else
+ ret = 1;
+ break;
+ case XFER_MW_DMA_2:
+ case XFER_MW_DMA_1:
+ case XFER_MW_DMA_0:
+ ret = set_timings_mdma(drive, pmif->kind, timings, timings2, speed, 0);
+ break;
+ case XFER_SW_DMA_2:
+ case XFER_SW_DMA_1:
+ case XFER_SW_DMA_0:
+ return 1;
+#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
+ case XFER_PIO_4:
+ case XFER_PIO_3:
+ case XFER_PIO_2:
+ case XFER_PIO_1:
+ case XFER_PIO_0:
+ pmac_ide_tuneproc(drive, speed & 0x07);
+ break;
+ default:
+ ret = 1;
+ }
+ if (ret)
+ return ret;
+
+ ret = pmac_ide_do_setfeature(drive, speed);
+ if (ret)
+ return ret;
+
+ pmac_ide_do_update_timings(drive);
+ drive->current_speed = speed;
+
+ return 0;
+}
+
+/*
+ * Blast some well known "safe" values to the timing registers at init or
+ * wakeup from sleep time, before we do real calculation
+ */
+static void __pmac
+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;
+}
+
+unsigned long __pmac
+pmac_ide_get_base(int index)
+{
+ return pmac_ide[index].regbase;
+}
+
+int __pmac
+pmac_ide_check_base(unsigned long base)
+{
+ int ix;
+
+ for (ix = 0; ix < MAX_HWIFS; ++ix)
+ if (base == pmac_ide[ix].regbase)
+ return ix;
+ return -1;
+}
+
+int __pmac
+pmac_ide_get_irq(unsigned long base)
+{
+ int ix;
+
+ for (ix = 0; ix < MAX_HWIFS; ++ix)
+ if (base == pmac_ide[ix].regbase)
+ return pmac_ide[ix].irq;
+ return 0;
+}
+
+static int ide_majors[] __pmacdata = { 3, 22, 33, 34, 56, 57 };
+
+dev_t __init
+pmac_find_ide_boot(char *bootdevice, int n)
+{
+ int i;
+
+ /*
+ * Look through the list of IDE interfaces for this one.
+ */
+ for (i = 0; i < pmac_ide_count; ++i) {
+ char *name;
+ if (!pmac_ide[i].node || !pmac_ide[i].node->full_name)
+ continue;
+ name = pmac_ide[i].node->full_name;
+ if (memcmp(name, bootdevice, n) == 0 && name[n] == 0) {
+ /* XXX should cope with the 2nd drive as well... */
+ return MKDEV(ide_majors[i], 0);
+ }
+ }
+
+ return 0;
+}
+
+/* Suspend call back, should be called after the child devices
+ * have actually been suspended
+ */
+static int
+pmac_ide_do_suspend(ide_hwif_t *hwif)
+{
+ pmac_ide_hwif_t *pmif = (pmac_ide_hwif_t *)hwif->hwif_data;
+
+ /* We clear the timings */
+ pmif->timings[0] = 0;
+ pmif->timings[1] = 0;
+
+#ifdef CONFIG_BLK_DEV_IDE_PMAC_BLINK
+ /* Note: This code will be called for every hwif, thus we'll
+ * try several time to stop the LED blinker timer, but that
+ * should be harmless
+ */
+ if (pmu_ide_blink_enabled) {
+ unsigned long flags;
+
+ /* Make sure we don't hit the PMU blink */
+ spin_lock_irqsave(&pmu_blink_lock, flags);
+ if (pmu_blink_ledstate)
+ del_timer(&pmu_blink_timer);
+ pmu_blink_ledstate = 0;
+ spin_unlock_irqrestore(&pmu_blink_lock, flags);
+ }
+#endif /* CONFIG_BLK_DEV_IDE_PMAC_BLINK */
+
+ /* 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(ide_hwif_t *hwif)
+{
+ pmac_ide_hwif_t *pmif = (pmac_ide_hwif_t *)hwif->hwif_data;
+
+ /* 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);
+ msleep(jiffies_to_msecs(IDE_WAKEUP_DELAY));
+
+ /* 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);
+ }
+ }
+
+ /* Sanitize drive timings */
+ sanitize_timings(pmif);
+
+ return 0;
+}
+
+/*
+ * Setup, register & probe an IDE channel driven by this driver, this is
+ * called by one of the 2 probe functions (macio or PCI). Note that a channel
+ * that ends up beeing free of any device is not kept around by this driver
+ * (it is kept in 2.4). This introduce an interface numbering change on some
+ * rare machines unfortunately, but it's better this way.
+ */
+static int
+pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
+{
+ struct device_node *np = pmif->node;
+ int *bidp, i;
+
+ pmif->cable_80 = 0;
+ pmif->broken_dma = pmif->broken_dma_warn = 0;
+ if (device_is_compatible(np, "shasta-ata"))
+ pmif->kind = controller_sh_ata6;
+ else if (device_is_compatible(np, "kauai-ata"))
+ pmif->kind = controller_un_ata6;
+ else if (device_is_compatible(np, "K2-UATA"))
+ pmif->kind = controller_k2_ata6;
+ else if (device_is_compatible(np, "keylargo-ata")) {
+ if (strcmp(np->name, "ata-4") == 0)
+ pmif->kind = controller_kl_ata4;
+ else
+ pmif->kind = controller_kl_ata3;
+ } else if (device_is_compatible(np, "heathrow-ata"))
+ pmif->kind = controller_heathrow;
+ else {
+ pmif->kind = controller_ohare;
+ pmif->broken_dma = 1;
+ }
+
+ bidp = (int *)get_property(np, "AAPL,bus-id", NULL);
+ pmif->aapl_bus_id = bidp ? *bidp : 0;
+
+ /* Get cable type from device-tree */
+ if (pmif->kind == controller_kl_ata4 || pmif->kind == controller_un_ata6
+ || pmif->kind == controller_k2_ata6
+ || pmif->kind == controller_sh_ata6) {
+ char* cable = get_property(np, "cable-type", NULL);
+ if (cable && !strncmp(cable, "80-", 3))
+ pmif->cable_80 = 1;
+ }
+ /* 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 (device_is_compatible(np, "K2-UATA") ||
+ device_is_compatible(np, "shasta-ata"))
+ pmif->cable_80 = 1;
+
+ /* 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);
+
+#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_PBOOK
+ media_bay_set_ide_infos(np->parent, pmif->regbase, pmif->irq, hwif->index);
+#endif /* CONFIG_PMAC_PBOOK */
+ 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));
+ }
+
+ /* Setup MMIO ops */
+ default_hwif_mmiops(hwif);
+ hwif->OUTBSYNC = pmac_outbsync;
+
+ /* Tell common code _not_ to mess with resources */
+ hwif->mmio = 2;
+ hwif->hwif_data = pmif;
+ pmac_ide_init_hwif_ports(&hwif->hw, pmif->regbase, 0, &hwif->irq);
+ memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
+ hwif->chipset = ide_pmac;
+ hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET] || pmif->mediabay;
+ hwif->hold = pmif->mediabay;
+ hwif->udma_four = pmif->cable_80;
+ hwif->drives[0].unmask = 1;
+ hwif->drives[1].unmask = 1;
+ hwif->tuneproc = pmac_ide_tuneproc;
+ if (pmif->kind == controller_un_ata6
+ || pmif->kind == controller_k2_ata6
+ || pmif->kind == controller_sh_ata6)
+ hwif->selectproc = pmac_ide_kauai_selectproc;
+ else
+ hwif->selectproc = pmac_ide_selectproc;
+ hwif->speedproc = pmac_ide_tune_chipset;
+
+#ifdef CONFIG_BLK_DEV_IDE_PMAC_BLINK
+ pmu_ide_blink_enabled = pmu_hd_blink_init();
+
+ if (pmu_ide_blink_enabled)
+ hwif->led_act = pmu_hd_kick_blink;
+#endif
+
+ printk(KERN_INFO "ide%d: Found Apple %s controller, bus ID %d%s, irq %d\n",
+ hwif->index, model_name[pmif->kind], pmif->aapl_bus_id,
+ pmif->mediabay ? " (mediabay)" : "", hwif->irq);
+
+#ifdef CONFIG_PMAC_PBOOK
+ if (pmif->mediabay && check_media_bay_by_base(pmif->regbase, MB_CD) == 0)
+ hwif->noprobe = 0;
+#endif /* CONFIG_PMAC_PBOOK */
+
+ hwif->sg_max_nents = MAX_DCMDS;
+
+#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
+ /* has a DBDMA controller channel */
+ if (pmif->dma_regs)
+ pmac_ide_setup_dma(pmif, hwif);
+#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
+
+ /* We probe the hwif now */
+ probe_hwif_init(hwif);
+
+ /* The code IDE code will have set hwif->present if we have devices attached,
+ * if we don't, the discard the interface except if we are on a media bay slot
+ */
+ if (!hwif->present && !pmif->mediabay) {
+ printk(KERN_INFO "ide%d: Bus empty, interface released.\n",
+ hwif->index);
+ default_hwif_iops(hwif);
+ for (i = IDE_DATA_OFFSET; i <= IDE_CONTROL_OFFSET; ++i)
+ hwif->io_ports[i] = 0;
+ hwif->chipset = ide_unknown;
+ hwif->noprobe = 1;
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+/*
+ * Attach to a macio probed interface
+ */
+static int __devinit
+pmac_ide_macio_attach(struct macio_dev *mdev, const struct of_match *match)
+{
+ void __iomem *base;
+ unsigned long regbase;
+ int irq;
+ ide_hwif_t *hwif;
+ pmac_ide_hwif_t *pmif;
+ int i, rc;
+
+ i = 0;
+ while (i < MAX_HWIFS && (ide_hwifs[i].io_ports[IDE_DATA_OFFSET] != 0
+ || pmac_ide[i].node != NULL))
+ ++i;
+ if (i >= MAX_HWIFS) {
+ printk(KERN_ERR "ide-pmac: MacIO interface attach with no slot\n");
+ printk(KERN_ERR " %s\n", mdev->ofdev.node->full_name);
+ return -ENODEV;
+ }
+
+ pmif = &pmac_ide[i];
+ hwif = &ide_hwifs[i];
+
+ if (mdev->ofdev.node->n_addrs == 0) {
+ printk(KERN_WARNING "ide%d: no address for %s\n",
+ i, mdev->ofdev.node->full_name);
+ return -ENXIO;
+ }
+
+ /* Request memory resource for IO ports */
+ if (macio_request_resource(mdev, 0, "ide-pmac (ports)")) {
+ printk(KERN_ERR "ide%d: can't request mmio resource !\n", i);
+ return -EBUSY;
+ }
+
+ /* 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%d: no intrs for device %s, using 13\n",
+ i, mdev->ofdev.node->full_name);
+ irq = 13;
+ } else
+ irq = macio_irq(mdev, 0);
+
+ base = ioremap(macio_resource_start(mdev, 0), 0x400);
+ regbase = (unsigned long) base;
+
+ hwif->pci_dev = mdev->bus->pdev;
+ hwif->gendev.parent = &mdev->ofdev.dev;
+
+ pmif->mdev = mdev;
+ pmif->node = mdev->ofdev.node;
+ pmif->regbase = regbase;
+ pmif->irq = irq;
+ pmif->kauai_fcr = NULL;
+#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
+ if (macio_resource_count(mdev) >= 2) {
+ if (macio_request_resource(mdev, 1, "ide-pmac (dma)"))
+ printk(KERN_WARNING "ide%d: can't request DMA resource !\n", i);
+ else
+ pmif->dma_regs = ioremap(macio_resource_start(mdev, 1), 0x1000);
+ } else
+ pmif->dma_regs = NULL;
+#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
+ dev_set_drvdata(&mdev->ofdev.dev, hwif);
+
+ rc = pmac_ide_setup_device(pmif, hwif);
+ 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);
+ memset(pmif, 0, sizeof(*pmif));
+ macio_release_resource(mdev, 0);
+ if (pmif->dma_regs)
+ macio_release_resource(mdev, 1);
+ }
+
+ return rc;
+}
+
+static int
+pmac_ide_macio_suspend(struct macio_dev *mdev, u32 state)
+{
+ ide_hwif_t *hwif = (ide_hwif_t *)dev_get_drvdata(&mdev->ofdev.dev);
+ int rc = 0;
+
+ if (state != mdev->ofdev.dev.power.power_state && state >= 2) {
+ rc = pmac_ide_do_suspend(hwif);
+ if (rc == 0)
+ mdev->ofdev.dev.power.power_state = state;
+ }
+
+ return rc;
+}
+
+static int
+pmac_ide_macio_resume(struct macio_dev *mdev)
+{
+ ide_hwif_t *hwif = (ide_hwif_t *)dev_get_drvdata(&mdev->ofdev.dev);
+ int rc = 0;
+
+ if (mdev->ofdev.dev.power.power_state != 0) {
+ rc = pmac_ide_do_resume(hwif);
+ if (rc == 0)
+ mdev->ofdev.dev.power.power_state = 0;
+ }
+
+ 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)
+{
+ ide_hwif_t *hwif;
+ struct device_node *np;
+ pmac_ide_hwif_t *pmif;
+ void __iomem *base;
+ unsigned long rbase, rlen;
+ int i, rc;
+
+ 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;
+ }
+ i = 0;
+ while (i < MAX_HWIFS && (ide_hwifs[i].io_ports[IDE_DATA_OFFSET] != 0
+ || pmac_ide[i].node != NULL))
+ ++i;
+ if (i >= MAX_HWIFS) {
+ printk(KERN_ERR "ide-pmac: PCI interface attach with no slot\n");
+ printk(KERN_ERR " %s\n", np->full_name);
+ return -ENODEV;
+ }
+
+ pmif = &pmac_ide[i];
+ hwif = &ide_hwifs[i];
+
+ if (pci_enable_device(pdev)) {
+ printk(KERN_WARNING "ide%i: Can't enable PCI device for %s\n",
+ i, np->full_name);
+ return -ENXIO;
+ }
+ pci_set_master(pdev);
+
+ if (pci_request_regions(pdev, "Kauai ATA")) {
+ printk(KERN_ERR "ide%d: Cannot obtain PCI resources for %s\n",
+ i, np->full_name);
+ return -ENXIO;
+ }
+
+ hwif->pci_dev = pdev;
+ hwif->gendev.parent = &pdev->dev;
+ 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;
+#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
+ pmif->dma_regs = base + 0x1000;
+#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
+ pmif->kauai_fcr = base;
+ pmif->irq = pdev->irq;
+
+ pci_set_drvdata(pdev, hwif);
+
+ rc = pmac_ide_setup_device(pmif, hwif);
+ if (rc != 0) {
+ /* The inteface is released to the common IDE layer */
+ pci_set_drvdata(pdev, NULL);
+ iounmap(base);
+ memset(pmif, 0, sizeof(*pmif));
+ pci_release_regions(pdev);
+ }
+
+ return rc;
+}
+
+static int
+pmac_ide_pci_suspend(struct pci_dev *pdev, u32 state)
+{
+ ide_hwif_t *hwif = (ide_hwif_t *)pci_get_drvdata(pdev);
+ int rc = 0;
+
+ if (state != pdev->dev.power.power_state && state >= 2) {
+ rc = pmac_ide_do_suspend(hwif);
+ if (rc == 0)
+ pdev->dev.power.power_state = state;
+ }
+
+ return rc;
+}
+
+static int
+pmac_ide_pci_resume(struct pci_dev *pdev)
+{
+ ide_hwif_t *hwif = (ide_hwif_t *)pci_get_drvdata(pdev);
+ int rc = 0;
+
+ if (pdev->dev.power.power_state != 0) {
+ rc = pmac_ide_do_resume(hwif);
+ if (rc == 0)
+ pdev->dev.power.power_state = 0;
+ }
+
+ return rc;
+}
+
+static struct of_match pmac_ide_macio_match[] =
+{
+ {
+ .name = "IDE",
+ .type = OF_ANY_MATCH,
+ .compatible = OF_ANY_MATCH
+ },
+ {
+ .name = "ATA",
+ .type = OF_ANY_MATCH,
+ .compatible = OF_ANY_MATCH
+ },
+ {
+ .name = OF_ANY_MATCH,
+ .type = "ide",
+ .compatible = OF_ANY_MATCH
+ },
+ {
+ .name = OF_ANY_MATCH,
+ .type = "ata",
+ .compatible = OF_ANY_MATCH
+ },
+ {},
+};
+
+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 struct pci_device_id pmac_ide_pci_match[] = {
+ { PCI_VENDOR_ID_APPLE, PCI_DEVIEC_ID_APPLE_UNI_N_ATA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_IPID_ATA100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_K2_ATA100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_SH_ATA,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 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);
+
+void __init
+pmac_ide_probe(void)
+{
+ if (_machine != _MACH_Pmac)
+ return;
+
+#ifdef CONFIG_BLK_DEV_IDE_PMAC_ATA100FIRST
+ pci_register_driver(&pmac_ide_pci_driver);
+ macio_register_driver(&pmac_ide_macio_driver);
+#else
+ macio_register_driver(&pmac_ide_macio_driver);
+ pci_register_driver(&pmac_ide_pci_driver);
+#endif
+}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
+
+/*
+ * pmac_ide_build_dmatable builds the DBDMA command list
+ * for a transfer and sets the DBDMA channel to point to it.
+ */
+static int __pmac
+pmac_ide_build_dmatable(ide_drive_t *drive, struct request *rq)
+{
+ struct dbdma_cmd *table;
+ int i, count = 0;
+ ide_hwif_t *hwif = HWIF(drive);
+ pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)hwif->hwif_data;
+ 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++;
+ 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:
+ pci_unmap_sg(hwif->pci_dev,
+ hwif->sg_table,
+ hwif->sg_nents,
+ hwif->sg_dma_direction);
+ return 0; /* revert to PIO for this request */
+}
+
+/* Teardown mappings after DMA has completed. */
+static void __pmac
+pmac_ide_destroy_dmatable (ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ struct pci_dev *dev = HWIF(drive)->pci_dev;
+ struct scatterlist *sg = hwif->sg_table;
+ int nents = hwif->sg_nents;
+
+ if (nents) {
+ pci_unmap_sg(dev, sg, nents, hwif->sg_dma_direction);
+ hwif->sg_nents = 0;
+ }
+}
+
+/*
+ * Pick up best MDMA timing for the drive and apply it
+ */
+static int __pmac
+pmac_ide_mdma_enable(ide_drive_t *drive, u16 mode)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)hwif->hwif_data;
+ int drive_cycle_time;
+ struct hd_driveid *id = drive->id;
+ u32 *timings, *timings2;
+ u32 timing_local[2];
+ int ret;
+
+ /* which drive is it ? */
+ timings = &pmif->timings[drive->select.b.unit & 0x01];
+ timings2 = &pmif->timings[(drive->select.b.unit & 0x01) + 2];
+
+ /* Check if drive provide explicit cycle time */
+ if ((id->field_valid & 2) && (id->eide_dma_time))
+ drive_cycle_time = id->eide_dma_time;
+ else
+ drive_cycle_time = 0;
+
+ /* Copy timings to local image */
+ timing_local[0] = *timings;
+ timing_local[1] = *timings2;
+
+ /* Calculate controller timings */
+ ret = set_timings_mdma( drive, pmif->kind,
+ &timing_local[0],
+ &timing_local[1],
+ mode,
+ drive_cycle_time);
+ if (ret)
+ return 0;
+
+ /* Set feature on drive */
+ printk(KERN_INFO "%s: Enabling MultiWord DMA %d\n", drive->name, mode & 0xf);
+ ret = pmac_ide_do_setfeature(drive, mode);
+ if (ret) {
+ printk(KERN_WARNING "%s: Failed !\n", drive->name);
+ return 0;
+ }
+
+ /* Apply timings to controller */
+ *timings = timing_local[0];
+ *timings2 = timing_local[1];
+
+ /* Set speed info in drive */
+ drive->current_speed = mode;
+ if (!drive->init_speed)
+ drive->init_speed = mode;
+
+ return 1;
+}
+
+/*
+ * Pick up best UDMA timing for the drive and apply it
+ */
+static int __pmac
+pmac_ide_udma_enable(ide_drive_t *drive, u16 mode)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)hwif->hwif_data;
+ u32 *timings, *timings2;
+ u32 timing_local[2];
+ int ret;
+
+ /* which drive is it ? */
+ timings = &pmif->timings[drive->select.b.unit & 0x01];
+ timings2 = &pmif->timings[(drive->select.b.unit & 0x01) + 2];
+
+ /* Copy timings to local image */
+ timing_local[0] = *timings;
+ timing_local[1] = *timings2;
+
+ /* Calculate timings for interface */
+ if (pmif->kind == controller_un_ata6
+ || pmif->kind == controller_k2_ata6)
+ ret = set_timings_udma_ata6( &timing_local[0],
+ &timing_local[1],
+ mode);
+ else if (pmif->kind == controller_sh_ata6)
+ ret = set_timings_udma_shasta( &timing_local[0],
+ &timing_local[1],
+ mode);
+ else
+ ret = set_timings_udma_ata4(&timing_local[0], mode);
+ if (ret)
+ return 0;
+
+ /* Set feature on drive */
+ printk(KERN_INFO "%s: Enabling Ultra DMA %d\n", drive->name, mode & 0x0f);
+ ret = pmac_ide_do_setfeature(drive, mode);
+ if (ret) {
+ printk(KERN_WARNING "%s: Failed !\n", drive->name);
+ return 0;
+ }
+
+ /* Apply timings to controller */
+ *timings = timing_local[0];
+ *timings2 = timing_local[1];
+
+ /* Set speed info in drive */
+ drive->current_speed = mode;
+ if (!drive->init_speed)
+ drive->init_speed = mode;
+
+ return 1;
+}
+
+/*
+ * Check what is the best DMA timing setting for the drive and
+ * call appropriate functions to apply it.
+ */
+static int __pmac
+pmac_ide_dma_check(ide_drive_t *drive)
+{
+ struct hd_driveid *id = drive->id;
+ ide_hwif_t *hwif = HWIF(drive);
+ pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)hwif->hwif_data;
+ int enable = 1;
+ int map;
+ drive->using_dma = 0;
+
+ if (drive->media == ide_floppy)
+ enable = 0;
+ if (((id->capability & 1) == 0) && !__ide_dma_good_drive(drive))
+ enable = 0;
+ if (__ide_dma_bad_drive(drive))
+ enable = 0;
+
+ if (enable) {
+ short mode;
+
+ map = XFER_MWDMA;
+ if (pmif->kind == controller_kl_ata4
+ || pmif->kind == controller_un_ata6
+ || pmif->kind == controller_k2_ata6
+ || pmif->kind == controller_sh_ata6) {
+ map |= XFER_UDMA;
+ if (pmif->cable_80) {
+ map |= XFER_UDMA_66;
+ if (pmif->kind == controller_un_ata6 ||
+ pmif->kind == controller_k2_ata6 ||
+ pmif->kind == controller_sh_ata6)
+ map |= XFER_UDMA_100;
+ if (pmif->kind == controller_sh_ata6)
+ map |= XFER_UDMA_133;
+ }
+ }
+ mode = ide_find_best_mode(drive, map);
+ if (mode & XFER_UDMA)
+ drive->using_dma = pmac_ide_udma_enable(drive, mode);
+ else if (mode & XFER_MWDMA)
+ drive->using_dma = pmac_ide_mdma_enable(drive, mode);
+ hwif->OUTB(0, IDE_CONTROL_REG);
+ /* Apply settings to controller */
+ pmac_ide_do_update_timings(drive);
+ }
+ return 0;
+}
+
+/*
+ * 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
+pmac_ide_dma_setup(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)hwif->hwif_data;
+ struct request *rq = HWGROUP(drive)->rq;
+ u8 unit = (drive->select.b.unit & 0x01);
+ u8 ata4;
+
+ if (pmif == NULL)
+ return 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
+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
+pmac_ide_dma_start(ide_drive_t *drive)
+{
+ pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data;
+ 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
+pmac_ide_dma_end (ide_drive_t *drive)
+{
+ pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data;
+ volatile struct dbdma_regs __iomem *dma;
+ u32 dstat;
+
+ if (pmif == NULL)
+ return 0;
+ dma = pmif->dma_regs;
+
+ drive->waiting_for_dma = 0;
+ dstat = readl(&dma->status);
+ writel(((RUN|WAKE|DEAD) << 16), &dma->control);
+ pmac_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
+pmac_ide_dma_test_irq (ide_drive_t *drive)
+{
+ pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data;
+ volatile struct dbdma_regs __iomem *dma;
+ unsigned long status, timeout;
+
+ if (pmif == NULL)
+ return 0;
+ dma = pmif->dma_regs;
+
+ /* 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 (!drive->waiting_for_dma)
+ printk(KERN_WARNING "ide%d, ide_dma_test_irq \
+ called while not waiting\n", HWIF(drive)->index);
+
+ /* 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 int __pmac
+pmac_ide_dma_host_off (ide_drive_t *drive)
+{
+ return 0;
+}
+
+static int __pmac
+pmac_ide_dma_host_on (ide_drive_t *drive)
+{
+ return 0;
+}
+
+static int __pmac
+pmac_ide_dma_lostirq (ide_drive_t *drive)
+{
+ pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data;
+ volatile struct dbdma_regs __iomem *dma;
+ unsigned long status;
+
+ if (pmif == NULL)
+ return 0;
+ dma = pmif->dma_regs;
+
+ status = readl(&dma->status);
+ printk(KERN_ERR "ide-pmac lost interrupt, dma status: %lx\n", status);
+ return 0;
+}
+
+/*
+ * Allocate the data structures needed for using DMA with an interface
+ * and fill the proper list of functions pointers
+ */
+static void __init
+pmac_ide_setup_dma(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
+{
+ /* We won't need pci_dev if we switch to generic consistent
+ * DMA routines ...
+ */
+ if (hwif->pci_dev == NULL)
+ return;
+ /*
+ * 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(
+ hwif->pci_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;
+ }
+
+ hwif->ide_dma_off_quietly = &__ide_dma_off_quietly;
+ hwif->ide_dma_on = &__ide_dma_on;
+ hwif->ide_dma_check = &pmac_ide_dma_check;
+ hwif->dma_setup = &pmac_ide_dma_setup;
+ hwif->dma_exec_cmd = &pmac_ide_dma_exec_cmd;
+ hwif->dma_start = &pmac_ide_dma_start;
+ hwif->ide_dma_end = &pmac_ide_dma_end;
+ hwif->ide_dma_test_irq = &pmac_ide_dma_test_irq;
+ hwif->ide_dma_host_off = &pmac_ide_dma_host_off;
+ hwif->ide_dma_host_on = &pmac_ide_dma_host_on;
+ hwif->ide_dma_timeout = &__ide_dma_timeout;
+ hwif->ide_dma_lostirq = &pmac_ide_dma_lostirq;
+
+ hwif->atapi_dma = 1;
+ switch(pmif->kind) {
+ case controller_sh_ata6:
+ hwif->ultra_mask = pmif->cable_80 ? 0x7f : 0x07;
+ hwif->mwdma_mask = 0x07;
+ hwif->swdma_mask = 0x00;
+ break;
+ case controller_un_ata6:
+ case controller_k2_ata6:
+ hwif->ultra_mask = pmif->cable_80 ? 0x3f : 0x07;
+ hwif->mwdma_mask = 0x07;
+ hwif->swdma_mask = 0x00;
+ break;
+ case controller_kl_ata4:
+ hwif->ultra_mask = pmif->cable_80 ? 0x1f : 0x07;
+ hwif->mwdma_mask = 0x07;
+ hwif->swdma_mask = 0x00;
+ break;
+ default:
+ hwif->ultra_mask = 0x00;
+ hwif->mwdma_mask = 0x07;
+ hwif->swdma_mask = 0x00;
+ break;
+ }
+}
+
+#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
diff --git a/drivers/ide/setup-pci.c b/drivers/ide/setup-pci.c
new file mode 100644
index 000000000000..e501675ad72e
--- /dev/null
+++ b/drivers/ide/setup-pci.c
@@ -0,0 +1,901 @@
+/*
+ * linux/drivers/ide/setup-pci.c Version 1.10 2002/08/19
+ *
+ * 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
+ *
+ * Recent Changes
+ * Split the set up function into multiple functions
+ * Use pci_set_master
+ * Fix misreporting of I/O v MMIO problems
+ * Initial fixups for simplex devices
+ */
+
+/*
+ * This module provides support for automatic detection and
+ * configuration of all PCI IDE interfaces present in a system.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/ide.h>
+#include <linux/dma-mapping.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+
+/**
+ * ide_match_hwif - match a PCI IDE against an ide_hwif
+ * @io_base: I/O base of device
+ * @bootable: set if its bootable
+ * @name: name of device
+ *
+ * Match a PCI IDE port against an entry in ide_hwifs[],
+ * based on io_base port if possible. Return the matching hwif,
+ * or a new hwif. If we find an error (clashing, out of devices, etc)
+ * return NULL
+ *
+ * FIXME: we need to handle mmio matches here too
+ */
+
+static ide_hwif_t *ide_match_hwif(unsigned long io_base, u8 bootable, const char *name)
+{
+ int h;
+ ide_hwif_t *hwif;
+
+ /*
+ * Look for a hwif with matching io_base specified using
+ * parameters to ide_setup().
+ */
+ for (h = 0; h < MAX_HWIFS; ++h) {
+ hwif = &ide_hwifs[h];
+ if (hwif->io_ports[IDE_DATA_OFFSET] == io_base) {
+ if (hwif->chipset == ide_forced)
+ return hwif; /* a perfect match */
+ }
+ }
+ /*
+ * Look for a hwif with matching io_base default value.
+ * If chipset is "ide_unknown", then claim that hwif slot.
+ * Otherwise, some other chipset has already claimed it.. :(
+ */
+ for (h = 0; h < MAX_HWIFS; ++h) {
+ hwif = &ide_hwifs[h];
+ if (hwif->io_ports[IDE_DATA_OFFSET] == io_base) {
+ if (hwif->chipset == ide_unknown)
+ return hwif; /* match */
+ printk(KERN_ERR "%s: port 0x%04lx already claimed by %s\n",
+ name, io_base, hwif->name);
+ return NULL; /* already claimed */
+ }
+ }
+ /*
+ * Okay, there is no hwif matching our io_base,
+ * so we'll just 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 1f0/170 (the ide0/ide1 defaults).
+ *
+ * Unless there is a bootable card that does not use the standard
+ * ports 1f0/170 (the ide0/ide1 defaults). The (bootable) flag.
+ */
+ if (bootable) {
+ for (h = 0; h < MAX_HWIFS; ++h) {
+ hwif = &ide_hwifs[h];
+ if (hwif->chipset == ide_unknown)
+ return hwif; /* pick an unused entry */
+ }
+ } else {
+ for (h = 2; h < MAX_HWIFS; ++h) {
+ hwif = ide_hwifs + h;
+ if (hwif->chipset == ide_unknown)
+ return hwif; /* pick an unused entry */
+ }
+ }
+ for (h = 0; h < 2; ++h) {
+ hwif = ide_hwifs + h;
+ if (hwif->chipset == ide_unknown)
+ return hwif; /* pick an unused entry */
+ }
+ printk(KERN_ERR "%s: too many IDE interfaces, no room in table\n", name);
+ return NULL;
+}
+
+/**
+ * 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: device not capable of full "
+ "native PCI mode\n", name);
+ return -EOPNOTSUPP;
+ }
+ printk("%s: placing both ports into native PCI mode\n", name);
+ (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: rewrite of PROGIF failed, wanted "
+ "0x%04x, got 0x%04x\n",
+ name, progif|5, progif);
+ return -EOPNOTSUPP;
+ }
+ }
+ return 0;
+}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA_PCI
+
+#ifdef CONFIG_BLK_DEV_IDEDMA_FORCED
+/*
+ * Long lost data from 2.0.34 that is now in 2.0.39
+ *
+ * This was used in ./drivers/block/triton.c to do DMA Base address setup
+ * when PnP failed. Oh the things we forget. I believe this was part
+ * of SFF-8038i that has been withdrawn from public access... :-((
+ */
+#define DEFAULT_BMIBA 0xe800 /* in case BIOS did not init it */
+#define DEFAULT_BMCRBA 0xcc00 /* VIA's default value */
+#define DEFAULT_BMALIBA 0xd400 /* ALI's default value */
+#endif /* CONFIG_BLK_DEV_IDEDMA_FORCED */
+
+/**
+ * ide_get_or_set_dma_base - setup BMIBA
+ * @hwif: Interface
+ *
+ * Fetch the DMA Bus-Master-I/O-Base-Address (BMIBA) from PCI space:
+ * If need be we set up the DMA base. Where a device has a partner that
+ * is already in DMA mode we check and enforce IDE simplex rules.
+ */
+
+static unsigned long ide_get_or_set_dma_base (ide_hwif_t *hwif)
+{
+ unsigned long dma_base = 0;
+ struct pci_dev *dev = hwif->pci_dev;
+
+#ifdef CONFIG_BLK_DEV_IDEDMA_FORCED
+ int second_chance = 0;
+
+second_chance_to_dma:
+#endif /* CONFIG_BLK_DEV_IDEDMA_FORCED */
+
+ if (hwif->mmio)
+ return hwif->dma_base;
+
+ if (hwif->mate && hwif->mate->dma_base) {
+ dma_base = hwif->mate->dma_base - (hwif->channel ? 0 : 8);
+ } else {
+ dma_base = pci_resource_start(dev, 4);
+ if (!dma_base) {
+ printk(KERN_ERR "%s: dma_base is invalid\n",
+ hwif->cds->name);
+ }
+ }
+
+#ifdef CONFIG_BLK_DEV_IDEDMA_FORCED
+ /* FIXME - should use pci_assign_resource surely */
+ if ((!dma_base) && (!second_chance)) {
+ unsigned long set_bmiba = 0;
+ second_chance++;
+ switch(dev->vendor) {
+ case PCI_VENDOR_ID_AL:
+ set_bmiba = DEFAULT_BMALIBA; break;
+ case PCI_VENDOR_ID_VIA:
+ set_bmiba = DEFAULT_BMCRBA; break;
+ case PCI_VENDOR_ID_INTEL:
+ set_bmiba = DEFAULT_BMIBA; break;
+ default:
+ return dma_base;
+ }
+ pci_write_config_dword(dev, 0x20, set_bmiba|1);
+ goto second_chance_to_dma;
+ }
+#endif /* CONFIG_BLK_DEV_IDEDMA_FORCED */
+
+ if (dma_base) {
+ u8 simplex_stat = 0;
+ dma_base += hwif->channel ? 8 : 0;
+
+ switch(dev->device) {
+ case PCI_DEVICE_ID_AL_M5219:
+ case PCI_DEVICE_ID_AL_M5229:
+ case PCI_DEVICE_ID_AMD_VIPER_7409:
+ case PCI_DEVICE_ID_CMD_643:
+ case PCI_DEVICE_ID_SERVERWORKS_CSB5IDE:
+ simplex_stat = hwif->INB(dma_base + 2);
+ hwif->OUTB((simplex_stat&0x60),(dma_base + 2));
+ simplex_stat = hwif->INB(dma_base + 2);
+ if (simplex_stat & 0x80) {
+ printk(KERN_INFO "%s: simplex device: "
+ "DMA forced\n",
+ hwif->cds->name);
+ }
+ break;
+ default:
+ /*
+ * If the device claims "simplex" DMA,
+ * this means 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.
+ */
+ simplex_stat = hwif->INB(dma_base + 2);
+ if (simplex_stat & 0x80) {
+ /* simplex device? */
+/*
+ * 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.
+ */
+ if (hwif->mate && hwif->mate->dma_base) {
+ printk(KERN_INFO "%s: simplex device: "
+ "DMA disabled\n",
+ hwif->cds->name);
+ dma_base = 0;
+ }
+ }
+ }
+ }
+ return dma_base;
+}
+#endif /* CONFIG_BLK_DEV_IDEDMA_PCI */
+
+void ide_setup_pci_noise (struct pci_dev *dev, ide_pci_device_t *d)
+{
+ printk(KERN_INFO "%s: IDE controller at PCI slot %s\n",
+ d->name, pci_name(dev));
+}
+
+EXPORT_SYMBOL_GPL(ide_setup_pci_noise);
+
+
+/**
+ * ide_pci_enable - do PCI enables
+ * @dev: PCI device
+ * @d: IDE pci device data
+ *
+ * Enable the IDE PCI device. We attempt to enable the device in full
+ * but if that fails then we only need BAR4 so we will enable that.
+ *
+ * Returns zero on success or an error code
+ */
+
+static int ide_pci_enable(struct pci_dev *dev, ide_pci_device_t *d)
+{
+ int ret;
+
+ if (pci_enable_device(dev)) {
+ ret = pci_enable_device_bars(dev, 1 << 4);
+ if (ret < 0) {
+ printk(KERN_WARNING "%s: (ide_setup_pci_device:) "
+ "Could not enable device.\n", d->name);
+ goto out;
+ }
+ printk(KERN_WARNING "%s: BIOS configuration fixed.\n", d->name);
+ }
+
+ /*
+ * assume all devices can do 32-bit dma for now. we can add a
+ * dma mask field to the ide_pci_device_t 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: can't set dma mask\n", d->name);
+ goto out;
+ }
+
+ /* FIXME: Temporary - until we put in the hotplug interface logic
+ Check that the bits we want are not in use by someone else. */
+ ret = pci_request_region(dev, 4, "ide_tmp");
+ if (ret < 0)
+ goto out;
+
+ pci_release_region(dev, 4);
+out:
+ return ret;
+}
+
+/**
+ * ide_pci_configure - configure an unconfigured device
+ * @dev: PCI device
+ * @d: IDE pci device data
+ *
+ * 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, ide_pci_device_t *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: device disabled (BIOS)\n", d->name);
+ return -ENODEV;
+ }
+ if (pci_read_config_word(dev, PCI_COMMAND, &pcicmd)) {
+ printk(KERN_ERR "%s: error accessing PCI regs\n", d->name);
+ return -EIO;
+ }
+ if (!(pcicmd & PCI_COMMAND_IO)) {
+ printk(KERN_ERR "%s: unable to enable IDE controller\n", d->name);
+ return -ENXIO;
+ }
+ return 0;
+}
+
+/**
+ * ide_pci_check_iomem - check a register is I/O
+ * @dev: pci device
+ * @d: ide_pci_device
+ * @bar: bar number
+ *
+ * Checks if a BAR is configured and points to MMIO space. If so
+ * print an error and return an error code. Otherwise return 0
+ */
+
+static int ide_pci_check_iomem(struct pci_dev *dev, ide_pci_device_t *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 & PCI_BASE_ADDRESS_IO_MASK)
+ return 0;
+
+ /* Bad */
+ printk(KERN_ERR "%s: IO baseregs (BIOS) are reported "
+ "as MEM, report to "
+ "<andre@linux-ide.org>.\n", d->name);
+ return -EINVAL;
+}
+
+/**
+ * ide_hwif_configure - configure an IDE interface
+ * @dev: PCI device holding interface
+ * @d: IDE pci data
+ * @mate: Paired interface if any
+ *
+ * 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 the new hardware interface structure, or NULL on a failure
+ */
+
+static ide_hwif_t *ide_hwif_configure(struct pci_dev *dev, ide_pci_device_t *d, ide_hwif_t *mate, int port, int irq)
+{
+ unsigned long ctl = 0, base = 0;
+ ide_hwif_t *hwif;
+
+ if ((d->flags & IDEPCI_FLAG_ISA_PORTS) == 0) {
+ /* Possibly we should fail if these checks report true */
+ ide_pci_check_iomem(dev, d, 2*port);
+ ide_pci_check_iomem(dev, d, 2*port+1);
+
+ ctl = pci_resource_start(dev, 2*port+1);
+ base = pci_resource_start(dev, 2*port);
+ if ((ctl && !base) || (base && !ctl)) {
+ printk(KERN_ERR "%s: inconsistent baseregs (BIOS) "
+ "for port %d, skipping\n", d->name, port);
+ return NULL;
+ }
+ }
+ if (!ctl)
+ {
+ /* Use default values */
+ ctl = port ? 0x374 : 0x3f4;
+ base = port ? 0x170 : 0x1f0;
+ }
+ if ((hwif = ide_match_hwif(base, d->bootable, d->name)) == NULL)
+ return NULL; /* no room in ide_hwifs[] */
+ if (hwif->io_ports[IDE_DATA_OFFSET] != base ||
+ hwif->io_ports[IDE_CONTROL_OFFSET] != (ctl | 2)) {
+ memset(&hwif->hw, 0, sizeof(hwif->hw));
+#ifndef IDE_ARCH_OBSOLETE_INIT
+ ide_std_init_ports(&hwif->hw, base, (ctl | 2));
+ hwif->hw.io_ports[IDE_IRQ_OFFSET] = 0;
+#else
+ ide_init_hwif_ports(&hwif->hw, base, (ctl | 2), NULL);
+#endif
+ memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
+ hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET];
+ }
+ hwif->chipset = ide_pci;
+ hwif->pci_dev = dev;
+ hwif->cds = (struct ide_pci_device_s *) d;
+ hwif->channel = port;
+
+ if (!hwif->irq)
+ hwif->irq = irq;
+ if (mate) {
+ hwif->mate = mate;
+ mate->mate = hwif;
+ }
+ return hwif;
+}
+
+/**
+ * ide_hwif_setup_dma - configure DMA interface
+ * @dev: PCI device
+ * @d: IDE pci data
+ * @hwif: Hardware interface we are configuring
+ *
+ * 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
+ */
+
+#ifndef CONFIG_BLK_DEV_IDEDMA_PCI
+static void ide_hwif_setup_dma(struct pci_dev *dev, ide_pci_device_t *d, ide_hwif_t *hwif)
+{
+}
+#else
+static void ide_hwif_setup_dma(struct pci_dev *dev, ide_pci_device_t *d, ide_hwif_t *hwif)
+{
+ u16 pcicmd;
+ pci_read_config_word(dev, PCI_COMMAND, &pcicmd);
+
+ if ((d->autodma == AUTODMA) ||
+ ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE &&
+ (dev->class & 0x80))) {
+ unsigned long dma_base = ide_get_or_set_dma_base(hwif);
+ if (dma_base && !(pcicmd & PCI_COMMAND_MASTER)) {
+ /*
+ * Set up BM-DMA capability
+ * (PnP BIOS should have done this)
+ */
+ /* default DMA off if we had to configure it here */
+ hwif->autodma = 0;
+ pci_set_master(dev);
+ if (pci_read_config_word(dev, PCI_COMMAND, &pcicmd) || !(pcicmd & PCI_COMMAND_MASTER)) {
+ printk(KERN_ERR "%s: %s error updating PCICMD\n",
+ hwif->name, d->name);
+ dma_base = 0;
+ }
+ }
+ if (dma_base) {
+ if (d->init_dma) {
+ d->init_dma(hwif, dma_base);
+ } else {
+ ide_setup_dma(hwif, dma_base, 8);
+ }
+ } else {
+ printk(KERN_INFO "%s: %s Bus-Master DMA disabled "
+ "(BIOS)\n", hwif->name, d->name);
+ }
+ }
+}
+
+#ifndef CONFIG_IDEDMA_PCI_AUTO
+#warning CONFIG_IDEDMA_PCI_AUTO=n support is obsolete, and will be removed soon.
+#endif
+
+#endif /* CONFIG_BLK_DEV_IDEDMA_PCI*/
+
+/**
+ * ide_setup_pci_controller - set up IDE PCI
+ * @dev: PCI device
+ * @d: IDE PCI data
+ * @noisy: verbose flag
+ * @config: returned as 1 if we configured the hardware
+ *
+ * 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, ide_pci_device_t *d, int noisy, int *config)
+{
+ int ret;
+ u32 class_rev;
+ 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: error accessing PCI regs\n", d->name);
+ goto out;
+ }
+ if (!(pcicmd & PCI_COMMAND_IO)) { /* is device disabled? */
+ ret = ide_pci_configure(dev, d);
+ if (ret < 0)
+ goto out;
+ *config = 1;
+ printk(KERN_INFO "%s: device enabled (Linux)\n", d->name);
+ }
+
+ pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
+ class_rev &= 0xff;
+ if (noisy)
+ printk(KERN_INFO "%s: chipset revision %d\n", d->name, class_rev);
+out:
+ return ret;
+}
+
+/**
+ * ide_pci_setup_ports - configure ports/devices on PCI IDE
+ * @dev: PCI device
+ * @d: IDE pci device info
+ * @pciirq: IRQ line
+ * @index: ata index 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, ide_pci_device_t *d, int pciirq, ata_index_t *index)
+{
+ int port;
+ int at_least_one_hwif_enabled = 0;
+ ide_hwif_t *hwif, *mate = NULL;
+ static int secondpdc = 0;
+ u8 tmp;
+
+ index->all = 0xf0f0;
+
+ /*
+ * Set up the IDE ports
+ */
+
+ for (port = 0; port <= 1; ++port) {
+ ide_pci_enablebit_t *e = &(d->enablebits[port]);
+
+ /*
+ * If this is a Promise FakeRaid controller,
+ * the 2nd controller will be marked as
+ * disabled while it is actually there and enabled
+ * by the bios for raid purposes.
+ * Skip the normal "is it enabled" test for those.
+ */
+ if ((d->flags & IDEPCI_FLAG_FORCE_PDC) &&
+ (secondpdc++==1) && (port==1))
+ goto controller_ok;
+
+ if (e->reg && (pci_read_config_byte(dev, e->reg, &tmp) ||
+ (tmp & e->mask) != e->val))
+ continue; /* port not enabled */
+controller_ok:
+
+ if (d->channels <= port)
+ break;
+
+ if ((hwif = ide_hwif_configure(dev, d, mate, port, pciirq)) == NULL)
+ continue;
+
+ /* setup proper ancestral information */
+ hwif->gendev.parent = &dev->dev;
+
+ if (hwif->channel) {
+ index->b.high = hwif->index;
+ } else {
+ index->b.low = hwif->index;
+ }
+
+
+ if (d->init_iops)
+ d->init_iops(hwif);
+
+ if (d->autodma == NODMA)
+ goto bypass_legacy_dma;
+
+ if(d->init_setup_dma)
+ d->init_setup_dma(dev, d, hwif);
+ else
+ ide_hwif_setup_dma(dev, d, hwif);
+bypass_legacy_dma:
+ if (d->init_hwif)
+ /* Call chipset-specific routine
+ * for each enabled hwif
+ */
+ d->init_hwif(hwif);
+
+ mate = hwif;
+ at_least_one_hwif_enabled = 1;
+ }
+ if (!at_least_one_hwif_enabled)
+ printk(KERN_INFO "%s: neither IDE port enabled (BIOS)\n", d->name);
+}
+
+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 ide_pci_device_t struct;
+ * for all other chipsets, we just assume both interfaces are enabled.
+ */
+static int do_ide_setup_pci_device(struct pci_dev *dev, ide_pci_device_t *d,
+ ata_index_t *index, u8 noisy)
+{
+ static ata_index_t ata_index = { .b = { .low = 0xff, .high = 0xff } };
+ int tried_config = 0;
+ int pciirq, ret;
+
+ ret = ide_setup_pci_controller(dev, d, noisy, &tried_config);
+ if (ret < 0)
+ goto out;
+
+ /*
+ * Can we trust the reported IRQ?
+ */
+ pciirq = dev->irq;
+
+ /* 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: not 100%% native mode: "
+ "will probe irqs later\n", d->name);
+ /*
+ * 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, d->name) : 0;
+ if (ret < 0)
+ goto out;
+ pciirq = ret;
+ } else if (tried_config) {
+ if (noisy)
+ printk(KERN_INFO "%s: will probe irqs later\n", d->name);
+ pciirq = 0;
+ } else if (!pciirq) {
+ if (noisy)
+ printk(KERN_WARNING "%s: bad irq (%d): will probe later\n",
+ d->name, pciirq);
+ pciirq = 0;
+ } else {
+ if (d->init_chipset) {
+ ret = d->init_chipset(dev, d->name);
+ if (ret < 0)
+ goto out;
+ }
+ if (noisy)
+#ifdef __sparc__
+ printk(KERN_INFO "%s: 100%% native mode on irq %s\n",
+ d->name, __irq_itoa(pciirq));
+#else
+ printk(KERN_INFO "%s: 100%% native mode on irq %d\n",
+ d->name, pciirq);
+#endif
+ }
+
+ /* FIXME: silent failure can happen */
+
+ *index = ata_index;
+ ide_pci_setup_ports(dev, d, pciirq, index);
+out:
+ return ret;
+}
+
+int ide_setup_pci_device(struct pci_dev *dev, ide_pci_device_t *d)
+{
+ ata_index_t index_list;
+ int ret;
+
+ ret = do_ide_setup_pci_device(dev, d, &index_list, 1);
+ if (ret < 0)
+ goto out;
+
+ if ((index_list.b.low & 0xf0) != 0xf0)
+ probe_hwif_init_with_fixup(&ide_hwifs[index_list.b.low], d->fixup);
+ if ((index_list.b.high & 0xf0) != 0xf0)
+ probe_hwif_init_with_fixup(&ide_hwifs[index_list.b.high], d->fixup);
+
+ create_proc_ide_interfaces();
+out:
+ return ret;
+}
+
+EXPORT_SYMBOL_GPL(ide_setup_pci_device);
+
+int ide_setup_pci_devices(struct pci_dev *dev1, struct pci_dev *dev2,
+ ide_pci_device_t *d)
+{
+ struct pci_dev *pdev[] = { dev1, dev2 };
+ ata_index_t index_list[2];
+ int ret, i;
+
+ for (i = 0; i < 2; i++) {
+ ret = do_ide_setup_pci_device(pdev[i], d, index_list + i, !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;
+ }
+
+ for (i = 0; i < 2; i++) {
+ u8 idx[2] = { index_list[i].b.low, index_list[i].b.high };
+ int j;
+
+ for (j = 0; j < 2; j++) {
+ if ((idx[j] & 0xf0) != 0xf0)
+ probe_hwif_init(ide_hwifs + idx[j]);
+ }
+ }
+
+ create_proc_ide_interfaces();
+out:
+ return ret;
+}
+
+EXPORT_SYMBOL_GPL(ide_setup_pci_devices);
+
+/*
+ * Module interfaces
+ */
+
+static int pre_init = 1; /* Before first ordered IDE scan */
+static LIST_HEAD(ide_pci_drivers);
+
+/*
+ * ide_register_pci_driver - attach IDE driver
+ * @driver: pci 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.
+ *
+ * The driver_data of the driver table must point to an ide_pci_device_t
+ * describing the interface.
+ *
+ * Returns are the same as for pci_register_driver
+ */
+
+int ide_pci_register_driver(struct pci_driver *driver)
+{
+ if(!pre_init)
+ return pci_module_init(driver);
+ list_add_tail(&driver->node, &ide_pci_drivers);
+ return 0;
+}
+
+EXPORT_SYMBOL_GPL(ide_pci_register_driver);
+
+/**
+ * ide_unregister_pci_driver - unregister an IDE driver
+ * @driver: driver to remove
+ *
+ * Unregister a currently installed IDE driver. Returns are the same
+ * as for pci_unregister_driver
+ */
+
+void ide_pci_unregister_driver(struct pci_driver *driver)
+{
+ if(!pre_init)
+ pci_unregister_driver(driver);
+ else
+ list_del(&driver->node);
+}
+
+EXPORT_SYMBOL_GPL(ide_pci_unregister_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_device(d->id_table, dev);
+ if(id != NULL)
+ {
+ if(d->probe(dev, id) >= 0)
+ {
+ dev->driver = d;
+ return 1;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+/**
+ * ide_scan_pcibus - perform the initial IDE driver scan
+ * @scan_direction: set for reverse order scanning
+ *
+ * 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.
+ */
+
+void __init ide_scan_pcibus (int scan_direction)
+{
+ struct pci_dev *dev = NULL;
+ struct pci_driver *d;
+ struct list_head *l, *n;
+
+ pre_init = 0;
+ if (!scan_direction) {
+ while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
+ ide_scan_pcidev(dev);
+ }
+ } else {
+ while ((dev = pci_find_device_reverse(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
+ 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);
+ pci_register_driver(d);
+ }
+}