aboutsummaryrefslogtreecommitdiff
path: root/drivers/ide
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 15:20:36 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 15:20:36 -0700
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/ide
downloadlinux-1da177e4c3f41524e886b7f1b8a0c1fc7321cac2.tar.gz
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
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 00000000000..3ac0a535b4a
--- /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 00000000000..5be8ad6dc9e
--- /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 00000000000..6a78f0755f2
--- /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 00000000000..9d474e5fd8d
--- /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 00000000000..308897e57e4
--- /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 00000000000..23488c4d1fc
--- /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 00000000000..3058217767d
--- /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 00000000000..fdc294325d0
--- /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 00000000000..5b40220d3dd
--- /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 00000000000..fb91cb8bf2d
--- /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 00000000000..33a020faeab
--- /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 00000000000..7ca3e5afc66
--- /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 00000000000..5d54f775610
--- /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 00000000000..2d2eefb610d
--- /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 00000000000..36c0b74a4e4
--- /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 00000000000..99fd5615113
--- /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 00000000000..248e3cc8b35
--- /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 00000000000..53024942a7e
--- /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 00000000000..6806d407e9c
--- /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 00000000000..df7d1504f84
--- /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 00000000000..554473a95cf
--- /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 00000000000..bdff5ac5805
--- /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 00000000000..48254485498
--- /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;
+ *