diff options
Diffstat (limited to 'drivers/ide')
149 files changed, 31967 insertions, 42885 deletions
diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig index b6fb167e20f..a04c49f2a01 100644 --- a/drivers/ide/Kconfig +++ b/drivers/ide/Kconfig @@ -1,99 +1,48 @@ # # IDE ATA ATAPI Block device driver configuration # -# Andre Hedrick <andre@linux-ide.org> -# -menu "ATA/ATAPI/MFM/RLL support" +# Select HAVE_IDE if IDE is supported +config HAVE_IDE + bool -config IDE - tristate "ATA/ATAPI/MFM/RLL support" +menuconfig IDE + tristate "ATA/ATAPI/MFM/RLL support (DEPRECATED)" + depends on HAVE_IDE + depends on BLOCK ---help--- - If you say Y here, your kernel will be able to manage low cost mass - storage units such as ATA/(E)IDE and ATAPI units. The most common - cases are IDE hard drives and ATAPI CD-ROM drives. - - If your system is pure SCSI and doesn't use these interfaces, you - can say N here. - - Integrated Disk Electronics (IDE aka ATA-1) is a connecting standard - for mass storage units such as hard disks. It was designed by - Western Digital and Compaq Computer in 1984. It was then named - ST506. Quite a number of disks use the IDE interface. - - AT Attachment (ATA) is the superset of the IDE specifications. - ST506 was also called ATA-1. - - Fast-IDE is ATA-2 (also named Fast ATA), Enhanced IDE (EIDE) is - ATA-3. It provides support for larger disks (up to 8.4GB by means of - the LBA standard), more disks (4 instead of 2) and for other mass - storage units such as tapes and cdrom. UDMA/33 (aka UltraDMA/33) is - ATA-4 and provides faster (and more CPU friendly) transfer modes - than previous PIO (Programmed processor Input/Output) from previous - ATA/IDE standards by means of fast DMA controllers. - - ATA Packet Interface (ATAPI) is a protocol used by EIDE tape and - CD-ROM drives, similar in many respects to the SCSI protocol. - - SMART IDE (Self Monitoring, Analysis and Reporting Technology) was - designed in order to prevent data corruption and disk crash by - detecting pre hardware failure conditions (heat, access time, and - the like...). Disks built since June 1995 may follow this standard. - The kernel itself doesn't manage this; however there are quite a - number of user programs such as smart that can query the status of - SMART parameters from disk drives. + If you say Y here, your kernel will be able to manage ATA/(E)IDE and + ATAPI units. The most common cases are IDE hard drives and ATAPI + CD-ROM drives. + + This subsystem is currently in maintenance mode with only bug fix + changes applied. Users of ATA hardware are encouraged to migrate to + the newer ATA subsystem ("Serial ATA (prod) and Parallel ATA + (experimental) drivers") which is more actively maintained. To compile this driver as a module, choose M here: the - module will be called ide. + module will be called ide-core. - For further information, please read <file:Documentation/ide.txt>. + For further information, please read <file:Documentation/ide/ide.txt>. - If unsure, say Y. + If unsure, say N. if IDE -config IDE_MAX_HWIFS - int "Max IDE interfaces" - depends on ALPHA || SUPERH || IA64 - 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. +comment "Please see Documentation/ide/ide.txt for help/info on IDE 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>. +config IDE_XFER_MODE + bool - To fine-tune ATA/IDE drive/interface parameters for improved - performance, look for the hdparm package at - <ftp://ibiblio.org/pub/Linux/system/hardware/>. +config IDE_TIMINGS + bool + select IDE_XFER_MODE - 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. +config IDE_ATAPI + bool - 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 IDE_LEGACY + bool config BLK_DEV_IDE_SATA bool "Support for SATA (deprecated; conflicts with libata SATA driver)" @@ -101,8 +50,10 @@ config BLK_DEV_IDE_SATA ---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 main driver, "libata", uses the SCSI subsystem + and supports most modern SATA controllers. In order to use it + you may take a look at "Serial ATA (prod) and Parallel ATA + (experimental) drivers". The IDE driver (which you are currently configuring) supports a few first-generation SATA controllers. @@ -115,48 +66,39 @@ config BLK_DEV_IDE_SATA 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. +config IDE_GD + tristate "generic ATA/ATAPI disk support" + default y + help + Support for ATA/ATAPI disks (including ATAPI floppy drives). - To compile this driver as a module, choose M here: the - module will be called ide-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. + To compile this driver as a module, choose M here. + The module will be called ide-gd_mod. If unsure, say Y. -config IDEDISK_MULTI_MODE - bool "Use multi-mode by default" +config IDE_GD_ATA + bool "ATA disk support" + depends on IDE_GD + default y help - If you get this error, try to say Y here: + This will include support for ATA hard disks. + + If unsure, say Y. - hda: set_multmode: status=0x51 { DriveReady SeekComplete Error } - hda: set_multmode: error=0x04 { DriveStatusError } +config IDE_GD_ATAPI + bool "ATAPI floppy support" + depends on IDE_GD + select IDE_ATAPI + help + This will include support for ATAPI floppy drives + (i.e. Iomega ZIP or MKE LS-120). - If in doubt, say N. + For information about jumper settings and the question + of when a ZIP drive uses a partition table, see + <http://www.win.tue.nl/~aeb/linux/zip/zip-1.html>. + + If unsure, say N. config BLK_DEV_IDECS tristate "PCMCIA IDE support" @@ -165,8 +107,16 @@ config BLK_DEV_IDECS Support for Compact Flash cards, outboard IDE disks, tape drives, and CD-ROM drives connected through a PCMCIA card. +config BLK_DEV_DELKIN + tristate "Cardbus IDE support (Delkin/ASKA/Workbit)" + depends on CARDBUS && PCI + help + Support for Delkin, ASKA, and Workbit Cardbus CompactFlash + Adapters. This may also work for similar SD and XD adapters. + config BLK_DEV_IDECD tristate "Include IDE/ATAPI CDROM support" + select IDE_ATAPI ---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 @@ -180,16 +130,21 @@ config BLK_DEV_IDECD 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_IDECD_VERBOSE_ERRORS + bool "Verbose error logging for IDE/ATAPI CDROM driver" if EXPERT + depends on BLK_DEV_IDECD + default y + help + Turn this on to have the driver print out the meanings of the + ATAPI error codes. This will use up additional 8kB of kernel-space + memory, though. + config BLK_DEV_IDETAPE - tristate "Include IDE/ATAPI TAPE support (EXPERIMENTAL)" - depends on EXPERIMENTAL + tristate "Include IDE/ATAPI TAPE support" + select IDE_ATAPI help If you have an IDE tape drive using the ATAPI protocol, say Y. ATAPI is a newer protocol used by IDE tape and CD-ROM drives, @@ -204,63 +159,18 @@ config BLK_DEV_IDETAPE 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. + <file:drivers/ide/ide-tape.c> and <file:Documentation/ide/ide.txt> + files for usage information. To compile this driver as a module, choose M here: the module will be called ide-tape. -config BLK_DEV_IDEFLOPPY - tristate "Include IDE/ATAPI FLOPPY support" +config BLK_DEV_IDEACPI + bool "IDE ACPI support" + depends on ACPI ---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. + Implement ACPI support for generic IDE devices. On modern + machines ACPI support is required to properly handle ACPI S3 states. config IDE_TASK_IOCTL bool "IDE Taskfile Access" @@ -272,17 +182,52 @@ config IDE_TASK_IOCTL If you are unsure, say N here. +config IDE_PROC_FS + bool "legacy /proc/ide/ support" + depends on IDE && PROC_FS + default y + help + This option enables support for the various files in + /proc/ide. In Linux 2.6 this has been superseded by + files in sysfs but many legacy applications rely on this. + + If unsure say Y. + comment "IDE chipset support/bugfixes" config IDE_GENERIC tristate "generic/default IDE chipset support" - default y + depends on ALPHA || X86 || IA64 || M32R || MIPS || ARCH_RPC + default ARM && ARCH_RPC + help + This is the generic IDE driver. This driver attaches to the + fixed legacy ports (e.g. on PCs 0x1f0/0x170, 0x1e8/0x168 and + so on). Please note that if this driver is built into the + kernel or loaded before other ATA (IDE or libata) drivers + and the controller is located at legacy ports, this driver + may grab those ports and thus can prevent the controller + specific driver from attaching. + + Also, currently, IDE generic doesn't allow IRQ sharing + meaning that the IRQs it grabs won't be available to other + controllers sharing those IRQs which usually makes drivers + for those controllers fail. Generally, it's not a good idea + to load IDE generic driver on modern systems. + + If unsure, say N. + +config BLK_DEV_PLATFORM + tristate "Platform driver for IDE interfaces" help - If unsure, say Y. + This is the platform IDE driver, used mostly for Memory Mapped + IDE devices, like Compact Flashes running in True IDE mode. + + If unsure, say N. config BLK_DEV_CMD640 - bool "CMD640 chipset bugfix/support" + tristate "CMD640 chipset bugfix/support" depends on X86 + select IDE_TIMINGS ---help--- The CMD-Technologies CMD640 IDE chip is used on many common 486 and Pentium motherboards, usually in combination with a "Neptune" or @@ -296,13 +241,13 @@ config BLK_DEV_CMD640 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 + to enable the CMD640 bugfix/support: "cmd640.probe_vlb". (Try "man bootparam" or see the documentation of your boot loader about how to pass options to the kernel.) The CMD640 chip is also used on add-in cards by Acculogic, and on the "CSA-6400E PCI to IDE controller" that some people have. For - details, read <file:Documentation/ide.txt>. + details, read <file:Documentation/ide/ide.txt>. config BLK_DEV_CMD640_ENHANCED bool "CMD640 enhanced support" @@ -310,40 +255,47 @@ config BLK_DEV_CMD640_ENHANCED 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 + <file:Documentation/ide/ide.txt>. If you have a CMD640 IDE interface and your BIOS does not already do this for you, then say Y here. Otherwise say N. config BLK_DEV_IDEPNP - bool "PNP EIDE support" + tristate "PNP EIDE support" depends on PNP help If you have a PnP (Plug and Play) compatible EIDE card and would like the kernel to automatically detect and activate it, say Y here. +config BLK_DEV_IDEDMA_SFF + bool + +if PCI + +comment "PCI IDE chipsets support" + config BLK_DEV_IDEPCI - bool "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. + bool -config IDEPCI_SHARE_IRQ - bool "Sharing PCI IDE interrupts support" - depends on PCI && BLK_DEV_IDEPCI +config IDEPCI_PCIBUS_ORDER + bool "Probe IDE PCI devices in the PCI bus order (DEPRECATED)" + depends on IDE=y && BLK_DEV_IDEPCI + default y help - 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. + Probe IDE PCI devices in the order in which they appear on the + PCI bus (i.e. 00:1f.1 PCI device before 02:01.0 PCI device) + instead of the order in which IDE PCI host drivers are loaded. - It is safe to say Y to this question, in most cases. - If unsure, say N. + Please note that this method of assuring stable naming of + IDE devices is unreliable and use other means for achieving + it (i.e. udev). + If in doubt, say N. + +# TODO: split it on per host driver config options (or module parameters) config BLK_DEV_OFFBOARD - bool "Boot off-board chipsets first support" - depends on PCI && BLK_DEV_IDEPCI + bool "Boot off-board chipsets first support (DEPRECATED)" + depends on BLK_DEV_IDEPCI && (BLK_DEV_AEC62XX || BLK_DEV_GENERIC || BLK_DEV_HPT366 || BLK_DEV_PDC202XX_NEW || BLK_DEV_PDC202XX_OLD || BLK_DEV_TC86C001) help Normally, IDE controllers built into the motherboard (on-board controllers) are assigned to ide0 and ide1 while those on add-in PCI @@ -353,31 +305,33 @@ config BLK_DEV_OFFBOARD 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. + Please also note that this method of assuring stable naming of + IDE devices is unreliable and use other means for achieving it + (i.e. udev). + If in doubt, say N. config BLK_DEV_GENERIC tristate "Generic PCI IDE Chipset Support" - depends on BLK_DEV_IDEPCI + select BLK_DEV_IDEPCI + help + This option provides generic support for various PCI IDE Chipsets + which otherwise might not be supported. config BLK_DEV_OPTI621 - tristate "OPTi 82C621 chipset enhanced support (EXPERIMENTAL)" - depends on PCI && BLK_DEV_IDEPCI && EXPERIMENTAL + tristate "OPTi 82C621 chipset enhanced support" + select BLK_DEV_IDEPCI help This is a driver for the OPTi 82C621 EIDE controller. - Please read the comments at the top of <file:drivers/ide/pci/opti621.c>. + Please read the comments at the top of <file:drivers/ide/opti621.c>. config BLK_DEV_RZ1000 tristate "RZ1000 chipset bugfix/support" - depends on PCI && BLK_DEV_IDEPCI && X86 + depends on X86 + select BLK_DEV_IDEPCI help The PC-Technologies RZ1000 IDE chip is used on many common 486 and Pentium motherboards, usually along with the "Neptune" chipset. @@ -387,68 +341,14 @@ config BLK_DEV_RZ1000 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. + bool + select BLK_DEV_IDEPCI + select BLK_DEV_IDEDMA_SFF config BLK_DEV_AEC62XX tristate "AEC62XX chipset support" + select BLK_DEV_IDEDMA_PCI help This driver adds explicit support for Acard AEC62xx (Artop ATP8xx) IDE controllers. This allows the kernel to change PIO, DMA and UDMA @@ -456,34 +356,23 @@ config BLK_DEV_AEC62XX config BLK_DEV_ALI15X3 tristate "ALI M15x3 chipset support" + select IDE_TIMINGS + select BLK_DEV_IDEDMA_PCI help This driver ensures (U)DMA support for ALI 1533, 1543 and 1543C onboard chipsets. It also tests for Simplex mode and enables normal dual channel support. - 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>. + Please read the comments at the top of + <file:drivers/ide/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" + depends on !ARM + select IDE_TIMINGS + select BLK_DEV_IDEDMA_PCI help This driver adds explicit support for AMD-7xx and AMD-8111 chips and also for the nVidia nForce chip. This allows the kernel to @@ -493,6 +382,7 @@ config BLK_DEV_AMD74XX config BLK_DEV_ATIIXP tristate "ATI IXP chipset IDE support" depends on X86 + select BLK_DEV_IDEDMA_PCI help This driver adds explicit support for ATI IXP chipset. This allows the kernel to change PIO, DMA and UDMA speeds @@ -502,28 +392,32 @@ config BLK_DEV_ATIIXP config BLK_DEV_CMD64X tristate "CMD64{3|6|8|9} chipset support" + select IDE_TIMINGS + select BLK_DEV_IDEDMA_PCI help Say Y here if you have an IDE controller which uses any of these chipsets: CMD643, CMD646, or CMD648. config BLK_DEV_TRIFLEX tristate "Compaq Triflex IDE support" + select BLK_DEV_IDEDMA_PCI help Say Y here if you have a Compaq Triflex IDE controller, such as those commonly found on Compaq Pentium-Pro systems config BLK_DEV_CY82C693 tristate "CY82C693 chipset support" + depends on ALPHA + select IDE_TIMINGS + select BLK_DEV_IDEDMA_PCI help This driver adds detection and support for the CY82C693 chipset used on Digital's PC-Alpha 164SX boards. - 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 + depends on X86_32 || COMPILE_TEST + select BLK_DEV_IDEDMA_PCI help Include support for PIO tuning and virtual DMA on the Cyrix MediaGX 5510/5520 chipset. This will automatically be detected and @@ -533,6 +427,8 @@ config BLK_DEV_CS5520 config BLK_DEV_CS5530 tristate "Cyrix/National Semiconductor CS5530 MediaGX chipset support" + depends on X86_32 || COMPILE_TEST + select BLK_DEV_IDEDMA_PCI help Include support for UDMA on the Cyrix MediaGX 5530 chipset. This will automatically be detected and configured if found. @@ -541,36 +437,28 @@ config BLK_DEV_CS5530 config BLK_DEV_CS5535 tristate "AMD CS5535 chipset support" - depends on X86 && !X86_64 + depends on X86_32 + select BLK_DEV_IDEDMA_PCI help Include support for UDMA on the NSC/AMD CS5535 companion chipset. This will automatically be detected and configured if found. It is safe to say Y to this question. -config BLK_DEV_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 +config BLK_DEV_CS5536 + tristate "CS5536 chipset support" + depends on X86_32 + select BLK_DEV_IDEDMA_PCI 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. + This option enables support for the AMD CS5536 + companion chip used with the Geode LX processor family. If unsure, say N. config BLK_DEV_HPT366 tristate "HPT36X/37X chipset support" - ---help--- + select BLK_DEV_IDEDMA_PCI + help HPT366 is an Ultra DMA chipset for ATA-66. HPT368 is an Ultra DMA chipset for ATA-66 RAID Based. HPT370 is an Ultra DMA chipset for ATA-100. @@ -585,52 +473,67 @@ config BLK_DEV_HPT366 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. + should use the fore mentioned option and call at LILO. This driver requires dynamic tuning of the chipset during the ide-probe at boot. It is reported to support DVD II drives, by the manufacturer. +config BLK_DEV_JMICRON + tristate "JMicron JMB36x support" + select BLK_DEV_IDEDMA_PCI + help + Basic support for the JMicron ATA controllers. For full support + use the libata drivers. + config BLK_DEV_SC1200 tristate "National SCx200 chipset support" + depends on X86_32 || COMPILE_TEST + select BLK_DEV_IDEDMA_PCI help - This driver adds support for the built in IDE on the National - SCx200 series of embedded x86 "Geode" systems + This driver adds support for the on-board IDE controller on the + National SCx200 series of embedded x86 "Geode" systems. config BLK_DEV_PIIX - tristate "Intel PIIXn chipsets support" + tristate "Intel PIIX/ICH chipsets support" + select BLK_DEV_IDEDMA_PCI 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. + This driver adds explicit support for Intel PIIX and ICH chips. + This allows the kernel to change PIO, DMA and UDMA speeds and to + configure the chip to optimum performance. config BLK_DEV_IT8172 - bool "IT8172 IDE support" - depends on (MIPS_ITE8172 || MIPS_IVR) + tristate "IT8172 IDE support" + select BLK_DEV_IDEDMA_PCI 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>. + This driver adds support for the IDE controller on the + IT8172 System Controller. + +config BLK_DEV_IT8213 + tristate "IT8213 IDE support" + select BLK_DEV_IDEDMA_PCI + help + This driver adds support for the ITE 8213 IDE controller. config BLK_DEV_IT821X tristate "IT821X IDE support" + select BLK_DEV_IDEDMA_PCI help This driver adds support for the ITE 8211 IDE controller and the IT 8212 IDE RAID controller in both RAID and pass-through mode. config BLK_DEV_NS87415 tristate "NS87415 chipset support" + select BLK_DEV_IDEDMA_PCI help This driver adds detection and support for the NS87415 chip (used mainly on SPARC64 and PA-RISC machines). - Please read the comments at the top of <file:drivers/ide/pci/ns87415.c>. + Please read the comments at the top of <file:drivers/ide/ns87415.c>. config BLK_DEV_PDC202XX_OLD tristate "PROMISE PDC202{46|62|65|67} support" + select BLK_DEV_IDEDMA_PCI help Promise Ultra33 or PDC20246 Promise Ultra66 or PDC20262 @@ -642,39 +545,20 @@ config BLK_DEV_PDC202XX_OLD 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. + for more than one card. Please read the comments at the top of - <file:drivers/ide/pci/pdc202xx_old.c>. - - If unsure, say N. - -config 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 successfully 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>. + <file:drivers/ide/pdc202xx_old.c>. If unsure, say N. config BLK_DEV_PDC202XX_NEW tristate "PROMISE PDC202{68|69|70|71|75|76|77} support" + select BLK_DEV_IDEDMA_PCI config BLK_DEV_SVWKS tristate "ServerWorks OSB4/CSB5/CSB6 chipsets support" + select BLK_DEV_IDEDMA_PCI help This driver adds PIO/(U)DMA support for the ServerWorks OSB4/CSB5 chipsets. @@ -682,7 +566,7 @@ config BLK_DEV_SVWKS config BLK_DEV_SGIIOC4 tristate "Silicon Graphics IOC4 chipset ATA/ATAPI support" depends on (IA64_SGI_SN2 || IA64_GENERIC) && SGI_IOC4 - select IDEPCI_SHARE_IRQ + select BLK_DEV_IDEDMA_PCI help This driver adds PIO & MultiMode DMA-2 support for the SGI IOC4 chipset, which has one channel and can support two devices. @@ -690,6 +574,7 @@ config BLK_DEV_SGIIOC4 config BLK_DEV_SIIMAGE tristate "Silicon Image chipset support" + select BLK_DEV_IDEDMA_PCI help This driver adds PIO/(U)DMA support for the SI CMD680 and SII 3112 (Serial ATA) chips. @@ -697,7 +582,8 @@ config BLK_DEV_SIIMAGE config BLK_DEV_SIS5513 tristate "SiS5513 chipset support" depends on X86 - ---help--- + select BLK_DEV_IDEDMA_PCI + help This driver ensures (U)DMA support for SIS5513 chipset family based mainboards. @@ -708,13 +594,21 @@ config BLK_DEV_SIS5513 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/sis5513.c>. - Please read the comments at the top of <file:drivers/ide/pci/sis5513.c>. +config BLK_DEV_SL82C105 + tristate "Winbond SL82c105 support" + depends on (PPC || ARM) + select IDE_TIMINGS + select BLK_DEV_IDEDMA_PCI + help + If you have a Winbond SL82c105 IDE controller, say Y here to enable + special configuration for this chip. This is common on various CHRP + motherboards, but could be used elsewhere. If in doubt, say Y. config BLK_DEV_SLC90E66 tristate "SLC90E66 chipset support" + select BLK_DEV_IDEDMA_PCI help This driver ensures (U)DMA support for Victory66 SouthBridges for SMsC with Intel NorthBridges. This is an Ultra66 based chipset. @@ -722,39 +616,57 @@ config BLK_DEV_SLC90E66 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>. + <file:drivers/ide/slc90e66.c>. config BLK_DEV_TRM290 tristate "Tekram TRM290 chipset support" + select BLK_DEV_IDEDMA_PCI help This driver adds support for bus master DMA transfers using the Tekram TRM290 PCI IDE chip. Volunteers are needed for further tweaking and development. - Please read the comments at the top of <file:drivers/ide/pci/trm290.c>. + Please read the comments at the top of <file:drivers/ide/trm290.c>. config BLK_DEV_VIA82CXXX tristate "VIA82CXXX chipset support" + select IDE_TIMINGS + select BLK_DEV_IDEDMA_PCI help This driver adds explicit support for VIA BusMastering IDE chips. This allows the kernel to change PIO, DMA and UDMA speeds and to configure the chip to optimum performance. +config BLK_DEV_TC86C001 + tristate "Toshiba TC86C001 support" + select BLK_DEV_IDEDMA_PCI + help + This driver adds support for Toshiba TC86C001 GOKU-S chip. + +config BLK_DEV_CELLEB + tristate "Toshiba's Cell Reference Set IDE support" + depends on PPC_CELLEB + select BLK_DEV_IDEDMA_PCI + help + This driver provides support for the on-board IDE controller on + Toshiba Cell Reference Board. + If unsure, say Y. + endif +# TODO: BLK_DEV_IDEDMA_PCI -> BLK_DEV_IDEDMA_SFF config BLK_DEV_IDE_PMAC - bool "Builtin PowerMac IDE support" - depends on PPC_PMAC && IDE=y + tristate "PowerMac on-board IDE support" + depends on PPC_PMAC + select IDE_TIMINGS + select BLK_DEV_IDEDMA_PCI help - This driver provides support for the built-in IDE controller on + This driver provides support for the on-board IDE controller on most of the recent Apple Power Macintoshes and PowerBooks. If unsure, say Y. config BLK_DEV_IDE_PMAC_ATA100FIRST - bool "Probe internal ATA/100 (Kauai) first" + bool "Probe on-board ATA/100 (Kauai) first" depends on BLK_DEV_IDE_PMAC help This option will cause the ATA/100 controller found in UniNorth2 @@ -764,43 +676,32 @@ config BLK_DEV_IDE_PMAC_ATA100FIRST 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 - select BLK_DEV_IDEDMA_PCI - 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_SWARM - tristate "IDE for Sibyte evaluation boards" - depends on SIBYTE_SB1xxx_SOC - config BLK_DEV_IDE_AU1XXX bool "IDE for AMD Alchemy Au1200" - depends on SOC_AU1200 + depends on MIPS_ALCHEMY + select IDE_XFER_MODE choice prompt "IDE Mode for AMD Alchemy Au1200" - default CONFIG_BLK_DEV_IDE_AU1XXX_PIO_DBDMA - depends on SOC_AU1200 && BLK_DEV_IDE_AU1XXX + default BLK_DEV_IDE_AU1XXX_PIO_DBDMA + depends on BLK_DEV_IDE_AU1XXX config BLK_DEV_IDE_AU1XXX_PIO_DBDMA bool "PIO+DbDMA IDE for AMD Alchemy Au1200" config BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA bool "MDMA2+DbDMA IDE for AMD Alchemy Au1200" - depends on SOC_AU1200 && BLK_DEV_IDE_AU1XXX + depends on BLK_DEV_IDE_AU1XXX endchoice -config BLK_DEV_IDE_AU1XXX_SEQTS_PER_RQ - int "Maximum transfer size (KB) per request (up to 128)" - default "128" - depends BLK_DEV_IDE_AU1XXX +config BLK_DEV_IDE_TX4938 + tristate "TX4938 internal IDE support" + depends on SOC_TX4938 + select IDE_TIMINGS -config IDE_ARM - def_bool ARM && (ARCH_A5K || ARCH_CLPS7500 || ARCH_RPC || ARCH_SHARK) +config BLK_DEV_IDE_TX4939 + tristate "TX4939 internal IDE support" + depends on SOC_TX4939 + select BLK_DEV_IDEDMA_SFF config BLK_DEV_IDE_ICSIDE tristate "ICS IDE interface support" @@ -817,19 +718,6 @@ config BLK_DEV_IDEDMA_ICS 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 @@ -837,248 +725,156 @@ config BLK_DEV_IDE_RAPIDE 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" + tristate "Amiga Gayle IDE interface support" depends on AMIGA help This is the IDE driver for the Amiga Gayle IDE interface. It supports both the `A1200 style' and `A4000 style' of the Gayle IDE interface, - This includes builtin IDE interfaces on some Amiga models (A600, + This includes on-board IDE interfaces on some Amiga models (A600, A1200, A4000, and A4000T), and IDE interfaces on the Zorro expansion bus (M-Tech E-Matrix 530 expansion card). + + It also provides support for the so-called `IDE doublers' (made + by various manufacturers, e.g. Eyetech) that can be connected to + the on-board IDE interface of some Amiga models. Using such an IDE + doubler, you can connect up to four instead of two IDE devices to + the Amiga's on-board IDE interface. The feature is enabled at kernel + runtime using the "gayle.doubler" kernel boot parameter. + 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 + tristate "Buddha/Catweasel/X-Surf IDE interface support" + depends on ZORRO 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. + 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" + tristate "Falcon IDE interface support" depends on ATARI help - This is the IDE driver for the builtin IDE interface on the Atari + This is the IDE driver for the on-board IDE interface on the Atari Falcon. Say Y if you have a Falcon and want to use IDE devices (hard - disks, CD-ROM drives, etc.) that are connected to the builtin IDE + disks, CD-ROM drives, etc.) that are connected to the on-board IDE interface. config BLK_DEV_MAC_IDE - bool "Macintosh Quadra/Powerbook IDE interface support" + tristate "Macintosh Quadra/Powerbook IDE interface support" depends on MAC help - This is the IDE driver for the builtin IDE interface on some m68k + This is the IDE driver for the on-board IDE interface on some m68k Macintosh models. It supports both the `Quadra style' (used in Quadra/ Centris 630 and Performa 588 models) and `Powerbook style' (used in the Powerbook 150 and 190 models) IDE interface. Say Y if you have such an Macintosh model and want to use IDE devices (hard disks, CD-ROM drives, etc.) that are connected to the - builtin IDE interface. + on-board IDE interface. config BLK_DEV_Q40IDE - bool "Q40/Q60 IDE interface support" + tristate "Q40/Q60 IDE interface support" depends on Q40 help Enable the on-board IDE controller in the Q40/Q60. This should normally be on; disable it only if you are running a custom hard drive subsystem through an expansion card. -config BLK_DEV_MPC8xx_IDE - bool "MPC8xx IDE support" - depends on 8xx && IDE=y && BLK_DEV_IDE=y +config BLK_DEV_PALMCHIP_BK3710 + tristate "Palmchip bk3710 IDE controller support" + depends on ARCH_DAVINCI + select IDE_TIMINGS + select BLK_DEV_IDEDMA_SFF 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 + Say Y here if you want to support the onchip IDE controller on the + TI DaVinci SoC # 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 +if ISA && (ALPHA || X86 || MIPS) +comment "Other IDE chipsets support" comment "Note: most of these also require special kernel boot parameters" config BLK_DEV_4DRIVES - bool "Generic 4 drives/port support" + tristate "Generic 4 drives/port support" help Certain older chipsets, including the Tekram 690CD, use a single set of I/O ports at 0x1f0 to control up to four drives, instead of the customary two drives per port. Support for this can be enabled at - runtime using the "ide0=four" kernel boot parameter if you say Y - here. + runtime using the "ide-4drives.probe" kernel boot parameter if you + say Y here. config BLK_DEV_ALI14XX tristate "ALI M14xx support" + select IDE_TIMINGS + select IDE_LEGACY help - This driver is enabled at runtime using the "ide0=ali14xx" kernel + This driver is enabled at runtime using the "ali14xx.probe" kernel boot parameter. It enables support for the secondary IDE interface of the ALI M1439/1443/1445/1487/1489 chipsets, and permits faster - I/O speeds to be set as well. See the files - <file:Documentation/ide.txt> and <file:drivers/ide/legacy/ali14xx.c> for - more info. + I/O speeds to be set as well. + See the files <file:Documentation/ide/ide.txt> and + <file:drivers/ide/ali14xx.c> for more info. config BLK_DEV_DTC2278 tristate "DTC-2278 support" + select IDE_XFER_MODE + select IDE_LEGACY help - This driver is enabled at runtime using the "ide0=dtc2278" kernel + This driver is enabled at runtime using the "dtc2278.probe" kernel boot parameter. It enables support for the secondary IDE interface of the DTC-2278 card, and permits faster I/O speeds to be set as - well. See the <file:Documentation/ide.txt> and - <file:drivers/ide/legacy/dtc2278.c> files for more info. + well. See the <file:Documentation/ide/ide.txt> and + <file:drivers/ide/dtc2278.c> files for more info. config BLK_DEV_HT6560B tristate "Holtek HT6560B support" + select IDE_TIMINGS + select IDE_LEGACY help - This driver is enabled at runtime using the "ide0=ht6560b" kernel + This driver is enabled at runtime using the "ht6560b.probe" kernel boot parameter. It enables support for the secondary IDE interface of the Holtek card, and permits faster I/O speeds to be set as well. - See the <file:Documentation/ide.txt> and - <file:drivers/ide/legacy/ht6560b.c> files for more info. + See the <file:Documentation/ide/ide.txt> and + <file:drivers/ide/ht6560b.c> files for more info. config BLK_DEV_QD65XX tristate "QDI QD65xx support" + select IDE_TIMINGS + select IDE_LEGACY help - This driver is enabled at runtime using the "ide0=qd65xx" kernel + This driver is enabled at runtime using the "qd65xx.probe" kernel boot parameter. It permits faster I/O speeds to be set. See the - <file:Documentation/ide.txt> and <file:drivers/ide/legacy/qd65xx.c> for - more info. + <file:Documentation/ide/ide.txt> and <file:drivers/ide/qd65xx.c> + for more info. config BLK_DEV_UMC8672 tristate "UMC-8672 support" + select IDE_XFER_MODE + select IDE_LEGACY help - This driver is enabled at runtime using the "ide0=umc8672" kernel + This driver is enabled at runtime using the "umc8672.probe" kernel boot parameter. It enables support for the secondary IDE interface of the UMC-8672, and permits faster I/O speeds to be set as well. - See the files <file:Documentation/ide.txt> and - <file:drivers/ide/legacy/umc8672.c> for more info. + See the files <file:Documentation/ide/ide.txt> and + <file:drivers/ide/umc8672.c> for more info. endif config BLK_DEV_IDEDMA - def_bool BLK_DEV_IDEDMA_PCI || BLK_DEV_IDEDMA_PMAC || BLK_DEV_IDEDMA_ICS || BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA - -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 answer 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 + def_bool BLK_DEV_IDEDMA_SFF || \ + BLK_DEV_IDEDMA_ICS || BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA + select IDE_XFER_MODE -endmenu +endif # IDE diff --git a/drivers/ide/Makefile b/drivers/ide/Makefile index 569fae71750..a04ee82f1c8 100644 --- a/drivers/ide/Makefile +++ b/drivers/ide/Makefile @@ -1,53 +1,116 @@ # -# Makefile for the kernel ata, atapi, and ide block device drivers. +# link order is important here # -# 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 +ccflags-y := -Idrivers/ide -ide-core-$(CONFIG_BLK_DEV_CMD640) += pci/cmd640.o +ide-core-y += ide.o ide-ioctls.o ide-io.o ide-iops.o ide-lib.o ide-probe.o \ + ide-taskfile.o ide-pm.o ide-park.o ide-sysfs.o ide-devsets.o \ + ide-io-std.o ide-eh.o -# Core IDE code - must come before legacy +# core IDE code +ide-core-$(CONFIG_IDE_XFER_MODE) += ide-pio-blacklist.o ide-xfer-mode.o +ide-core-$(CONFIG_IDE_TIMINGS) += ide-timings.o +ide-core-$(CONFIG_IDE_ATAPI) += ide-atapi.o ide-core-$(CONFIG_BLK_DEV_IDEPCI) += setup-pci.o ide-core-$(CONFIG_BLK_DEV_IDEDMA) += ide-dma.o -ide-core-$(CONFIG_PROC_FS) += ide-proc.o -ide-core-$(CONFIG_BLK_DEV_IDEPNP) += ide-pnp.o +ide-core-$(CONFIG_BLK_DEV_IDEDMA_SFF) += ide-dma-sff.o +ide-core-$(CONFIG_IDE_PROC_FS) += ide-proc.o +ide-core-$(CONFIG_BLK_DEV_IDEACPI) += ide-acpi.o +ide-core-$(CONFIG_IDE_LEGACY) += ide-legacy.o + +obj-$(CONFIG_IDE) += ide-core.o + +obj-$(CONFIG_BLK_DEV_ALI14XX) += ali14xx.o +obj-$(CONFIG_BLK_DEV_UMC8672) += umc8672.o +obj-$(CONFIG_BLK_DEV_DTC2278) += dtc2278.o +obj-$(CONFIG_BLK_DEV_HT6560B) += ht6560b.o +obj-$(CONFIG_BLK_DEV_QD65XX) += qd65xx.o +obj-$(CONFIG_BLK_DEV_4DRIVES) += ide-4drives.o + +obj-$(CONFIG_BLK_DEV_GAYLE) += gayle.o +obj-$(CONFIG_BLK_DEV_FALCON_IDE) += falconide.o +obj-$(CONFIG_BLK_DEV_MAC_IDE) += macide.o +obj-$(CONFIG_BLK_DEV_Q40IDE) += q40ide.o +obj-$(CONFIG_BLK_DEV_BUDDHA) += buddha.o + +obj-$(CONFIG_BLK_DEV_AEC62XX) += aec62xx.o +obj-$(CONFIG_BLK_DEV_ALI15X3) += alim15x3.o +obj-$(CONFIG_BLK_DEV_AMD74XX) += amd74xx.o +obj-$(CONFIG_BLK_DEV_ATIIXP) += atiixp.o +obj-$(CONFIG_BLK_DEV_CELLEB) += scc_pata.o +obj-$(CONFIG_BLK_DEV_CMD64X) += cmd64x.o +obj-$(CONFIG_BLK_DEV_CS5520) += cs5520.o +obj-$(CONFIG_BLK_DEV_CS5530) += cs5530.o +obj-$(CONFIG_BLK_DEV_CS5535) += cs5535.o +obj-$(CONFIG_BLK_DEV_CS5536) += cs5536.o +obj-$(CONFIG_BLK_DEV_SC1200) += sc1200.o +obj-$(CONFIG_BLK_DEV_CY82C693) += cy82c693.o +obj-$(CONFIG_BLK_DEV_DELKIN) += delkin_cb.o +obj-$(CONFIG_BLK_DEV_HPT366) += hpt366.o +obj-$(CONFIG_BLK_DEV_IT8172) += it8172.o +obj-$(CONFIG_BLK_DEV_IT8213) += it8213.o +obj-$(CONFIG_BLK_DEV_IT821X) += it821x.o +obj-$(CONFIG_BLK_DEV_JMICRON) += jmicron.o +obj-$(CONFIG_BLK_DEV_NS87415) += ns87415.o +obj-$(CONFIG_BLK_DEV_OPTI621) += opti621.o +obj-$(CONFIG_BLK_DEV_PDC202XX_OLD) += pdc202xx_old.o +obj-$(CONFIG_BLK_DEV_PDC202XX_NEW) += pdc202xx_new.o +obj-$(CONFIG_BLK_DEV_PIIX) += piix.o +obj-$(CONFIG_BLK_DEV_RZ1000) += rz1000.o +obj-$(CONFIG_BLK_DEV_SVWKS) += serverworks.o +obj-$(CONFIG_BLK_DEV_SGIIOC4) += sgiioc4.o +obj-$(CONFIG_BLK_DEV_SIIMAGE) += siimage.o +obj-$(CONFIG_BLK_DEV_SIS5513) += sis5513.o +obj-$(CONFIG_BLK_DEV_SL82C105) += sl82c105.o +obj-$(CONFIG_BLK_DEV_SLC90E66) += slc90e66.o +obj-$(CONFIG_BLK_DEV_TC86C001) += tc86c001.o +obj-$(CONFIG_BLK_DEV_TRIFLEX) += triflex.o +obj-$(CONFIG_BLK_DEV_TRM290) += trm290.o +obj-$(CONFIG_BLK_DEV_VIA82CXXX) += via82cxxx.o -# built-in only drivers from arm/ -ide-core-$(CONFIG_IDE_ARM) += arm/ide_arm.o +# Must appear at the end of the block +obj-$(CONFIG_BLK_DEV_GENERIC) += ide-pci-generic.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 +obj-$(CONFIG_IDEPCI_PCIBUS_ORDER) += ide-scan-pci.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 +obj-$(CONFIG_BLK_DEV_CMD640) += cmd640.o -# built-in only drivers from h8300/ -ide-core-$(CONFIG_H8300) += h8300/ide-h8300.o +obj-$(CONFIG_BLK_DEV_IDE_PMAC) += pmac.o -obj-$(CONFIG_BLK_DEV_IDE) += ide-core.o obj-$(CONFIG_IDE_GENERIC) += ide-generic.o +obj-$(CONFIG_BLK_DEV_IDEPNP) += ide-pnp.o -obj-$(CONFIG_BLK_DEV_IDEDISK) += ide-disk.o -obj-$(CONFIG_BLK_DEV_IDECD) += ide-cd.o +ide-gd_mod-y += ide-gd.o +ide-cd_mod-y += ide-cd.o ide-cd_ioctl.o ide-cd_verbose.o + +ifeq ($(CONFIG_IDE_GD_ATA), y) + ide-gd_mod-y += ide-disk.o ide-disk_ioctl.o +ifeq ($(CONFIG_IDE_PROC_FS), y) + ide-gd_mod-y += ide-disk_proc.o +endif +endif + +ifeq ($(CONFIG_IDE_GD_ATAPI), y) + ide-gd_mod-y += ide-floppy.o ide-floppy_ioctl.o +ifeq ($(CONFIG_IDE_PROC_FS), y) + ide-gd_mod-y += ide-floppy_proc.o +endif +endif + +obj-$(CONFIG_IDE_GD) += ide-gd_mod.o +obj-$(CONFIG_BLK_DEV_IDECD) += ide-cd_mod.o obj-$(CONFIG_BLK_DEV_IDETAPE) += ide-tape.o -obj-$(CONFIG_BLK_DEV_IDEFLOPPY) += ide-floppy.o -obj-$(CONFIG_BLK_DEV_IDE) += legacy/ arm/ mips/ -obj-$(CONFIG_BLK_DEV_HD) += legacy/ -obj-$(CONFIG_ETRAX_IDE) += cris/ +obj-$(CONFIG_BLK_DEV_IDECS) += ide-cs.o + +obj-$(CONFIG_BLK_DEV_PLATFORM) += ide_platform.o + +obj-$(CONFIG_BLK_DEV_IDE_ICSIDE) += icside.o +obj-$(CONFIG_BLK_DEV_IDE_RAPIDE) += rapide.o +obj-$(CONFIG_BLK_DEV_PALMCHIP_BK3710) += palm_bk3710.o + +obj-$(CONFIG_BLK_DEV_IDE_AU1XXX) += au1xxx-ide.o + +obj-$(CONFIG_BLK_DEV_IDE_TX4938) += tx4938ide.o +obj-$(CONFIG_BLK_DEV_IDE_TX4939) += tx4939ide.o diff --git a/drivers/ide/aec62xx.c b/drivers/ide/aec62xx.c new file mode 100644 index 00000000000..c7eaf20af92 --- /dev/null +++ b/drivers/ide/aec62xx.c @@ -0,0 +1,330 @@ +/* + * Copyright (C) 1999-2002 Andre Hedrick <andre@linux-ide.org> + * Copyright (C) 2007 MontaVista Software, Inc. <source@mvista.com> + * + */ + +#include <linux/module.h> +#include <linux/types.h> +#include <linux/pci.h> +#include <linux/ide.h> +#include <linux/init.h> + +#include <asm/io.h> + +#define DRV_NAME "aec62xx" + +struct chipset_bus_clock_list_entry { + u8 xfer_speed; + u8 chipset_settings; + u8 ultra_settings; +}; + +static const struct chipset_bus_clock_list_entry aec6xxx_33_base [] = { + { XFER_UDMA_6, 0x31, 0x07 }, + { XFER_UDMA_5, 0x31, 0x06 }, + { XFER_UDMA_4, 0x31, 0x05 }, + { XFER_UDMA_3, 0x31, 0x04 }, + { XFER_UDMA_2, 0x31, 0x03 }, + { XFER_UDMA_1, 0x31, 0x02 }, + { XFER_UDMA_0, 0x31, 0x01 }, + + { XFER_MW_DMA_2, 0x31, 0x00 }, + { XFER_MW_DMA_1, 0x31, 0x00 }, + { XFER_MW_DMA_0, 0x0a, 0x00 }, + { XFER_PIO_4, 0x31, 0x00 }, + { XFER_PIO_3, 0x33, 0x00 }, + { XFER_PIO_2, 0x08, 0x00 }, + { XFER_PIO_1, 0x0a, 0x00 }, + { XFER_PIO_0, 0x00, 0x00 }, + { 0, 0x00, 0x00 } +}; + +static const struct chipset_bus_clock_list_entry aec6xxx_34_base [] = { + { XFER_UDMA_6, 0x41, 0x06 }, + { XFER_UDMA_5, 0x41, 0x05 }, + { XFER_UDMA_4, 0x41, 0x04 }, + { XFER_UDMA_3, 0x41, 0x03 }, + { XFER_UDMA_2, 0x41, 0x02 }, + { XFER_UDMA_1, 0x41, 0x01 }, + { XFER_UDMA_0, 0x41, 0x01 }, + + { XFER_MW_DMA_2, 0x41, 0x00 }, + { XFER_MW_DMA_1, 0x42, 0x00 }, + { XFER_MW_DMA_0, 0x7a, 0x00 }, + { XFER_PIO_4, 0x41, 0x00 }, + { XFER_PIO_3, 0x43, 0x00 }, + { XFER_PIO_2, 0x78, 0x00 }, + { XFER_PIO_1, 0x7a, 0x00 }, + { XFER_PIO_0, 0x70, 0x00 }, + { 0, 0x00, 0x00 } +}; + +/* + * TO DO: active tuning and correction of cards without a bios. + */ +static u8 pci_bus_clock_list (u8 speed, struct chipset_bus_clock_list_entry * chipset_table) +{ + for ( ; chipset_table->xfer_speed ; chipset_table++) + if (chipset_table->xfer_speed == speed) { + return chipset_table->chipset_settings; + } + return chipset_table->chipset_settings; +} + +static u8 pci_bus_clock_list_ultra (u8 speed, struct chipset_bus_clock_list_entry * chipset_table) +{ + for ( ; chipset_table->xfer_speed ; chipset_table++) + if (chipset_table->xfer_speed == speed) { + return chipset_table->ultra_settings; + } + return chipset_table->ultra_settings; +} + +static void aec6210_set_mode(ide_hwif_t *hwif, ide_drive_t *drive) +{ + struct pci_dev *dev = to_pci_dev(hwif->dev); + struct ide_host *host = pci_get_drvdata(dev); + struct chipset_bus_clock_list_entry *bus_clock = host->host_priv; + u16 d_conf = 0; + u8 ultra = 0, ultra_conf = 0; + u8 tmp0 = 0, tmp1 = 0, tmp2 = 0; + const u8 speed = drive->dma_mode; + unsigned long flags; + + local_irq_save(flags); + /* 0x40|(2*drive->dn): Active, 0x41|(2*drive->dn): Recovery */ + pci_read_config_word(dev, 0x40|(2*drive->dn), &d_conf); + tmp0 = pci_bus_clock_list(speed, bus_clock); + d_conf = ((tmp0 & 0xf0) << 4) | (tmp0 & 0xf); + pci_write_config_word(dev, 0x40|(2*drive->dn), d_conf); + + tmp1 = 0x00; + tmp2 = 0x00; + pci_read_config_byte(dev, 0x54, &ultra); + tmp1 = ((0x00 << (2*drive->dn)) | (ultra & ~(3 << (2*drive->dn)))); + ultra_conf = pci_bus_clock_list_ultra(speed, bus_clock); + tmp2 = ((ultra_conf << (2*drive->dn)) | (tmp1 & ~(3 << (2*drive->dn)))); + pci_write_config_byte(dev, 0x54, tmp2); + local_irq_restore(flags); +} + +static void aec6260_set_mode(ide_hwif_t *hwif, ide_drive_t *drive) +{ + struct pci_dev *dev = to_pci_dev(hwif->dev); + struct ide_host *host = pci_get_drvdata(dev); + struct chipset_bus_clock_list_entry *bus_clock = host->host_priv; + u8 unit = drive->dn & 1; + u8 tmp1 = 0, tmp2 = 0; + u8 ultra = 0, drive_conf = 0, ultra_conf = 0; + const u8 speed = drive->dma_mode; + unsigned long flags; + + local_irq_save(flags); + /* high 4-bits: Active, low 4-bits: Recovery */ + pci_read_config_byte(dev, 0x40|drive->dn, &drive_conf); + drive_conf = pci_bus_clock_list(speed, bus_clock); + pci_write_config_byte(dev, 0x40|drive->dn, drive_conf); + + pci_read_config_byte(dev, (0x44|hwif->channel), &ultra); + tmp1 = ((0x00 << (4*unit)) | (ultra & ~(7 << (4*unit)))); + ultra_conf = pci_bus_clock_list_ultra(speed, bus_clock); + tmp2 = ((ultra_conf << (4*unit)) | (tmp1 & ~(7 << (4*unit)))); + pci_write_config_byte(dev, (0x44|hwif->channel), tmp2); + local_irq_restore(flags); +} + +static void aec_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) +{ + drive->dma_mode = drive->pio_mode; + hwif->port_ops->set_dma_mode(hwif, drive); +} + +static int init_chipset_aec62xx(struct pci_dev *dev) +{ + /* These are necessary to get AEC6280 Macintosh cards to work */ + if ((dev->device == PCI_DEVICE_ID_ARTOP_ATP865) || + (dev->device == PCI_DEVICE_ID_ARTOP_ATP865R)) { + u8 reg49h = 0, reg4ah = 0; + /* Clear reset and test bits. */ + pci_read_config_byte(dev, 0x49, ®49h); + pci_write_config_byte(dev, 0x49, reg49h & ~0x30); + /* Enable chip interrupt output. */ + pci_read_config_byte(dev, 0x4a, ®4ah); + pci_write_config_byte(dev, 0x4a, reg4ah & ~0x01); + /* Enable burst mode. */ + pci_read_config_byte(dev, 0x4a, ®4ah); + pci_write_config_byte(dev, 0x4a, reg4ah | 0x80); + } + + return 0; +} + +static u8 atp86x_cable_detect(ide_hwif_t *hwif) +{ + struct pci_dev *dev = to_pci_dev(hwif->dev); + u8 ata66 = 0, mask = hwif->channel ? 0x02 : 0x01; + + pci_read_config_byte(dev, 0x49, &ata66); + + return (ata66 & mask) ? ATA_CBL_PATA40 : ATA_CBL_PATA80; +} + +static const struct ide_port_ops atp850_port_ops = { + .set_pio_mode = aec_set_pio_mode, + .set_dma_mode = aec6210_set_mode, +}; + +static const struct ide_port_ops atp86x_port_ops = { + .set_pio_mode = aec_set_pio_mode, + .set_dma_mode = aec6260_set_mode, + .cable_detect = atp86x_cable_detect, +}; + +static const struct ide_port_info aec62xx_chipsets[] = { + { /* 0: AEC6210 */ + .name = DRV_NAME, + .init_chipset = init_chipset_aec62xx, + .enablebits = {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}}, + .port_ops = &atp850_port_ops, + .host_flags = IDE_HFLAG_SERIALIZE | + IDE_HFLAG_NO_ATAPI_DMA | + IDE_HFLAG_NO_DSC | + IDE_HFLAG_OFF_BOARD, + .pio_mask = ATA_PIO4, + .mwdma_mask = ATA_MWDMA2, + .udma_mask = ATA_UDMA2, + }, + { /* 1: AEC6260 */ + .name = DRV_NAME, + .init_chipset = init_chipset_aec62xx, + .port_ops = &atp86x_port_ops, + .host_flags = IDE_HFLAG_NO_ATAPI_DMA | IDE_HFLAG_NO_AUTODMA | + IDE_HFLAG_OFF_BOARD, + .pio_mask = ATA_PIO4, + .mwdma_mask = ATA_MWDMA2, + .udma_mask = ATA_UDMA4, + }, + { /* 2: AEC6260R */ + .name = DRV_NAME, + .init_chipset = init_chipset_aec62xx, + .enablebits = {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}}, + .port_ops = &atp86x_port_ops, + .host_flags = IDE_HFLAG_NO_ATAPI_DMA | + IDE_HFLAG_NON_BOOTABLE, + .pio_mask = ATA_PIO4, + .mwdma_mask = ATA_MWDMA2, + .udma_mask = ATA_UDMA4, + }, + { /* 3: AEC6280 */ + .name = DRV_NAME, + .init_chipset = init_chipset_aec62xx, + .port_ops = &atp86x_port_ops, + .host_flags = IDE_HFLAG_NO_ATAPI_DMA | + IDE_HFLAG_OFF_BOARD, + .pio_mask = ATA_PIO4, + .mwdma_mask = ATA_MWDMA2, + .udma_mask = ATA_UDMA5, + }, + { /* 4: AEC6280R */ + .name = DRV_NAME, + .init_chipset = init_chipset_aec62xx, + .enablebits = {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}}, + .port_ops = &atp86x_port_ops, + .host_flags = IDE_HFLAG_NO_ATAPI_DMA | + IDE_HFLAG_OFF_BOARD, + .pio_mask = ATA_PIO4, + .mwdma_mask = ATA_MWDMA2, + .udma_mask = ATA_UDMA5, + } +}; + +/** + * aec62xx_init_one - called when a AEC is found + * @dev: the aec62xx device + * @id: the matching pci id + * + * Called when the PCI registration layer (or the IDE initialization) + * finds a device matching our IDE device tables. + * + * NOTE: since we're going to modify the 'name' field for AEC-6[26]80[R] + * chips, pass a local copy of 'struct ide_port_info' down the call chain. + */ + +static int aec62xx_init_one(struct pci_dev *dev, const struct pci_device_id *id) +{ + const struct chipset_bus_clock_list_entry *bus_clock; + struct ide_port_info d; + u8 idx = id->driver_data; + int bus_speed = ide_pci_clk ? ide_pci_clk : 33; + int err; + + if (bus_speed <= 33) + bus_clock = aec6xxx_33_base; + else + bus_clock = aec6xxx_34_base; + + err = pci_enable_device(dev); + if (err) + return err; + + d = aec62xx_chipsets[idx]; + + if (idx == 3 || idx == 4) { + unsigned long dma_base = pci_resource_start(dev, 4); + + if (inb(dma_base + 2) & 0x10) { + printk(KERN_INFO DRV_NAME " %s: AEC6880%s card detected" + "\n", pci_name(dev), (idx == 4) ? "R" : ""); + d.udma_mask = ATA_UDMA6; + } + } + + err = ide_pci_init_one(dev, &d, (void *)bus_clock); + if (err) + pci_disable_device(dev); + + return err; +} + +static void aec62xx_remove(struct pci_dev *dev) +{ + ide_pci_remove(dev); + pci_disable_device(dev); +} + +static const struct pci_device_id aec62xx_pci_tbl[] = { + { PCI_VDEVICE(ARTOP, PCI_DEVICE_ID_ARTOP_ATP850UF), 0 }, + { PCI_VDEVICE(ARTOP, PCI_DEVICE_ID_ARTOP_ATP860), 1 }, + { PCI_VDEVICE(ARTOP, PCI_DEVICE_ID_ARTOP_ATP860R), 2 }, + { PCI_VDEVICE(ARTOP, PCI_DEVICE_ID_ARTOP_ATP865), 3 }, + { PCI_VDEVICE(ARTOP, PCI_DEVICE_ID_ARTOP_ATP865R), 4 }, + { 0, }, +}; +MODULE_DEVICE_TABLE(pci, aec62xx_pci_tbl); + +static struct pci_driver aec62xx_pci_driver = { + .name = "AEC62xx_IDE", + .id_table = aec62xx_pci_tbl, + .probe = aec62xx_init_one, + .remove = aec62xx_remove, + .suspend = ide_pci_suspend, + .resume = ide_pci_resume, +}; + +static int __init aec62xx_ide_init(void) +{ + return ide_pci_register_driver(&aec62xx_pci_driver); +} + +static void __exit aec62xx_ide_exit(void) +{ + pci_unregister_driver(&aec62xx_pci_driver); +} + +module_init(aec62xx_ide_init); +module_exit(aec62xx_ide_exit); + +MODULE_AUTHOR("Andre Hedrick"); +MODULE_DESCRIPTION("PCI driver module for ARTOP AEC62xx IDE"); +MODULE_LICENSE("GPL"); diff --git a/drivers/ide/legacy/ali14xx.c b/drivers/ide/ali14xx.c index 9c544467cb7..8f3570ee64c 100644 --- a/drivers/ide/legacy/ali14xx.c +++ b/drivers/ide/ali14xx.c @@ -1,6 +1,4 @@ /* - * linux/drivers/ide/legacy/ali14xx.c Version 0.03 Feb 09, 1996 - * * Copyright (C) 1996 Linus Torvalds & author (see below) */ @@ -37,8 +35,6 @@ * mode 4 for a while now with no trouble.) -Derek */ -#undef REALLY_SLOW_IO /* most systems can safely undef this */ - #include <linux/module.h> #include <linux/types.h> #include <linux/kernel.h> @@ -47,20 +43,22 @@ #include <linux/mm.h> #include <linux/ioport.h> #include <linux/blkdev.h> -#include <linux/hdreg.h> #include <linux/ide.h> #include <linux/init.h> #include <asm/io.h> +#define DRV_NAME "ali14xx" + /* port addresses for auto-detection */ #define ALI_NUM_PORTS 4 -static int ports[ALI_NUM_PORTS] __initdata = {0x074, 0x0f4, 0x034, 0x0e4}; +static const int ports[ALI_NUM_PORTS] __initconst = + { 0x074, 0x0f4, 0x034, 0x0e4 }; /* register initialization data */ typedef struct { u8 reg, data; } RegInitializer; -static RegInitializer initData[] __initdata = { +static const RegInitializer initData[] __initconst = { {0x01, 0x0f}, {0x02, 0x00}, {0x03, 0x00}, {0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x2b}, {0x0a, 0x0f}, {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00}, {0x28, 0x00}, @@ -70,8 +68,6 @@ static RegInitializer initData[] __initdata = { {0x35, 0x03}, {0x00, 0x00} }; -#define ALI_MAX_PIO 4 - /* timing parameter registers for each drive */ static struct { u8 reg1, reg2, reg3, reg4; } regTab[4] = { {0x03, 0x26, 0x04, 0x27}, /* drive 0 */ @@ -91,7 +87,7 @@ static u8 regOff; /* output to base port to close registers */ /* * Read a controller register. */ -static inline u8 inReg (u8 reg) +static inline u8 inReg(u8 reg) { outb_p(reg, regPort); return inb(dataPort); @@ -100,31 +96,32 @@ static inline u8 inReg (u8 reg) /* * Write a controller register. */ -static void outReg (u8 data, u8 reg) +static void outReg(u8 data, u8 reg) { outb_p(reg, regPort); outb_p(data, dataPort); } +static DEFINE_SPINLOCK(ali14xx_lock); + /* * Set PIO mode for the specified drive. * This function computes timing parameters * and sets controller registers accordingly. */ -static void ali14xx_tune_drive (ide_drive_t *drive, u8 pio) +static void ali14xx_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) { int driveNum; int time1, time2; u8 param1, param2, param3, param4; unsigned long flags; - ide_pio_data_t d; - int bus_speed = system_bus_clock(); - - pio = ide_get_best_pio_mode(drive, pio, ALI_MAX_PIO, &d); + int bus_speed = ide_vlb_clk ? ide_vlb_clk : 50; + const u8 pio = drive->pio_mode - XFER_PIO_0; + struct ide_timing *t = ide_timing_find_mode(XFER_PIO_0 + pio); /* calculate timing, according to PIO mode */ - time1 = d.cycle_time; - time2 = ide_pio_timings[pio].active_time; + time1 = ide_pio_cycle_time(drive, pio); + time2 = t->active; param3 = param1 = (time2 * bus_speed + 999) / 1000; param4 = param2 = (time1 * bus_speed + 999) / 1000 - param1; if (pio < 3) { @@ -135,21 +132,21 @@ static void ali14xx_tune_drive (ide_drive_t *drive, u8 pio) drive->name, pio, time1, time2, param1, param2, param3, param4); /* stuff timing parameters into controller registers */ - driveNum = (HWIF(drive)->index << 1) + drive->select.b.unit; - spin_lock_irqsave(&ide_lock, flags); + driveNum = (drive->hwif->index << 1) + (drive->dn & 1); + spin_lock_irqsave(&ali14xx_lock, flags); outb_p(regOn, basePort); outReg(param1, regTab[driveNum].reg1); outReg(param2, regTab[driveNum].reg2); outReg(param3, regTab[driveNum].reg3); outReg(param4, regTab[driveNum].reg4); outb_p(regOff, basePort); - spin_unlock_irqrestore(&ide_lock, flags); + spin_unlock_irqrestore(&ali14xx_lock, flags); } /* * Auto-detect the IDE controller port. */ -static int __init findPort (void) +static int __init findPort(void) { int i; u8 t; @@ -181,8 +178,9 @@ static int __init findPort (void) /* * Initialize controller registers with default values. */ -static int __init initRegisters (void) { - RegInitializer *p; +static int __init initRegisters(void) +{ + const RegInitializer *p; u8 t; unsigned long flags; @@ -197,10 +195,20 @@ static int __init initRegisters (void) { return t; } +static const struct ide_port_ops ali14xx_port_ops = { + .set_pio_mode = ali14xx_set_pio_mode, +}; + +static const struct ide_port_info ali14xx_port_info = { + .name = DRV_NAME, + .chipset = ide_ali14xx, + .port_ops = &ali14xx_port_ops, + .host_flags = IDE_HFLAG_NO_DMA, + .pio_mask = ATA_PIO4, +}; + static int __init ali14xx_probe(void) { - ide_hwif_t *hwif, *mate; - printk(KERN_DEBUG "ali14xx: base=0x%03x, regOn=0x%02x.\n", basePort, regOn); @@ -210,29 +218,19 @@ static int __init ali14xx_probe(void) return 1; } - hwif = &ide_hwifs[0]; - mate = &ide_hwifs[1]; - - hwif->chipset = ide_ali14xx; - hwif->tuneproc = &ali14xx_tune_drive; - hwif->mate = mate; - - mate->chipset = ide_ali14xx; - mate->tuneproc = &ali14xx_tune_drive; - mate->mate = hwif; - mate->channel = 1; - - probe_hwif_init(hwif); - probe_hwif_init(mate); + return ide_legacy_device_add(&ali14xx_port_info, 0); +} - create_proc_ide_interfaces(); +static bool probe_ali14xx; - return 0; -} +module_param_named(probe, probe_ali14xx, bool, 0); +MODULE_PARM_DESC(probe, "probe for ALI M14xx chipsets"); -/* Can be called directly from ide.c. */ -int __init ali14xx_init(void) +static int __init ali14xx_init(void) { + if (probe_ali14xx == 0) + goto out; + /* auto-detect IDE controller port */ if (findPort()) { if (ali14xx_probe()) @@ -240,12 +238,11 @@ int __init ali14xx_init(void) return 0; } printk(KERN_ERR "ali14xx: not found.\n"); +out: return -ENODEV; } -#ifdef MODULE module_init(ali14xx_init); -#endif MODULE_AUTHOR("see local file"); MODULE_DESCRIPTION("support of ALI 14XX IDE chipsets"); diff --git a/drivers/ide/alim15x3.c b/drivers/ide/alim15x3.c new file mode 100644 index 00000000000..36f76e28a0b --- /dev/null +++ b/drivers/ide/alim15x3.c @@ -0,0 +1,602 @@ +/* + * Copyright (C) 1998-2000 Michel Aubry, Maintainer + * Copyright (C) 1998-2000 Andrzej Krzysztofowicz, Maintainer + * Copyright (C) 1999-2000 CJ, cjtsai@ali.com.tw, Maintainer + * + * Copyright (C) 1998-2000 Andre Hedrick (andre@linux-ide.org) + * May be copied or modified under the terms of the GNU General Public License + * Copyright (C) 2002 Alan Cox + * ALi (now ULi M5228) support by Clear Zhang <Clear.Zhang@ali.com.tw> + * Copyright (C) 2007 MontaVista Software, Inc. <source@mvista.com> + * Copyright (C) 2007-2010 Bartlomiej Zolnierkiewicz + * + * (U)DMA capable version of ali 1533/1543(C), 1535(D) + * + ********************************************************************** + * 9/7/99 --Parts from the above author are included and need to be + * converted into standard interface, once I finish the thought. + * + * Recent changes + * Don't use LBA48 mode on ALi <= 0xC4 + * Don't poke 0x79 with a non ALi northbridge + * Don't flip undefined bits on newer chipsets (fix Fujitsu laptop hang) + * Allow UDMA6 on revisions > 0xC4 + * + * Documentation + * Chipset documentation available under NDA only + * + */ + +#include <linux/module.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/pci.h> +#include <linux/ide.h> +#include <linux/init.h> +#include <linux/dmi.h> + +#include <asm/io.h> + +#define DRV_NAME "alim15x3" + +/* + * ALi devices are not plug in. Otherwise these static values would + * need to go. They ought to go away anyway + */ + +static u8 m5229_revision; +static u8 chip_is_1543c_e; +static struct pci_dev *isa_dev; + +static void ali_fifo_control(ide_hwif_t *hwif, ide_drive_t *drive, int on) +{ + struct pci_dev *pdev = to_pci_dev(hwif->dev); + int pio_fifo = 0x54 + hwif->channel; + u8 fifo; + int shift = 4 * (drive->dn & 1); + + pci_read_config_byte(pdev, pio_fifo, &fifo); + fifo &= ~(0x0F << shift); + fifo |= (on << shift); + pci_write_config_byte(pdev, pio_fifo, fifo); +} + +static void ali_program_timings(ide_hwif_t *hwif, ide_drive_t *drive, + struct ide_timing *t, u8 ultra) +{ + struct pci_dev *dev = to_pci_dev(hwif->dev); + int port = hwif->channel ? 0x5c : 0x58; + int udmat = 0x56 + hwif->channel; + u8 unit = drive->dn & 1, udma; + int shift = 4 * unit; + + /* Set up the UDMA */ + pci_read_config_byte(dev, udmat, &udma); + udma &= ~(0x0F << shift); + udma |= ultra << shift; + pci_write_config_byte(dev, udmat, udma); + + if (t == NULL) + return; + + t->setup = clamp_val(t->setup, 1, 8) & 7; + t->act8b = clamp_val(t->act8b, 1, 8) & 7; + t->rec8b = clamp_val(t->rec8b, 1, 16) & 15; + t->active = clamp_val(t->active, 1, 8) & 7; + t->recover = clamp_val(t->recover, 1, 16) & 15; + + pci_write_config_byte(dev, port, t->setup); + pci_write_config_byte(dev, port + 1, (t->act8b << 4) | t->rec8b); + pci_write_config_byte(dev, port + unit + 2, + (t->active << 4) | t->recover); +} + +/** + * ali_set_pio_mode - set host controller for PIO mode + * @hwif: port + * @drive: drive + * + * Program the controller for the given PIO mode. + */ + +static void ali_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) +{ + ide_drive_t *pair = ide_get_pair_dev(drive); + int bus_speed = ide_pci_clk ? ide_pci_clk : 33; + unsigned long T = 1000000 / bus_speed; /* PCI clock based */ + struct ide_timing t; + + ide_timing_compute(drive, drive->pio_mode, &t, T, 1); + if (pair) { + struct ide_timing p; + + ide_timing_compute(pair, pair->pio_mode, &p, T, 1); + ide_timing_merge(&p, &t, &t, + IDE_TIMING_SETUP | IDE_TIMING_8BIT); + if (pair->dma_mode) { + ide_timing_compute(pair, pair->dma_mode, &p, T, 1); + ide_timing_merge(&p, &t, &t, + IDE_TIMING_SETUP | IDE_TIMING_8BIT); + } + } + + /* + * PIO mode => ATA FIFO on, ATAPI FIFO off + */ + ali_fifo_control(hwif, drive, (drive->media == ide_disk) ? 0x05 : 0x00); + + ali_program_timings(hwif, drive, &t, 0); +} + +/** + * ali_udma_filter - compute UDMA mask + * @drive: IDE device + * + * Return available UDMA modes. + * + * The actual rules for the ALi are: + * No UDMA on revisions <= 0x20 + * Disk only for revisions < 0xC2 + * Not WDC drives on M1543C-E (?) + */ + +static u8 ali_udma_filter(ide_drive_t *drive) +{ + if (m5229_revision > 0x20 && m5229_revision < 0xC2) { + if (drive->media != ide_disk) + return 0; + if (chip_is_1543c_e && + strstr((char *)&drive->id[ATA_ID_PROD], "WDC ")) + return 0; + } + + return drive->hwif->ultra_mask; +} + +/** + * ali_set_dma_mode - set host controller for DMA mode + * @hwif: port + * @drive: drive + * + * Configure the hardware for the desired IDE transfer mode. + */ + +static void ali_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive) +{ + static u8 udma_timing[7] = { 0xC, 0xB, 0xA, 0x9, 0x8, 0xF, 0xD }; + struct pci_dev *dev = to_pci_dev(hwif->dev); + ide_drive_t *pair = ide_get_pair_dev(drive); + int bus_speed = ide_pci_clk ? ide_pci_clk : 33; + unsigned long T = 1000000 / bus_speed; /* PCI clock based */ + const u8 speed = drive->dma_mode; + u8 tmpbyte = 0x00; + struct ide_timing t; + + if (speed < XFER_UDMA_0) { + ide_timing_compute(drive, drive->dma_mode, &t, T, 1); + if (pair) { + struct ide_timing p; + + ide_timing_compute(pair, pair->pio_mode, &p, T, 1); + ide_timing_merge(&p, &t, &t, + IDE_TIMING_SETUP | IDE_TIMING_8BIT); + if (pair->dma_mode) { + ide_timing_compute(pair, pair->dma_mode, + &p, T, 1); + ide_timing_merge(&p, &t, &t, + IDE_TIMING_SETUP | IDE_TIMING_8BIT); + } + } + ali_program_timings(hwif, drive, &t, 0); + } else { + ali_program_timings(hwif, drive, NULL, + udma_timing[speed - XFER_UDMA_0]); + if (speed >= XFER_UDMA_3) { + pci_read_config_byte(dev, 0x4b, &tmpbyte); + tmpbyte |= 1; + pci_write_config_byte(dev, 0x4b, tmpbyte); + } + } +} + +/** + * ali_dma_check - DMA check + * @drive: target device + * @cmd: command + * + * Returns 1 if the DMA cannot be performed, zero on success. + */ + +static int ali_dma_check(ide_drive_t *drive, struct ide_cmd *cmd) +{ + if (m5229_revision < 0xC2 && drive->media != ide_disk) { + if (cmd->tf_flags & IDE_TFLAG_WRITE) + return 1; /* try PIO instead of DMA */ + } + return 0; +} + +/** + * init_chipset_ali15x3 - Initialise an ALi IDE controller + * @dev: PCI device + * + * This function initializes the ALI IDE controller and where + * appropriate also sets up the 1533 southbridge. + */ + +static int init_chipset_ali15x3(struct pci_dev *dev) +{ + unsigned long flags; + u8 tmpbyte; + struct pci_dev *north = pci_get_slot(dev->bus, PCI_DEVFN(0,0)); + + m5229_revision = dev->revision; + + isa_dev = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL); + + local_irq_save(flags); + + if (m5229_revision < 0xC2) { + /* + * revision 0x20 (1543-E, 1543-F) + * revision 0xC0, 0xC1 (1543C-C, 1543C-D, 1543C-E) + * clear CD-ROM DMA write bit, m5229, 0x4b, bit 7 + */ + pci_read_config_byte(dev, 0x4b, &tmpbyte); + /* + * clear bit 7 + */ + pci_write_config_byte(dev, 0x4b, tmpbyte & 0x7F); + /* + * check m1533, 0x5e, bit 1~4 == 1001 => & 00011110 = 00010010 + */ + if (m5229_revision >= 0x20 && isa_dev) { + pci_read_config_byte(isa_dev, 0x5e, &tmpbyte); + chip_is_1543c_e = ((tmpbyte & 0x1e) == 0x12) ? 1: 0; + } + goto out; + } + + /* + * 1543C-B?, 1535, 1535D, 1553 + * Note 1: not all "motherboard" support this detection + * Note 2: if no udma 66 device, the detection may "error". + * but in this case, we will not set the device to + * ultra 66, the detection result is not important + */ + + /* + * enable "Cable Detection", m5229, 0x4b, bit3 + */ + pci_read_config_byte(dev, 0x4b, &tmpbyte); + pci_write_config_byte(dev, 0x4b, tmpbyte | 0x08); + + /* + * We should only tune the 1533 enable if we are using an ALi + * North bridge. We might have no north found on some zany + * box without a device at 0:0.0. The ALi bridge will be at + * 0:0.0 so if we didn't find one we know what is cooking. + */ + if (north && north->vendor != PCI_VENDOR_ID_AL) + goto out; + + if (m5229_revision < 0xC5 && isa_dev) + { + /* + * set south-bridge's enable bit, m1533, 0x79 + */ + + pci_read_config_byte(isa_dev, 0x79, &tmpbyte); + if (m5229_revision == 0xC2) { + /* + * 1543C-B0 (m1533, 0x79, bit 2) + */ + pci_write_config_byte(isa_dev, 0x79, tmpbyte | 0x04); + } else if (m5229_revision >= 0xC3) { + /* + * 1553/1535 (m1533, 0x79, bit 1) + */ + pci_write_config_byte(isa_dev, 0x79, tmpbyte | 0x02); + } + } + +out: + /* + * CD_ROM DMA on (m5229, 0x53, bit0) + * Enable this bit even if we want to use PIO. + * PIO FIFO off (m5229, 0x53, bit1) + * The hardware will use 0x54h and 0x55h to control PIO FIFO. + * (Not on later devices it seems) + * + * 0x53 changes meaning on later revs - we must no touch + * bit 1 on them. Need to check if 0x20 is the right break. + */ + if (m5229_revision >= 0x20) { + pci_read_config_byte(dev, 0x53, &tmpbyte); + + if (m5229_revision <= 0x20) + tmpbyte = (tmpbyte & (~0x02)) | 0x01; + else if (m5229_revision == 0xc7 || m5229_revision == 0xc8) + tmpbyte |= 0x03; + else + tmpbyte |= 0x01; + + pci_write_config_byte(dev, 0x53, tmpbyte); + } + pci_dev_put(north); + pci_dev_put(isa_dev); + local_irq_restore(flags); + return 0; +} + +/* + * Cable special cases + */ + +static const struct dmi_system_id cable_dmi_table[] = { + { + .ident = "HP Pavilion N5430", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "Hewlett-Packard"), + DMI_MATCH(DMI_BOARD_VERSION, "OmniBook N32N-736"), + }, + }, + { + .ident = "Toshiba Satellite S1800-814", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), + DMI_MATCH(DMI_PRODUCT_NAME, "S1800-814"), + }, + }, + { } +}; + +static int ali_cable_override(struct pci_dev *pdev) +{ + /* Fujitsu P2000 */ + if (pdev->subsystem_vendor == 0x10CF && + pdev->subsystem_device == 0x10AF) + return 1; + + /* Mitac 8317 (Winbook-A) and relatives */ + if (pdev->subsystem_vendor == 0x1071 && + pdev->subsystem_device == 0x8317) + return 1; + + /* Systems by DMI */ + if (dmi_check_system(cable_dmi_table)) + return 1; + + return 0; +} + +/** + * ali_cable_detect - cable detection + * @hwif: IDE interface + * + * This checks if the controller and the cable are capable + * of UDMA66 transfers. It doesn't check the drives. + */ + +static u8 ali_cable_detect(ide_hwif_t *hwif) +{ + struct pci_dev *dev = to_pci_dev(hwif->dev); + u8 cbl = ATA_CBL_PATA40, tmpbyte; + + if (m5229_revision >= 0xC2) { + /* + * m5229 80-pin cable detection (from Host View) + * + * 0x4a bit0 is 0 => primary channel has 80-pin + * 0x4a bit1 is 0 => secondary channel has 80-pin + * + * Certain laptops use short but suitable cables + * and don't implement the detect logic. + */ + if (ali_cable_override(dev)) + cbl = ATA_CBL_PATA40_SHORT; + else { + pci_read_config_byte(dev, 0x4a, &tmpbyte); + if ((tmpbyte & (1 << hwif->channel)) == 0) + cbl = ATA_CBL_PATA80; + } + } + + return cbl; +} + +#ifndef CONFIG_SPARC64 +/** + * init_hwif_ali15x3 - Initialize the ALI IDE x86 stuff + * @hwif: interface to configure + * + * Obtain the IRQ tables for an ALi based IDE solution on the PC + * class platforms. This part of the code isn't applicable to the + * Sparc systems. + */ + +static void init_hwif_ali15x3(ide_hwif_t *hwif) +{ + u8 ideic, inmir; + s8 irq_routing_table[] = { -1, 9, 3, 10, 4, 5, 7, 6, + 1, 11, 0, 12, 0, 14, 0, 15 }; + int irq = -1; + + if (isa_dev) { + /* + * read IDE interface control + */ + pci_read_config_byte(isa_dev, 0x58, &ideic); + + /* bit0, bit1 */ + ideic = ideic & 0x03; + + /* get IRQ for IDE Controller */ + if ((hwif->channel && ideic == 0x03) || + (!hwif->channel && !ideic)) { + /* + * get SIRQ1 routing table + */ + pci_read_config_byte(isa_dev, 0x44, &inmir); + inmir = inmir & 0x0f; + irq = irq_routing_table[inmir]; + } else if (hwif->channel && !(ideic & 0x01)) { + /* + * get SIRQ2 routing table + */ + pci_read_config_byte(isa_dev, 0x75, &inmir); + inmir = inmir & 0x0f; + irq = irq_routing_table[inmir]; + } + if(irq >= 0) + hwif->irq = irq; + } +} +#else +#define init_hwif_ali15x3 NULL +#endif /* CONFIG_SPARC64 */ + +/** + * init_dma_ali15x3 - set up DMA on ALi15x3 + * @hwif: IDE interface + * @d: IDE port info + * + * Set up the DMA functionality on the ALi 15x3. + */ + +static int init_dma_ali15x3(ide_hwif_t *hwif, const struct ide_port_info *d) +{ + struct pci_dev *dev = to_pci_dev(hwif->dev); + unsigned long base = ide_pci_dma_base(hwif, d); + + if (base == 0) + return -1; + + hwif->dma_base = base; + + if (ide_pci_check_simplex(hwif, d) < 0) + return -1; + + if (ide_pci_set_master(dev, d->name) < 0) + return -1; + + if (!hwif->channel) + outb(inb(base + 2) & 0x60, base + 2); + + printk(KERN_INFO " %s: BM-DMA at 0x%04lx-0x%04lx\n", + hwif->name, base, base + 7); + + if (ide_allocate_dma_engine(hwif)) + return -1; + + return 0; +} + +static const struct ide_port_ops ali_port_ops = { + .set_pio_mode = ali_set_pio_mode, + .set_dma_mode = ali_set_dma_mode, + .udma_filter = ali_udma_filter, + .cable_detect = ali_cable_detect, +}; + +static const struct ide_dma_ops ali_dma_ops = { + .dma_host_set = ide_dma_host_set, + .dma_setup = ide_dma_setup, + .dma_start = ide_dma_start, + .dma_end = ide_dma_end, + .dma_test_irq = ide_dma_test_irq, + .dma_lost_irq = ide_dma_lost_irq, + .dma_check = ali_dma_check, + .dma_timer_expiry = ide_dma_sff_timer_expiry, + .dma_sff_read_status = ide_dma_sff_read_status, +}; + +static const struct ide_port_info ali15x3_chipset = { + .name = DRV_NAME, + .init_chipset = init_chipset_ali15x3, + .init_hwif = init_hwif_ali15x3, + .init_dma = init_dma_ali15x3, + .port_ops = &ali_port_ops, + .dma_ops = &sff_dma_ops, + .pio_mask = ATA_PIO5, + .swdma_mask = ATA_SWDMA2, + .mwdma_mask = ATA_MWDMA2, +}; + +/** + * alim15x3_init_one - set up an ALi15x3 IDE controller + * @dev: PCI device to set up + * + * Perform the actual set up for an ALi15x3 that has been found by the + * hot plug layer. + */ + +static int alim15x3_init_one(struct pci_dev *dev, + const struct pci_device_id *id) +{ + struct ide_port_info d = ali15x3_chipset; + u8 rev = dev->revision, idx = id->driver_data; + + /* don't use LBA48 DMA on ALi devices before rev 0xC5 */ + if (rev <= 0xC4) + d.host_flags |= IDE_HFLAG_NO_LBA48_DMA; + + if (rev >= 0x20) { + if (rev == 0x20) + d.host_flags |= IDE_HFLAG_NO_ATAPI_DMA; + + if (rev < 0xC2) + d.udma_mask = ATA_UDMA2; + else if (rev == 0xC2 || rev == 0xC3) + d.udma_mask = ATA_UDMA4; + else if (rev == 0xC4) + d.udma_mask = ATA_UDMA5; + else + d.udma_mask = ATA_UDMA6; + + d.dma_ops = &ali_dma_ops; + } else { + d.host_flags |= IDE_HFLAG_NO_DMA; + + d.mwdma_mask = d.swdma_mask = 0; + } + + if (idx == 0) + d.host_flags |= IDE_HFLAG_CLEAR_SIMPLEX; + + return ide_pci_init_one(dev, &d, NULL); +} + + +static const struct pci_device_id alim15x3_pci_tbl[] = { + { PCI_VDEVICE(AL, PCI_DEVICE_ID_AL_M5229), 0 }, + { PCI_VDEVICE(AL, PCI_DEVICE_ID_AL_M5228), 1 }, + { 0, }, +}; +MODULE_DEVICE_TABLE(pci, alim15x3_pci_tbl); + +static struct pci_driver alim15x3_pci_driver = { + .name = "ALI15x3_IDE", + .id_table = alim15x3_pci_tbl, + .probe = alim15x3_init_one, + .remove = ide_pci_remove, + .suspend = ide_pci_suspend, + .resume = ide_pci_resume, +}; + +static int __init ali15x3_ide_init(void) +{ + return ide_pci_register_driver(&alim15x3_pci_driver); +} + +static void __exit ali15x3_ide_exit(void) +{ + pci_unregister_driver(&alim15x3_pci_driver); +} + +module_init(ali15x3_ide_init); +module_exit(ali15x3_ide_exit); + +MODULE_AUTHOR("Michael Aubry, Andrzej Krzysztofowicz, CJ, Andre Hedrick, Alan Cox, Bartlomiej Zolnierkiewicz"); +MODULE_DESCRIPTION("PCI driver module for ALi 15x3 IDE"); +MODULE_LICENSE("GPL"); diff --git a/drivers/ide/amd74xx.c b/drivers/ide/amd74xx.c new file mode 100644 index 00000000000..cbfe846911d --- /dev/null +++ b/drivers/ide/amd74xx.c @@ -0,0 +1,347 @@ +/* + * AMD 755/756/766/8111 and nVidia nForce/2/2s/3/3s/CK804/MCP04 + * IDE driver for Linux. + * + * Copyright (c) 2000-2002 Vojtech Pavlik + * Copyright (c) 2007-2010 Bartlomiej Zolnierkiewicz + * + * Based on the work of: + * Andre Hedrick + */ + +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/pci.h> +#include <linux/init.h> +#include <linux/ide.h> + +#define DRV_NAME "amd74xx" + +enum { + AMD_IDE_CONFIG = 0x41, + AMD_CABLE_DETECT = 0x42, + AMD_DRIVE_TIMING = 0x48, + AMD_8BIT_TIMING = 0x4e, + AMD_ADDRESS_SETUP = 0x4c, + AMD_UDMA_TIMING = 0x50, +}; + +static unsigned int amd_80w; +static unsigned int amd_clock; + +static char *amd_dma[] = { "16", "25", "33", "44", "66", "100", "133" }; +static unsigned char amd_cyc2udma[] = { 6, 6, 5, 4, 0, 1, 1, 2, 2, 3, 3, 3, 3, 3, 3, 7 }; + +static inline u8 amd_offset(struct pci_dev *dev) +{ + return (dev->vendor == PCI_VENDOR_ID_NVIDIA) ? 0x10 : 0; +} + +/* + * amd_set_speed() writes timing values to the chipset registers + */ + +static void amd_set_speed(struct pci_dev *dev, u8 dn, u8 udma_mask, + struct ide_timing *timing) +{ + u8 t = 0, offset = amd_offset(dev); + + pci_read_config_byte(dev, AMD_ADDRESS_SETUP + offset, &t); + t = (t & ~(3 << ((3 - dn) << 1))) | ((clamp_val(timing->setup, 1, 4) - 1) << ((3 - dn) << 1)); + pci_write_config_byte(dev, AMD_ADDRESS_SETUP + offset, t); + + pci_write_config_byte(dev, AMD_8BIT_TIMING + offset + (1 - (dn >> 1)), + ((clamp_val(timing->act8b, 1, 16) - 1) << 4) | (clamp_val(timing->rec8b, 1, 16) - 1)); + + pci_write_config_byte(dev, AMD_DRIVE_TIMING + offset + (3 - dn), + ((clamp_val(timing->active, 1, 16) - 1) << 4) | (clamp_val(timing->recover, 1, 16) - 1)); + + switch (udma_mask) { + case ATA_UDMA2: t = timing->udma ? (0xc0 | (clamp_val(timing->udma, 2, 5) - 2)) : 0x03; break; + case ATA_UDMA4: t = timing->udma ? (0xc0 | amd_cyc2udma[clamp_val(timing->udma, 2, 10)]) : 0x03; break; + case ATA_UDMA5: t = timing->udma ? (0xc0 | amd_cyc2udma[clamp_val(timing->udma, 1, 10)]) : 0x03; break; + case ATA_UDMA6: t = timing->udma ? (0xc0 | amd_cyc2udma[clamp_val(timing->udma, 1, 15)]) : 0x03; break; + default: return; + } + + if (timing->udma) + pci_write_config_byte(dev, AMD_UDMA_TIMING + offset + 3 - dn, t); +} + +/* + * amd_set_drive() computes timing values and configures the chipset + * to a desired transfer mode. It also can be called by upper layers. + */ + +static void amd_set_drive(ide_hwif_t *hwif, ide_drive_t *drive) +{ + struct pci_dev *dev = to_pci_dev(hwif->dev); + ide_drive_t *peer = ide_get_pair_dev(drive); + struct ide_timing t, p; + int T, UT; + u8 udma_mask = hwif->ultra_mask; + const u8 speed = drive->dma_mode; + + T = 1000000000 / amd_clock; + UT = (udma_mask == ATA_UDMA2) ? T : (T / 2); + + ide_timing_compute(drive, speed, &t, T, UT); + + if (peer) { + ide_timing_compute(peer, peer->pio_mode, &p, T, UT); + ide_timing_merge(&p, &t, &t, IDE_TIMING_8BIT); + } + + if (speed == XFER_UDMA_5 && amd_clock <= 33333) t.udma = 1; + if (speed == XFER_UDMA_6 && amd_clock <= 33333) t.udma = 15; + + amd_set_speed(dev, drive->dn, udma_mask, &t); +} + +/* + * amd_set_pio_mode() is a callback from upper layers for PIO-only tuning. + */ + +static void amd_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) +{ + drive->dma_mode = drive->pio_mode; + amd_set_drive(hwif, drive); +} + +static void amd7409_cable_detect(struct pci_dev *dev) +{ + /* no host side cable detection */ + amd_80w = 0x03; +} + +static void amd7411_cable_detect(struct pci_dev *dev) +{ + int i; + u32 u = 0; + u8 t = 0, offset = amd_offset(dev); + + pci_read_config_byte(dev, AMD_CABLE_DETECT + offset, &t); + pci_read_config_dword(dev, AMD_UDMA_TIMING + offset, &u); + amd_80w = ((t & 0x3) ? 1 : 0) | ((t & 0xc) ? 2 : 0); + for (i = 24; i >= 0; i -= 8) + if (((u >> i) & 4) && !(amd_80w & (1 << (1 - (i >> 4))))) { + printk(KERN_WARNING DRV_NAME " %s: BIOS didn't set " + "cable bits correctly. Enabling workaround.\n", + pci_name(dev)); + amd_80w |= (1 << (1 - (i >> 4))); + } +} + +/* + * The initialization callback. Initialize drive independent registers. + */ + +static int init_chipset_amd74xx(struct pci_dev *dev) +{ + u8 t = 0, offset = amd_offset(dev); + +/* + * Check 80-wire cable presence. + */ + + if (dev->vendor == PCI_VENDOR_ID_AMD && + dev->device == PCI_DEVICE_ID_AMD_COBRA_7401) + ; /* no UDMA > 2 */ + else if (dev->vendor == PCI_VENDOR_ID_AMD && + dev->device == PCI_DEVICE_ID_AMD_VIPER_7409) + amd7409_cable_detect(dev); + else + amd7411_cable_detect(dev); + +/* + * Take care of prefetch & postwrite. + */ + + pci_read_config_byte(dev, AMD_IDE_CONFIG + offset, &t); + /* + * Check for broken FIFO support. + */ + if (dev->vendor == PCI_VENDOR_ID_AMD && + dev->device == PCI_DEVICE_ID_AMD_VIPER_7411) + t &= 0x0f; + else + t |= 0xf0; + pci_write_config_byte(dev, AMD_IDE_CONFIG + offset, t); + + return 0; +} + +static u8 amd_cable_detect(ide_hwif_t *hwif) +{ + if ((amd_80w >> hwif->channel) & 1) + return ATA_CBL_PATA80; + else + return ATA_CBL_PATA40; +} + +static const struct ide_port_ops amd_port_ops = { + .set_pio_mode = amd_set_pio_mode, + .set_dma_mode = amd_set_drive, + .cable_detect = amd_cable_detect, +}; + +#define IDE_HFLAGS_AMD \ + (IDE_HFLAG_PIO_NO_BLACKLIST | \ + IDE_HFLAG_POST_SET_MODE | \ + IDE_HFLAG_IO_32BIT | \ + IDE_HFLAG_UNMASK_IRQS) + +#define DECLARE_AMD_DEV(swdma, udma) \ + { \ + .name = DRV_NAME, \ + .init_chipset = init_chipset_amd74xx, \ + .enablebits = {{0x40,0x02,0x02}, {0x40,0x01,0x01}}, \ + .port_ops = &amd_port_ops, \ + .host_flags = IDE_HFLAGS_AMD, \ + .pio_mask = ATA_PIO5, \ + .swdma_mask = swdma, \ + .mwdma_mask = ATA_MWDMA2, \ + .udma_mask = udma, \ + } + +#define DECLARE_NV_DEV(udma) \ + { \ + .name = DRV_NAME, \ + .init_chipset = init_chipset_amd74xx, \ + .enablebits = {{0x50,0x02,0x02}, {0x50,0x01,0x01}}, \ + .port_ops = &amd_port_ops, \ + .host_flags = IDE_HFLAGS_AMD, \ + .pio_mask = ATA_PIO5, \ + .swdma_mask = ATA_SWDMA2, \ + .mwdma_mask = ATA_MWDMA2, \ + .udma_mask = udma, \ + } + +static const struct ide_port_info amd74xx_chipsets[] = { + /* 0: AMD7401 */ DECLARE_AMD_DEV(0x00, ATA_UDMA2), + /* 1: AMD7409 */ DECLARE_AMD_DEV(ATA_SWDMA2, ATA_UDMA4), + /* 2: AMD7411/7441 */ DECLARE_AMD_DEV(ATA_SWDMA2, ATA_UDMA5), + /* 3: AMD8111 */ DECLARE_AMD_DEV(ATA_SWDMA2, ATA_UDMA6), + + /* 4: NFORCE */ DECLARE_NV_DEV(ATA_UDMA5), + /* 5: >= NFORCE2 */ DECLARE_NV_DEV(ATA_UDMA6), + + /* 6: AMD5536 */ DECLARE_AMD_DEV(ATA_SWDMA2, ATA_UDMA5), +}; + +static int amd74xx_probe(struct pci_dev *dev, const struct pci_device_id *id) +{ + struct ide_port_info d; + u8 idx = id->driver_data; + + d = amd74xx_chipsets[idx]; + + /* + * Check for bad SWDMA and incorrectly wired Serenade mainboards. + */ + if (idx == 1) { + if (dev->revision <= 7) + d.swdma_mask = 0; + d.host_flags |= IDE_HFLAG_CLEAR_SIMPLEX; + } else if (idx == 3) { + if (dev->subsystem_vendor == PCI_VENDOR_ID_AMD && + dev->subsystem_device == PCI_DEVICE_ID_AMD_SERENADE) + d.udma_mask = ATA_UDMA5; + } + + /* + * It seems that on some nVidia controllers using AltStatus + * register can be unreliable so default to Status register + * if the device is in Compatibility Mode. + */ + if (dev->vendor == PCI_VENDOR_ID_NVIDIA && + ide_pci_is_in_compatibility_mode(dev)) + d.host_flags |= IDE_HFLAG_BROKEN_ALTSTATUS; + + printk(KERN_INFO "%s %s: UDMA%s controller\n", + d.name, pci_name(dev), amd_dma[fls(d.udma_mask) - 1]); + + /* + * Determine the system bus clock. + */ + amd_clock = (ide_pci_clk ? ide_pci_clk : 33) * 1000; + + switch (amd_clock) { + case 33000: amd_clock = 33333; break; + case 37000: amd_clock = 37500; break; + case 41000: amd_clock = 41666; break; + } + + if (amd_clock < 20000 || amd_clock > 50000) { + printk(KERN_WARNING "%s: User given PCI clock speed impossible" + " (%d), using 33 MHz instead.\n", + d.name, amd_clock); + amd_clock = 33333; + } + + return ide_pci_init_one(dev, &d, NULL); +} + +static const struct pci_device_id amd74xx_pci_tbl[] = { + { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_COBRA_7401), 0 }, + { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_VIPER_7409), 1 }, + { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_VIPER_7411), 2 }, + { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_OPUS_7441), 2 }, + { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_8111_IDE), 3 }, + { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_IDE), 4 }, + { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2_IDE), 5 }, + { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_IDE), 5 }, +#ifdef CONFIG_BLK_DEV_IDE_SATA + { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_SATA), 5 }, +#endif + { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3_IDE), 5 }, + { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_IDE), 5 }, +#ifdef CONFIG_BLK_DEV_IDE_SATA + { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA), 5 }, + { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA2), 5 }, +#endif + { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_IDE), 5 }, + { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE), 5 }, + { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_IDE), 5 }, + { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_IDE), 5 }, + { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_IDE), 5 }, + { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP65_IDE), 5 }, + { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP67_IDE), 5 }, + { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP73_IDE), 5 }, + { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP77_IDE), 5 }, + { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_CS5536_IDE), 6 }, + { 0, }, +}; +MODULE_DEVICE_TABLE(pci, amd74xx_pci_tbl); + +static struct pci_driver amd74xx_pci_driver = { + .name = "AMD_IDE", + .id_table = amd74xx_pci_tbl, + .probe = amd74xx_probe, + .remove = ide_pci_remove, + .suspend = ide_pci_suspend, + .resume = ide_pci_resume, +}; + +static int __init amd74xx_ide_init(void) +{ + return ide_pci_register_driver(&amd74xx_pci_driver); +} + +static void __exit amd74xx_ide_exit(void) +{ + pci_unregister_driver(&amd74xx_pci_driver); +} + +module_init(amd74xx_ide_init); +module_exit(amd74xx_ide_exit); + +MODULE_AUTHOR("Vojtech Pavlik, Bartlomiej Zolnierkiewicz"); +MODULE_DESCRIPTION("AMD PCI IDE driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/ide/arm/Makefile b/drivers/ide/arm/Makefile deleted file mode 100644 index 6a78f0755f2..00000000000 --- a/drivers/ide/arm/Makefile +++ /dev/null @@ -1,6 +0,0 @@ - -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 deleted file mode 100644 index 9d474e5fd8d..00000000000 --- a/drivers/ide/arm/bast-ide.c +++ /dev/null @@ -1,71 +0,0 @@ -/* 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/ide_arm.c b/drivers/ide/arm/ide_arm.c deleted file mode 100644 index 23488c4d1fc..00000000000 --- a/drivers/ide/arm/ide_arm.c +++ /dev/null @@ -1,43 +0,0 @@ -/* - * 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 deleted file mode 100644 index 3058217767d..00000000000 --- a/drivers/ide/arm/rapide.c +++ /dev/null @@ -1,125 +0,0 @@ -/* - * 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/atiixp.c b/drivers/ide/atiixp.c new file mode 100644 index 00000000000..dbd0f242ec1 --- /dev/null +++ b/drivers/ide/atiixp.c @@ -0,0 +1,211 @@ +/* + * Copyright (C) 2003 ATI Inc. <hyu@ati.com> + * Copyright (C) 2004,2007 Bartlomiej Zolnierkiewicz + */ + +#include <linux/types.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/pci.h> +#include <linux/ide.h> +#include <linux/init.h> + +#define DRV_NAME "atiixp" + +#define ATIIXP_IDE_PIO_TIMING 0x40 +#define ATIIXP_IDE_MDMA_TIMING 0x44 +#define ATIIXP_IDE_PIO_CONTROL 0x48 +#define ATIIXP_IDE_PIO_MODE 0x4a +#define ATIIXP_IDE_UDMA_CONTROL 0x54 +#define ATIIXP_IDE_UDMA_MODE 0x56 + +typedef struct { + u8 command_width; + u8 recover_width; +} atiixp_ide_timing; + +static atiixp_ide_timing pio_timing[] = { + { 0x05, 0x0d }, + { 0x04, 0x07 }, + { 0x03, 0x04 }, + { 0x02, 0x02 }, + { 0x02, 0x00 }, +}; + +static atiixp_ide_timing mdma_timing[] = { + { 0x07, 0x07 }, + { 0x02, 0x01 }, + { 0x02, 0x00 }, +}; + +static DEFINE_SPINLOCK(atiixp_lock); + +/** + * atiixp_set_pio_mode - set host controller for PIO mode + * @hwif: port + * @drive: drive + * + * Set the interface PIO mode. + */ + +static void atiixp_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) +{ + struct pci_dev *dev = to_pci_dev(hwif->dev); + unsigned long flags; + int timing_shift = (drive->dn ^ 1) * 8; + u32 pio_timing_data; + u16 pio_mode_data; + const u8 pio = drive->pio_mode - XFER_PIO_0; + + spin_lock_irqsave(&atiixp_lock, flags); + + pci_read_config_word(dev, ATIIXP_IDE_PIO_MODE, &pio_mode_data); + pio_mode_data &= ~(0x07 << (drive->dn * 4)); + pio_mode_data |= (pio << (drive->dn * 4)); + pci_write_config_word(dev, ATIIXP_IDE_PIO_MODE, pio_mode_data); + + pci_read_config_dword(dev, ATIIXP_IDE_PIO_TIMING, &pio_timing_data); + pio_timing_data &= ~(0xff << timing_shift); + pio_timing_data |= (pio_timing[pio].recover_width << timing_shift) | + (pio_timing[pio].command_width << (timing_shift + 4)); + pci_write_config_dword(dev, ATIIXP_IDE_PIO_TIMING, pio_timing_data); + + spin_unlock_irqrestore(&atiixp_lock, flags); +} + +/** + * atiixp_set_dma_mode - set host controller for DMA mode + * @hwif: port + * @drive: drive + * + * Set a ATIIXP host controller to the desired DMA mode. This involves + * programming the right timing data into the PCI configuration space. + */ + +static void atiixp_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive) +{ + struct pci_dev *dev = to_pci_dev(hwif->dev); + unsigned long flags; + int timing_shift = (drive->dn ^ 1) * 8; + u32 tmp32; + u16 tmp16; + u16 udma_ctl = 0; + const u8 speed = drive->dma_mode; + + spin_lock_irqsave(&atiixp_lock, flags); + + pci_read_config_word(dev, ATIIXP_IDE_UDMA_CONTROL, &udma_ctl); + + if (speed >= XFER_UDMA_0) { + pci_read_config_word(dev, ATIIXP_IDE_UDMA_MODE, &tmp16); + tmp16 &= ~(0x07 << (drive->dn * 4)); + tmp16 |= ((speed & 0x07) << (drive->dn * 4)); + pci_write_config_word(dev, ATIIXP_IDE_UDMA_MODE, tmp16); + + udma_ctl |= (1 << drive->dn); + } else if (speed >= XFER_MW_DMA_0) { + u8 i = speed & 0x03; + + pci_read_config_dword(dev, ATIIXP_IDE_MDMA_TIMING, &tmp32); + tmp32 &= ~(0xff << timing_shift); + tmp32 |= (mdma_timing[i].recover_width << timing_shift) | + (mdma_timing[i].command_width << (timing_shift + 4)); + pci_write_config_dword(dev, ATIIXP_IDE_MDMA_TIMING, tmp32); + + udma_ctl &= ~(1 << drive->dn); + } + + pci_write_config_word(dev, ATIIXP_IDE_UDMA_CONTROL, udma_ctl); + + spin_unlock_irqrestore(&atiixp_lock, flags); +} + +static u8 atiixp_cable_detect(ide_hwif_t *hwif) +{ + struct pci_dev *pdev = to_pci_dev(hwif->dev); + u8 udma_mode = 0, ch = hwif->channel; + + pci_read_config_byte(pdev, ATIIXP_IDE_UDMA_MODE + ch, &udma_mode); + + if ((udma_mode & 0x07) >= 0x04 || (udma_mode & 0x70) >= 0x40) + return ATA_CBL_PATA80; + else + return ATA_CBL_PATA40; +} + +static const struct ide_port_ops atiixp_port_ops = { + .set_pio_mode = atiixp_set_pio_mode, + .set_dma_mode = atiixp_set_dma_mode, + .cable_detect = atiixp_cable_detect, +}; + +static const struct ide_port_info atiixp_pci_info[] = { + { /* 0: IXP200/300/400/700 */ + .name = DRV_NAME, + .enablebits = {{0x48,0x01,0x00}, {0x48,0x08,0x00}}, + .port_ops = &atiixp_port_ops, + .pio_mask = ATA_PIO4, + .mwdma_mask = ATA_MWDMA2, + .udma_mask = ATA_UDMA5, + }, + { /* 1: IXP600 */ + .name = DRV_NAME, + .enablebits = {{0x48,0x01,0x00}, {0x00,0x00,0x00}}, + .port_ops = &atiixp_port_ops, + .host_flags = IDE_HFLAG_SINGLE, + .pio_mask = ATA_PIO4, + .mwdma_mask = ATA_MWDMA2, + .udma_mask = ATA_UDMA5, + }, +}; + +/** + * atiixp_init_one - called when a ATIIXP is found + * @dev: the atiixp device + * @id: the matching pci id + * + * Called when the PCI registration layer (or the IDE initialization) + * finds a device matching our IDE device tables. + */ + +static int atiixp_init_one(struct pci_dev *dev, const struct pci_device_id *id) +{ + return ide_pci_init_one(dev, &atiixp_pci_info[id->driver_data], NULL); +} + +static const struct pci_device_id atiixp_pci_tbl[] = { + { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP200_IDE), 0 }, + { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP300_IDE), 0 }, + { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP400_IDE), 0 }, + { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP600_IDE), 1 }, + { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP700_IDE), 0 }, + { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_HUDSON2_IDE), 0 }, + { 0, }, +}; +MODULE_DEVICE_TABLE(pci, atiixp_pci_tbl); + +static struct pci_driver atiixp_pci_driver = { + .name = "ATIIXP_IDE", + .id_table = atiixp_pci_tbl, + .probe = atiixp_init_one, + .remove = ide_pci_remove, + .suspend = ide_pci_suspend, + .resume = ide_pci_resume, +}; + +static int __init atiixp_ide_init(void) +{ + return ide_pci_register_driver(&atiixp_pci_driver); +} + +static void __exit atiixp_ide_exit(void) +{ + pci_unregister_driver(&atiixp_pci_driver); +} + +module_init(atiixp_ide_init); +module_exit(atiixp_ide_exit); + +MODULE_AUTHOR("HUI YU"); +MODULE_DESCRIPTION("PCI driver module for ATI IXP IDE"); +MODULE_LICENSE("GPL"); diff --git a/drivers/ide/au1xxx-ide.c b/drivers/ide/au1xxx-ide.c new file mode 100644 index 00000000000..259786ca8b7 --- /dev/null +++ b/drivers/ide/au1xxx-ide.c @@ -0,0 +1,609 @@ +/* + * BRIEF MODULE DESCRIPTION + * AMD Alchemy Au1xxx IDE interface routines over the Static Bus + * + * Copyright (c) 2003-2005 AMD, Personal Connectivity Solutions + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Note: for more information, please refer "AMD Alchemy Au1200/Au1550 IDE + * Interface and Linux Device Driver" Application Note. + */ +#include <linux/types.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/delay.h> +#include <linux/platform_device.h> +#include <linux/init.h> +#include <linux/ide.h> +#include <linux/scatterlist.h> + +#include <asm/mach-au1x00/au1000.h> +#include <asm/mach-au1x00/au1xxx_dbdma.h> +#include <asm/mach-au1x00/au1xxx_ide.h> + +#define DRV_NAME "au1200-ide" +#define DRV_AUTHOR "Enrico Walther <enrico.walther@amd.com> / Pete Popov <ppopov@embeddedalley.com>" + +#ifndef IDE_REG_SHIFT +#define IDE_REG_SHIFT 5 +#endif + +/* enable the burstmode in the dbdma */ +#define IDE_AU1XXX_BURSTMODE 1 + +static _auide_hwif auide_hwif; + +#if defined(CONFIG_BLK_DEV_IDE_AU1XXX_PIO_DBDMA) + +static inline void auide_insw(unsigned long port, void *addr, u32 count) +{ + _auide_hwif *ahwif = &auide_hwif; + chan_tab_t *ctp; + au1x_ddma_desc_t *dp; + + if (!au1xxx_dbdma_put_dest(ahwif->rx_chan, virt_to_phys(addr), + count << 1, DDMA_FLAGS_NOIE)) { + printk(KERN_ERR "%s failed %d\n", __func__, __LINE__); + return; + } + ctp = *((chan_tab_t **)ahwif->rx_chan); + dp = ctp->cur_ptr; + while (dp->dscr_cmd0 & DSCR_CMD0_V) + ; + ctp->cur_ptr = au1xxx_ddma_get_nextptr_virt(dp); +} + +static inline void auide_outsw(unsigned long port, void *addr, u32 count) +{ + _auide_hwif *ahwif = &auide_hwif; + chan_tab_t *ctp; + au1x_ddma_desc_t *dp; + + if (!au1xxx_dbdma_put_source(ahwif->tx_chan, virt_to_phys(addr), + count << 1, DDMA_FLAGS_NOIE)) { + printk(KERN_ERR "%s failed %d\n", __func__, __LINE__); + return; + } + ctp = *((chan_tab_t **)ahwif->tx_chan); + dp = ctp->cur_ptr; + while (dp->dscr_cmd0 & DSCR_CMD0_V) + ; + ctp->cur_ptr = au1xxx_ddma_get_nextptr_virt(dp); +} + +static void au1xxx_input_data(ide_drive_t *drive, struct ide_cmd *cmd, + void *buf, unsigned int len) +{ + auide_insw(drive->hwif->io_ports.data_addr, buf, (len + 1) / 2); +} + +static void au1xxx_output_data(ide_drive_t *drive, struct ide_cmd *cmd, + void *buf, unsigned int len) +{ + auide_outsw(drive->hwif->io_ports.data_addr, buf, (len + 1) / 2); +} +#endif + +static void au1xxx_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) +{ + int mem_sttime = 0, mem_stcfg = au_readl(MEM_STCFG2); + + switch (drive->pio_mode - XFER_PIO_0) { + case 0: + mem_sttime = SBC_IDE_TIMING(PIO0); + + /* set configuration for RCS2# */ + mem_stcfg |= TS_MASK; + mem_stcfg &= ~TCSOE_MASK; + mem_stcfg &= ~TOECS_MASK; + mem_stcfg |= SBC_IDE_PIO0_TCSOE | SBC_IDE_PIO0_TOECS; + break; + + case 1: + mem_sttime = SBC_IDE_TIMING(PIO1); + + /* set configuration for RCS2# */ + mem_stcfg |= TS_MASK; + mem_stcfg &= ~TCSOE_MASK; + mem_stcfg &= ~TOECS_MASK; + mem_stcfg |= SBC_IDE_PIO1_TCSOE | SBC_IDE_PIO1_TOECS; + break; + + case 2: + mem_sttime = SBC_IDE_TIMING(PIO2); + + /* set configuration for RCS2# */ + mem_stcfg &= ~TS_MASK; + mem_stcfg &= ~TCSOE_MASK; + mem_stcfg &= ~TOECS_MASK; + mem_stcfg |= SBC_IDE_PIO2_TCSOE | SBC_IDE_PIO2_TOECS; + break; + + case 3: + mem_sttime = SBC_IDE_TIMING(PIO3); + + /* set configuration for RCS2# */ + mem_stcfg &= ~TS_MASK; + mem_stcfg &= ~TCSOE_MASK; + mem_stcfg &= ~TOECS_MASK; + mem_stcfg |= SBC_IDE_PIO3_TCSOE | SBC_IDE_PIO3_TOECS; + + break; + + case 4: + mem_sttime = SBC_IDE_TIMING(PIO4); + + /* set configuration for RCS2# */ + mem_stcfg &= ~TS_MASK; + mem_stcfg &= ~TCSOE_MASK; + mem_stcfg &= ~TOECS_MASK; + mem_stcfg |= SBC_IDE_PIO4_TCSOE | SBC_IDE_PIO4_TOECS; + break; + } + + au_writel(mem_sttime,MEM_STTIME2); + au_writel(mem_stcfg,MEM_STCFG2); +} + +static void auide_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive) +{ + int mem_sttime = 0, mem_stcfg = au_readl(MEM_STCFG2); + + switch (drive->dma_mode) { +#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA + case XFER_MW_DMA_2: + mem_sttime = SBC_IDE_TIMING(MDMA2); + + /* set configuration for RCS2# */ + mem_stcfg &= ~TS_MASK; + mem_stcfg &= ~TCSOE_MASK; + mem_stcfg &= ~TOECS_MASK; + mem_stcfg |= SBC_IDE_MDMA2_TCSOE | SBC_IDE_MDMA2_TOECS; + + break; + case XFER_MW_DMA_1: + mem_sttime = SBC_IDE_TIMING(MDMA1); + + /* set configuration for RCS2# */ + mem_stcfg &= ~TS_MASK; + mem_stcfg &= ~TCSOE_MASK; + mem_stcfg &= ~TOECS_MASK; + mem_stcfg |= SBC_IDE_MDMA1_TCSOE | SBC_IDE_MDMA1_TOECS; + + break; + case XFER_MW_DMA_0: + mem_sttime = SBC_IDE_TIMING(MDMA0); + + /* set configuration for RCS2# */ + mem_stcfg |= TS_MASK; + mem_stcfg &= ~TCSOE_MASK; + mem_stcfg &= ~TOECS_MASK; + mem_stcfg |= SBC_IDE_MDMA0_TCSOE | SBC_IDE_MDMA0_TOECS; + + break; +#endif + } + + au_writel(mem_sttime,MEM_STTIME2); + au_writel(mem_stcfg,MEM_STCFG2); +} + +/* + * Multi-Word DMA + DbDMA functions + */ + +#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA +static int auide_build_dmatable(ide_drive_t *drive, struct ide_cmd *cmd) +{ + ide_hwif_t *hwif = drive->hwif; + _auide_hwif *ahwif = &auide_hwif; + struct scatterlist *sg; + int i = cmd->sg_nents, count = 0; + int iswrite = !!(cmd->tf_flags & IDE_TFLAG_WRITE); + + /* Save for interrupt context */ + ahwif->drive = drive; + + /* fill the descriptors */ + sg = hwif->sg_table; + while (i && sg_dma_len(sg)) { + u32 cur_addr; + u32 cur_len; + + cur_addr = sg_dma_address(sg); + cur_len = sg_dma_len(sg); + + while (cur_len) { + u32 flags = DDMA_FLAGS_NOIE; + unsigned int tc = (cur_len < 0xfe00)? cur_len: 0xfe00; + + if (++count >= PRD_ENTRIES) { + printk(KERN_WARNING "%s: DMA table too small\n", + drive->name); + return 0; + } + + /* Lets enable intr for the last descriptor only */ + if (1==i) + flags = DDMA_FLAGS_IE; + else + flags = DDMA_FLAGS_NOIE; + + if (iswrite) { + if (!au1xxx_dbdma_put_source(ahwif->tx_chan, + sg_phys(sg), tc, flags)) { + printk(KERN_ERR "%s failed %d\n", + __func__, __LINE__); + } + } else { + if (!au1xxx_dbdma_put_dest(ahwif->rx_chan, + sg_phys(sg), tc, flags)) { + printk(KERN_ERR "%s failed %d\n", + __func__, __LINE__); + } + } + + cur_addr += tc; + cur_len -= tc; + } + sg = sg_next(sg); + i--; + } + + if (count) + return 1; + + return 0; /* revert to PIO for this request */ +} + +static int auide_dma_end(ide_drive_t *drive) +{ + return 0; +} + +static void auide_dma_start(ide_drive_t *drive ) +{ +} + + +static int auide_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd) +{ + if (auide_build_dmatable(drive, cmd) == 0) + return 1; + + return 0; +} + +static int auide_dma_test_irq(ide_drive_t *drive) +{ + /* If dbdma didn't execute the STOP command yet, the + * active bit is still set + */ + drive->waiting_for_dma++; + if (drive->waiting_for_dma >= DMA_WAIT_TIMEOUT) { + printk(KERN_WARNING "%s: timeout waiting for ddma to complete\n", + drive->name); + return 1; + } + udelay(10); + return 0; +} + +static void auide_dma_host_set(ide_drive_t *drive, int on) +{ +} + +static void auide_ddma_tx_callback(int irq, void *param) +{ +} + +static void auide_ddma_rx_callback(int irq, void *param) +{ +} +#endif /* end CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA */ + +static void auide_init_dbdma_dev(dbdev_tab_t *dev, u32 dev_id, u32 tsize, + u32 devwidth, u32 flags, u32 regbase) +{ + dev->dev_id = dev_id; + dev->dev_physaddr = CPHYSADDR(regbase); + dev->dev_intlevel = 0; + dev->dev_intpolarity = 0; + dev->dev_tsize = tsize; + dev->dev_devwidth = devwidth; + dev->dev_flags = flags; +} + +#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA +static const struct ide_dma_ops au1xxx_dma_ops = { + .dma_host_set = auide_dma_host_set, + .dma_setup = auide_dma_setup, + .dma_start = auide_dma_start, + .dma_end = auide_dma_end, + .dma_test_irq = auide_dma_test_irq, + .dma_lost_irq = ide_dma_lost_irq, +}; + +static int auide_ddma_init(ide_hwif_t *hwif, const struct ide_port_info *d) +{ + _auide_hwif *auide = &auide_hwif; + dbdev_tab_t source_dev_tab, target_dev_tab; + u32 dev_id, tsize, devwidth, flags; + + dev_id = hwif->ddma_id; + + tsize = 8; /* 1 */ + devwidth = 32; /* 16 */ + +#ifdef IDE_AU1XXX_BURSTMODE + flags = DEV_FLAGS_SYNC | DEV_FLAGS_BURSTABLE; +#else + flags = DEV_FLAGS_SYNC; +#endif + + /* setup dev_tab for tx channel */ + auide_init_dbdma_dev(&source_dev_tab, dev_id, tsize, devwidth, + DEV_FLAGS_OUT | flags, auide->regbase); + auide->tx_dev_id = au1xxx_ddma_add_device( &source_dev_tab ); + + auide_init_dbdma_dev(&source_dev_tab, dev_id, tsize, devwidth, + DEV_FLAGS_IN | flags, auide->regbase); + auide->rx_dev_id = au1xxx_ddma_add_device( &source_dev_tab ); + + /* We also need to add a target device for the DMA */ + auide_init_dbdma_dev(&target_dev_tab, (u32)DSCR_CMD0_ALWAYS, tsize, + devwidth, DEV_FLAGS_ANYUSE, auide->regbase); + auide->target_dev_id = au1xxx_ddma_add_device(&target_dev_tab); + + /* Get a channel for TX */ + auide->tx_chan = au1xxx_dbdma_chan_alloc(auide->target_dev_id, + auide->tx_dev_id, + auide_ddma_tx_callback, + (void*)auide); + + /* Get a channel for RX */ + auide->rx_chan = au1xxx_dbdma_chan_alloc(auide->rx_dev_id, + auide->target_dev_id, + auide_ddma_rx_callback, + (void*)auide); + + auide->tx_desc_head = (void*)au1xxx_dbdma_ring_alloc(auide->tx_chan, + NUM_DESCRIPTORS); + auide->rx_desc_head = (void*)au1xxx_dbdma_ring_alloc(auide->rx_chan, + NUM_DESCRIPTORS); + + /* FIXME: check return value */ + (void)ide_allocate_dma_engine(hwif); + + au1xxx_dbdma_start( auide->tx_chan ); + au1xxx_dbdma_start( auide->rx_chan ); + + return 0; +} +#else +static int auide_ddma_init(ide_hwif_t *hwif, const struct ide_port_info *d) +{ + _auide_hwif *auide = &auide_hwif; + dbdev_tab_t source_dev_tab; + int flags; + +#ifdef IDE_AU1XXX_BURSTMODE + flags = DEV_FLAGS_SYNC | DEV_FLAGS_BURSTABLE; +#else + flags = DEV_FLAGS_SYNC; +#endif + + /* setup dev_tab for tx channel */ + auide_init_dbdma_dev(&source_dev_tab, (u32)DSCR_CMD0_ALWAYS, 8, 32, + DEV_FLAGS_OUT | flags, auide->regbase); + auide->tx_dev_id = au1xxx_ddma_add_device( &source_dev_tab ); + + auide_init_dbdma_dev(&source_dev_tab, (u32)DSCR_CMD0_ALWAYS, 8, 32, + DEV_FLAGS_IN | flags, auide->regbase); + auide->rx_dev_id = au1xxx_ddma_add_device( &source_dev_tab ); + + /* Get a channel for TX */ + auide->tx_chan = au1xxx_dbdma_chan_alloc(DSCR_CMD0_ALWAYS, + auide->tx_dev_id, + NULL, + (void*)auide); + + /* Get a channel for RX */ + auide->rx_chan = au1xxx_dbdma_chan_alloc(auide->rx_dev_id, + DSCR_CMD0_ALWAYS, + NULL, + (void*)auide); + + auide->tx_desc_head = (void*)au1xxx_dbdma_ring_alloc(auide->tx_chan, + NUM_DESCRIPTORS); + auide->rx_desc_head = (void*)au1xxx_dbdma_ring_alloc(auide->rx_chan, + NUM_DESCRIPTORS); + + au1xxx_dbdma_start( auide->tx_chan ); + au1xxx_dbdma_start( auide->rx_chan ); + + return 0; +} +#endif + +static void auide_setup_ports(struct ide_hw *hw, _auide_hwif *ahwif) +{ + int i; + unsigned long *ata_regs = hw->io_ports_array; + + /* FIXME? */ + for (i = 0; i < 8; i++) + *ata_regs++ = ahwif->regbase + (i << IDE_REG_SHIFT); + + /* set the Alternative Status register */ + *ata_regs = ahwif->regbase + (14 << IDE_REG_SHIFT); +} + +#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_PIO_DBDMA +static const struct ide_tp_ops au1xxx_tp_ops = { + .exec_command = ide_exec_command, + .read_status = ide_read_status, + .read_altstatus = ide_read_altstatus, + .write_devctl = ide_write_devctl, + + .dev_select = ide_dev_select, + .tf_load = ide_tf_load, + .tf_read = ide_tf_read, + + .input_data = au1xxx_input_data, + .output_data = au1xxx_output_data, +}; +#endif + +static const struct ide_port_ops au1xxx_port_ops = { + .set_pio_mode = au1xxx_set_pio_mode, + .set_dma_mode = auide_set_dma_mode, +}; + +static const struct ide_port_info au1xxx_port_info = { + .init_dma = auide_ddma_init, +#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_PIO_DBDMA + .tp_ops = &au1xxx_tp_ops, +#endif + .port_ops = &au1xxx_port_ops, +#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA + .dma_ops = &au1xxx_dma_ops, +#endif + .host_flags = IDE_HFLAG_POST_SET_MODE | + IDE_HFLAG_NO_IO_32BIT | + IDE_HFLAG_UNMASK_IRQS, + .pio_mask = ATA_PIO4, +#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA + .mwdma_mask = ATA_MWDMA2, +#endif + .chipset = ide_au1xxx, +}; + +static int au_ide_probe(struct platform_device *dev) +{ + _auide_hwif *ahwif = &auide_hwif; + struct resource *res; + struct ide_host *host; + int ret = 0; + struct ide_hw hw, *hws[] = { &hw }; + +#if defined(CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA) + char *mode = "MWDMA2"; +#elif defined(CONFIG_BLK_DEV_IDE_AU1XXX_PIO_DBDMA) + char *mode = "PIO+DDMA(offload)"; +#endif + + memset(&auide_hwif, 0, sizeof(_auide_hwif)); + ahwif->irq = platform_get_irq(dev, 0); + + res = platform_get_resource(dev, IORESOURCE_MEM, 0); + + if (res == NULL) { + pr_debug("%s %d: no base address\n", DRV_NAME, dev->id); + ret = -ENODEV; + goto out; + } + if (ahwif->irq < 0) { + pr_debug("%s %d: no IRQ\n", DRV_NAME, dev->id); + ret = -ENODEV; + goto out; + } + + if (!request_mem_region(res->start, resource_size(res), dev->name)) { + pr_debug("%s: request_mem_region failed\n", DRV_NAME); + ret = -EBUSY; + goto out; + } + + ahwif->regbase = (u32)ioremap(res->start, resource_size(res)); + if (ahwif->regbase == 0) { + ret = -ENOMEM; + goto out; + } + + res = platform_get_resource(dev, IORESOURCE_DMA, 0); + if (!res) { + pr_debug("%s: no DDMA ID resource\n", DRV_NAME); + ret = -ENODEV; + goto out; + } + ahwif->ddma_id = res->start; + + memset(&hw, 0, sizeof(hw)); + auide_setup_ports(&hw, ahwif); + hw.irq = ahwif->irq; + hw.dev = &dev->dev; + + ret = ide_host_add(&au1xxx_port_info, hws, 1, &host); + if (ret) + goto out; + + auide_hwif.hwif = host->ports[0]; + + platform_set_drvdata(dev, host); + + printk(KERN_INFO "Au1xxx IDE(builtin) configured for %s\n", mode ); + + out: + return ret; +} + +static int au_ide_remove(struct platform_device *dev) +{ + struct resource *res; + struct ide_host *host = platform_get_drvdata(dev); + _auide_hwif *ahwif = &auide_hwif; + + ide_host_remove(host); + + iounmap((void *)ahwif->regbase); + + res = platform_get_resource(dev, IORESOURCE_MEM, 0); + release_mem_region(res->start, resource_size(res)); + + return 0; +} + +static struct platform_driver au1200_ide_driver = { + .driver = { + .name = "au1200-ide", + .owner = THIS_MODULE, + }, + .probe = au_ide_probe, + .remove = au_ide_remove, +}; + +static int __init au_ide_init(void) +{ + return platform_driver_register(&au1200_ide_driver); +} + +static void __exit au_ide_exit(void) +{ + platform_driver_unregister(&au1200_ide_driver); +} + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("AU1200 IDE driver"); + +module_init(au_ide_init); +module_exit(au_ide_exit); diff --git a/drivers/ide/legacy/buddha.c b/drivers/ide/buddha.c index 0391a312287..46eaf58d881 100644 --- a/drivers/ide/legacy/buddha.c +++ b/drivers/ide/buddha.c @@ -1,5 +1,5 @@ /* - * linux/drivers/ide/legacy/buddha.c -- Amiga Buddha, Catweasel and X-Surf IDE Driver + * Amiga Buddha, Catweasel and X-Surf IDE Driver * * Copyright (C) 1997, 2001 by Geert Uytterhoeven and others * @@ -20,10 +20,10 @@ #include <linux/mm.h> #include <linux/interrupt.h> #include <linux/blkdev.h> -#include <linux/hdreg.h> #include <linux/zorro.h> #include <linux/ide.h> #include <linux/init.h> +#include <linux/module.h> #include <asm/amigahw.h> #include <asm/amigaints.h> @@ -37,6 +37,8 @@ #define CATWEASEL_NUM_HWIFS 3 #define XSURF_NUM_HWIFS 2 +#define MAX_NUM_HWIFS 3 + /* * Bases of the IDE interfaces (relative to the board address) */ @@ -56,31 +58,11 @@ static u_int xsurf_bases[XSURF_NUM_HWIFS] __initdata = { XSURF_BASE1, XSURF_BASE2 }; - /* * Offsets from one of the above bases */ -#define BUDDHA_DATA 0x00 -#define BUDDHA_ERROR 0x06 /* see err-bits */ -#define BUDDHA_NSECTOR 0x0a /* nr of sectors to read/write */ -#define BUDDHA_SECTOR 0x0e /* starting sector */ -#define BUDDHA_LCYL 0x12 /* starting cylinder */ -#define BUDDHA_HCYL 0x16 /* high byte of starting cyl */ -#define BUDDHA_SELECT 0x1a /* 101dhhhh , d=drive, hhhh=head */ -#define BUDDHA_STATUS 0x1e /* see status-bits */ #define BUDDHA_CONTROL 0x11a -#define XSURF_CONTROL -1 /* X-Surf has no CS1* (Control/AltStat) */ - -static int buddha_offsets[IDE_NR_PORTS] __initdata = { - BUDDHA_DATA, BUDDHA_ERROR, BUDDHA_NSECTOR, BUDDHA_SECTOR, BUDDHA_LCYL, - BUDDHA_HCYL, BUDDHA_SELECT, BUDDHA_STATUS, BUDDHA_CONTROL, -1 -}; - -static int xsurf_offsets[IDE_NR_PORTS] __initdata = { - BUDDHA_DATA, BUDDHA_ERROR, BUDDHA_NSECTOR, BUDDHA_SECTOR, BUDDHA_LCYL, - BUDDHA_HCYL, BUDDHA_SELECT, BUDDHA_STATUS, XSURF_CONTROL, -1 -}; /* * Other registers @@ -112,50 +94,80 @@ typedef enum BuddhaType_Enum { BOARD_BUDDHA, BOARD_CATWEASEL, BOARD_XSURF } BuddhaType; +static const char *buddha_board_name[] = { "Buddha", "Catweasel", "X-Surf" }; /* * Check and acknowledge the interrupt status */ -static int buddha_ack_intr(ide_hwif_t *hwif) +static int buddha_test_irq(ide_hwif_t *hwif) { unsigned char ch; - ch = z_readb(hwif->io_ports[IDE_IRQ_OFFSET]); + ch = z_readb(hwif->io_ports.irq_addr); if (!(ch & 0x80)) return 0; return 1; } -static int xsurf_ack_intr(ide_hwif_t *hwif) +static void xsurf_clear_irq(ide_drive_t *drive) { - unsigned char ch; + /* + * X-Surf needs 0 written to IRQ register to ensure ISA bit A11 stays at 0 + */ + z_writeb(0, drive->hwif->io_ports.irq_addr); +} - ch = z_readb(hwif->io_ports[IDE_IRQ_OFFSET]); - /* X-Surf needs a 0 written to IRQ register to ensure ISA bit A11 stays at 0 */ - z_writeb(0, hwif->io_ports[IDE_IRQ_OFFSET]); - if (!(ch & 0x80)) - return 0; - return 1; +static void __init buddha_setup_ports(struct ide_hw *hw, unsigned long base, + unsigned long ctl, unsigned long irq_port) +{ + int i; + + memset(hw, 0, sizeof(*hw)); + + hw->io_ports.data_addr = base; + + for (i = 1; i < 8; i++) + hw->io_ports_array[i] = base + 2 + i * 4; + + hw->io_ports.ctl_addr = ctl; + hw->io_ports.irq_addr = irq_port; + + hw->irq = IRQ_AMIGA_PORTS; } +static const struct ide_port_ops buddha_port_ops = { + .test_irq = buddha_test_irq, +}; + +static const struct ide_port_ops xsurf_port_ops = { + .clear_irq = xsurf_clear_irq, + .test_irq = buddha_test_irq, +}; + +static const struct ide_port_info buddha_port_info = { + .port_ops = &buddha_port_ops, + .host_flags = IDE_HFLAG_MMIO | IDE_HFLAG_NO_DMA, + .irq_flags = IRQF_SHARED, + .chipset = ide_generic, +}; + /* * Probe for a Buddha or Catweasel IDE interface */ -void __init buddha_init(void) +static int __init buddha_init(void) { - hw_regs_t hw; - ide_hwif_t *hwif; - int i, index; - struct zorro_dev *z = NULL; u_long buddha_board = 0; BuddhaType type; - int buddha_num_hwifs; + int buddha_num_hwifs, i; while ((z = zorro_find_device(ZORRO_WILDCARD, z))) { unsigned long board; + struct ide_hw hw[MAX_NUM_HWIFS], *hws[MAX_NUM_HWIFS]; + struct ide_port_info d = buddha_port_info; + if (z->id == ZORRO_PROD_INDIVIDUAL_COMPUTERS_BUDDHA) { buddha_num_hwifs = BUDDHA_NUM_HWIFS; type=BOARD_BUDDHA; @@ -165,15 +177,12 @@ void __init buddha_init(void) } else if (z->id == ZORRO_PROD_INDIVIDUAL_COMPUTERS_X_SURF) { buddha_num_hwifs = XSURF_NUM_HWIFS; type=BOARD_XSURF; + d.port_ops = &xsurf_port_ops; } else continue; board = z->resource.start; -/* - * FIXME: we now have selectable mmio v/s iomio transports. - */ - if(type != BOARD_XSURF) { if (!request_mem_region(board+BUDDHA_BASE1, 0x800, "IDE")) continue; @@ -189,47 +198,41 @@ fail_base2: continue; } } - buddha_board = ZTWO_VADDR(board); + buddha_board = (unsigned long)ZTWO_VADDR(board); /* write to BUDDHA_IRQ_MR to enable the board IRQ */ /* X-Surf doesn't have this. IRQs are always on */ if (type != BOARD_XSURF) z_writeb(0, buddha_board+BUDDHA_IRQ_MR); - - for(i=0;i<buddha_num_hwifs;i++) { - if(type != BOARD_XSURF) { - ide_setup_ports(&hw, (buddha_board+buddha_bases[i]), - buddha_offsets, 0, - (buddha_board+buddha_irqports[i]), - buddha_ack_intr, -// budda_iops, - IRQ_AMIGA_PORTS); + + printk(KERN_INFO "ide: %s IDE controller\n", + buddha_board_name[type]); + + for (i = 0; i < buddha_num_hwifs; i++) { + unsigned long base, ctl, irq_port; + + if (type != BOARD_XSURF) { + base = buddha_board + buddha_bases[i]; + ctl = base + BUDDHA_CONTROL; + irq_port = buddha_board + buddha_irqports[i]; } else { - ide_setup_ports(&hw, (buddha_board+xsurf_bases[i]), - xsurf_offsets, 0, - (buddha_board+xsurf_irqports[i]), - xsurf_ack_intr, -// xsurf_iops, - IRQ_AMIGA_PORTS); - } - - index = ide_register_hw(&hw, &hwif); - if (index != -1) { - hwif->mmio = 2; - printk("ide%d: ", index); - switch(type) { - case BOARD_BUDDHA: - printk("Buddha"); - break; - case BOARD_CATWEASEL: - printk("Catweasel"); - break; - case BOARD_XSURF: - printk("X-Surf"); - break; - } - printk(" IDE interface\n"); - } + base = buddha_board + xsurf_bases[i]; + /* X-Surf has no CS1* (Control/AltStat) */ + ctl = 0; + irq_port = buddha_board + xsurf_irqports[i]; + } + + buddha_setup_ports(&hw[i], base, ctl, irq_port); + + hws[i] = &hw[i]; } + + ide_host_add(&d, hws, i, NULL); } + + return 0; } + +module_init(buddha_init); + +MODULE_LICENSE("GPL"); diff --git a/drivers/ide/pci/cmd640.c b/drivers/ide/cmd640.c index 61b5f9c0b2f..70f0a2754c1 100644 --- a/drivers/ide/pci/cmd640.c +++ b/drivers/ide/cmd640.c @@ -1,12 +1,10 @@ /* - * linux/drivers/ide/pci/cmd640.c Version 1.02 Sep 01, 1996 - * * Copyright (C) 1995-1996 Linus Torvalds & authors (see below) */ /* * Original authors: abramov@cecmow.enet.dec.com (Igor Abramov) - * mlord@pobox.com (Mark Lord) + * mlord@pobox.com (Mark Lord) * * See linux/MAINTAINERS for address of current maintainer. * @@ -98,28 +96,22 @@ * (patch courtesy of Zoltan Hidvegi) */ -#undef REALLY_SLOW_IO /* most systems can safely undef this */ #define CMD640_PREFETCH_MASKS 1 -//#define CMD640_DUMP_REGS +/*#define CMD640_DUMP_REGS */ #include <linux/types.h> #include <linux/kernel.h> #include <linux/delay.h> -#include <linux/timer.h> -#include <linux/mm.h> -#include <linux/ioport.h> -#include <linux/blkdev.h> -#include <linux/hdreg.h> #include <linux/ide.h> #include <linux/init.h> +#include <linux/module.h> #include <asm/io.h> -/* - * This flag is set in ide.c by the parameter: ide0=cmd640_vlb - */ -int cmd640_vlb = 0; +#define DRV_NAME "cmd640" + +static bool cmd640_vlb; /* * CMD640 specific registers definition. @@ -162,6 +154,7 @@ int cmd640_vlb = 0; #define ARTTIM23 0x57 #define ARTTIM23_DIS_RA2 0x04 #define ARTTIM23_DIS_RA3 0x08 +#define ARTTIM23_IDE23INTR 0x10 #define DRWTIM23 0x58 #define BRST 0x59 @@ -186,11 +179,7 @@ static u8 recovery_counts[4] = {16, 16, 16, 16}; /* Recovery count (encoded) */ #endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */ -/* - * These are initialized to point at the devices we control - */ -static ide_hwif_t *cmd_hwif0, *cmd_hwif1; -static ide_drive_t *cmd_drives[4]; +static DEFINE_SPINLOCK(cmd640_lock); /* * Interface to access cmd640x registers @@ -212,13 +201,13 @@ static unsigned int cmd640_chip_version; /* PCI method 1 access */ -static void put_cmd640_reg_pci1 (u16 reg, u8 val) +static void put_cmd640_reg_pci1(u16 reg, u8 val) { outl_p((reg & 0xfc) | cmd640_key, 0xcf8); outb_p(val, (reg & 3) | 0xcfc); } -static u8 get_cmd640_reg_pci1 (u16 reg) +static u8 get_cmd640_reg_pci1(u16 reg) { outl_p((reg & 0xfc) | cmd640_key, 0xcf8); return inb_p((reg & 3) | 0xcfc); @@ -226,14 +215,14 @@ static u8 get_cmd640_reg_pci1 (u16 reg) /* PCI method 2 access (from CMD datasheet) */ -static void put_cmd640_reg_pci2 (u16 reg, u8 val) +static void put_cmd640_reg_pci2(u16 reg, u8 val) { outb_p(0x10, 0xcf8); outb_p(val, cmd640_key + reg); outb_p(0, 0xcf8); } -static u8 get_cmd640_reg_pci2 (u16 reg) +static u8 get_cmd640_reg_pci2(u16 reg) { u8 b; @@ -245,13 +234,13 @@ static u8 get_cmd640_reg_pci2 (u16 reg) /* VLB access */ -static void put_cmd640_reg_vlb (u16 reg, u8 val) +static void put_cmd640_reg_vlb(u16 reg, u8 val) { outb_p(reg, cmd640_key); outb_p(val, cmd640_key + 4); } -static u8 get_cmd640_reg_vlb (u16 reg) +static u8 get_cmd640_reg_vlb(u16 reg) { outb_p(reg, cmd640_key); return inb_p(cmd640_key + 4); @@ -259,12 +248,12 @@ static u8 get_cmd640_reg_vlb (u16 reg) static u8 get_cmd640_reg(u16 reg) { - u8 b; unsigned long flags; + u8 b; - spin_lock_irqsave(&ide_lock, flags); + spin_lock_irqsave(&cmd640_lock, flags); b = __get_cmd640_reg(reg); - spin_unlock_irqrestore(&ide_lock, flags); + spin_unlock_irqrestore(&cmd640_lock, flags); return b; } @@ -272,12 +261,12 @@ static void put_cmd640_reg(u16 reg, u8 val) { unsigned long flags; - spin_lock_irqsave(&ide_lock, flags); - __put_cmd640_reg(reg,val); - spin_unlock_irqrestore(&ide_lock, flags); + spin_lock_irqsave(&cmd640_lock, flags); + __put_cmd640_reg(reg, val); + spin_unlock_irqrestore(&cmd640_lock, flags); } -static int __init match_pci_cmd640_device (void) +static int __init match_pci_cmd640_device(void) { const u8 ven_dev[4] = {0x95, 0x10, 0x40, 0x06}; unsigned int i; @@ -297,7 +286,7 @@ static int __init match_pci_cmd640_device (void) /* * Probe for CMD640x -- pci method 1 */ -static int __init probe_for_cmd640_pci1 (void) +static int __init probe_for_cmd640_pci1(void) { __get_cmd640_reg = get_cmd640_reg_pci1; __put_cmd640_reg = put_cmd640_reg_pci1; @@ -313,7 +302,7 @@ static int __init probe_for_cmd640_pci1 (void) /* * Probe for CMD640x -- pci method 2 */ -static int __init probe_for_cmd640_pci2 (void) +static int __init probe_for_cmd640_pci2(void) { __get_cmd640_reg = get_cmd640_reg_pci2; __put_cmd640_reg = put_cmd640_reg_pci2; @@ -327,7 +316,7 @@ static int __init probe_for_cmd640_pci2 (void) /* * Probe for CMD640x -- vlb */ -static int __init probe_for_cmd640_vlb (void) +static int __init probe_for_cmd640_vlb(void) { u8 b; @@ -348,23 +337,23 @@ static int __init probe_for_cmd640_vlb (void) * Returns 1 if an IDE interface/drive exists at 0x170, * Returns 0 otherwise. */ -static int __init secondary_port_responding (void) +static int __init secondary_port_responding(void) { unsigned long flags; - spin_lock_irqsave(&ide_lock, flags); + spin_lock_irqsave(&cmd640_lock, flags); - outb_p(0x0a, 0x170 + IDE_SELECT_OFFSET); /* select drive0 */ + outb_p(0x0a, 0x176); /* select drive0 */ udelay(100); - if ((inb_p(0x170 + IDE_SELECT_OFFSET) & 0x1f) != 0x0a) { - outb_p(0x1a, 0x170 + IDE_SELECT_OFFSET); /* select drive1 */ + if ((inb_p(0x176) & 0x1f) != 0x0a) { + outb_p(0x1a, 0x176); /* select drive1 */ udelay(100); - if ((inb_p(0x170 + IDE_SELECT_OFFSET) & 0x1f) != 0x1a) { - spin_unlock_irqrestore(&ide_lock, flags); + if ((inb_p(0x176) & 0x1f) != 0x1a) { + spin_unlock_irqrestore(&cmd640_lock, flags); return 0; /* nothing responded */ } } - spin_unlock_irqrestore(&ide_lock, flags); + spin_unlock_irqrestore(&cmd640_lock, flags); return 1; /* success */ } @@ -372,7 +361,7 @@ static int __init secondary_port_responding (void) /* * Dump out all cmd640 registers. May be called from ide.c */ -static void cmd640_dump_regs (void) +static void cmd640_dump_regs(void) { unsigned int reg = cmd640_vlb ? 0x50 : 0x00; @@ -387,87 +376,58 @@ static void cmd640_dump_regs (void) } #endif -/* - * Check whether prefetch is on for a drive, - * and initialize the unmask flags for safe operation. - */ -static void __init check_prefetch (unsigned int index) +static void __set_prefetch_mode(ide_drive_t *drive, int mode) { - ide_drive_t *drive = cmd_drives[index]; - u8 b = get_cmd640_reg(prefetch_regs[index]); - - if (b & prefetch_masks[index]) { /* is prefetch off? */ - drive->no_unmask = 0; - drive->no_io_32bit = 1; - drive->io_32bit = 0; - } else { + if (mode) { /* want prefetch on? */ #if CMD640_PREFETCH_MASKS - drive->no_unmask = 1; - drive->unmask = 0; + drive->dev_flags |= IDE_DFLAG_NO_UNMASK; + drive->dev_flags &= ~IDE_DFLAG_UNMASK; #endif - drive->no_io_32bit = 0; + drive->dev_flags &= ~IDE_DFLAG_NO_IO_32BIT; + } else { + drive->dev_flags &= ~IDE_DFLAG_NO_UNMASK; + drive->dev_flags |= IDE_DFLAG_NO_IO_32BIT; + drive->io_32bit = 0; } } +#ifndef CONFIG_BLK_DEV_CMD640_ENHANCED /* - * Figure out which devices we control + * Check whether prefetch is on for a drive, + * and initialize the unmask flags for safe operation. */ -static void __init setup_device_ptrs (void) +static void __init check_prefetch(ide_drive_t *drive, unsigned int index) { - unsigned int i; + u8 b = get_cmd640_reg(prefetch_regs[index]); - cmd_hwif0 = &ide_hwifs[0]; /* default, if not found below */ - cmd_hwif1 = &ide_hwifs[1]; /* default, if not found below */ - for (i = 0; i < MAX_HWIFS; i++) { - ide_hwif_t *hwif = &ide_hwifs[i]; - if (hwif->chipset == ide_unknown || hwif->chipset == ide_forced) { - if (hwif->io_ports[IDE_DATA_OFFSET] == 0x1f0) - cmd_hwif0 = hwif; - else if (hwif->io_ports[IDE_DATA_OFFSET] == 0x170) - cmd_hwif1 = hwif; - } - } - cmd_drives[0] = &cmd_hwif0->drives[0]; - cmd_drives[1] = &cmd_hwif0->drives[1]; - cmd_drives[2] = &cmd_hwif1->drives[0]; - cmd_drives[3] = &cmd_hwif1->drives[1]; + __set_prefetch_mode(drive, (b & prefetch_masks[index]) ? 0 : 1); } - -#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED +#else /* * Sets prefetch mode for a drive. */ -static void set_prefetch_mode (unsigned int index, int mode) +static void set_prefetch_mode(ide_drive_t *drive, unsigned int index, int mode) { - ide_drive_t *drive = cmd_drives[index]; + unsigned long flags; int reg = prefetch_regs[index]; u8 b; - unsigned long flags; - spin_lock_irqsave(&ide_lock, flags); + spin_lock_irqsave(&cmd640_lock, flags); b = __get_cmd640_reg(reg); - if (mode) { /* want prefetch on? */ -#if CMD640_PREFETCH_MASKS - drive->no_unmask = 1; - drive->unmask = 0; -#endif - drive->no_io_32bit = 0; + __set_prefetch_mode(drive, mode); + if (mode) b &= ~prefetch_masks[index]; /* enable prefetch */ - } else { - drive->no_unmask = 0; - drive->no_io_32bit = 1; - drive->io_32bit = 0; + else b |= prefetch_masks[index]; /* disable prefetch */ - } __put_cmd640_reg(reg, b); - spin_unlock_irqrestore(&ide_lock, flags); + spin_unlock_irqrestore(&cmd640_lock, flags); } /* * Dump out current drive clocks settings */ -static void display_clocks (unsigned int index) +static void display_clocks(unsigned int index) { u8 active_count, recovery_count; @@ -486,44 +446,16 @@ static void display_clocks (unsigned int index) * Pack active and recovery counts into single byte representation * used by controller */ -static inline u8 pack_nibbles (u8 upper, u8 lower) +static inline u8 pack_nibbles(u8 upper, u8 lower) { return ((upper & 0x0f) << 4) | (lower & 0x0f); } /* - * This routine retrieves the initial drive timings from the chipset. - */ -static void __init retrieve_drive_counts (unsigned int index) -{ - u8 b; - - /* - * Get the internal setup timing, and convert to clock count - */ - b = get_cmd640_reg(arttim_regs[index]) & ~0x3f; - switch (b) { - case 0x00: b = 4; break; - case 0x80: b = 3; break; - case 0x40: b = 2; break; - default: b = 5; break; - } - setup_counts[index] = b; - - /* - * Get the active/recovery counts - */ - b = get_cmd640_reg(drwtim_regs[index]); - active_counts[index] = (b >> 4) ? (b >> 4) : 0x10; - recovery_counts[index] = (b & 0x0f) ? (b & 0x0f) : 0x10; -} - - -/* * This routine writes the prepared setup/active/recovery counts * for a drive into the cmd640 chipset registers to active them. */ -static void program_drive_counts (unsigned int index) +static void program_drive_counts(ide_drive_t *drive, unsigned int index) { unsigned long flags; u8 setup_count = setup_counts[index]; @@ -537,8 +469,10 @@ static void program_drive_counts (unsigned int index) * so we merge the timings, using the slowest value for each timing. */ if (index > 1) { - unsigned int mate; - if (cmd_drives[mate = index ^ 1]->present) { + ide_drive_t *peer = ide_get_pair_dev(drive); + unsigned int mate = index ^ 1; + + if (peer) { if (setup_count < setup_counts[mate]) setup_count = setup_counts[mate]; if (active_count < active_counts[mate]) @@ -552,17 +486,17 @@ static void program_drive_counts (unsigned int index) * Convert setup_count to internal chipset representation */ switch (setup_count) { - case 4: setup_count = 0x00; break; - case 3: setup_count = 0x80; break; - case 1: - case 2: setup_count = 0x40; break; - default: setup_count = 0xc0; /* case 5 */ + case 4: setup_count = 0x00; break; + case 3: setup_count = 0x80; break; + case 1: + case 2: setup_count = 0x40; break; + default: setup_count = 0xc0; /* case 5 */ } /* * Now that everything is ready, program the new timings */ - spin_lock_irqsave(&ide_lock, flags); + spin_lock_irqsave(&cmd640_lock, flags); /* * Program the address_setup clocks into ARTTIM reg, * and then the active/recovery counts into the DRWTIM reg @@ -571,33 +505,43 @@ static void program_drive_counts (unsigned int index) setup_count |= __get_cmd640_reg(arttim_regs[index]) & 0x3f; __put_cmd640_reg(arttim_regs[index], setup_count); __put_cmd640_reg(drwtim_regs[index], pack_nibbles(active_count, recovery_count)); - spin_unlock_irqrestore(&ide_lock, flags); + spin_unlock_irqrestore(&cmd640_lock, flags); } /* * Set a specific pio_mode for a drive */ -static void cmd640_set_mode (unsigned int index, u8 pio_mode, unsigned int cycle_time) +static void cmd640_set_mode(ide_drive_t *drive, unsigned int index, + u8 pio_mode, unsigned int cycle_time) { + struct ide_timing *t; int setup_time, active_time, recovery_time, clock_time; u8 setup_count, active_count, recovery_count, recovery_count2, cycle_count; - int bus_speed = system_bus_clock(); + int bus_speed; + + if (cmd640_vlb) + bus_speed = ide_vlb_clk ? ide_vlb_clk : 50; + else + bus_speed = ide_pci_clk ? ide_pci_clk : 33; if (pio_mode > 5) pio_mode = 5; - setup_time = ide_pio_timings[pio_mode].setup_time; - active_time = ide_pio_timings[pio_mode].active_time; + + t = ide_timing_find_mode(XFER_PIO_0 + pio_mode); + setup_time = t->setup; + active_time = t->active; + recovery_time = cycle_time - (setup_time + active_time); clock_time = 1000 / bus_speed; - cycle_count = (cycle_time + clock_time - 1) / clock_time; + cycle_count = DIV_ROUND_UP(cycle_time, clock_time); - setup_count = (setup_time + clock_time - 1) / clock_time; + setup_count = DIV_ROUND_UP(setup_time, clock_time); - active_count = (active_time + clock_time - 1) / clock_time; + active_count = DIV_ROUND_UP(active_time, clock_time); if (active_count < 2) active_count = 2; /* minimum allowed by cmd640 */ - recovery_count = (recovery_time + clock_time - 1) / clock_time; + recovery_count = DIV_ROUND_UP(recovery_time, clock_time); recovery_count2 = cycle_count - (setup_count + active_count); if (recovery_count2 > recovery_count) recovery_count = recovery_count2; @@ -626,73 +570,102 @@ static void cmd640_set_mode (unsigned int index, u8 pio_mode, unsigned int cycle * 1) this is the wrong place to do it (proper is do_special() in ide.c) * 2) in practice this is rarely, if ever, necessary */ - program_drive_counts (index); + program_drive_counts(drive, index); } -/* - * Drive PIO mode selection: - */ -static void cmd640_tune_drive (ide_drive_t *drive, u8 mode_wanted) +static void cmd640_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) { + unsigned int index = 0, cycle_time; + const u8 pio = drive->pio_mode - XFER_PIO_0; u8 b; - ide_pio_data_t d; - unsigned int index = 0; - while (drive != cmd_drives[index]) { - if (++index > 3) { - printk("%s: bad news in cmd640_tune_drive\n", drive->name); - return; - } - } - switch (mode_wanted) { - case 6: /* set fast-devsel off */ - case 7: /* set fast-devsel on */ - mode_wanted &= 1; - b = get_cmd640_reg(CNTRL) & ~0x27; - if (mode_wanted) - b |= 0x27; - put_cmd640_reg(CNTRL, b); - printk("%s: %sabled cmd640 fast host timing (devsel)\n", drive->name, mode_wanted ? "en" : "dis"); - return; - - case 8: /* set prefetch off */ - case 9: /* set prefetch on */ - mode_wanted &= 1; - set_prefetch_mode(index, mode_wanted); - printk("%s: %sabled cmd640 prefetch\n", drive->name, mode_wanted ? "en" : "dis"); - return; + switch (pio) { + case 6: /* set fast-devsel off */ + case 7: /* set fast-devsel on */ + b = get_cmd640_reg(CNTRL) & ~0x27; + if (pio & 1) + b |= 0x27; + put_cmd640_reg(CNTRL, b); + printk("%s: %sabled cmd640 fast host timing (devsel)\n", + drive->name, (pio & 1) ? "en" : "dis"); + return; + case 8: /* set prefetch off */ + case 9: /* set prefetch on */ + set_prefetch_mode(drive, index, pio & 1); + printk("%s: %sabled cmd640 prefetch\n", + drive->name, (pio & 1) ? "en" : "dis"); + return; } - (void) ide_get_best_pio_mode (drive, mode_wanted, 5, &d); - cmd640_set_mode (index, d.pio_mode, d.cycle_time); + cycle_time = ide_pio_cycle_time(drive, pio); + cmd640_set_mode(drive, index, pio, cycle_time); + + printk("%s: selected cmd640 PIO mode%d (%dns)", + drive->name, pio, cycle_time); - printk ("%s: selected cmd640 PIO mode%d (%dns)%s", - drive->name, - d.pio_mode, - d.cycle_time, - d.overridden ? " (overriding vendor mode)" : ""); display_clocks(index); - return; } +#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */ + +static void __init cmd640_init_dev(ide_drive_t *drive) +{ + unsigned int i = drive->hwif->channel * 2 + (drive->dn & 1); +#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED + /* + * Reset timing to the slowest speed and turn off prefetch. + * This way, the drive identify code has a better chance. + */ + setup_counts[i] = 4; /* max possible */ + active_counts[i] = 16; /* max possible */ + recovery_counts[i] = 16; /* max possible */ + program_drive_counts(drive, i); + set_prefetch_mode(drive, i, 0); + printk(KERN_INFO DRV_NAME ": drive%d timings/prefetch cleared\n", i); +#else + /* + * Set the drive unmask flags to match the prefetch setting. + */ + check_prefetch(drive, i); + printk(KERN_INFO DRV_NAME ": drive%d timings/prefetch(%s) preserved\n", + i, (drive->dev_flags & IDE_DFLAG_NO_IO_32BIT) ? "off" : "on"); #endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */ +} + +static int cmd640_test_irq(ide_hwif_t *hwif) +{ + int irq_reg = hwif->channel ? ARTTIM23 : CFR; + u8 irq_mask = hwif->channel ? ARTTIM23_IDE23INTR : + CFR_IDE01INTR; + u8 irq_stat = get_cmd640_reg(irq_reg); + + return (irq_stat & irq_mask) ? 1 : 0; +} + +static const struct ide_port_ops cmd640_port_ops = { + .init_dev = cmd640_init_dev, +#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED + .set_pio_mode = cmd640_set_pio_mode, +#endif + .test_irq = cmd640_test_irq, +}; static int pci_conf1(void) { - u32 tmp; unsigned long flags; + u32 tmp; - spin_lock_irqsave(&ide_lock, flags); + spin_lock_irqsave(&cmd640_lock, flags); outb(0x01, 0xCFB); tmp = inl(0xCF8); outl(0x80000000, 0xCF8); if (inl(0xCF8) == 0x80000000) { outl(tmp, 0xCF8); - spin_unlock_irqrestore(&ide_lock, flags); + spin_unlock_irqrestore(&cmd640_lock, flags); return 1; } outl(tmp, 0xCF8); - spin_unlock_irqrestore(&ide_lock, flags); + spin_unlock_irqrestore(&cmd640_lock, flags); return 0; } @@ -700,30 +673,55 @@ static int pci_conf2(void) { unsigned long flags; - spin_lock_irqsave(&ide_lock, flags); + spin_lock_irqsave(&cmd640_lock, flags); outb(0x00, 0xCFB); outb(0x00, 0xCF8); outb(0x00, 0xCFA); if (inb(0xCF8) == 0x00 && inb(0xCF8) == 0x00) { - spin_unlock_irqrestore(&ide_lock, flags); + spin_unlock_irqrestore(&cmd640_lock, flags); return 1; } - spin_unlock_irqrestore(&ide_lock, flags); + spin_unlock_irqrestore(&cmd640_lock, flags); + return 0; +} + +static const struct ide_port_info cmd640_port_info __initconst = { + .chipset = ide_cmd640, + .host_flags = IDE_HFLAG_SERIALIZE | + IDE_HFLAG_NO_DMA | + IDE_HFLAG_ABUSE_PREFETCH | + IDE_HFLAG_ABUSE_FAST_DEVSEL, + .port_ops = &cmd640_port_ops, + .pio_mask = ATA_PIO5, +}; + +static int cmd640x_init_one(unsigned long base, unsigned long ctl) +{ + if (!request_region(base, 8, DRV_NAME)) { + printk(KERN_ERR "%s: I/O resource 0x%lX-0x%lX not free.\n", + DRV_NAME, base, base + 7); + return -EBUSY; + } + + if (!request_region(ctl, 1, DRV_NAME)) { + printk(KERN_ERR "%s: I/O resource 0x%lX not free.\n", + DRV_NAME, ctl); + release_region(base, 8); + return -EBUSY; + } + return 0; } /* - * Probe for a cmd640 chipset, and initialize it if found. Called from ide.c + * Probe for a cmd640 chipset, and initialize it if found. */ -int __init ide_probe_for_cmd640x (void) +static int __init cmd640x_init(void) { -#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED - int second_port_toggled = 0; -#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */ - int second_port_cmd640 = 0; + int second_port_cmd640 = 0, rc; const char *bus_type, *port2; - unsigned int index; u8 b, cfr; + struct ide_hw hw[2], *hws[2]; if (cmd640_vlb && probe_for_cmd640_vlb()) { bus_type = "VLB"; @@ -758,20 +756,36 @@ int __init ide_probe_for_cmd640x (void) cfr = get_cmd640_reg(CFR); cmd640_chip_version = cfr & CFR_DEVREV; if (cmd640_chip_version == 0) { - printk ("ide: bad cmd640 revision: %d\n", cmd640_chip_version); + printk("ide: bad cmd640 revision: %d\n", cmd640_chip_version); return 0; } + rc = cmd640x_init_one(0x1f0, 0x3f6); + if (rc) + return rc; + + rc = cmd640x_init_one(0x170, 0x376); + if (rc) { + release_region(0x3f6, 1); + release_region(0x1f0, 8); + return rc; + } + + memset(&hw, 0, sizeof(hw)); + + ide_std_init_ports(&hw[0], 0x1f0, 0x3f6); + hw[0].irq = 14; + + ide_std_init_ports(&hw[1], 0x170, 0x376); + hw[1].irq = 15; + + printk(KERN_INFO "cmd640: buggy cmd640%c interface on %s, config=0x%02x" + "\n", 'a' + cmd640_chip_version - 1, bus_type, cfr); + /* * Initialize data for primary port */ - setup_device_ptrs (); - printk("%s: buggy cmd640%c interface on %s, config=0x%02x\n", - cmd_hwif0->name, 'a' + cmd640_chip_version - 1, bus_type, cfr); - cmd_hwif0->chipset = ide_cmd640; -#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED - cmd_hwif0->tuneproc = &cmd640_tune_drive; -#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */ + hws[0] = &hw[0]; /* * Ensure compatibility by always using the slowest timings @@ -783,96 +797,51 @@ int __init ide_probe_for_cmd640x (void) put_cmd640_reg(CMDTIM, 0); put_cmd640_reg(BRST, 0x40); + b = get_cmd640_reg(CNTRL); + /* * Try to enable the secondary interface, if not already enabled */ - if (cmd_hwif1->noprobe) { - port2 = "not probed"; + if (secondary_port_responding()) { + if ((b & CNTRL_ENA_2ND)) { + second_port_cmd640 = 1; + port2 = "okay"; + } else if (cmd640_vlb) { + second_port_cmd640 = 1; + port2 = "alive"; + } else + port2 = "not cmd640"; } else { - b = get_cmd640_reg(CNTRL); + put_cmd640_reg(CNTRL, b ^ CNTRL_ENA_2ND); /* toggle the bit */ if (secondary_port_responding()) { - if ((b & CNTRL_ENA_2ND)) { - second_port_cmd640 = 1; - port2 = "okay"; - } else if (cmd640_vlb) { - second_port_cmd640 = 1; - port2 = "alive"; - } else - port2 = "not cmd640"; + second_port_cmd640 = 1; + port2 = "enabled"; } else { - put_cmd640_reg(CNTRL, b ^ CNTRL_ENA_2ND); /* toggle the bit */ - if (secondary_port_responding()) { - second_port_cmd640 = 1; -#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED - second_port_toggled = 1; -#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */ - port2 = "enabled"; - } else { - put_cmd640_reg(CNTRL, b); /* restore original setting */ - port2 = "not responding"; - } + put_cmd640_reg(CNTRL, b); /* restore original setting */ + port2 = "not responding"; } } /* * Initialize data for secondary cmd640 port, if enabled */ - if (second_port_cmd640) { - cmd_hwif0->serialized = 1; - cmd_hwif1->serialized = 1; - cmd_hwif1->chipset = ide_cmd640; - cmd_hwif0->mate = cmd_hwif1; - cmd_hwif1->mate = cmd_hwif0; - cmd_hwif1->channel = 1; -#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED - cmd_hwif1->tuneproc = &cmd640_tune_drive; -#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */ - } - printk(KERN_INFO "%s: %sserialized, secondary interface %s\n", cmd_hwif1->name, - cmd_hwif0->serialized ? "" : "not ", port2); + if (second_port_cmd640) + hws[1] = &hw[1]; - /* - * Establish initial timings/prefetch for all drives. - * Do not unnecessarily disturb any prior BIOS setup of these. - */ - for (index = 0; index < (2 + (second_port_cmd640 << 1)); index++) { - ide_drive_t *drive = cmd_drives[index]; -#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED - if (drive->autotune || ((index > 1) && second_port_toggled)) { - /* - * Reset timing to the slowest speed and turn off prefetch. - * This way, the drive identify code has a better chance. - */ - setup_counts [index] = 4; /* max possible */ - active_counts [index] = 16; /* max possible */ - recovery_counts [index] = 16; /* max possible */ - program_drive_counts (index); - set_prefetch_mode (index, 0); - printk("cmd640: drive%d timings/prefetch cleared\n", index); - } else { - /* - * Record timings/prefetch without changing them. - * This preserves any prior BIOS setup. - */ - retrieve_drive_counts (index); - check_prefetch (index); - printk("cmd640: drive%d timings/prefetch(%s) preserved", - index, drive->no_io_32bit ? "off" : "on"); - display_clocks(index); - } -#else - /* - * Set the drive unmask flags to match the prefetch setting - */ - check_prefetch (index); - printk("cmd640: drive%d timings/prefetch(%s) preserved\n", - index, drive->no_io_32bit ? "off" : "on"); -#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */ - } + printk(KERN_INFO "cmd640: %sserialized, secondary interface %s\n", + second_port_cmd640 ? "" : "not ", port2); #ifdef CMD640_DUMP_REGS cmd640_dump_regs(); #endif - return 1; + + return ide_host_add(&cmd640_port_info, hws, second_port_cmd640 ? 2 : 1, + NULL); } +module_param_named(probe_vlb, cmd640_vlb, bool, 0); +MODULE_PARM_DESC(probe_vlb, "probe for VLB version of CMD640 chipset"); + +module_init(cmd640x_init); + +MODULE_LICENSE("GPL"); diff --git a/drivers/ide/cmd64x.c b/drivers/ide/cmd64x.c new file mode 100644 index 00000000000..b127ed60c73 --- /dev/null +++ b/drivers/ide/cmd64x.c @@ -0,0 +1,448 @@ +/* + * cmd64x.c: Enable interrupts at initialization time on Ultra/PCI machines. + * Due to massive hardware bugs, UltraDMA is only supported + * on the 646U2 and not on the 646U. + * + * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be) + * Copyright (C) 1998 David S. Miller (davem@redhat.com) + * + * Copyright (C) 1999-2002 Andre Hedrick <andre@linux-ide.org> + * Copyright (C) 2007-2010 Bartlomiej Zolnierkiewicz + * Copyright (C) 2007,2009 MontaVista Software, Inc. <source@mvista.com> + */ + +#include <linux/module.h> +#include <linux/types.h> +#include <linux/pci.h> +#include <linux/ide.h> +#include <linux/init.h> + +#include <asm/io.h> + +#define DRV_NAME "cmd64x" + +/* + * CMD64x specific registers definition. + */ +#define CFR 0x50 +#define CFR_INTR_CH0 0x04 + +#define CMDTIM 0x52 +#define ARTTIM0 0x53 +#define DRWTIM0 0x54 +#define ARTTIM1 0x55 +#define DRWTIM1 0x56 +#define ARTTIM23 0x57 +#define ARTTIM23_DIS_RA2 0x04 +#define ARTTIM23_DIS_RA3 0x08 +#define ARTTIM23_INTR_CH1 0x10 +#define DRWTIM2 0x58 +#define BRST 0x59 +#define DRWTIM3 0x5b + +#define BMIDECR0 0x70 +#define MRDMODE 0x71 +#define MRDMODE_INTR_CH0 0x04 +#define MRDMODE_INTR_CH1 0x08 +#define UDIDETCR0 0x73 +#define DTPR0 0x74 +#define BMIDECR1 0x78 +#define BMIDECSR 0x79 +#define UDIDETCR1 0x7B +#define DTPR1 0x7C + +static void cmd64x_program_timings(ide_drive_t *drive, u8 mode) +{ + ide_hwif_t *hwif = drive->hwif; + struct pci_dev *dev = to_pci_dev(drive->hwif->dev); + int bus_speed = ide_pci_clk ? ide_pci_clk : 33; + const unsigned long T = 1000000 / bus_speed; + static const u8 recovery_values[] = + {15, 15, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 0}; + static const u8 setup_values[] = {0x40, 0x40, 0x40, 0x80, 0, 0xc0}; + static const u8 arttim_regs[4] = {ARTTIM0, ARTTIM1, ARTTIM23, ARTTIM23}; + static const u8 drwtim_regs[4] = {DRWTIM0, DRWTIM1, DRWTIM2, DRWTIM3}; + struct ide_timing t; + u8 arttim = 0; + + ide_timing_compute(drive, mode, &t, T, 0); + + /* + * In case we've got too long recovery phase, try to lengthen + * the active phase + */ + if (t.recover > 16) { + t.active += t.recover - 16; + t.recover = 16; + } + if (t.active > 16) /* shouldn't actually happen... */ + t.active = 16; + + /* + * Convert values to internal chipset representation + */ + t.recover = recovery_values[t.recover]; + t.active &= 0x0f; + + /* Program the active/recovery counts into the DRWTIM register */ + pci_write_config_byte(dev, drwtim_regs[drive->dn], + (t.active << 4) | t.recover); + + /* + * The primary channel has individual address setup timing registers + * for each drive and the hardware selects the slowest timing itself. + * The secondary channel has one common register and we have to select + * the slowest address setup timing ourselves. + */ + if (hwif->channel) { + ide_drive_t *pair = ide_get_pair_dev(drive); + + if (pair) { + struct ide_timing tp; + + ide_timing_compute(pair, pair->pio_mode, &tp, T, 0); + ide_timing_merge(&t, &tp, &t, IDE_TIMING_SETUP); + if (pair->dma_mode) { + ide_timing_compute(pair, pair->dma_mode, + &tp, T, 0); + ide_timing_merge(&tp, &t, &t, IDE_TIMING_SETUP); + } + } + } + + if (t.setup > 5) /* shouldn't actually happen... */ + t.setup = 5; + + /* + * Program the address setup clocks into the ARTTIM registers. + * Avoid clearing the secondary channel's interrupt bit. + */ + (void) pci_read_config_byte (dev, arttim_regs[drive->dn], &arttim); + if (hwif->channel) + arttim &= ~ARTTIM23_INTR_CH1; + arttim &= ~0xc0; + arttim |= setup_values[t.setup]; + (void) pci_write_config_byte(dev, arttim_regs[drive->dn], arttim); +} + +/* + * Attempts to set drive's PIO mode. + * Special cases are 8: prefetch off, 9: prefetch on (both never worked) + */ + +static void cmd64x_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) +{ + const u8 pio = drive->pio_mode - XFER_PIO_0; + + /* + * Filter out the prefetch control values + * to prevent PIO5 from being programmed + */ + if (pio == 8 || pio == 9) + return; + + cmd64x_program_timings(drive, XFER_PIO_0 + pio); +} + +static void cmd64x_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive) +{ + struct pci_dev *dev = to_pci_dev(hwif->dev); + u8 unit = drive->dn & 0x01; + u8 regU = 0, pciU = hwif->channel ? UDIDETCR1 : UDIDETCR0; + const u8 speed = drive->dma_mode; + + pci_read_config_byte(dev, pciU, ®U); + regU &= ~(unit ? 0xCA : 0x35); + + switch(speed) { + case XFER_UDMA_5: + regU |= unit ? 0x0A : 0x05; + break; + case XFER_UDMA_4: + regU |= unit ? 0x4A : 0x15; + break; + case XFER_UDMA_3: + regU |= unit ? 0x8A : 0x25; + break; + case XFER_UDMA_2: + regU |= unit ? 0x42 : 0x11; + break; + case XFER_UDMA_1: + regU |= unit ? 0x82 : 0x21; + break; + case XFER_UDMA_0: + regU |= unit ? 0xC2 : 0x31; + break; + case XFER_MW_DMA_2: + case XFER_MW_DMA_1: + case XFER_MW_DMA_0: + cmd64x_program_timings(drive, speed); + break; + } + + pci_write_config_byte(dev, pciU, regU); +} + +static void cmd648_clear_irq(ide_drive_t *drive) +{ + ide_hwif_t *hwif = drive->hwif; + struct pci_dev *dev = to_pci_dev(hwif->dev); + unsigned long base = pci_resource_start(dev, 4); + u8 irq_mask = hwif->channel ? MRDMODE_INTR_CH1 : + MRDMODE_INTR_CH0; + u8 mrdmode = inb(base + 1); + + /* clear the interrupt bit */ + outb((mrdmode & ~(MRDMODE_INTR_CH0 | MRDMODE_INTR_CH1)) | irq_mask, + base + 1); +} + +static void cmd64x_clear_irq(ide_drive_t *drive) +{ + ide_hwif_t *hwif = drive->hwif; + struct pci_dev *dev = to_pci_dev(hwif->dev); + int irq_reg = hwif->channel ? ARTTIM23 : CFR; + u8 irq_mask = hwif->channel ? ARTTIM23_INTR_CH1 : + CFR_INTR_CH0; + u8 irq_stat = 0; + + (void) pci_read_config_byte(dev, irq_reg, &irq_stat); + /* clear the interrupt bit */ + (void) pci_write_config_byte(dev, irq_reg, irq_stat | irq_mask); +} + +static int cmd648_test_irq(ide_hwif_t *hwif) +{ + struct pci_dev *dev = to_pci_dev(hwif->dev); + unsigned long base = pci_resource_start(dev, 4); + u8 irq_mask = hwif->channel ? MRDMODE_INTR_CH1 : + MRDMODE_INTR_CH0; + u8 mrdmode = inb(base + 1); + + pr_debug("%s: mrdmode: 0x%02x irq_mask: 0x%02x\n", + hwif->name, mrdmode, irq_mask); + + return (mrdmode & irq_mask) ? 1 : 0; +} + +static int cmd64x_test_irq(ide_hwif_t *hwif) +{ + struct pci_dev *dev = to_pci_dev(hwif->dev); + int irq_reg = hwif->channel ? ARTTIM23 : CFR; + u8 irq_mask = hwif->channel ? ARTTIM23_INTR_CH1 : + CFR_INTR_CH0; + u8 irq_stat = 0; + + (void) pci_read_config_byte(dev, irq_reg, &irq_stat); + + pr_debug("%s: irq_stat: 0x%02x irq_mask: 0x%02x\n", + hwif->name, irq_stat, irq_mask); + + return (irq_stat & irq_mask) ? 1 : 0; +} + +/* + * ASUS P55T2P4D with CMD646 chipset revision 0x01 requires the old + * event order for DMA transfers. + */ + +static int cmd646_1_dma_end(ide_drive_t *drive) +{ + ide_hwif_t *hwif = drive->hwif; + u8 dma_stat = 0, dma_cmd = 0; + + /* get DMA status */ + dma_stat = inb(hwif->dma_base + ATA_DMA_STATUS); + /* read DMA command state */ + dma_cmd = inb(hwif->dma_base + ATA_DMA_CMD); + /* stop DMA */ + outb(dma_cmd & ~1, hwif->dma_base + ATA_DMA_CMD); + /* clear the INTR & ERROR bits */ + outb(dma_stat | 6, hwif->dma_base + ATA_DMA_STATUS); + /* verify good DMA status */ + return (dma_stat & 7) != 4; +} + +static int init_chipset_cmd64x(struct pci_dev *dev) +{ + u8 mrdmode = 0; + + /* Set a good latency timer and cache line size value. */ + (void) pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64); + /* FIXME: pci_set_master() to ensure a good latency timer value */ + + /* + * Enable interrupts, select MEMORY READ LINE for reads. + * + * NOTE: although not mentioned in the PCI0646U specs, + * bits 0-1 are write only and won't be read back as + * set or not -- PCI0646U2 specs clarify this point. + */ + (void) pci_read_config_byte (dev, MRDMODE, &mrdmode); + mrdmode &= ~0x30; + (void) pci_write_config_byte(dev, MRDMODE, (mrdmode | 0x02)); + + return 0; +} + +static u8 cmd64x_cable_detect(ide_hwif_t *hwif) +{ + struct pci_dev *dev = to_pci_dev(hwif->dev); + u8 bmidecsr = 0, mask = hwif->channel ? 0x02 : 0x01; + + switch (dev->device) { + case PCI_DEVICE_ID_CMD_648: + case PCI_DEVICE_ID_CMD_649: + pci_read_config_byte(dev, BMIDECSR, &bmidecsr); + return (bmidecsr & mask) ? ATA_CBL_PATA80 : ATA_CBL_PATA40; + default: + return ATA_CBL_PATA40; + } +} + +static const struct ide_port_ops cmd64x_port_ops = { + .set_pio_mode = cmd64x_set_pio_mode, + .set_dma_mode = cmd64x_set_dma_mode, + .clear_irq = cmd64x_clear_irq, + .test_irq = cmd64x_test_irq, + .cable_detect = cmd64x_cable_detect, +}; + +static const struct ide_port_ops cmd648_port_ops = { + .set_pio_mode = cmd64x_set_pio_mode, + .set_dma_mode = cmd64x_set_dma_mode, + .clear_irq = cmd648_clear_irq, + .test_irq = cmd648_test_irq, + .cable_detect = cmd64x_cable_detect, +}; + +static const struct ide_dma_ops cmd646_rev1_dma_ops = { + .dma_host_set = ide_dma_host_set, + .dma_setup = ide_dma_setup, + .dma_start = ide_dma_start, + .dma_end = cmd646_1_dma_end, + .dma_test_irq = ide_dma_test_irq, + .dma_lost_irq = ide_dma_lost_irq, + .dma_timer_expiry = ide_dma_sff_timer_expiry, + .dma_sff_read_status = ide_dma_sff_read_status, +}; + +static const struct ide_port_info cmd64x_chipsets[] = { + { /* 0: CMD643 */ + .name = DRV_NAME, + .init_chipset = init_chipset_cmd64x, + .enablebits = {{0x00,0x00,0x00}, {0x51,0x08,0x08}}, + .port_ops = &cmd64x_port_ops, + .host_flags = IDE_HFLAG_CLEAR_SIMPLEX | + IDE_HFLAG_ABUSE_PREFETCH | + IDE_HFLAG_SERIALIZE, + .pio_mask = ATA_PIO5, + .mwdma_mask = ATA_MWDMA2, + .udma_mask = 0x00, /* no udma */ + }, + { /* 1: CMD646 */ + .name = DRV_NAME, + .init_chipset = init_chipset_cmd64x, + .enablebits = {{0x51,0x04,0x04}, {0x51,0x08,0x08}}, + .port_ops = &cmd648_port_ops, + .host_flags = IDE_HFLAG_ABUSE_PREFETCH | + IDE_HFLAG_SERIALIZE, + .pio_mask = ATA_PIO5, + .mwdma_mask = ATA_MWDMA2, + .udma_mask = ATA_UDMA2, + }, + { /* 2: CMD648 */ + .name = DRV_NAME, + .init_chipset = init_chipset_cmd64x, + .enablebits = {{0x51,0x04,0x04}, {0x51,0x08,0x08}}, + .port_ops = &cmd648_port_ops, + .host_flags = IDE_HFLAG_ABUSE_PREFETCH, + .pio_mask = ATA_PIO5, + .mwdma_mask = ATA_MWDMA2, + .udma_mask = ATA_UDMA4, + }, + { /* 3: CMD649 */ + .name = DRV_NAME, + .init_chipset = init_chipset_cmd64x, + .enablebits = {{0x51,0x04,0x04}, {0x51,0x08,0x08}}, + .port_ops = &cmd648_port_ops, + .host_flags = IDE_HFLAG_ABUSE_PREFETCH, + .pio_mask = ATA_PIO5, + .mwdma_mask = ATA_MWDMA2, + .udma_mask = ATA_UDMA5, + } +}; + +static int cmd64x_init_one(struct pci_dev *dev, const struct pci_device_id *id) +{ + struct ide_port_info d; + u8 idx = id->driver_data; + + d = cmd64x_chipsets[idx]; + + if (idx == 1) { + /* + * UltraDMA only supported on PCI646U and PCI646U2, which + * correspond to revisions 0x03, 0x05 and 0x07 respectively. + * Actually, although the CMD tech support people won't + * tell me the details, the 0x03 revision cannot support + * UDMA correctly without hardware modifications, and even + * then it only works with Quantum disks due to some + * hold time assumptions in the 646U part which are fixed + * in the 646U2. + * + * So we only do UltraDMA on revision 0x05 and 0x07 chipsets. + */ + if (dev->revision < 5) { + d.udma_mask = 0x00; + /* + * The original PCI0646 didn't have the primary + * channel enable bit, it appeared starting with + * PCI0646U (i.e. revision ID 3). + */ + if (dev->revision < 3) { + d.enablebits[0].reg = 0; + d.port_ops = &cmd64x_port_ops; + if (dev->revision == 1) + d.dma_ops = &cmd646_rev1_dma_ops; + } + } + } + + return ide_pci_init_one(dev, &d, NULL); +} + +static const struct pci_device_id cmd64x_pci_tbl[] = { + { PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_643), 0 }, + { PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_646), 1 }, + { PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_648), 2 }, + { PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_649), 3 }, + { 0, }, +}; +MODULE_DEVICE_TABLE(pci, cmd64x_pci_tbl); + +static struct pci_driver cmd64x_pci_driver = { + .name = "CMD64x_IDE", + .id_table = cmd64x_pci_tbl, + .probe = cmd64x_init_one, + .remove = ide_pci_remove, + .suspend = ide_pci_suspend, + .resume = ide_pci_resume, +}; + +static int __init cmd64x_ide_init(void) +{ + return ide_pci_register_driver(&cmd64x_pci_driver); +} + +static void __exit cmd64x_ide_exit(void) +{ + pci_unregister_driver(&cmd64x_pci_driver); +} + +module_init(cmd64x_ide_init); +module_exit(cmd64x_ide_exit); + +MODULE_AUTHOR("Eddie Dost, David Miller, Andre Hedrick, Bartlomiej Zolnierkiewicz"); +MODULE_DESCRIPTION("PCI driver module for CMD64x IDE"); +MODULE_LICENSE("GPL"); diff --git a/drivers/ide/cris/Makefile b/drivers/ide/cris/Makefile deleted file mode 100644 index 6176e8d6b2e..00000000000 --- a/drivers/ide/cris/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -EXTRA_CFLAGS += -Idrivers/ide - -obj-y += ide-cris.o diff --git a/drivers/ide/cris/ide-cris.c b/drivers/ide/cris/ide-cris.c deleted file mode 100644 index 5797e0b5a13..00000000000 --- a/drivers/ide/cris/ide-cris.c +++ /dev/null @@ -1,1106 +0,0 @@ -/* $Id: cris-ide-driver.patch,v 1.1 2005/06/29 21:39:07 akpm 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-2005 Axis Communications AB - * - * Authors: Bjorn Wesen (initial version) - * Mikael Starvik (crisv32 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/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 <asm/io.h> -#include <asm/dma.h> - -/* number of 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 - -#define LOWDB(x) -#define D(x) - -enum /* Transfer types */ -{ - TYPE_PIO, - TYPE_DMA, - TYPE_UDMA -}; - -/* CRISv32 specifics */ -#ifdef CONFIG_ETRAX_ARCH_V32 -#include <asm/arch/hwregs/ata_defs.h> -#include <asm/arch/hwregs/dma_defs.h> -#include <asm/arch/hwregs/dma.h> -#include <asm/arch/pinmux.h> - -#define ATA_UDMA2_CYC 2 -#define ATA_UDMA2_DVS 3 -#define ATA_UDMA1_CYC 2 -#define ATA_UDMA1_DVS 4 -#define ATA_UDMA0_CYC 4 -#define ATA_UDMA0_DVS 6 -#define ATA_DMA2_STROBE 7 -#define ATA_DMA2_HOLD 1 -#define ATA_DMA1_STROBE 8 -#define ATA_DMA1_HOLD 3 -#define ATA_DMA0_STROBE 25 -#define ATA_DMA0_HOLD 19 -#define ATA_PIO4_SETUP 3 -#define ATA_PIO4_STROBE 7 -#define ATA_PIO4_HOLD 1 -#define ATA_PIO3_SETUP 3 -#define ATA_PIO3_STROBE 9 -#define ATA_PIO3_HOLD 3 -#define ATA_PIO2_SETUP 3 -#define ATA_PIO2_STROBE 13 -#define ATA_PIO2_HOLD 5 -#define ATA_PIO1_SETUP 5 -#define ATA_PIO1_STROBE 23 -#define ATA_PIO1_HOLD 9 -#define ATA_PIO0_SETUP 9 -#define ATA_PIO0_STROBE 39 -#define ATA_PIO0_HOLD 9 - -int -cris_ide_ack_intr(ide_hwif_t* hwif) -{ - reg_ata_rw_ctrl2 ctrl2 = REG_TYPE_CONV(reg_ata_rw_ctrl2, - int, hwif->io_ports[0]); - REG_WR_INT(ata, regi_ata, rw_ack_intr, 1 << ctrl2.sel); - return 1; -} - -static inline int -cris_ide_busy(void) -{ - reg_ata_rs_stat_data stat_data; - stat_data = REG_RD(ata, regi_ata, rs_stat_data); - return stat_data.busy; -} - -static inline int -cris_ide_ready(void) -{ - return !cris_ide_busy(); -} - -static inline int -cris_ide_data_available(unsigned short* data) -{ - reg_ata_rs_stat_data stat_data; - stat_data = REG_RD(ata, regi_ata, rs_stat_data); - *data = stat_data.data; - return stat_data.dav; -} - -static void -cris_ide_write_command(unsigned long command) -{ - REG_WR_INT(ata, regi_ata, rw_ctrl2, command); /* write data to the drive's register */ -} - -static void -cris_ide_set_speed(int type, int setup, int strobe, int hold) -{ - reg_ata_rw_ctrl0 ctrl0 = REG_RD(ata, regi_ata, rw_ctrl0); - reg_ata_rw_ctrl1 ctrl1 = REG_RD(ata, regi_ata, rw_ctrl1); - - if (type == TYPE_PIO) { - ctrl0.pio_setup = setup; - ctrl0.pio_strb = strobe; - ctrl0.pio_hold = hold; - } else if (type == TYPE_DMA) { - ctrl0.dma_strb = strobe; - ctrl0.dma_hold = hold; - } else if (type == TYPE_UDMA) { - ctrl1.udma_tcyc = setup; - ctrl1.udma_tdvs = strobe; - } - REG_WR(ata, regi_ata, rw_ctrl0, ctrl0); - REG_WR(ata, regi_ata, rw_ctrl1, ctrl1); -} - -static unsigned long -cris_ide_base_address(int bus) -{ - reg_ata_rw_ctrl2 ctrl2 = {0}; - ctrl2.sel = bus; - return REG_TYPE_CONV(int, reg_ata_rw_ctrl2, ctrl2); -} - -static unsigned long -cris_ide_reg_addr(unsigned long addr, int cs0, int cs1) -{ - reg_ata_rw_ctrl2 ctrl2 = {0}; - ctrl2.addr = addr; - ctrl2.cs1 = cs1; - ctrl2.cs0 = cs0; - return REG_TYPE_CONV(int, reg_ata_rw_ctrl2, ctrl2); -} - -static __init void -cris_ide_reset(unsigned val) -{ - reg_ata_rw_ctrl0 ctrl0 = {0}; - ctrl0.rst = val ? regk_ata_active : regk_ata_inactive; - REG_WR(ata, regi_ata, rw_ctrl0, ctrl0); -} - -static __init void -cris_ide_init(void) -{ - reg_ata_rw_ctrl0 ctrl0 = {0}; - reg_ata_rw_intr_mask intr_mask = {0}; - - ctrl0.en = regk_ata_yes; - REG_WR(ata, regi_ata, rw_ctrl0, ctrl0); - - intr_mask.bus0 = regk_ata_yes; - intr_mask.bus1 = regk_ata_yes; - intr_mask.bus2 = regk_ata_yes; - intr_mask.bus3 = regk_ata_yes; - - REG_WR(ata, regi_ata, rw_intr_mask, intr_mask); - - crisv32_request_dma(2, "ETRAX FS built-in ATA", DMA_VERBOSE_ON_ERROR, 0, dma_ata); - crisv32_request_dma(3, "ETRAX FS built-in ATA", DMA_VERBOSE_ON_ERROR, 0, dma_ata); - - crisv32_pinmux_alloc_fixed(pinmux_ata); - crisv32_pinmux_alloc_fixed(pinmux_ata0); - crisv32_pinmux_alloc_fixed(pinmux_ata1); - crisv32_pinmux_alloc_fixed(pinmux_ata2); - crisv32_pinmux_alloc_fixed(pinmux_ata3); - - DMA_RESET(regi_dma2); - DMA_ENABLE(regi_dma2); - DMA_RESET(regi_dma3); - DMA_ENABLE(regi_dma3); - - DMA_WR_CMD (regi_dma2, regk_dma_set_w_size2); - DMA_WR_CMD (regi_dma3, regk_dma_set_w_size2); -} - -static dma_descr_context mycontext __attribute__ ((__aligned__(32))); - -#define cris_dma_descr_type dma_descr_data -#define cris_pio_read regk_ata_rd -#define cris_ultra_mask 0x7 -#define MAX_DESCR_SIZE 0xffffffffUL - -static unsigned long -cris_ide_get_reg(unsigned long reg) -{ - return (reg & 0x0e000000) >> 25; -} - -static void -cris_ide_fill_descriptor(cris_dma_descr_type *d, void* buf, unsigned int len, int last) -{ - d->buf = (char*)virt_to_phys(buf); - d->after = d->buf + len; - d->eol = last; -} - -static void -cris_ide_start_dma(ide_drive_t *drive, cris_dma_descr_type *d, int dir,int type,int len) -{ - reg_ata_rw_ctrl2 ctrl2 = REG_TYPE_CONV(reg_ata_rw_ctrl2, int, IDE_DATA_REG); - reg_ata_rw_trf_cnt trf_cnt = {0}; - - mycontext.saved_data = (dma_descr_data*)virt_to_phys(d); - mycontext.saved_data_buf = d->buf; - /* start the dma channel */ - DMA_START_CONTEXT(dir ? regi_dma3 : regi_dma2, virt_to_phys(&mycontext)); - - /* initiate a multi word dma read using PIO handshaking */ - trf_cnt.cnt = len >> 1; - /* Due to a "feature" the transfer count has to be one extra word for UDMA. */ - if (type == TYPE_UDMA) - trf_cnt.cnt++; - REG_WR(ata, regi_ata, rw_trf_cnt, trf_cnt); - - ctrl2.rw = dir ? regk_ata_rd : regk_ata_wr; - ctrl2.trf_mode = regk_ata_dma; - ctrl2.hsh = type == TYPE_PIO ? regk_ata_pio : - type == TYPE_DMA ? regk_ata_dma : regk_ata_udma; - ctrl2.multi = regk_ata_yes; - ctrl2.dma_size = regk_ata_word; - REG_WR(ata, regi_ata, rw_ctrl2, ctrl2); -} - -static void -cris_ide_wait_dma(int dir) -{ - reg_dma_rw_stat status; - do - { - status = REG_RD(dma, dir ? regi_dma3 : regi_dma2, rw_stat); - } while(status.list_state != regk_dma_data_at_eol); -} - -static int cris_dma_test_irq(ide_drive_t *drive) -{ - int intr = REG_RD_INT(ata, regi_ata, r_intr); - reg_ata_rw_ctrl2 ctrl2 = REG_TYPE_CONV(reg_ata_rw_ctrl2, int, IDE_DATA_REG); - return intr & (1 << ctrl2.sel) ? 1 : 0; -} - -static void cris_ide_initialize_dma(int dir) -{ -} - -#else -/* CRISv10 specifics */ -#include <asm/arch/svinto.h> -#include <asm/arch/io_interface_mux.h> - -/* 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_UDMA2_CYC 0 /* No UDMA supported, just to make it compile. */ -#define ATA_UDMA2_DVS 0 -#define ATA_UDMA1_CYC 0 -#define ATA_UDMA1_DVS 0 -#define ATA_UDMA0_CYC 0 -#define ATA_UDMA0_DVS 0 -#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 - -int -cris_ide_ack_intr(ide_hwif_t* hwif) -{ - return 1; -} - -static inline int -cris_ide_busy(void) -{ - return *R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy) ; -} - -static inline int -cris_ide_ready(void) -{ - return *R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, tr_rdy) ; -} - -static inline int -cris_ide_data_available(unsigned short* data) -{ - unsigned long status = *R_ATA_STATUS_DATA; - *data = (unsigned short)status; - return status & IO_MASK(R_ATA_STATUS_DATA, dav); -} - -static void -cris_ide_write_command(unsigned long command) -{ - *R_ATA_CTRL_DATA = command; -} - -static void -cris_ide_set_speed(int type, int setup, int strobe, int hold) -{ - static int pio_setup = ATA_PIO4_SETUP; - static int pio_strobe = ATA_PIO4_STROBE; - static int pio_hold = ATA_PIO4_HOLD; - static int dma_strobe = ATA_DMA2_STROBE; - static int dma_hold = ATA_DMA2_HOLD; - - if (type == TYPE_PIO) { - pio_setup = setup; - pio_strobe = strobe; - pio_hold = hold; - } else if (type == TYPE_DMA) { - dma_strobe = strobe; - dma_hold = hold; - } - *R_ATA_CONFIG = ( IO_FIELD( R_ATA_CONFIG, enable, 1 ) | - IO_FIELD( R_ATA_CONFIG, dma_strobe, dma_strobe ) | - IO_FIELD( R_ATA_CONFIG, dma_hold, dma_hold ) | - IO_FIELD( R_ATA_CONFIG, pio_setup, pio_setup ) | - IO_FIELD( R_ATA_CONFIG, pio_strobe, pio_strobe ) | - IO_FIELD( R_ATA_CONFIG, pio_hold, pio_hold ) ); -} - -static unsigned long -cris_ide_base_address(int bus) -{ - return IO_FIELD(R_ATA_CTRL_DATA, sel, bus); -} - -static unsigned long -cris_ide_reg_addr(unsigned long addr, int cs0, int cs1) -{ - return IO_FIELD(R_ATA_CTRL_DATA, addr, addr) | - IO_FIELD(R_ATA_CTRL_DATA, cs0, cs0) | - IO_FIELD(R_ATA_CTRL_DATA, cs1, cs1); -} - -static __init void -cris_ide_reset(unsigned val) -{ -#ifdef CONFIG_ETRAX_IDE_G27_RESET - REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow, 27, val); -#endif -#ifdef CONFIG_ETRAX_IDE_CSE1_16_RESET - REG_SHADOW_SET(port_cse1_addr, port_cse1_shadow, 16, val); -#endif -#ifdef CONFIG_ETRAX_IDE_CSP0_8_RESET - REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, 8, val); -#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, val); -#endif -} - -static __init void -cris_ide_init(void) -{ - volatile unsigned int dummy; - - *R_ATA_CTRL_DATA = 0; - *R_ATA_TRANSFER_CNT = 0; - *R_ATA_CONFIG = 0; - - if (cris_request_io_interface(if_ata, "ETRAX100LX IDE")) { - printk(KERN_CRIT "ide: Failed to get IO interface\n"); - return; - } else if (cris_request_dma(ATA_TX_DMA_NBR, - "ETRAX100LX IDE TX", - DMA_VERBOSE_ON_ERROR, - dma_ata)) { - cris_free_io_interface(if_ata); - printk(KERN_CRIT "ide: Failed to get Tx DMA channel\n"); - return; - } else if (cris_request_dma(ATA_RX_DMA_NBR, - "ETRAX100LX IDE RX", - DMA_VERBOSE_ON_ERROR, - dma_ata)) { - cris_free_dma(ATA_TX_DMA_NBR, "ETRAX100LX IDE Tx"); - cris_free_io_interface(if_ata); - printk(KERN_CRIT "ide: Failed to get Rx DMA channel\n"); - return; - } - - /* 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 )); - *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 ) ); - - /* 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); -} - -#define cris_dma_descr_type etrax_dma_descr -#define cris_pio_read IO_STATE(R_ATA_CTRL_DATA, rw, read) -#define cris_ultra_mask 0x0 -#define MAX_DESCR_SIZE 0x10000UL - -static unsigned long -cris_ide_get_reg(unsigned long reg) -{ - return (reg & 0x0e000000) >> 25; -} - -static void -cris_ide_fill_descriptor(cris_dma_descr_type *d, void* buf, unsigned int len, int last) -{ - d->buf = virt_to_phys(buf); - d->sw_len = len == MAX_DESCR_SIZE ? 0 : len; - if (last) - d->ctrl |= d_eol; -} - -static void cris_ide_start_dma(ide_drive_t *drive, cris_dma_descr_type *d, int dir, int type, int len) -{ - unsigned long cmd; - - if (dir) { - /* 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(d); - *R_DMA_CH3_CMD = IO_STATE(R_DMA_CH3_CMD, cmd, start); - - } else { - *R_DMA_CH2_FIRST = virt_to_phys(d); - *R_DMA_CH2_CMD = IO_STATE(R_DMA_CH2_CMD, cmd, start); - } - - /* initiate a multi word dma read using DMA handshaking */ - - *R_ATA_TRANSFER_CNT = - IO_FIELD(R_ATA_TRANSFER_CNT, count, len >> 1); - - cmd = dir ? IO_STATE(R_ATA_CTRL_DATA, rw, read) : IO_STATE(R_ATA_CTRL_DATA, rw, write); - cmd |= type == TYPE_PIO ? IO_STATE(R_ATA_CTRL_DATA, handsh, pio) : - IO_STATE(R_ATA_CTRL_DATA, handsh, dma); - *R_ATA_CTRL_DATA = - cmd | - IO_FIELD(R_ATA_CTRL_DATA, data, IDE_DATA_REG) | - IO_STATE(R_ATA_CTRL_DATA, src_dst, dma) | - IO_STATE(R_ATA_CTRL_DATA, multi, on) | - IO_STATE(R_ATA_CTRL_DATA, dma_size, word); -} - -static void -cris_ide_wait_dma(int dir) -{ - if (dir) - WAIT_DMA(ATA_RX_DMA_NBR); - else - WAIT_DMA(ATA_TX_DMA_NBR); -} - -static int cris_dma_test_irq(ide_drive_t *drive) -{ - int intr = *R_IRQ_MASK0_RD; - int bus = IO_EXTRACT(R_ATA_CTRL_DATA, sel, IDE_DATA_REG); - return intr & (1 << (bus + IO_BITNR(R_IRQ_MASK0_RD, ata_irq0))) ? 1 : 0; -} - - -static void cris_ide_initialize_dma(int dir) -{ - if (dir) - { - RESET_DMA(ATA_RX_DMA_NBR); /* sometimes the DMA channel get stuck so we need to do this */ - WAIT_DMA(ATA_RX_DMA_NBR); - } - else - { - RESET_DMA(ATA_TX_DMA_NBR); /* sometimes the DMA channel get stuck so we need to do this */ - WAIT_DMA(ATA_TX_DMA_NBR); - } -} - -#endif - -void -cris_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 */ - do { - timeleft--; - } while(timeleft && cris_ide_busy()); - - /* - * 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); - - cris_ide_write_command(reg|data); /* write data to the drive's register */ - - timeleft = IDE_REGISTER_TIMEOUT; - /* wait for transmitter ready */ - do { - timeleft--; - } while(timeleft && !cris_ide_ready()); -} - -void -cris_ide_outb(unsigned char data, unsigned long reg) -{ - cris_ide_outw(data, reg); -} - -void -cris_ide_outbsync(ide_drive_t *drive, u8 addr, unsigned long port) -{ - cris_ide_outw(addr, port); -} - -unsigned short -cris_ide_inw(unsigned long reg) { - int timeleft; - unsigned short val; - - timeleft = IDE_REGISTER_TIMEOUT; - /* wait for busy flag */ - do { - timeleft--; - } while(timeleft && cris_ide_busy()); - - 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 (cris_ide_get_reg(reg) == IDE_STATUS_OFFSET) - return BUSY_STAT; - else - /* For other rare cases we assume 0 is good enough. */ - return 0; - } - - cris_ide_write_command(reg | cris_pio_read); - - timeleft = IDE_REGISTER_TIMEOUT; - /* wait for available */ - do { - timeleft--; - } while(timeleft && !cris_ide_data_available(&val)); - - if(!timeleft) - return 0; - - LOWDB(printk("inb: 0x%x from reg 0x%x\n", val & 0xff, reg)); - - return val; -} - -unsigned char -cris_ide_inb(unsigned long reg) -{ - return (unsigned char)cris_ide_inw(reg); -} - -static int cris_dma_check (ide_drive_t *drive); -static int cris_dma_end (ide_drive_t *drive); -static int cris_dma_setup (ide_drive_t *drive); -static void cris_dma_exec_cmd (ide_drive_t *drive, u8 command); -static int cris_dma_test_irq(ide_drive_t *drive); -static void cris_dma_start(ide_drive_t *drive); -static void cris_ide_input_data (ide_drive_t *drive, void *, unsigned int); -static void cris_ide_output_data (ide_drive_t *drive, void *, unsigned int); -static void cris_atapi_input_bytes(ide_drive_t *drive, void *, unsigned int); -static void cris_atapi_output_bytes(ide_drive_t *drive, void *, unsigned int); -static int cris_dma_off (ide_drive_t *drive); -static int cris_dma_on (ide_drive_t *drive); - -static void tune_cris_ide(ide_drive_t *drive, u8 pio) -{ - int setup, strobe, hold; - - switch(pio) - { - case 0: - setup = ATA_PIO0_SETUP; - strobe = ATA_PIO0_STROBE; - hold = ATA_PIO0_HOLD; - break; - case 1: - setup = ATA_PIO1_SETUP; - strobe = ATA_PIO1_STROBE; - hold = ATA_PIO1_HOLD; - break; - case 2: - setup = ATA_PIO2_SETUP; - strobe = ATA_PIO2_STROBE; - hold = ATA_PIO2_HOLD; - break; - case 3: - setup = ATA_PIO3_SETUP; - strobe = ATA_PIO3_STROBE; - hold = ATA_PIO3_HOLD; - break; - case 4: - setup = ATA_PIO4_SETUP; - strobe = ATA_PIO4_STROBE; - hold = ATA_PIO4_HOLD; - break; - default: - return; - } - - cris_ide_set_speed(TYPE_PIO, setup, strobe, hold); -} - -static int speed_cris_ide(ide_drive_t *drive, u8 speed) -{ - int cyc = 0, dvs = 0, strobe = 0, hold = 0; - - if (speed >= XFER_PIO_0 && speed <= XFER_PIO_4) { - tune_cris_ide(drive, speed - XFER_PIO_0); - return 0; - } - - switch(speed) - { - case XFER_UDMA_0: - cyc = ATA_UDMA0_CYC; - dvs = ATA_UDMA0_DVS; - break; - case XFER_UDMA_1: - cyc = ATA_UDMA1_CYC; - dvs = ATA_UDMA1_DVS; - break; - case XFER_UDMA_2: - cyc = ATA_UDMA2_CYC; - dvs = ATA_UDMA2_DVS; - break; - case XFER_MW_DMA_0: - strobe = ATA_DMA0_STROBE; - hold = ATA_DMA0_HOLD; - break; - case XFER_MW_DMA_1: - strobe = ATA_DMA1_STROBE; - hold = ATA_DMA1_HOLD; - break; - case XFER_MW_DMA_2: - strobe = ATA_DMA2_STROBE; - hold = ATA_DMA2_HOLD; - break; - default: - return 0; - } - - if (speed >= XFER_UDMA_0) - cris_ide_set_speed(TYPE_UDMA, cyc, dvs, 0); - else - cris_ide_set_speed(TYPE_DMA, 0, strobe, hold); - - return 0; -} - -void __init -init_e100_ide (void) -{ - hw_regs_t hw; - int ide_offsets[IDE_NR_PORTS]; - int h; - int i; - - printk("ide: ETRAX FS built-in ATA DMA controller\n"); - - for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) - ide_offsets[i] = cris_ide_reg_addr(i, 0, 1); - - /* the IDE control register is at ATA address 6, with CS1 active instead of CS0 */ - ide_offsets[IDE_CONTROL_OFFSET] = cris_ide_reg_addr(6, 1, 0); - - /* first fill in some stuff in the ide_hwifs fields */ - - for(h = 0; h < MAX_HWIFS; h++) { - ide_hwif_t *hwif = &ide_hwifs[h]; - ide_setup_ports(&hw, cris_ide_base_address(h), - ide_offsets, - 0, 0, cris_ide_ack_intr, - ide_default_irq(0)); - ide_register_hw(&hw, &hwif); - hwif->mmio = 2; - hwif->chipset = ide_etrax100; - hwif->tuneproc = &tune_cris_ide; - hwif->speedproc = &speed_cris_ide; - hwif->ata_input_data = &cris_ide_input_data; - hwif->ata_output_data = &cris_ide_output_data; - hwif->atapi_input_bytes = &cris_atapi_input_bytes; - hwif->atapi_output_bytes = &cris_atapi_output_bytes; - hwif->ide_dma_check = &cris_dma_check; - hwif->ide_dma_end = &cris_dma_end; - hwif->dma_setup = &cris_dma_setup; - hwif->dma_exec_cmd = &cris_dma_exec_cmd; - hwif->ide_dma_test_irq = &cris_dma_test_irq; - hwif->dma_start = &cris_dma_start; - hwif->OUTB = &cris_ide_outb; - hwif->OUTW = &cris_ide_outw; - hwif->OUTBSYNC = &cris_ide_outbsync; - hwif->INB = &cris_ide_inb; - hwif->INW = &cris_ide_inw; - hwif->ide_dma_host_off = &cris_dma_off; - hwif->ide_dma_host_on = &cris_dma_on; - hwif->ide_dma_off_quietly = &cris_dma_off; - hwif->udma_four = 0; - hwif->ultra_mask = cris_ultra_mask; - hwif->mwdma_mask = 0x07; /* Multiword DMA 0-2 */ - hwif->swdma_mask = 0x07; /* Singleword DMA 0-2 */ - } - - /* Reset pulse */ - cris_ide_reset(0); - udelay(25); - cris_ide_reset(1); - - cris_ide_init(); - - cris_ide_set_speed(TYPE_PIO, ATA_PIO4_SETUP, ATA_PIO4_STROBE, ATA_PIO4_HOLD); - cris_ide_set_speed(TYPE_DMA, 0, ATA_DMA2_STROBE, ATA_DMA2_HOLD); - cris_ide_set_speed(TYPE_UDMA, ATA_UDMA2_CYC, ATA_UDMA2_DVS, 0); -} - -static int cris_dma_off (ide_drive_t *drive) -{ - return 0; -} - -static int cris_dma_on (ide_drive_t *drive) -{ - return 0; -} - - -static cris_dma_descr_type mydescr __attribute__ ((__aligned__(16))); - -/* - * 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 -cris_atapi_input_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount) -{ - D(printk("atapi_input_bytes, buffer 0x%x, count %d\n", - buffer, bytecount)); - - if(bytecount & 1) { - printk("warning, odd bytecount in cdrom_in_bytes = %d.\n", bytecount); - bytecount++; /* to round off */ - } - - /* setup DMA and start transfer */ - - cris_ide_fill_descriptor(&mydescr, buffer, bytecount, 1); - cris_ide_start_dma(drive, &mydescr, 1, TYPE_PIO, bytecount); - - /* wait for completion */ - LED_DISK_READ(1); - cris_ide_wait_dma(1); - LED_DISK_READ(0); -} - -static void -cris_atapi_output_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount) -{ - D(printk("atapi_output_bytes, buffer 0x%x, count %d\n", - buffer, bytecount)); - - if(bytecount & 1) { - printk("odd bytecount %d in atapi_out_bytes!\n", bytecount); - bytecount++; - } - - cris_ide_fill_descriptor(&mydescr, buffer, bytecount, 1); - cris_ide_start_dma(drive, &mydescr, 0, TYPE_PIO, bytecount); - - /* wait for completion */ - - LED_DISK_WRITE(1); - LED_DISK_READ(1); - cris_ide_wait_dma(0); - LED_DISK_WRITE(0); -} - -/* - * This is used for most PIO data transfers *from* the IDE interface - */ -static void -cris_ide_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount) -{ - cris_atapi_input_bytes(drive, buffer, wcount << 2); -} - -/* - * This is used for most PIO data transfers *to* the IDE interface - */ -static void -cris_ide_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount) -{ - cris_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 cris_dma_descr_type ata_descrs[MAX_DMA_DESCRS] __attribute__ ((__aligned__(16))); -static unsigned int ata_tot_size; - -/* - * cris_ide_build_dmatable() prepares a dma request. - * Returns 0 if all went okay, returns 1 otherwise. - */ -static int cris_ide_build_dmatable (ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - struct scatterlist* sg; - struct request *rq = drive->hwif->hwgroup->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 - rw_trf_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 rw_trf_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 > MAX_DESCR_SIZE it has to be splitted into new descriptors. Since we - don't handle size > 131072 only one split is necessary */ - - if(size > MAX_DESCR_SIZE) { - cris_ide_fill_descriptor(&ata_descrs[count], (void*)addr, MAX_DESCR_SIZE, 0); - count++; - ata_tot_size += MAX_DESCR_SIZE; - size -= MAX_DESCR_SIZE; - addr += MAX_DESCR_SIZE; - } - - cris_ide_fill_descriptor(&ata_descrs[count], (void*)addr, size,i ? 0 : 1); - count++; - ata_tot_size += size; - } - - if (count) { - /* 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 cris_config_drive_for_dma (ide_drive_t *drive) -{ - u8 speed = ide_dma_speed(drive, 1); - - if (!speed) - return 0; - - speed_cris_ide(drive, speed); - ide_config_drive_speed(drive, speed); - - return ide_dma_enable(drive); -} - -/* - * cris_dma_intr() is the handler for disk read/write DMA interrupts - */ -static ide_startstop_t cris_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. - * - * For ATAPI devices, we just prepare for DMA and return. The caller should - * then issue the packet command to the drive and call us again with - * cris_dma_start afterwards. - * - * 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 cris_dma_check(ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - struct hd_driveid* id = drive->id; - - if (id && (id->capability & 1)) { - if (ide_use_dma(drive)) { - if (cris_config_drive_for_dma(drive)) - return hwif->ide_dma_on(drive); - } - } - - return hwif->ide_dma_off_quietly(drive); -} - -static int cris_dma_end(ide_drive_t *drive) -{ - drive->waiting_for_dma = 0; - return 0; -} - -static int cris_dma_setup(ide_drive_t *drive) -{ - struct request *rq = drive->hwif->hwgroup->rq; - - cris_ide_initialize_dma(!rq_data_dir(rq)); - if (cris_ide_build_dmatable (drive)) { - ide_map_sg(drive, rq); - return 1; - } - - drive->waiting_for_dma = 1; - return 0; -} - -static void cris_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, &cris_dma_intr, WAIT_CMD, NULL); - - /* issue cmd to drive */ - cris_ide_outb(command, IDE_COMMAND_REG); -} - -static void cris_dma_start(ide_drive_t *drive) -{ - struct request *rq = drive->hwif->hwgroup->rq; - int writing = rq_data_dir(rq); - int type = TYPE_DMA; - - if (drive->current_speed >= XFER_UDMA_0) - type = TYPE_UDMA; - - cris_ide_start_dma(drive, &ata_descrs[0], writing ? 0 : 1, type, ata_tot_size); - - if (writing) { - LED_DISK_WRITE(1); - } else { - LED_DISK_READ(1); - } -} diff --git a/drivers/ide/cs5520.c b/drivers/ide/cs5520.c new file mode 100644 index 00000000000..6250aee3050 --- /dev/null +++ b/drivers/ide/cs5520.c @@ -0,0 +1,168 @@ +/* + * IDE tuning and bus mastering support for the CS5510/CS5520 + * chipsets + * + * The CS5510/CS5520 are slightly unusual devices. Unlike the + * typical IDE controllers they do bus mastering with the drive in + * PIO mode and smarter silicon. + * + * The practical upshot of this is that we must always tune the + * drive for the right PIO mode. We must also ignore all the blacklists + * and the drive bus mastering DMA information. + * + * *** This driver is strictly experimental *** + * + * (c) Copyright Red Hat Inc 2002 + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * For the avoidance of doubt the "preferred form" of this code is one which + * is in an open non patent encumbered format. Where cryptographic key signing + * forms part of the process of creating an executable the information + * including keys needed to generate an equivalently functional executable + * are deemed to be part of the source code. + * + */ + +#include <linux/module.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/ide.h> +#include <linux/dma-mapping.h> + +#define DRV_NAME "cs5520" + +struct pio_clocks +{ + int address; + int assert; + int recovery; +}; + +static struct pio_clocks cs5520_pio_clocks[]={ + {3, 6, 11}, + {2, 5, 6}, + {1, 4, 3}, + {1, 3, 2}, + {1, 2, 1} +}; + +static void cs5520_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) +{ + struct pci_dev *pdev = to_pci_dev(hwif->dev); + int controller = drive->dn > 1 ? 1 : 0; + const u8 pio = drive->pio_mode - XFER_PIO_0; + + /* 8bit CAT/CRT - 8bit command timing for channel */ + pci_write_config_byte(pdev, 0x62 + controller, + (cs5520_pio_clocks[pio].recovery << 4) | + (cs5520_pio_clocks[pio].assert)); + + /* 0x64 - 16bit Primary, 0x68 - 16bit Secondary */ + + /* FIXME: should these use address ? */ + /* Data read timing */ + pci_write_config_byte(pdev, 0x64 + 4*controller + (drive->dn&1), + (cs5520_pio_clocks[pio].recovery << 4) | + (cs5520_pio_clocks[pio].assert)); + /* Write command timing */ + pci_write_config_byte(pdev, 0x66 + 4*controller + (drive->dn&1), + (cs5520_pio_clocks[pio].recovery << 4) | + (cs5520_pio_clocks[pio].assert)); +} + +static void cs5520_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive) +{ + printk(KERN_ERR "cs55x0: bad ide timing.\n"); + + drive->pio_mode = XFER_PIO_0 + 0; + cs5520_set_pio_mode(hwif, drive); +} + +static const struct ide_port_ops cs5520_port_ops = { + .set_pio_mode = cs5520_set_pio_mode, + .set_dma_mode = cs5520_set_dma_mode, +}; + +static const struct ide_port_info cyrix_chipset = { + .name = DRV_NAME, + .enablebits = { { 0x60, 0x01, 0x01 }, { 0x60, 0x02, 0x02 } }, + .port_ops = &cs5520_port_ops, + .host_flags = IDE_HFLAG_ISA_PORTS | IDE_HFLAG_CS5520, + .pio_mask = ATA_PIO4, +}; + +/* + * The 5510/5520 are a bit weird. They don't quite set up the way + * the PCI helper layer expects so we must do much of the set up + * work longhand. + */ + +static int cs5520_init_one(struct pci_dev *dev, const struct pci_device_id *id) +{ + const struct ide_port_info *d = &cyrix_chipset; + struct ide_hw hw[2], *hws[] = { NULL, NULL }; + + ide_setup_pci_noise(dev, d); + + /* We must not grab the entire device, it has 'ISA' space in its + * BARS too and we will freak out other bits of the kernel + */ + if (pci_enable_device_io(dev)) { + printk(KERN_WARNING "%s: Unable to enable 55x0.\n", d->name); + return -ENODEV; + } + pci_set_master(dev); + if (pci_set_dma_mask(dev, DMA_BIT_MASK(32))) { + printk(KERN_WARNING "%s: No suitable DMA available.\n", + d->name); + return -ENODEV; + } + + /* + * Now the chipset is configured we can let the core + * do all the device setup for us + */ + + ide_pci_setup_ports(dev, d, &hw[0], &hws[0]); + hw[0].irq = 14; + hw[1].irq = 15; + + return ide_host_add(d, hws, 2, NULL); +} + +static const struct pci_device_id cs5520_pci_tbl[] = { + { PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5510), 0 }, + { PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5520), 1 }, + { 0, }, +}; +MODULE_DEVICE_TABLE(pci, cs5520_pci_tbl); + +static struct pci_driver cs5520_pci_driver = { + .name = "Cyrix_IDE", + .id_table = cs5520_pci_tbl, + .probe = cs5520_init_one, + .suspend = ide_pci_suspend, + .resume = ide_pci_resume, +}; + +static int __init cs5520_ide_init(void) +{ + return ide_pci_register_driver(&cs5520_pci_driver); +} + +module_init(cs5520_ide_init); + +MODULE_AUTHOR("Alan Cox"); +MODULE_DESCRIPTION("PCI driver module for Cyrix 5510/5520 IDE"); +MODULE_LICENSE("GPL"); diff --git a/drivers/ide/cs5530.c b/drivers/ide/cs5530.c new file mode 100644 index 00000000000..65371599b97 --- /dev/null +++ b/drivers/ide/cs5530.c @@ -0,0 +1,295 @@ +/* + * Copyright (C) 2000 Andre Hedrick <andre@linux-ide.org> + * Copyright (C) 2000 Mark Lord <mlord@pobox.com> + * Copyright (C) 2007 Bartlomiej Zolnierkiewicz + * + * May be copied or modified under the terms of the GNU General Public License + * + * Development of this chipset driver was funded + * by the nice folks at National Semiconductor. + * + * Documentation: + * CS5530 documentation available from National Semiconductor. + */ + +#include <linux/module.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/pci.h> +#include <linux/init.h> +#include <linux/ide.h> + +#include <asm/io.h> + +#define DRV_NAME "cs5530" + +/* + * Here are the standard PIO mode 0-4 timings for each "format". + * Format-0 uses fast data reg timings, with slower command reg timings. + * Format-1 uses fast timings for all registers, but won't work with all drives. + */ +static unsigned int cs5530_pio_timings[2][5] = { + {0x00009172, 0x00012171, 0x00020080, 0x00032010, 0x00040010}, + {0xd1329172, 0x71212171, 0x30200080, 0x20102010, 0x00100010} +}; + +/* + * After chip reset, the PIO timings are set to 0x0000e132, which is not valid. + */ +#define CS5530_BAD_PIO(timings) (((timings)&~0x80000000)==0x0000e132) +#define CS5530_BASEREG(hwif) (((hwif)->dma_base & ~0xf) + ((hwif)->channel ? 0x30 : 0x20)) + +/** + * cs5530_set_pio_mode - set host controller for PIO mode + * @hwif: port + * @drive: drive + * + * Handles setting of PIO mode for the chipset. + * + * The init_hwif_cs5530() routine guarantees that all drives + * will have valid default PIO timings set up before we get here. + */ + +static void cs5530_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) +{ + unsigned long basereg = CS5530_BASEREG(hwif); + unsigned int format = (inl(basereg + 4) >> 31) & 1; + const u8 pio = drive->pio_mode - XFER_PIO_0; + + outl(cs5530_pio_timings[format][pio], basereg + ((drive->dn & 1)<<3)); +} + +/** + * cs5530_udma_filter - UDMA filter + * @drive: drive + * + * cs5530_udma_filter() does UDMA mask filtering for the given drive + * taking into the consideration capabilities of the mate device. + * + * The CS5530 specifies that two drives sharing a cable cannot mix + * UDMA/MDMA. It has to be one or the other, for the pair, though + * different timings can still be chosen for each drive. We could + * set the appropriate timing bits on the fly, but that might be + * a bit confusing. So, for now we statically handle this requirement + * by looking at our mate drive to see what it is capable of, before + * choosing a mode for our own drive. + * + * Note: This relies on the fact we never fail from UDMA to MWDMA2 + * but instead drop to PIO. + */ + +static u8 cs5530_udma_filter(ide_drive_t *drive) +{ + ide_hwif_t *hwif = drive->hwif; + ide_drive_t *mate = ide_get_pair_dev(drive); + u16 *mateid; + u8 mask = hwif->ultra_mask; + + if (mate == NULL) + goto out; + mateid = mate->id; + + if (ata_id_has_dma(mateid) && __ide_dma_bad_drive(mate) == 0) { + if ((mateid[ATA_ID_FIELD_VALID] & 4) && + (mateid[ATA_ID_UDMA_MODES] & 7)) + goto out; + if (mateid[ATA_ID_MWDMA_MODES] & 7) + mask = 0; + } +out: + return mask; +} + +static void cs5530_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive) +{ + unsigned long basereg; + unsigned int reg, timings = 0; + + switch (drive->dma_mode) { + case XFER_UDMA_0: timings = 0x00921250; break; + case XFER_UDMA_1: timings = 0x00911140; break; + case XFER_UDMA_2: timings = 0x00911030; break; + case XFER_MW_DMA_0: timings = 0x00077771; break; + case XFER_MW_DMA_1: timings = 0x00012121; break; + case XFER_MW_DMA_2: timings = 0x00002020; break; + } + basereg = CS5530_BASEREG(hwif); + reg = inl(basereg + 4); /* get drive0 config register */ + timings |= reg & 0x80000000; /* preserve PIO format bit */ + if ((drive-> dn & 1) == 0) { /* are we configuring drive0? */ + outl(timings, basereg + 4); /* write drive0 config register */ + } else { + if (timings & 0x00100000) + reg |= 0x00100000; /* enable UDMA timings for both drives */ + else + reg &= ~0x00100000; /* disable UDMA timings for both drives */ + outl(reg, basereg + 4); /* write drive0 config register */ + outl(timings, basereg + 12); /* write drive1 config register */ + } +} + +/** + * init_chipset_5530 - set up 5530 bridge + * @dev: PCI device + * + * Initialize the cs5530 bridge for reliable IDE DMA operation. + */ + +static int init_chipset_cs5530(struct pci_dev *dev) +{ + struct pci_dev *master_0 = NULL, *cs5530_0 = NULL; + + if (pci_resource_start(dev, 4) == 0) + return -EFAULT; + + dev = NULL; + while ((dev = pci_get_device(PCI_VENDOR_ID_CYRIX, PCI_ANY_ID, dev)) != NULL) { + switch (dev->device) { + case PCI_DEVICE_ID_CYRIX_PCI_MASTER: + master_0 = pci_dev_get(dev); + break; + case PCI_DEVICE_ID_CYRIX_5530_LEGACY: + cs5530_0 = pci_dev_get(dev); + break; + } + } + if (!master_0) { + printk(KERN_ERR DRV_NAME ": unable to locate PCI MASTER function\n"); + goto out; + } + if (!cs5530_0) { + printk(KERN_ERR DRV_NAME ": unable to locate CS5530 LEGACY function\n"); + goto out; + } + + /* + * Enable BusMaster and MemoryWriteAndInvalidate for the cs5530: + * --> OR 0x14 into 16-bit PCI COMMAND reg of function 0 of the cs5530 + */ + + pci_set_master(cs5530_0); + pci_try_set_mwi(cs5530_0); + + /* + * Set PCI CacheLineSize to 16-bytes: + * --> Write 0x04 into 8-bit PCI CACHELINESIZE reg of function 0 of the cs5530 + */ + + pci_write_config_byte(cs5530_0, PCI_CACHE_LINE_SIZE, 0x04); + + /* + * Disable trapping of UDMA register accesses (Win98 hack): + * --> Write 0x5006 into 16-bit reg at offset 0xd0 of function 0 of the cs5530 + */ + + pci_write_config_word(cs5530_0, 0xd0, 0x5006); + + /* + * Bit-1 at 0x40 enables MemoryWriteAndInvalidate on internal X-bus: + * The other settings are what is necessary to get the register + * into a sane state for IDE DMA operation. + */ + + pci_write_config_byte(master_0, 0x40, 0x1e); + + /* + * Set max PCI burst size (16-bytes seems to work best): + * 16bytes: set bit-1 at 0x41 (reg value of 0x16) + * all others: clear bit-1 at 0x41, and do: + * 128bytes: OR 0x00 at 0x41 + * 256bytes: OR 0x04 at 0x41 + * 512bytes: OR 0x08 at 0x41 + * 1024bytes: OR 0x0c at 0x41 + */ + + pci_write_config_byte(master_0, 0x41, 0x14); + + /* + * These settings are necessary to get the chip + * into a sane state for IDE DMA operation. + */ + + pci_write_config_byte(master_0, 0x42, 0x00); + pci_write_config_byte(master_0, 0x43, 0xc1); + +out: + pci_dev_put(master_0); + pci_dev_put(cs5530_0); + return 0; +} + +/** + * init_hwif_cs5530 - initialise an IDE channel + * @hwif: IDE to initialize + * + * This gets invoked by the IDE driver once for each channel. It + * performs channel-specific pre-initialization before drive probing. + */ + +static void init_hwif_cs5530 (ide_hwif_t *hwif) +{ + unsigned long basereg; + u32 d0_timings; + + basereg = CS5530_BASEREG(hwif); + d0_timings = inl(basereg + 0); + if (CS5530_BAD_PIO(d0_timings)) + outl(cs5530_pio_timings[(d0_timings >> 31) & 1][0], basereg + 0); + if (CS5530_BAD_PIO(inl(basereg + 8))) + outl(cs5530_pio_timings[(d0_timings >> 31) & 1][0], basereg + 8); +} + +static const struct ide_port_ops cs5530_port_ops = { + .set_pio_mode = cs5530_set_pio_mode, + .set_dma_mode = cs5530_set_dma_mode, + .udma_filter = cs5530_udma_filter, +}; + +static const struct ide_port_info cs5530_chipset = { + .name = DRV_NAME, + .init_chipset = init_chipset_cs5530, + .init_hwif = init_hwif_cs5530, + .port_ops = &cs5530_port_ops, + .host_flags = IDE_HFLAG_SERIALIZE | + IDE_HFLAG_POST_SET_MODE, + .pio_mask = ATA_PIO4, + .mwdma_mask = ATA_MWDMA2, + .udma_mask = ATA_UDMA2, +}; + +static int cs5530_init_one(struct pci_dev *dev, const struct pci_device_id *id) +{ + return ide_pci_init_one(dev, &cs5530_chipset, NULL); +} + +static const struct pci_device_id cs5530_pci_tbl[] = { + { PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5530_IDE), 0 }, + { 0, }, +}; +MODULE_DEVICE_TABLE(pci, cs5530_pci_tbl); + +static struct pci_driver cs5530_pci_driver = { + .name = "CS5530 IDE", + .id_table = cs5530_pci_tbl, + .probe = cs5530_init_one, + .remove = ide_pci_remove, + .suspend = ide_pci_suspend, + .resume = ide_pci_resume, +}; + +static int __init cs5530_ide_init(void) +{ + return ide_pci_register_driver(&cs5530_pci_driver); +} + +static void __exit cs5530_ide_exit(void) +{ + pci_unregister_driver(&cs5530_pci_driver); +} + +module_init(cs5530_ide_init); +module_exit(cs5530_ide_exit); + +MODULE_AUTHOR("Mark Lord"); +MODULE_DESCRIPTION("PCI driver module for Cyrix/NS 5530 IDE"); +MODULE_LICENSE("GPL"); diff --git a/drivers/ide/cs5535.c b/drivers/ide/cs5535.c new file mode 100644 index 00000000000..3bc5b9a3401 --- /dev/null +++ b/drivers/ide/cs5535.c @@ -0,0 +1,219 @@ +/* + * Copyright (C) 2004-2005 Advanced Micro Devices, Inc. + * Copyright (C) 2007 Bartlomiej Zolnierkiewicz + * + * History: + * 09/20/2005 - Jaya Kumar <jayakumar.ide@gmail.com> + * - Reworked tuneproc, set_drive, misc mods to prep for mainline + * - Work was sponsored by CIS (M) Sdn Bhd. + * Ported to Kernel 2.6.11 on June 26, 2005 by + * Wolfgang Zuleger <wolfgang.zuleger@gmx.de> + * Alexander Kiausch <alex.kiausch@t-online.de> + * Originally developed by AMD for 2.4/2.6 + * + * Development of this chipset driver was funded + * by the nice folks at National Semiconductor/AMD. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * Documentation: + * CS5535 documentation available from AMD + */ + +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/ide.h> + +#define DRV_NAME "cs5535" + +#define MSR_ATAC_BASE 0x51300000 +#define ATAC_GLD_MSR_CAP (MSR_ATAC_BASE+0) +#define ATAC_GLD_MSR_CONFIG (MSR_ATAC_BASE+0x01) +#define ATAC_GLD_MSR_SMI (MSR_ATAC_BASE+0x02) +#define ATAC_GLD_MSR_ERROR (MSR_ATAC_BASE+0x03) +#define ATAC_GLD_MSR_PM (MSR_ATAC_BASE+0x04) +#define ATAC_GLD_MSR_DIAG (MSR_ATAC_BASE+0x05) +#define ATAC_IO_BAR (MSR_ATAC_BASE+0x08) +#define ATAC_RESET (MSR_ATAC_BASE+0x10) +#define ATAC_CH0D0_PIO (MSR_ATAC_BASE+0x20) +#define ATAC_CH0D0_DMA (MSR_ATAC_BASE+0x21) +#define ATAC_CH0D1_PIO (MSR_ATAC_BASE+0x22) +#define ATAC_CH0D1_DMA (MSR_ATAC_BASE+0x23) +#define ATAC_PCI_ABRTERR (MSR_ATAC_BASE+0x24) +#define ATAC_BM0_CMD_PRIM 0x00 +#define ATAC_BM0_STS_PRIM 0x02 +#define ATAC_BM0_PRD 0x04 +#define CS5535_CABLE_DETECT 0x48 + +/* Format I PIO settings. We separate out cmd and data for safer timings */ + +static unsigned int cs5535_pio_cmd_timings[5] = +{ 0xF7F4, 0x53F3, 0x13F1, 0x5131, 0x1131 }; +static unsigned int cs5535_pio_dta_timings[5] = +{ 0xF7F4, 0xF173, 0x8141, 0x5131, 0x1131 }; + +static unsigned int cs5535_mwdma_timings[3] = +{ 0x7F0FFFF3, 0x7F035352, 0x7f024241 }; + +static unsigned int cs5535_udma_timings[5] = +{ 0x7F7436A1, 0x7F733481, 0x7F723261, 0x7F713161, 0x7F703061 }; + +/* Macros to check if the register is the reset value - reset value is an + invalid timing and indicates the register has not been set previously */ + +#define CS5535_BAD_PIO(timings) ( (timings&~0x80000000UL) == 0x00009172 ) +#define CS5535_BAD_DMA(timings) ( (timings & 0x000FFFFF) == 0x00077771 ) + +/**** + * cs5535_set_speed - Configure the chipset to the new speed + * @drive: Drive to set up + * @speed: desired speed + * + * cs5535_set_speed() configures the chipset to a new speed. + */ +static void cs5535_set_speed(ide_drive_t *drive, const u8 speed) +{ + u32 reg = 0, dummy; + u8 unit = drive->dn & 1; + + /* Set the PIO timings */ + if (speed < XFER_SW_DMA_0) { + ide_drive_t *pair = ide_get_pair_dev(drive); + u8 cmd, pioa; + + cmd = pioa = speed - XFER_PIO_0; + + if (pair) { + u8 piob = pair->pio_mode - XFER_PIO_0; + + if (piob < cmd) + cmd = piob; + } + + /* Write the speed of the current drive */ + reg = (cs5535_pio_cmd_timings[cmd] << 16) | + cs5535_pio_dta_timings[pioa]; + wrmsr(unit ? ATAC_CH0D1_PIO : ATAC_CH0D0_PIO, reg, 0); + + /* And if nessesary - change the speed of the other drive */ + rdmsr(unit ? ATAC_CH0D0_PIO : ATAC_CH0D1_PIO, reg, dummy); + + if (((reg >> 16) & cs5535_pio_cmd_timings[cmd]) != + cs5535_pio_cmd_timings[cmd]) { + reg &= 0x0000FFFF; + reg |= cs5535_pio_cmd_timings[cmd] << 16; + wrmsr(unit ? ATAC_CH0D0_PIO : ATAC_CH0D1_PIO, reg, 0); + } + + /* Set bit 31 of the DMA register for PIO format 1 timings */ + rdmsr(unit ? ATAC_CH0D1_DMA : ATAC_CH0D0_DMA, reg, dummy); + wrmsr(unit ? ATAC_CH0D1_DMA : ATAC_CH0D0_DMA, + reg | 0x80000000UL, 0); + } else { + rdmsr(unit ? ATAC_CH0D1_DMA : ATAC_CH0D0_DMA, reg, dummy); + + reg &= 0x80000000UL; /* Preserve the PIO format bit */ + + if (speed >= XFER_UDMA_0 && speed <= XFER_UDMA_4) + reg |= cs5535_udma_timings[speed - XFER_UDMA_0]; + else if (speed >= XFER_MW_DMA_0 && speed <= XFER_MW_DMA_2) + reg |= cs5535_mwdma_timings[speed - XFER_MW_DMA_0]; + else + return; + + wrmsr(unit ? ATAC_CH0D1_DMA : ATAC_CH0D0_DMA, reg, 0); + } +} + +/** + * cs5535_set_dma_mode - set host controller for DMA mode + * @hwif: port + * @drive: drive + * + * Programs the chipset for DMA mode. + */ + +static void cs5535_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive) +{ + cs5535_set_speed(drive, drive->dma_mode); +} + +/** + * cs5535_set_pio_mode - set host controller for PIO mode + * @hwif: port + * @drive: drive + * + * A callback from the upper layers for PIO-only tuning. + */ + +static void cs5535_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) +{ + cs5535_set_speed(drive, drive->pio_mode); +} + +static u8 cs5535_cable_detect(ide_hwif_t *hwif) +{ + struct pci_dev *dev = to_pci_dev(hwif->dev); + u8 bit; + + /* if a 80 wire cable was detected */ + pci_read_config_byte(dev, CS5535_CABLE_DETECT, &bit); + + return (bit & 1) ? ATA_CBL_PATA80 : ATA_CBL_PATA40; +} + +static const struct ide_port_ops cs5535_port_ops = { + .set_pio_mode = cs5535_set_pio_mode, + .set_dma_mode = cs5535_set_dma_mode, + .cable_detect = cs5535_cable_detect, +}; + +static const struct ide_port_info cs5535_chipset = { + .name = DRV_NAME, + .port_ops = &cs5535_port_ops, + .host_flags = IDE_HFLAG_SINGLE | IDE_HFLAG_POST_SET_MODE, + .pio_mask = ATA_PIO4, + .mwdma_mask = ATA_MWDMA2, + .udma_mask = ATA_UDMA4, +}; + +static int cs5535_init_one(struct pci_dev *dev, const struct pci_device_id *id) +{ + return ide_pci_init_one(dev, &cs5535_chipset, NULL); +} + +static const struct pci_device_id cs5535_pci_tbl[] = { + { PCI_VDEVICE(NS, PCI_DEVICE_ID_NS_CS5535_IDE), 0 }, + { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_CS5535_IDE), }, + { 0, }, +}; + +MODULE_DEVICE_TABLE(pci, cs5535_pci_tbl); + +static struct pci_driver cs5535_pci_driver = { + .name = "CS5535_IDE", + .id_table = cs5535_pci_tbl, + .probe = cs5535_init_one, + .remove = ide_pci_remove, + .suspend = ide_pci_suspend, + .resume = ide_pci_resume, +}; + +static int __init cs5535_ide_init(void) +{ + return ide_pci_register_driver(&cs5535_pci_driver); +} + +static void __exit cs5535_ide_exit(void) +{ + pci_unregister_driver(&cs5535_pci_driver); +} + +module_init(cs5535_ide_init); +module_exit(cs5535_ide_exit); + +MODULE_AUTHOR("AMD"); +MODULE_DESCRIPTION("PCI driver module for AMD/NS CS5535 IDE"); +MODULE_LICENSE("GPL"); diff --git a/drivers/ide/cs5536.c b/drivers/ide/cs5536.c new file mode 100644 index 00000000000..de9185db41d --- /dev/null +++ b/drivers/ide/cs5536.c @@ -0,0 +1,306 @@ +/* + * CS5536 PATA support + * (C) 2007 Martin K. Petersen <mkp@mkp.net> + * (C) 2009 Bartlomiej Zolnierkiewicz + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Documentation: + * Available from AMD web site. + * + * The IDE timing registers for the CS5536 live in the Geode Machine + * Specific Register file and not PCI config space. Most BIOSes + * virtualize the PCI registers so the chip looks like a standard IDE + * controller. Unfortunately not all implementations get this right. + * In particular some have problems with unaligned accesses to the + * virtualized PCI registers. This driver always does full dword + * writes to work around the issue. Also, in case of a bad BIOS this + * driver can be loaded with the "msr=1" parameter which forces using + * the Machine Specific Registers to configure the device. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/init.h> +#include <linux/ide.h> +#include <asm/msr.h> + +#define DRV_NAME "cs5536" + +enum { + MSR_IDE_CFG = 0x51300010, + PCI_IDE_CFG = 0x40, + + CFG = 0, + DTC = 2, + CAST = 3, + ETC = 4, + + IDE_CFG_CHANEN = (1 << 1), + IDE_CFG_CABLE = (1 << 17) | (1 << 16), + + IDE_D0_SHIFT = 24, + IDE_D1_SHIFT = 16, + IDE_DRV_MASK = 0xff, + + IDE_CAST_D0_SHIFT = 6, + IDE_CAST_D1_SHIFT = 4, + IDE_CAST_DRV_MASK = 0x3, + + IDE_CAST_CMD_SHIFT = 24, + IDE_CAST_CMD_MASK = 0xff, + + IDE_ETC_UDMA_MASK = 0xc0, +}; + +static int use_msr; + +static int cs5536_read(struct pci_dev *pdev, int reg, u32 *val) +{ + if (unlikely(use_msr)) { + u32 dummy; + + rdmsr(MSR_IDE_CFG + reg, *val, dummy); + return 0; + } + + return pci_read_config_dword(pdev, PCI_IDE_CFG + reg * 4, val); +} + +static int cs5536_write(struct pci_dev *pdev, int reg, int val) +{ + if (unlikely(use_msr)) { + wrmsr(MSR_IDE_CFG + reg, val, 0); + return 0; + } + + return pci_write_config_dword(pdev, PCI_IDE_CFG + reg * 4, val); +} + +static void cs5536_program_dtc(ide_drive_t *drive, u8 tim) +{ + struct pci_dev *pdev = to_pci_dev(drive->hwif->dev); + int dshift = (drive->dn & 1) ? IDE_D1_SHIFT : IDE_D0_SHIFT; + u32 dtc; + + cs5536_read(pdev, DTC, &dtc); + dtc &= ~(IDE_DRV_MASK << dshift); + dtc |= tim << dshift; + cs5536_write(pdev, DTC, dtc); +} + +/** + * cs5536_cable_detect - detect cable type + * @hwif: Port to detect on + * + * Perform cable detection for ATA66 capable cable. + * + * Returns a cable type. + */ + +static u8 cs5536_cable_detect(ide_hwif_t *hwif) +{ + struct pci_dev *pdev = to_pci_dev(hwif->dev); + u32 cfg; + + cs5536_read(pdev, CFG, &cfg); + + if (cfg & IDE_CFG_CABLE) + return ATA_CBL_PATA80; + else + return ATA_CBL_PATA40; +} + +/** + * cs5536_set_pio_mode - PIO timing setup + * @hwif: ATA port + * @drive: ATA device + */ + +static void cs5536_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) +{ + static const u8 drv_timings[5] = { + 0x98, 0x55, 0x32, 0x21, 0x20, + }; + + static const u8 addr_timings[5] = { + 0x2, 0x1, 0x0, 0x0, 0x0, + }; + + static const u8 cmd_timings[5] = { + 0x99, 0x92, 0x90, 0x22, 0x20, + }; + + struct pci_dev *pdev = to_pci_dev(hwif->dev); + ide_drive_t *pair = ide_get_pair_dev(drive); + int cshift = (drive->dn & 1) ? IDE_CAST_D1_SHIFT : IDE_CAST_D0_SHIFT; + unsigned long timings = (unsigned long)ide_get_drivedata(drive); + u32 cast; + const u8 pio = drive->pio_mode - XFER_PIO_0; + u8 cmd_pio = pio; + + if (pair) + cmd_pio = min_t(u8, pio, pair->pio_mode - XFER_PIO_0); + + timings &= (IDE_DRV_MASK << 8); + timings |= drv_timings[pio]; + ide_set_drivedata(drive, (void *)timings); + + cs5536_program_dtc(drive, drv_timings[pio]); + + cs5536_read(pdev, CAST, &cast); + + cast &= ~(IDE_CAST_DRV_MASK << cshift); + cast |= addr_timings[pio] << cshift; + + cast &= ~(IDE_CAST_CMD_MASK << IDE_CAST_CMD_SHIFT); + cast |= cmd_timings[cmd_pio] << IDE_CAST_CMD_SHIFT; + + cs5536_write(pdev, CAST, cast); +} + +/** + * cs5536_set_dma_mode - DMA timing setup + * @hwif: ATA port + * @drive: ATA device + */ + +static void cs5536_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive) +{ + static const u8 udma_timings[6] = { + 0xc2, 0xc1, 0xc0, 0xc4, 0xc5, 0xc6, + }; + + static const u8 mwdma_timings[3] = { + 0x67, 0x21, 0x20, + }; + + struct pci_dev *pdev = to_pci_dev(hwif->dev); + int dshift = (drive->dn & 1) ? IDE_D1_SHIFT : IDE_D0_SHIFT; + unsigned long timings = (unsigned long)ide_get_drivedata(drive); + u32 etc; + const u8 mode = drive->dma_mode; + + cs5536_read(pdev, ETC, &etc); + + if (mode >= XFER_UDMA_0) { + etc &= ~(IDE_DRV_MASK << dshift); + etc |= udma_timings[mode - XFER_UDMA_0] << dshift; + } else { /* MWDMA */ + etc &= ~(IDE_ETC_UDMA_MASK << dshift); + timings &= IDE_DRV_MASK; + timings |= mwdma_timings[mode - XFER_MW_DMA_0] << 8; + ide_set_drivedata(drive, (void *)timings); + } + + cs5536_write(pdev, ETC, etc); +} + +static void cs5536_dma_start(ide_drive_t *drive) +{ + unsigned long timings = (unsigned long)ide_get_drivedata(drive); + + if (drive->current_speed < XFER_UDMA_0 && + (timings >> 8) != (timings & IDE_DRV_MASK)) + cs5536_program_dtc(drive, timings >> 8); + + ide_dma_start(drive); +} + +static int cs5536_dma_end(ide_drive_t *drive) +{ + int ret = ide_dma_end(drive); + unsigned long timings = (unsigned long)ide_get_drivedata(drive); + + if (drive->current_speed < XFER_UDMA_0 && + (timings >> 8) != (timings & IDE_DRV_MASK)) + cs5536_program_dtc(drive, timings & IDE_DRV_MASK); + + return ret; +} + +static const struct ide_port_ops cs5536_port_ops = { + .set_pio_mode = cs5536_set_pio_mode, + .set_dma_mode = cs5536_set_dma_mode, + .cable_detect = cs5536_cable_detect, +}; + +static const struct ide_dma_ops cs5536_dma_ops = { + .dma_host_set = ide_dma_host_set, + .dma_setup = ide_dma_setup, + .dma_start = cs5536_dma_start, + .dma_end = cs5536_dma_end, + .dma_test_irq = ide_dma_test_irq, + .dma_lost_irq = ide_dma_lost_irq, + .dma_timer_expiry = ide_dma_sff_timer_expiry, + .dma_sff_read_status = ide_dma_sff_read_status, +}; + +static const struct ide_port_info cs5536_info = { + .name = DRV_NAME, + .port_ops = &cs5536_port_ops, + .dma_ops = &cs5536_dma_ops, + .host_flags = IDE_HFLAG_SINGLE, + .pio_mask = ATA_PIO4, + .mwdma_mask = ATA_MWDMA2, + .udma_mask = ATA_UDMA5, +}; + +/** + * cs5536_init_one + * @dev: PCI device + * @id: Entry in match table + */ + +static int cs5536_init_one(struct pci_dev *dev, const struct pci_device_id *id) +{ + u32 cfg; + + if (use_msr) + printk(KERN_INFO DRV_NAME ": Using MSR regs instead of PCI\n"); + + cs5536_read(dev, CFG, &cfg); + + if ((cfg & IDE_CFG_CHANEN) == 0) { + printk(KERN_ERR DRV_NAME ": disabled by BIOS\n"); + return -ENODEV; + } + + return ide_pci_init_one(dev, &cs5536_info, NULL); +} + +static const struct pci_device_id cs5536_pci_tbl[] = { + { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_CS5536_IDE), }, + { }, +}; + +static struct pci_driver cs5536_pci_driver = { + .name = DRV_NAME, + .id_table = cs5536_pci_tbl, + .probe = cs5536_init_one, + .remove = ide_pci_remove, + .suspend = ide_pci_suspend, + .resume = ide_pci_resume, +}; + +module_pci_driver(cs5536_pci_driver); + +MODULE_AUTHOR("Martin K. Petersen, Bartlomiej Zolnierkiewicz"); +MODULE_DESCRIPTION("low-level driver for the CS5536 IDE controller"); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, cs5536_pci_tbl); + +module_param_named(msr, use_msr, int, 0644); +MODULE_PARM_DESC(msr, "Force using MSR to configure IDE function (Default: 0)"); diff --git a/drivers/ide/cy82c693.c b/drivers/ide/cy82c693.c new file mode 100644 index 00000000000..f5820079a28 --- /dev/null +++ b/drivers/ide/cy82c693.c @@ -0,0 +1,233 @@ +/* + * Copyright (C) 1998-2000 Andreas S. Krebs (akrebs@altavista.net), Maintainer + * Copyright (C) 1998-2002 Andre Hedrick <andre@linux-ide.org>, Integrator + * Copyright (C) 2007-2011 Bartlomiej Zolnierkiewicz + * + * CYPRESS CY82C693 chipset IDE controller + * + * The CY82C693 chipset is used on Digital's PC-Alpha 164SX boards. + */ + +#include <linux/module.h> +#include <linux/types.h> +#include <linux/pci.h> +#include <linux/ide.h> +#include <linux/init.h> + +#include <asm/io.h> + +#define DRV_NAME "cy82c693" + +/* + * NOTE: the value for busmaster timeout is tricky and I got it by + * trial and error! By using a to low value will cause DMA timeouts + * and drop IDE performance, and by using a to high value will cause + * audio playback to scatter. + * If you know a better value or how to calc it, please let me know. + */ + +/* twice the value written in cy82c693ub datasheet */ +#define BUSMASTER_TIMEOUT 0x50 +/* + * the value above was tested on my machine and it seems to work okay + */ + +/* here are the offset definitions for the registers */ +#define CY82_IDE_CMDREG 0x04 +#define CY82_IDE_ADDRSETUP 0x48 +#define CY82_IDE_MASTER_IOR 0x4C +#define CY82_IDE_MASTER_IOW 0x4D +#define CY82_IDE_SLAVE_IOR 0x4E +#define CY82_IDE_SLAVE_IOW 0x4F +#define CY82_IDE_MASTER_8BIT 0x50 +#define CY82_IDE_SLAVE_8BIT 0x51 + +#define CY82_INDEX_PORT 0x22 +#define CY82_DATA_PORT 0x23 + +#define CY82_INDEX_CHANNEL0 0x30 +#define CY82_INDEX_CHANNEL1 0x31 +#define CY82_INDEX_TIMEOUT 0x32 + +/* + * set DMA mode a specific channel for CY82C693 + */ + +static void cy82c693_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive) +{ + const u8 mode = drive->dma_mode; + u8 single = (mode & 0x10) >> 4, index = 0, data = 0; + + index = hwif->channel ? CY82_INDEX_CHANNEL1 : CY82_INDEX_CHANNEL0; + + data = (mode & 3) | (single << 2); + + outb(index, CY82_INDEX_PORT); + outb(data, CY82_DATA_PORT); + + /* + * note: below we set the value for Bus Master IDE TimeOut Register + * I'm not absolutely sure what this does, but it solved my problem + * with IDE DMA and sound, so I now can play sound and work with + * my IDE driver at the same time :-) + * + * If you know the correct (best) value for this register please + * let me know - ASK + */ + + data = BUSMASTER_TIMEOUT; + outb(CY82_INDEX_TIMEOUT, CY82_INDEX_PORT); + outb(data, CY82_DATA_PORT); +} + +static void cy82c693_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) +{ + struct pci_dev *dev = to_pci_dev(hwif->dev); + int bus_speed = ide_pci_clk ? ide_pci_clk : 33; + const unsigned long T = 1000000 / bus_speed; + unsigned int addrCtrl; + struct ide_timing t; + u8 time_16, time_8; + + /* select primary or secondary channel */ + if (drive->dn > 1) { /* drive is on the secondary channel */ + dev = pci_get_slot(dev->bus, dev->devfn+1); + if (!dev) { + printk(KERN_ERR "%s: tune_drive: " + "Cannot find secondary interface!\n", + drive->name); + return; + } + } + + ide_timing_compute(drive, drive->pio_mode, &t, T, 1); + + time_16 = clamp_val(t.recover - 1, 0, 15) | + (clamp_val(t.active - 1, 0, 15) << 4); + time_8 = clamp_val(t.act8b - 1, 0, 15) | + (clamp_val(t.rec8b - 1, 0, 15) << 4); + + /* now let's write the clocks registers */ + if ((drive->dn & 1) == 0) { + /* + * set master drive + * address setup control register + * is 32 bit !!! + */ + pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl); + + addrCtrl &= (~0xF); + addrCtrl |= clamp_val(t.setup - 1, 0, 15); + pci_write_config_dword(dev, CY82_IDE_ADDRSETUP, addrCtrl); + + /* now let's set the remaining registers */ + pci_write_config_byte(dev, CY82_IDE_MASTER_IOR, time_16); + pci_write_config_byte(dev, CY82_IDE_MASTER_IOW, time_16); + pci_write_config_byte(dev, CY82_IDE_MASTER_8BIT, time_8); + } else { + /* + * set slave drive + * address setup control register + * is 32 bit !!! + */ + pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl); + + addrCtrl &= (~0xF0); + addrCtrl |= (clamp_val(t.setup - 1, 0, 15) << 4); + pci_write_config_dword(dev, CY82_IDE_ADDRSETUP, addrCtrl); + + /* now let's set the remaining registers */ + pci_write_config_byte(dev, CY82_IDE_SLAVE_IOR, time_16); + pci_write_config_byte(dev, CY82_IDE_SLAVE_IOW, time_16); + pci_write_config_byte(dev, CY82_IDE_SLAVE_8BIT, time_8); + } + if (drive->dn > 1) + pci_dev_put(dev); +} + +static void init_iops_cy82c693(ide_hwif_t *hwif) +{ + static ide_hwif_t *primary; + struct pci_dev *dev = to_pci_dev(hwif->dev); + + if (PCI_FUNC(dev->devfn) == 1) + primary = hwif; + else { + hwif->mate = primary; + hwif->channel = 1; + } +} + +static const struct ide_port_ops cy82c693_port_ops = { + .set_pio_mode = cy82c693_set_pio_mode, + .set_dma_mode = cy82c693_set_dma_mode, +}; + +static const struct ide_port_info cy82c693_chipset = { + .name = DRV_NAME, + .init_iops = init_iops_cy82c693, + .port_ops = &cy82c693_port_ops, + .host_flags = IDE_HFLAG_SINGLE, + .pio_mask = ATA_PIO4, + .swdma_mask = ATA_SWDMA2, + .mwdma_mask = ATA_MWDMA2, +}; + +static int cy82c693_init_one(struct pci_dev *dev, + const struct pci_device_id *id) +{ + struct pci_dev *dev2; + int ret = -ENODEV; + + /* CY82C693 is more than only a IDE controller. + Function 1 is primary IDE channel, function 2 - secondary. */ + if ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE && + PCI_FUNC(dev->devfn) == 1) { + dev2 = pci_get_slot(dev->bus, dev->devfn + 1); + ret = ide_pci_init_two(dev, dev2, &cy82c693_chipset, NULL); + if (ret) + pci_dev_put(dev2); + } + return ret; +} + +static void cy82c693_remove(struct pci_dev *dev) +{ + struct ide_host *host = pci_get_drvdata(dev); + struct pci_dev *dev2 = host->dev[1] ? to_pci_dev(host->dev[1]) : NULL; + + ide_pci_remove(dev); + pci_dev_put(dev2); +} + +static const struct pci_device_id cy82c693_pci_tbl[] = { + { PCI_VDEVICE(CONTAQ, PCI_DEVICE_ID_CONTAQ_82C693), 0 }, + { 0, }, +}; +MODULE_DEVICE_TABLE(pci, cy82c693_pci_tbl); + +static struct pci_driver cy82c693_pci_driver = { + .name = "Cypress_IDE", + .id_table = cy82c693_pci_tbl, + .probe = cy82c693_init_one, + .remove = cy82c693_remove, + .suspend = ide_pci_suspend, + .resume = ide_pci_resume, +}; + +static int __init cy82c693_ide_init(void) +{ + return ide_pci_register_driver(&cy82c693_pci_driver); +} + +static void __exit cy82c693_ide_exit(void) +{ + pci_unregister_driver(&cy82c693_pci_driver); +} + +module_init(cy82c693_ide_init); +module_exit(cy82c693_ide_exit); + +MODULE_AUTHOR("Andreas Krebs, Andre Hedrick, Bartlomiej Zolnierkiewicz"); +MODULE_DESCRIPTION("PCI driver module for the Cypress CY82C693 IDE"); +MODULE_LICENSE("GPL"); diff --git a/drivers/ide/delkin_cb.c b/drivers/ide/delkin_cb.c new file mode 100644 index 00000000000..300daabaa57 --- /dev/null +++ b/drivers/ide/delkin_cb.c @@ -0,0 +1,181 @@ +/* + * Created 20 Oct 2004 by Mark Lord + * + * Basic support for Delkin/ASKA/Workbit Cardbus CompactFlash adapter + * + * Modeled after the 16-bit PCMCIA driver: ide-cs.c + * + * This is slightly peculiar, in that it is a PCI driver, + * but is NOT an IDE PCI driver -- the IDE layer does not directly + * support hot insertion/removal of PCI interfaces, so this driver + * is unable to use the IDE PCI interfaces. Instead, it uses the + * same interfaces as the ide-cs (PCMCIA) driver uses. + * On the plus side, the driver is also smaller/simpler this way. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + */ + +#include <linux/types.h> +#include <linux/module.h> +#include <linux/ide.h> +#include <linux/init.h> +#include <linux/pci.h> + +#include <asm/io.h> + +/* + * No chip documentation has yet been found, + * so these configuration values were pulled from + * a running Win98 system using "debug". + * This gives around 3MByte/second read performance, + * which is about 2/3 of what the chip is capable of. + * + * There is also a 4KByte mmio region on the card, + * but its purpose has yet to be reverse-engineered. + */ +static const u8 setup[] = { + 0x00, 0x05, 0xbe, 0x01, 0x20, 0x8f, 0x00, 0x00, + 0xa4, 0x1f, 0xb3, 0x1b, 0x00, 0x00, 0x00, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xa4, 0x83, 0x02, 0x13, +}; + +static const struct ide_port_ops delkin_cb_port_ops = { + .quirkproc = ide_undecoded_slave, +}; + +static int delkin_cb_init_chipset(struct pci_dev *dev) +{ + unsigned long base = pci_resource_start(dev, 0); + int i; + + outb(0x02, base + 0x1e); /* set nIEN to block interrupts */ + inb(base + 0x17); /* read status to clear interrupts */ + + for (i = 0; i < sizeof(setup); ++i) { + if (setup[i]) + outb(setup[i], base + i); + } + + return 0; +} + +static const struct ide_port_info delkin_cb_port_info = { + .port_ops = &delkin_cb_port_ops, + .host_flags = IDE_HFLAG_IO_32BIT | IDE_HFLAG_UNMASK_IRQS | + IDE_HFLAG_NO_DMA, + .irq_flags = IRQF_SHARED, + .init_chipset = delkin_cb_init_chipset, + .chipset = ide_pci, +}; + +static int delkin_cb_probe(struct pci_dev *dev, const struct pci_device_id *id) +{ + struct ide_host *host; + unsigned long base; + int rc; + struct ide_hw hw, *hws[] = { &hw }; + + rc = pci_enable_device(dev); + if (rc) { + printk(KERN_ERR "delkin_cb: pci_enable_device failed (%d)\n", rc); + return rc; + } + rc = pci_request_regions(dev, "delkin_cb"); + if (rc) { + printk(KERN_ERR "delkin_cb: pci_request_regions failed (%d)\n", rc); + pci_disable_device(dev); + return rc; + } + base = pci_resource_start(dev, 0); + + delkin_cb_init_chipset(dev); + + memset(&hw, 0, sizeof(hw)); + ide_std_init_ports(&hw, base + 0x10, base + 0x1e); + hw.irq = dev->irq; + hw.dev = &dev->dev; + + rc = ide_host_add(&delkin_cb_port_info, hws, 1, &host); + if (rc) + goto out_disable; + + pci_set_drvdata(dev, host); + + return 0; + +out_disable: + pci_release_regions(dev); + pci_disable_device(dev); + return rc; +} + +static void +delkin_cb_remove (struct pci_dev *dev) +{ + struct ide_host *host = pci_get_drvdata(dev); + + ide_host_remove(host); + + pci_release_regions(dev); + pci_disable_device(dev); +} + +#ifdef CONFIG_PM +static int delkin_cb_suspend(struct pci_dev *dev, pm_message_t state) +{ + pci_save_state(dev); + pci_disable_device(dev); + pci_set_power_state(dev, pci_choose_state(dev, state)); + + return 0; +} + +static int delkin_cb_resume(struct pci_dev *dev) +{ + struct ide_host *host = pci_get_drvdata(dev); + int rc; + + pci_set_power_state(dev, PCI_D0); + + rc = pci_enable_device(dev); + if (rc) + return rc; + + pci_restore_state(dev); + pci_set_master(dev); + + if (host->init_chipset) + host->init_chipset(dev); + + return 0; +} +#else +#define delkin_cb_suspend NULL +#define delkin_cb_resume NULL +#endif + +static struct pci_device_id delkin_cb_pci_tbl[] = { + { 0x1145, 0xf021, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + { 0x1145, 0xf024, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + { 0, }, +}; +MODULE_DEVICE_TABLE(pci, delkin_cb_pci_tbl); + +static struct pci_driver delkin_cb_pci_driver = { + .name = "Delkin-ASKA-Workbit Cardbus IDE", + .id_table = delkin_cb_pci_tbl, + .probe = delkin_cb_probe, + .remove = delkin_cb_remove, + .suspend = delkin_cb_suspend, + .resume = delkin_cb_resume, +}; + +module_pci_driver(delkin_cb_pci_driver); + +MODULE_AUTHOR("Mark Lord"); +MODULE_DESCRIPTION("Basic support for Delkin/ASKA/Workbit Cardbus IDE"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/ide/legacy/dtc2278.c b/drivers/ide/dtc2278.c index 3b1d33baaa2..8722df329cb 100644 --- a/drivers/ide/legacy/dtc2278.c +++ b/drivers/ide/dtc2278.c @@ -1,11 +1,7 @@ /* - * linux/drivers/ide/legacy/dtc2278.c Version 0.02 Feb 10, 1996 - * * Copyright (C) 1996 Linus Torvalds & author (see below) */ -#undef REALLY_SLOW_IO /* most systems can safely undef this */ - #include <linux/module.h> #include <linux/types.h> #include <linux/kernel.h> @@ -14,12 +10,13 @@ #include <linux/mm.h> #include <linux/ioport.h> #include <linux/blkdev.h> -#include <linux/hdreg.h> #include <linux/ide.h> #include <linux/init.h> #include <asm/io.h> +#define DRV_NAME "dtc2278" + /* * Changing this #undef to #define may solve start up problems in some systems. */ @@ -69,41 +66,48 @@ static void sub22 (char b, char c) } } -static void tune_dtc2278 (ide_drive_t *drive, u8 pio) +static DEFINE_SPINLOCK(dtc2278_lock); + +static void dtc2278_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) { unsigned long flags; - pio = ide_get_best_pio_mode(drive, pio, 4, NULL); - - if (pio >= 3) { - spin_lock_irqsave(&ide_lock, flags); + if (drive->pio_mode >= XFER_PIO_3) { + spin_lock_irqsave(&dtc2278_lock, flags); /* * This enables PIO mode4 (3?) on the first interface */ sub22(1,0xc3); sub22(0,0xa0); - spin_unlock_irqrestore(&ide_lock, flags); + spin_unlock_irqrestore(&dtc2278_lock, flags); } else { /* we don't know how to set it back again.. */ + /* Actually we do - there is a data sheet available for the + Winbond but does anyone actually care */ } - - /* - * 32bit I/O has to be enabled for *both* drives at the same time. - */ - drive->io_32bit = 1; - HWIF(drive)->drives[!drive->select.b.unit].io_32bit = 1; } -static int __init probe_dtc2278(void) +static const struct ide_port_ops dtc2278_port_ops = { + .set_pio_mode = dtc2278_set_pio_mode, +}; + +static const struct ide_port_info dtc2278_port_info __initconst = { + .name = DRV_NAME, + .chipset = ide_dtc2278, + .port_ops = &dtc2278_port_ops, + .host_flags = IDE_HFLAG_SERIALIZE | + IDE_HFLAG_NO_UNMASK_IRQS | + IDE_HFLAG_IO_32BIT | + /* disallow ->io_32bit changes */ + IDE_HFLAG_NO_IO_32BIT | + IDE_HFLAG_NO_DMA | + IDE_HFLAG_DTC2278, + .pio_mask = ATA_PIO4, +}; + +static int __init dtc2278_probe(void) { unsigned long flags; - ide_hwif_t *hwif, *mate; - - hwif = &ide_hwifs[0]; - mate = &ide_hwifs[1]; - - if (hwif->chipset != ide_unknown || mate->chipset != ide_unknown) - return 1; local_irq_save(flags); /* @@ -123,41 +127,27 @@ static int __init probe_dtc2278(void) #endif local_irq_restore(flags); - hwif->serialized = 1; - hwif->chipset = ide_dtc2278; - hwif->tuneproc = &tune_dtc2278; - hwif->drives[0].no_unmask = 1; - hwif->drives[1].no_unmask = 1; - hwif->mate = mate; - - mate->serialized = 1; - mate->chipset = ide_dtc2278; - mate->drives[0].no_unmask = 1; - mate->drives[1].no_unmask = 1; - mate->mate = hwif; - mate->channel = 1; - - probe_hwif_init(hwif); - probe_hwif_init(mate); + return ide_legacy_device_add(&dtc2278_port_info, 0); +} - create_proc_ide_interfaces(); +static bool probe_dtc2278; - return 0; -} +module_param_named(probe, probe_dtc2278, bool, 0); +MODULE_PARM_DESC(probe, "probe for DTC2278xx chipsets"); -/* Can be called directly from ide.c. */ -int __init dtc2278_init(void) +static int __init dtc2278_init(void) { - if (probe_dtc2278()) { + if (probe_dtc2278 == 0) + return -ENODEV; + + if (dtc2278_probe()) { printk(KERN_ERR "dtc2278: ide interfaces already in use!\n"); return -EBUSY; } return 0; } -#ifdef MODULE module_init(dtc2278_init); -#endif MODULE_AUTHOR("See Local File"); MODULE_DESCRIPTION("support of DTC-2278 VLB IDE chipsets"); diff --git a/drivers/ide/falconide.c b/drivers/ide/falconide.c new file mode 100644 index 00000000000..a5a07ccb81a --- /dev/null +++ b/drivers/ide/falconide.c @@ -0,0 +1,178 @@ +/* + * Atari Falcon IDE Driver + * + * Created 12 Jul 1997 by Geert Uytterhoeven + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + */ + +#include <linux/module.h> +#include <linux/types.h> +#include <linux/mm.h> +#include <linux/interrupt.h> +#include <linux/blkdev.h> +#include <linux/ide.h> +#include <linux/init.h> + +#include <asm/setup.h> +#include <asm/atarihw.h> +#include <asm/atariints.h> +#include <asm/atari_stdma.h> +#include <asm/ide.h> + +#define DRV_NAME "falconide" + + /* + * Base of the IDE interface + */ + +#define ATA_HD_BASE 0xfff00000 + + /* + * Offsets from the above base + */ + +#define ATA_HD_CONTROL 0x39 + + /* + * falconide_intr_lock is used to obtain access to the IDE interrupt, + * which is shared between several drivers. + */ + +static int falconide_intr_lock; + +static void falconide_release_lock(void) +{ + if (falconide_intr_lock == 0) { + printk(KERN_ERR "%s: bug\n", __func__); + return; + } + falconide_intr_lock = 0; + stdma_release(); +} + +static void falconide_get_lock(irq_handler_t handler, void *data) +{ + if (falconide_intr_lock == 0) { + if (in_interrupt() > 0) + panic("Falcon IDE hasn't ST-DMA lock in interrupt"); + stdma_lock(handler, data); + falconide_intr_lock = 1; + } +} + +static void falconide_input_data(ide_drive_t *drive, struct ide_cmd *cmd, + void *buf, unsigned int len) +{ + unsigned long data_addr = drive->hwif->io_ports.data_addr; + + if (drive->media == ide_disk && cmd && (cmd->tf_flags & IDE_TFLAG_FS)) { + __ide_mm_insw(data_addr, buf, (len + 1) / 2); + return; + } + + raw_insw_swapw((u16 *)data_addr, buf, (len + 1) / 2); +} + +static void falconide_output_data(ide_drive_t *drive, struct ide_cmd *cmd, + void *buf, unsigned int len) +{ + unsigned long data_addr = drive->hwif->io_ports.data_addr; + + if (drive->media == ide_disk && cmd && (cmd->tf_flags & IDE_TFLAG_FS)) { + __ide_mm_outsw(data_addr, buf, (len + 1) / 2); + return; + } + + raw_outsw_swapw((u16 *)data_addr, buf, (len + 1) / 2); +} + +/* Atari has a byte-swapped IDE interface */ +static const struct ide_tp_ops falconide_tp_ops = { + .exec_command = ide_exec_command, + .read_status = ide_read_status, + .read_altstatus = ide_read_altstatus, + .write_devctl = ide_write_devctl, + + .dev_select = ide_dev_select, + .tf_load = ide_tf_load, + .tf_read = ide_tf_read, + + .input_data = falconide_input_data, + .output_data = falconide_output_data, +}; + +static const struct ide_port_info falconide_port_info = { + .get_lock = falconide_get_lock, + .release_lock = falconide_release_lock, + .tp_ops = &falconide_tp_ops, + .host_flags = IDE_HFLAG_MMIO | IDE_HFLAG_SERIALIZE | + IDE_HFLAG_NO_DMA, + .irq_flags = IRQF_SHARED, + .chipset = ide_generic, +}; + +static void __init falconide_setup_ports(struct ide_hw *hw) +{ + int i; + + memset(hw, 0, sizeof(*hw)); + + hw->io_ports.data_addr = ATA_HD_BASE; + + for (i = 1; i < 8; i++) + hw->io_ports_array[i] = ATA_HD_BASE + 1 + i * 4; + + hw->io_ports.ctl_addr = ATA_HD_BASE + ATA_HD_CONTROL; + + hw->irq = IRQ_MFP_IDE; +} + + /* + * Probe for a Falcon IDE interface + */ + +static int __init falconide_init(void) +{ + struct ide_host *host; + struct ide_hw hw, *hws[] = { &hw }; + int rc; + + if (!MACH_IS_ATARI || !ATARIHW_PRESENT(IDE)) + return -ENODEV; + + printk(KERN_INFO "ide: Falcon IDE controller\n"); + + if (!request_mem_region(ATA_HD_BASE, 0x40, DRV_NAME)) { + printk(KERN_ERR "%s: resources busy\n", DRV_NAME); + return -EBUSY; + } + + falconide_setup_ports(&hw); + + host = ide_host_alloc(&falconide_port_info, hws, 1); + if (host == NULL) { + rc = -ENOMEM; + goto err; + } + + falconide_get_lock(NULL, NULL); + rc = ide_host_register(host, &falconide_port_info, hws); + falconide_release_lock(); + + if (rc) + goto err_free; + + return 0; +err_free: + ide_host_free(host); +err: + release_mem_region(ATA_HD_BASE, 0x40); + return rc; +} + +module_init(falconide_init); + +MODULE_LICENSE("GPL"); diff --git a/drivers/ide/gayle.c b/drivers/ide/gayle.c new file mode 100644 index 00000000000..97a2f9dc75d --- /dev/null +++ b/drivers/ide/gayle.c @@ -0,0 +1,189 @@ +/* + * Amiga Gayle IDE Driver + * + * Created 9 Jul 1997 by Geert Uytterhoeven + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + */ + +#include <linux/types.h> +#include <linux/mm.h> +#include <linux/interrupt.h> +#include <linux/blkdev.h> +#include <linux/ide.h> +#include <linux/init.h> +#include <linux/zorro.h> +#include <linux/module.h> +#include <linux/platform_device.h> + +#include <asm/setup.h> +#include <asm/amigahw.h> +#include <asm/amigaints.h> +#include <asm/amigayle.h> + + + /* + * Offsets from one of the above bases + */ + +#define GAYLE_CONTROL 0x101a + + /* + * These are at different offsets from the base + */ + +#define GAYLE_IRQ_4000 0xdd3020 /* MSB = 1, Harddisk is source of */ +#define GAYLE_IRQ_1200 0xda9000 /* interrupt */ + + + /* + * Offset of the secondary port for IDE doublers + * Note that GAYLE_CONTROL is NOT available then! + */ + +#define GAYLE_NEXT_PORT 0x1000 + +#define GAYLE_NUM_HWIFS 2 +#define GAYLE_NUM_PROBE_HWIFS (ide_doubler ? GAYLE_NUM_HWIFS : \ + GAYLE_NUM_HWIFS-1) +#define GAYLE_HAS_CONTROL_REG (!ide_doubler) + +static bool ide_doubler; +module_param_named(doubler, ide_doubler, bool, 0); +MODULE_PARM_DESC(doubler, "enable support for IDE doublers"); + + /* + * Check and acknowledge the interrupt status + */ + +static int gayle_test_irq(ide_hwif_t *hwif) +{ + unsigned char ch; + + ch = z_readb(hwif->io_ports.irq_addr); + if (!(ch & GAYLE_IRQ_IDE)) + return 0; + return 1; +} + +static void gayle_a1200_clear_irq(ide_drive_t *drive) +{ + ide_hwif_t *hwif = drive->hwif; + + (void)z_readb(hwif->io_ports.status_addr); + z_writeb(0x7c, hwif->io_ports.irq_addr); +} + +static void __init gayle_setup_ports(struct ide_hw *hw, unsigned long base, + unsigned long ctl, unsigned long irq_port) +{ + int i; + + memset(hw, 0, sizeof(*hw)); + + hw->io_ports.data_addr = base; + + for (i = 1; i < 8; i++) + hw->io_ports_array[i] = base + 2 + i * 4; + + hw->io_ports.ctl_addr = ctl; + hw->io_ports.irq_addr = irq_port; + + hw->irq = IRQ_AMIGA_PORTS; +} + +static const struct ide_port_ops gayle_a4000_port_ops = { + .test_irq = gayle_test_irq, +}; + +static const struct ide_port_ops gayle_a1200_port_ops = { + .clear_irq = gayle_a1200_clear_irq, + .test_irq = gayle_test_irq, +}; + +static const struct ide_port_info gayle_port_info = { + .host_flags = IDE_HFLAG_MMIO | IDE_HFLAG_SERIALIZE | + IDE_HFLAG_NO_DMA, + .irq_flags = IRQF_SHARED, + .chipset = ide_generic, +}; + + /* + * Probe for a Gayle IDE interface (and optionally for an IDE doubler) + */ + +static int __init amiga_gayle_ide_probe(struct platform_device *pdev) +{ + struct resource *res; + struct gayle_ide_platform_data *pdata; + unsigned long base, ctrlport, irqport; + unsigned int i; + int error; + struct ide_hw hw[GAYLE_NUM_HWIFS], *hws[GAYLE_NUM_HWIFS]; + struct ide_port_info d = gayle_port_info; + struct ide_host *host; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENODEV; + + if (!request_mem_region(res->start, resource_size(res), "IDE")) + return -EBUSY; + + pdata = dev_get_platdata(&pdev->dev); + pr_info("ide: Gayle IDE controller (A%u style%s)\n", + pdata->explicit_ack ? 1200 : 4000, + ide_doubler ? ", IDE doubler" : ""); + + base = (unsigned long)ZTWO_VADDR(pdata->base); + ctrlport = 0; + irqport = (unsigned long)ZTWO_VADDR(pdata->irqport); + if (pdata->explicit_ack) + d.port_ops = &gayle_a1200_port_ops; + else + d.port_ops = &gayle_a4000_port_ops; + + for (i = 0; i < GAYLE_NUM_PROBE_HWIFS; i++, base += GAYLE_NEXT_PORT) { + if (GAYLE_HAS_CONTROL_REG) + ctrlport = base + GAYLE_CONTROL; + + gayle_setup_ports(&hw[i], base, ctrlport, irqport); + hws[i] = &hw[i]; + } + + error = ide_host_add(&d, hws, i, &host); + if (error) + goto out; + + platform_set_drvdata(pdev, host); + return 0; + +out: + release_mem_region(res->start, resource_size(res)); + return error; +} + +static int __exit amiga_gayle_ide_remove(struct platform_device *pdev) +{ + struct ide_host *host = platform_get_drvdata(pdev); + struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + ide_host_remove(host); + release_mem_region(res->start, resource_size(res)); + return 0; +} + +static struct platform_driver amiga_gayle_ide_driver = { + .remove = __exit_p(amiga_gayle_ide_remove), + .driver = { + .name = "amiga-gayle-ide", + .owner = THIS_MODULE, + }, +}; + +module_platform_driver_probe(amiga_gayle_ide_driver, amiga_gayle_ide_probe); + +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:amiga-gayle-ide"); diff --git a/drivers/ide/h8300/ide-h8300.c b/drivers/ide/h8300/ide-h8300.c deleted file mode 100644 index 15955996a1f..00000000000 --- a/drivers/ide/h8300/ide-h8300.c +++ /dev/null @@ -1,118 +0,0 @@ -/* - * drivers/ide/ide-h8300.c - * H8/300 generic IDE interface - */ - -#include <linux/init.h> -#include <linux/ide.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/hpt366.c b/drivers/ide/hpt366.c new file mode 100644 index 00000000000..696b6c1ec94 --- /dev/null +++ b/drivers/ide/hpt366.c @@ -0,0 +1,1548 @@ +/* + * Copyright (C) 1999-2003 Andre Hedrick <andre@linux-ide.org> + * Portions Copyright (C) 2001 Sun Microsystems, Inc. + * Portions Copyright (C) 2003 Red Hat Inc + * Portions Copyright (C) 2007 Bartlomiej Zolnierkiewicz + * Portions Copyright (C) 2005-2009 MontaVista Software, Inc. + * + * Thanks to HighPoint Technologies for their assistance, and hardware. + * Special Thanks to Jon Burchmore in SanDiego for the deep pockets, his + * donation of an ABit BP6 mainboard, processor, and memory acellerated + * development and support. + * + * + * HighPoint has its own drivers (open source except for the RAID part) + * available from http://www.highpoint-tech.com/USA_new/service_support.htm + * This may be useful to anyone wanting to work on this driver, however do not + * trust them too much since the code tends to become less and less meaningful + * as the time passes... :-/ + * + * Note that final HPT370 support was done by force extraction of GPL. + * + * - add function for getting/setting power status of drive + * - the HPT370's state machine can get confused. reset it before each dma + * xfer to prevent that from happening. + * - reset state engine whenever we get an error. + * - check for busmaster state at end of dma. + * - use new highpoint timings. + * - detect bus speed using highpoint register. + * - use pll if we don't have a clock table. added a 66MHz table that's + * just 2x the 33MHz table. + * - removed turnaround. NOTE: we never want to switch between pll and + * pci clocks as the chip can glitch in those cases. the highpoint + * approved workaround slows everything down too much to be useful. in + * addition, we would have to serialize access to each chip. + * Adrian Sun <a.sun@sun.com> + * + * add drive timings for 66MHz PCI bus, + * fix ATA Cable signal detection, fix incorrect /proc info + * add /proc display for per-drive PIO/DMA/UDMA mode and + * per-channel ATA-33/66 Cable detect. + * Duncan Laurie <void@sun.com> + * + * fixup /proc output for multiple controllers + * Tim Hockin <thockin@sun.com> + * + * On hpt366: + * Reset the hpt366 on error, reset on dma + * Fix disabling Fast Interrupt hpt366. + * Mike Waychison <crlf@sun.com> + * + * Added support for 372N clocking and clock switching. The 372N needs + * different clocks on read/write. This requires overloading rw_disk and + * other deeply crazy things. Thanks to <http://www.hoerstreich.de> for + * keeping me sane. + * Alan Cox <alan@lxorguk.ukuu.org.uk> + * + * - fix the clock turnaround code: it was writing to the wrong ports when + * called for the secondary channel, caching the current clock mode per- + * channel caused the cached register value to get out of sync with the + * actual one, the channels weren't serialized, the turnaround shouldn't + * be done on 66 MHz PCI bus + * - disable UltraATA/100 for HPT370 by default as the 33 MHz clock being used + * does not allow for this speed anyway + * - avoid touching disabled channels (e.g. HPT371/N are single channel chips, + * their primary channel is kind of virtual, it isn't tied to any pins) + * - fix/remove bad/unused timing tables and use one set of tables for the whole + * HPT37x chip family; save space by introducing the separate transfer mode + * table in which the mode lookup is done + * - use f_CNT value saved by the HighPoint BIOS as reading it directly gives + * the wrong PCI frequency since DPLL has already been calibrated by BIOS; + * read it only from the function 0 of HPT374 chips + * - fix the hotswap code: it caused RESET- to glitch when tristating the bus, + * and for HPT36x the obsolete HDIO_TRISTATE_HWIF handler was called instead + * - pass to init_chipset() handlers a copy of the IDE PCI device structure as + * they tamper with its fields + * - pass to the init_setup handlers a copy of the ide_pci_device_t structure + * since they may tamper with its fields + * - prefix the driver startup messages with the real chip name + * - claim the extra 240 bytes of I/O space for all chips + * - optimize the UltraDMA filtering and the drive list lookup code + * - use pci_get_slot() to get to the function 1 of HPT36x/374 + * - cache offset of the channel's misc. control registers (MCRs) being used + * throughout the driver + * - only touch the relevant MCR when detecting the cable type on HPT374's + * function 1 + * - rename all the register related variables consistently + * - move all the interrupt twiddling code from the speedproc handlers into + * init_hwif_hpt366(), also grouping all the DMA related code together there + * - merge HPT36x/HPT37x speedproc handlers, fix PIO timing register mask and + * separate the UltraDMA and MWDMA masks there to avoid changing PIO timings + * when setting an UltraDMA mode + * - fix hpt3xx_tune_drive() to set the PIO mode requested, not always select + * the best possible one + * - clean up DMA timeout handling for HPT370 + * - switch to using the enumeration type to differ between the numerous chip + * variants, matching PCI device/revision ID with the chip type early, at the + * init_setup stage + * - extend the hpt_info structure to hold the DPLL and PCI clock frequencies, + * stop duplicating it for each channel by storing the pointer in the pci_dev + * structure: first, at the init_setup stage, point it to a static "template" + * with only the chip type and its specific base DPLL frequency, the highest + * UltraDMA mode, and the chip settings table pointer filled, then, at the + * init_chipset stage, allocate per-chip instance and fill it with the rest + * of the necessary information + * - get rid of the constant thresholds in the HPT37x PCI clock detection code, + * switch to calculating PCI clock frequency based on the chip's base DPLL + * frequency + * - switch to using the DPLL clock and enable UltraATA/133 mode by default on + * anything newer than HPT370/A (except HPT374 that is not capable of this + * mode according to the manual) + * - fold PCI clock detection and DPLL setup code into init_chipset_hpt366(), + * also fixing the interchanged 25/40 MHz PCI clock cases for HPT36x chips; + * unify HPT36x/37x timing setup code and the speedproc handlers by joining + * the register setting lists into the table indexed by the clock selected + * - set the correct hwif->ultra_mask for each individual chip + * - add Ultra and MW DMA mode filtering for the HPT37[24] based SATA cards + * - stop resetting HPT370's state machine before each DMA transfer as that has + * caused more harm than good + * Sergei Shtylyov, <sshtylyov@ru.mvista.com> or <source@mvista.com> + */ + +#include <linux/types.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/delay.h> +#include <linux/blkdev.h> +#include <linux/interrupt.h> +#include <linux/pci.h> +#include <linux/init.h> +#include <linux/ide.h> +#include <linux/slab.h> + +#include <asm/uaccess.h> +#include <asm/io.h> + +#define DRV_NAME "hpt366" + +/* various tuning parameters */ +#undef HPT_RESET_STATE_ENGINE +#undef HPT_DELAY_INTERRUPT + +static const char *bad_ata100_5[] = { + "IBM-DTLA-307075", + "IBM-DTLA-307060", + "IBM-DTLA-307045", + "IBM-DTLA-307030", + "IBM-DTLA-307020", + "IBM-DTLA-307015", + "IBM-DTLA-305040", + "IBM-DTLA-305030", + "IBM-DTLA-305020", + "IC35L010AVER07-0", + "IC35L020AVER07-0", + "IC35L030AVER07-0", + "IC35L040AVER07-0", + "IC35L060AVER07-0", + "WDC AC310200R", + NULL +}; + +static const char *bad_ata66_4[] = { + "IBM-DTLA-307075", + "IBM-DTLA-307060", + "IBM-DTLA-307045", + "IBM-DTLA-307030", + "IBM-DTLA-307020", + "IBM-DTLA-307015", + "IBM-DTLA-305040", + "IBM-DTLA-305030", + "IBM-DTLA-305020", + "IC35L010AVER07-0", + "IC35L020AVER07-0", + "IC35L030AVER07-0", + "IC35L040AVER07-0", + "IC35L060AVER07-0", + "WDC AC310200R", + "MAXTOR STM3320620A", + NULL +}; + +static const char *bad_ata66_3[] = { + "WDC AC310200R", + NULL +}; + +static const char *bad_ata33[] = { + "Maxtor 92720U8", "Maxtor 92040U6", "Maxtor 91360U4", "Maxtor 91020U3", "Maxtor 90845U3", "Maxtor 90650U2", + "Maxtor 91360D8", "Maxtor 91190D7", "Maxtor 91020D6", "Maxtor 90845D5", "Maxtor 90680D4", "Maxtor 90510D3", "Maxtor 90340D2", + "Maxtor 91152D8", "Maxtor 91008D7", "Maxtor 90845D6", "Maxtor 90840D6", "Maxtor 90720D5", "Maxtor 90648D5", "Maxtor 90576D4", + "Maxtor 90510D4", + "Maxtor 90432D3", "Maxtor 90288D2", "Maxtor 90256D2", + "Maxtor 91000D8", "Maxtor 90910D8", "Maxtor 90875D7", "Maxtor 90840D7", "Maxtor 90750D6", "Maxtor 90625D5", "Maxtor 90500D4", + "Maxtor 91728D8", "Maxtor 91512D7", "Maxtor 91303D6", "Maxtor 91080D5", "Maxtor 90845D4", "Maxtor 90680D4", "Maxtor 90648D3", "Maxtor 90432D2", + NULL +}; + +static u8 xfer_speeds[] = { + XFER_UDMA_6, + XFER_UDMA_5, + XFER_UDMA_4, + XFER_UDMA_3, + XFER_UDMA_2, + XFER_UDMA_1, + XFER_UDMA_0, + + XFER_MW_DMA_2, + XFER_MW_DMA_1, + XFER_MW_DMA_0, + + XFER_PIO_4, + XFER_PIO_3, + XFER_PIO_2, + XFER_PIO_1, + XFER_PIO_0 +}; + +/* Key for bus clock timings + * 36x 37x + * bits bits + * 0:3 0:3 data_high_time. Inactive time of DIOW_/DIOR_ for PIO and MW DMA. + * cycles = value + 1 + * 4:7 4:8 data_low_time. Active time of DIOW_/DIOR_ for PIO and MW DMA. + * cycles = value + 1 + * 8:11 9:12 cmd_high_time. Inactive time of DIOW_/DIOR_ during task file + * register access. + * 12:15 13:17 cmd_low_time. Active time of DIOW_/DIOR_ during task file + * register access. + * 16:18 18:20 udma_cycle_time. Clock cycles for UDMA xfer. + * - 21 CLK frequency: 0=ATA clock, 1=dual ATA clock. + * 19:21 22:24 pre_high_time. Time to initialize the 1st cycle for PIO and + * MW DMA xfer. + * 22:24 25:27 cmd_pre_high_time. Time to initialize the 1st PIO cycle for + * task file register access. + * 28 28 UDMA enable. + * 29 29 DMA enable. + * 30 30 PIO MST enable. If set, the chip is in bus master mode during + * PIO xfer. + * 31 31 FIFO enable. + */ + +static u32 forty_base_hpt36x[] = { + /* XFER_UDMA_6 */ 0x900fd943, + /* XFER_UDMA_5 */ 0x900fd943, + /* XFER_UDMA_4 */ 0x900fd943, + /* XFER_UDMA_3 */ 0x900ad943, + /* XFER_UDMA_2 */ 0x900bd943, + /* XFER_UDMA_1 */ 0x9008d943, + /* XFER_UDMA_0 */ 0x9008d943, + + /* XFER_MW_DMA_2 */ 0xa008d943, + /* XFER_MW_DMA_1 */ 0xa010d955, + /* XFER_MW_DMA_0 */ 0xa010d9fc, + + /* XFER_PIO_4 */ 0xc008d963, + /* XFER_PIO_3 */ 0xc010d974, + /* XFER_PIO_2 */ 0xc010d997, + /* XFER_PIO_1 */ 0xc010d9c7, + /* XFER_PIO_0 */ 0xc018d9d9 +}; + +static u32 thirty_three_base_hpt36x[] = { + /* XFER_UDMA_6 */ 0x90c9a731, + /* XFER_UDMA_5 */ 0x90c9a731, + /* XFER_UDMA_4 */ 0x90c9a731, + /* XFER_UDMA_3 */ 0x90cfa731, + /* XFER_UDMA_2 */ 0x90caa731, + /* XFER_UDMA_1 */ 0x90cba731, + /* XFER_UDMA_0 */ 0x90c8a731, + + /* XFER_MW_DMA_2 */ 0xa0c8a731, + /* XFER_MW_DMA_1 */ 0xa0c8a732, /* 0xa0c8a733 */ + /* XFER_MW_DMA_0 */ 0xa0c8a797, + + /* XFER_PIO_4 */ 0xc0c8a731, + /* XFER_PIO_3 */ 0xc0c8a742, + /* XFER_PIO_2 */ 0xc0d0a753, + /* XFER_PIO_1 */ 0xc0d0a7a3, /* 0xc0d0a793 */ + /* XFER_PIO_0 */ 0xc0d0a7aa /* 0xc0d0a7a7 */ +}; + +static u32 twenty_five_base_hpt36x[] = { + /* XFER_UDMA_6 */ 0x90c98521, + /* XFER_UDMA_5 */ 0x90c98521, + /* XFER_UDMA_4 */ 0x90c98521, + /* XFER_UDMA_3 */ 0x90cf8521, + /* XFER_UDMA_2 */ 0x90cf8521, + /* XFER_UDMA_1 */ 0x90cb8521, + /* XFER_UDMA_0 */ 0x90cb8521, + + /* XFER_MW_DMA_2 */ 0xa0ca8521, + /* XFER_MW_DMA_1 */ 0xa0ca8532, + /* XFER_MW_DMA_0 */ 0xa0ca8575, + + /* XFER_PIO_4 */ 0xc0ca8521, + /* XFER_PIO_3 */ 0xc0ca8532, + /* XFER_PIO_2 */ 0xc0ca8542, + /* XFER_PIO_1 */ 0xc0d08572, + /* XFER_PIO_0 */ 0xc0d08585 +}; + +/* + * The following are the new timing tables with PIO mode data/taskfile transfer + * overclocking fixed... + */ + +/* This table is taken from the HPT370 data manual rev. 1.02 */ +static u32 thirty_three_base_hpt37x[] = { + /* XFER_UDMA_6 */ 0x16455031, /* 0x16655031 ?? */ + /* XFER_UDMA_5 */ 0x16455031, + /* XFER_UDMA_4 */ 0x16455031, + /* XFER_UDMA_3 */ 0x166d5031, + /* XFER_UDMA_2 */ 0x16495031, + /* XFER_UDMA_1 */ 0x164d5033, + /* XFER_UDMA_0 */ 0x16515097, + + /* XFER_MW_DMA_2 */ 0x26515031, + /* XFER_MW_DMA_1 */ 0x26515033, + /* XFER_MW_DMA_0 */ 0x26515097, + + /* XFER_PIO_4 */ 0x06515021, + /* XFER_PIO_3 */ 0x06515022, + /* XFER_PIO_2 */ 0x06515033, + /* XFER_PIO_1 */ 0x06915065, + /* XFER_PIO_0 */ 0x06d1508a +}; + +static u32 fifty_base_hpt37x[] = { + /* XFER_UDMA_6 */ 0x1a861842, + /* XFER_UDMA_5 */ 0x1a861842, + /* XFER_UDMA_4 */ 0x1aae1842, + /* XFER_UDMA_3 */ 0x1a8e1842, + /* XFER_UDMA_2 */ 0x1a0e1842, + /* XFER_UDMA_1 */ 0x1a161854, + /* XFER_UDMA_0 */ 0x1a1a18ea, + + /* XFER_MW_DMA_2 */ 0x2a821842, + /* XFER_MW_DMA_1 */ 0x2a821854, + /* XFER_MW_DMA_0 */ 0x2a8218ea, + + /* XFER_PIO_4 */ 0x0a821842, + /* XFER_PIO_3 */ 0x0a821843, + /* XFER_PIO_2 */ 0x0a821855, + /* XFER_PIO_1 */ 0x0ac218a8, + /* XFER_PIO_0 */ 0x0b02190c +}; + +static u32 sixty_six_base_hpt37x[] = { + /* XFER_UDMA_6 */ 0x1c86fe62, + /* XFER_UDMA_5 */ 0x1caefe62, /* 0x1c8afe62 */ + /* XFER_UDMA_4 */ 0x1c8afe62, + /* XFER_UDMA_3 */ 0x1c8efe62, + /* XFER_UDMA_2 */ 0x1c92fe62, + /* XFER_UDMA_1 */ 0x1c9afe62, + /* XFER_UDMA_0 */ 0x1c82fe62, + + /* XFER_MW_DMA_2 */ 0x2c82fe62, + /* XFER_MW_DMA_1 */ 0x2c82fe66, + /* XFER_MW_DMA_0 */ 0x2c82ff2e, + + /* XFER_PIO_4 */ 0x0c82fe62, + /* XFER_PIO_3 */ 0x0c82fe84, + /* XFER_PIO_2 */ 0x0c82fea6, + /* XFER_PIO_1 */ 0x0d02ff26, + /* XFER_PIO_0 */ 0x0d42ff7f +}; + +#define HPT371_ALLOW_ATA133_6 1 +#define HPT302_ALLOW_ATA133_6 1 +#define HPT372_ALLOW_ATA133_6 1 +#define HPT370_ALLOW_ATA100_5 0 +#define HPT366_ALLOW_ATA66_4 1 +#define HPT366_ALLOW_ATA66_3 1 + +/* Supported ATA clock frequencies */ +enum ata_clock { + ATA_CLOCK_25MHZ, + ATA_CLOCK_33MHZ, + ATA_CLOCK_40MHZ, + ATA_CLOCK_50MHZ, + ATA_CLOCK_66MHZ, + NUM_ATA_CLOCKS +}; + +struct hpt_timings { + u32 pio_mask; + u32 dma_mask; + u32 ultra_mask; + u32 *clock_table[NUM_ATA_CLOCKS]; +}; + +/* + * Hold all the HighPoint chip information in one place. + */ + +struct hpt_info { + char *chip_name; /* Chip name */ + u8 chip_type; /* Chip type */ + u8 udma_mask; /* Allowed UltraDMA modes mask. */ + u8 dpll_clk; /* DPLL clock in MHz */ + u8 pci_clk; /* PCI clock in MHz */ + struct hpt_timings *timings; /* Chipset timing data */ + u8 clock; /* ATA clock selected */ +}; + +/* Supported HighPoint chips */ +enum { + HPT36x, + HPT370, + HPT370A, + HPT374, + HPT372, + HPT372A, + HPT302, + HPT371, + HPT372N, + HPT302N, + HPT371N +}; + +static struct hpt_timings hpt36x_timings = { + .pio_mask = 0xc1f8ffff, + .dma_mask = 0x303800ff, + .ultra_mask = 0x30070000, + .clock_table = { + [ATA_CLOCK_25MHZ] = twenty_five_base_hpt36x, + [ATA_CLOCK_33MHZ] = thirty_three_base_hpt36x, + [ATA_CLOCK_40MHZ] = forty_base_hpt36x, + [ATA_CLOCK_50MHZ] = NULL, + [ATA_CLOCK_66MHZ] = NULL + } +}; + +static struct hpt_timings hpt37x_timings = { + .pio_mask = 0xcfc3ffff, + .dma_mask = 0x31c001ff, + .ultra_mask = 0x303c0000, + .clock_table = { + [ATA_CLOCK_25MHZ] = NULL, + [ATA_CLOCK_33MHZ] = thirty_three_base_hpt37x, + [ATA_CLOCK_40MHZ] = NULL, + [ATA_CLOCK_50MHZ] = fifty_base_hpt37x, + [ATA_CLOCK_66MHZ] = sixty_six_base_hpt37x + } +}; + +static const struct hpt_info hpt36x = { + .chip_name = "HPT36x", + .chip_type = HPT36x, + .udma_mask = HPT366_ALLOW_ATA66_3 ? (HPT366_ALLOW_ATA66_4 ? ATA_UDMA4 : ATA_UDMA3) : ATA_UDMA2, + .dpll_clk = 0, /* no DPLL */ + .timings = &hpt36x_timings +}; + +static const struct hpt_info hpt370 = { + .chip_name = "HPT370", + .chip_type = HPT370, + .udma_mask = HPT370_ALLOW_ATA100_5 ? ATA_UDMA5 : ATA_UDMA4, + .dpll_clk = 48, + .timings = &hpt37x_timings +}; + +static const struct hpt_info hpt370a = { + .chip_name = "HPT370A", + .chip_type = HPT370A, + .udma_mask = HPT370_ALLOW_ATA100_5 ? ATA_UDMA5 : ATA_UDMA4, + .dpll_clk = 48, + .timings = &hpt37x_timings +}; + +static const struct hpt_info hpt374 = { + .chip_name = "HPT374", + .chip_type = HPT374, + .udma_mask = ATA_UDMA5, + .dpll_clk = 48, + .timings = &hpt37x_timings +}; + +static const struct hpt_info hpt372 = { + .chip_name = "HPT372", + .chip_type = HPT372, + .udma_mask = HPT372_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5, + .dpll_clk = 55, + .timings = &hpt37x_timings +}; + +static const struct hpt_info hpt372a = { + .chip_name = "HPT372A", + .chip_type = HPT372A, + .udma_mask = HPT372_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5, + .dpll_clk = 66, + .timings = &hpt37x_timings +}; + +static const struct hpt_info hpt302 = { + .chip_name = "HPT302", + .chip_type = HPT302, + .udma_mask = HPT302_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5, + .dpll_clk = 66, + .timings = &hpt37x_timings +}; + +static const struct hpt_info hpt371 = { + .chip_name = "HPT371", + .chip_type = HPT371, + .udma_mask = HPT371_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5, + .dpll_clk = 66, + .timings = &hpt37x_timings +}; + +static const struct hpt_info hpt372n = { + .chip_name = "HPT372N", + .chip_type = HPT372N, + .udma_mask = HPT372_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5, + .dpll_clk = 77, + .timings = &hpt37x_timings +}; + +static const struct hpt_info hpt302n = { + .chip_name = "HPT302N", + .chip_type = HPT302N, + .udma_mask = HPT302_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5, + .dpll_clk = 77, + .timings = &hpt37x_timings +}; + +static const struct hpt_info hpt371n = { + .chip_name = "HPT371N", + .chip_type = HPT371N, + .udma_mask = HPT371_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5, + .dpll_clk = 77, + .timings = &hpt37x_timings +}; + +static int check_in_drive_list(ide_drive_t *drive, const char **list) +{ + char *m = (char *)&drive->id[ATA_ID_PROD]; + + while (*list) + if (!strcmp(*list++, m)) + return 1; + return 0; +} + +static struct hpt_info *hpt3xx_get_info(struct device *dev) +{ + struct ide_host *host = dev_get_drvdata(dev); + struct hpt_info *info = (struct hpt_info *)host->host_priv; + + return dev == host->dev[1] ? info + 1 : info; +} + +/* + * The Marvell bridge chips used on the HighPoint SATA cards do not seem + * to support the UltraDMA modes 1, 2, and 3 as well as any MWDMA modes... + */ + +static u8 hpt3xx_udma_filter(ide_drive_t *drive) +{ + ide_hwif_t *hwif = drive->hwif; + struct hpt_info *info = hpt3xx_get_info(hwif->dev); + u8 mask = hwif->ultra_mask; + + switch (info->chip_type) { + case HPT36x: + if (!HPT366_ALLOW_ATA66_4 || + check_in_drive_list(drive, bad_ata66_4)) + mask = ATA_UDMA3; + + if (!HPT366_ALLOW_ATA66_3 || + check_in_drive_list(drive, bad_ata66_3)) + mask = ATA_UDMA2; + break; + case HPT370: + if (!HPT370_ALLOW_ATA100_5 || + check_in_drive_list(drive, bad_ata100_5)) + mask = ATA_UDMA4; + break; + case HPT370A: + if (!HPT370_ALLOW_ATA100_5 || + check_in_drive_list(drive, bad_ata100_5)) + return ATA_UDMA4; + case HPT372 : + case HPT372A: + case HPT372N: + case HPT374 : + if (ata_id_is_sata(drive->id)) + mask &= ~0x0e; + /* Fall thru */ + default: + return mask; + } + + return check_in_drive_list(drive, bad_ata33) ? 0x00 : mask; +} + +static u8 hpt3xx_mdma_filter(ide_drive_t *drive) +{ + ide_hwif_t *hwif = drive->hwif; + struct hpt_info *info = hpt3xx_get_info(hwif->dev); + + switch (info->chip_type) { + case HPT372 : + case HPT372A: + case HPT372N: + case HPT374 : + if (ata_id_is_sata(drive->id)) + return 0x00; + /* Fall thru */ + default: + return 0x07; + } +} + +static u32 get_speed_setting(u8 speed, struct hpt_info *info) +{ + int i; + + /* + * Lookup the transfer mode table to get the index into + * the timing table. + * + * NOTE: For XFER_PIO_SLOW, PIO mode 0 timings will be used. + */ + for (i = 0; i < ARRAY_SIZE(xfer_speeds) - 1; i++) + if (xfer_speeds[i] == speed) + break; + + return info->timings->clock_table[info->clock][i]; +} + +static void hpt3xx_set_mode(ide_hwif_t *hwif, ide_drive_t *drive) +{ + struct pci_dev *dev = to_pci_dev(hwif->dev); + struct hpt_info *info = hpt3xx_get_info(hwif->dev); + struct hpt_timings *t = info->timings; + u8 itr_addr = 0x40 + (drive->dn * 4); + u32 old_itr = 0; + const u8 speed = drive->dma_mode; + u32 new_itr = get_speed_setting(speed, info); + u32 itr_mask = speed < XFER_MW_DMA_0 ? t->pio_mask : + (speed < XFER_UDMA_0 ? t->dma_mask : + t->ultra_mask); + + pci_read_config_dword(dev, itr_addr, &old_itr); + new_itr = (old_itr & ~itr_mask) | (new_itr & itr_mask); + /* + * Disable on-chip PIO FIFO/buffer (and PIO MST mode as well) + * to avoid problems handling I/O errors later + */ + new_itr &= ~0xc0000000; + + pci_write_config_dword(dev, itr_addr, new_itr); +} + +static void hpt3xx_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) +{ + drive->dma_mode = drive->pio_mode; + hpt3xx_set_mode(hwif, drive); +} + +static void hpt3xx_maskproc(ide_drive_t *drive, int mask) +{ + ide_hwif_t *hwif = drive->hwif; + struct pci_dev *dev = to_pci_dev(hwif->dev); + struct hpt_info *info = hpt3xx_get_info(hwif->dev); + + if ((drive->dev_flags & IDE_DFLAG_NIEN_QUIRK) == 0) + return; + + if (info->chip_type >= HPT370) { + u8 scr1 = 0; + + pci_read_config_byte(dev, 0x5a, &scr1); + if (((scr1 & 0x10) >> 4) != mask) { + if (mask) + scr1 |= 0x10; + else + scr1 &= ~0x10; + pci_write_config_byte(dev, 0x5a, scr1); + } + } else if (mask) + disable_irq(hwif->irq); + else + enable_irq(hwif->irq); +} + +/* + * This is specific to the HPT366 UDMA chipset + * by HighPoint|Triones Technologies, Inc. + */ +static void hpt366_dma_lost_irq(ide_drive_t *drive) +{ + struct pci_dev *dev = to_pci_dev(drive->hwif->dev); + u8 mcr1 = 0, mcr3 = 0, scr1 = 0; + + pci_read_config_byte(dev, 0x50, &mcr1); + pci_read_config_byte(dev, 0x52, &mcr3); + pci_read_config_byte(dev, 0x5a, &scr1); + printk("%s: (%s) mcr1=0x%02x, mcr3=0x%02x, scr1=0x%02x\n", + drive->name, __func__, mcr1, mcr3, scr1); + if (scr1 & 0x10) + pci_write_config_byte(dev, 0x5a, scr1 & ~0x10); + ide_dma_lost_irq(drive); +} + +static void hpt370_clear_engine(ide_drive_t *drive) +{ + ide_hwif_t *hwif = drive->hwif; + struct pci_dev *dev = to_pci_dev(hwif->dev); + + pci_write_config_byte(dev, hwif->select_data, 0x37); + udelay(10); +} + +static void hpt370_irq_timeout(ide_drive_t *drive) +{ + ide_hwif_t *hwif = drive->hwif; + struct pci_dev *dev = to_pci_dev(hwif->dev); + u16 bfifo = 0; + u8 dma_cmd; + + pci_read_config_word(dev, hwif->select_data + 2, &bfifo); + printk(KERN_DEBUG "%s: %d bytes in FIFO\n", drive->name, bfifo & 0x1ff); + + /* get DMA command mode */ + dma_cmd = inb(hwif->dma_base + ATA_DMA_CMD); + /* stop DMA */ + outb(dma_cmd & ~ATA_DMA_START, hwif->dma_base + ATA_DMA_CMD); + hpt370_clear_engine(drive); +} + +static void hpt370_dma_start(ide_drive_t *drive) +{ +#ifdef HPT_RESET_STATE_ENGINE + hpt370_clear_engine(drive); +#endif + ide_dma_start(drive); +} + +static int hpt370_dma_end(ide_drive_t *drive) +{ + ide_hwif_t *hwif = drive->hwif; + u8 dma_stat = inb(hwif->dma_base + ATA_DMA_STATUS); + + if (dma_stat & ATA_DMA_ACTIVE) { + /* wait a little */ + udelay(20); + dma_stat = inb(hwif->dma_base + ATA_DMA_STATUS); + if (dma_stat & ATA_DMA_ACTIVE) + hpt370_irq_timeout(drive); + } + return ide_dma_end(drive); +} + +/* returns 1 if DMA IRQ issued, 0 otherwise */ +static int hpt374_dma_test_irq(ide_drive_t *drive) +{ + ide_hwif_t *hwif = drive->hwif; + struct pci_dev *dev = to_pci_dev(hwif->dev); + u16 bfifo = 0; + u8 dma_stat; + + pci_read_config_word(dev, hwif->select_data + 2, &bfifo); + if (bfifo & 0x1FF) { +// printk("%s: %d bytes in FIFO\n", drive->name, bfifo); + return 0; + } + + dma_stat = inb(hwif->dma_base + ATA_DMA_STATUS); + /* return 1 if INTR asserted */ + if (dma_stat & ATA_DMA_INTR) + return 1; + + return 0; +} + +static int hpt374_dma_end(ide_drive_t *drive) +{ + ide_hwif_t *hwif = drive->hwif; + struct pci_dev *dev = to_pci_dev(hwif->dev); + u8 mcr = 0, mcr_addr = hwif->select_data; + u8 bwsr = 0, mask = hwif->channel ? 0x02 : 0x01; + + pci_read_config_byte(dev, 0x6a, &bwsr); + pci_read_config_byte(dev, mcr_addr, &mcr); + if (bwsr & mask) + pci_write_config_byte(dev, mcr_addr, mcr | 0x30); + return ide_dma_end(drive); +} + +/** + * hpt3xxn_set_clock - perform clock switching dance + * @hwif: hwif to switch + * @mode: clocking mode (0x21 for write, 0x23 otherwise) + * + * Switch the DPLL clock on the HPT3xxN devices. This is a right mess. + */ + +static void hpt3xxn_set_clock(ide_hwif_t *hwif, u8 mode) +{ + unsigned long base = hwif->extra_base; + u8 scr2 = inb(base + 0x6b); + + if ((scr2 & 0x7f) == mode) + return; + + /* Tristate the bus */ + outb(0x80, base + 0x63); + outb(0x80, base + 0x67); + + /* Switch clock and reset channels */ + outb(mode, base + 0x6b); + outb(0xc0, base + 0x69); + + /* + * Reset the state machines. + * NOTE: avoid accidentally enabling the disabled channels. + */ + outb(inb(base + 0x60) | 0x32, base + 0x60); + outb(inb(base + 0x64) | 0x32, base + 0x64); + + /* Complete reset */ + outb(0x00, base + 0x69); + + /* Reconnect channels to bus */ + outb(0x00, base + 0x63); + outb(0x00, base + 0x67); +} + +/** + * hpt3xxn_rw_disk - prepare for I/O + * @drive: drive for command + * @rq: block request structure + * + * This is called when a disk I/O is issued to HPT3xxN. + * We need it because of the clock switching. + */ + +static void hpt3xxn_rw_disk(ide_drive_t *drive, struct request *rq) +{ + hpt3xxn_set_clock(drive->hwif, rq_data_dir(rq) ? 0x21 : 0x23); +} + +/** + * hpt37x_calibrate_dpll - calibrate the DPLL + * @dev: PCI device + * + * Perform a calibration cycle on the DPLL. + * Returns 1 if this succeeds + */ +static int hpt37x_calibrate_dpll(struct pci_dev *dev, u16 f_low, u16 f_high) +{ + u32 dpll = (f_high << 16) | f_low | 0x100; + u8 scr2; + int i; + + pci_write_config_dword(dev, 0x5c, dpll); + + /* Wait for oscillator ready */ + for(i = 0; i < 0x5000; ++i) { + udelay(50); + pci_read_config_byte(dev, 0x5b, &scr2); + if (scr2 & 0x80) + break; + } + /* See if it stays ready (we'll just bail out if it's not yet) */ + for(i = 0; i < 0x1000; ++i) { + pci_read_config_byte(dev, 0x5b, &scr2); + /* DPLL destabilized? */ + if(!(scr2 & 0x80)) + return 0; + } + /* Turn off tuning, we have the DPLL set */ + pci_read_config_dword (dev, 0x5c, &dpll); + pci_write_config_dword(dev, 0x5c, (dpll & ~0x100)); + return 1; +} + +static void hpt3xx_disable_fast_irq(struct pci_dev *dev, u8 mcr_addr) +{ + struct ide_host *host = pci_get_drvdata(dev); + struct hpt_info *info = host->host_priv + (&dev->dev == host->dev[1]); + u8 chip_type = info->chip_type; + u8 new_mcr, old_mcr = 0; + + /* + * Disable the "fast interrupt" prediction. Don't hold off + * on interrupts. (== 0x01 despite what the docs say) + */ + pci_read_config_byte(dev, mcr_addr + 1, &old_mcr); + + if (chip_type >= HPT374) + new_mcr = old_mcr & ~0x07; + else if (chip_type >= HPT370) { + new_mcr = old_mcr; + new_mcr &= ~0x02; +#ifdef HPT_DELAY_INTERRUPT + new_mcr &= ~0x01; +#else + new_mcr |= 0x01; +#endif + } else /* HPT366 and HPT368 */ + new_mcr = old_mcr & ~0x80; + + if (new_mcr != old_mcr) + pci_write_config_byte(dev, mcr_addr + 1, new_mcr); +} + +static int init_chipset_hpt366(struct pci_dev *dev) +{ + unsigned long io_base = pci_resource_start(dev, 4); + struct hpt_info *info = hpt3xx_get_info(&dev->dev); + const char *name = DRV_NAME; + u8 pci_clk, dpll_clk = 0; /* PCI and DPLL clock in MHz */ + u8 chip_type; + enum ata_clock clock; + + chip_type = info->chip_type; + + pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, (L1_CACHE_BYTES / 4)); + pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x78); + pci_write_config_byte(dev, PCI_MIN_GNT, 0x08); + pci_write_config_byte(dev, PCI_MAX_LAT, 0x08); + + /* + * First, try to estimate the PCI clock frequency... + */ + if (chip_type >= HPT370) { + u8 scr1 = 0; + u16 f_cnt = 0; + u32 temp = 0; + + /* Interrupt force enable. */ + pci_read_config_byte(dev, 0x5a, &scr1); + if (scr1 & 0x10) + pci_write_config_byte(dev, 0x5a, scr1 & ~0x10); + + /* + * HighPoint does this for HPT372A. + * NOTE: This register is only writeable via I/O space. + */ + if (chip_type == HPT372A) + outb(0x0e, io_base + 0x9c); + + /* + * Default to PCI clock. Make sure MA15/16 are set to output + * to prevent drives having problems with 40-pin cables. + */ + pci_write_config_byte(dev, 0x5b, 0x23); + + /* + * We'll have to read f_CNT value in order to determine + * the PCI clock frequency according to the following ratio: + * + * f_CNT = Fpci * 192 / Fdpll + * + * First try reading the register in which the HighPoint BIOS + * saves f_CNT value before reprogramming the DPLL from its + * default setting (which differs for the various chips). + * + * NOTE: This register is only accessible via I/O space; + * HPT374 BIOS only saves it for the function 0, so we have to + * always read it from there -- no need to check the result of + * pci_get_slot() for the function 0 as the whole device has + * been already "pinned" (via function 1) in init_setup_hpt374() + */ + if (chip_type == HPT374 && (PCI_FUNC(dev->devfn) & 1)) { + struct pci_dev *dev1 = pci_get_slot(dev->bus, + dev->devfn - 1); + unsigned long io_base = pci_resource_start(dev1, 4); + + temp = inl(io_base + 0x90); + pci_dev_put(dev1); + } else + temp = inl(io_base + 0x90); + + /* + * In case the signature check fails, we'll have to + * resort to reading the f_CNT register itself in hopes + * that nobody has touched the DPLL yet... + */ + if ((temp & 0xFFFFF000) != 0xABCDE000) { + int i; + + printk(KERN_WARNING "%s %s: no clock data saved by " + "BIOS\n", name, pci_name(dev)); + + /* Calculate the average value of f_CNT. */ + for (temp = i = 0; i < 128; i++) { + pci_read_config_word(dev, 0x78, &f_cnt); + temp += f_cnt & 0x1ff; + mdelay(1); + } + f_cnt = temp / 128; + } else + f_cnt = temp & 0x1ff; + + dpll_clk = info->dpll_clk; + pci_clk = (f_cnt * dpll_clk) / 192; + + /* Clamp PCI clock to bands. */ + if (pci_clk < 40) + pci_clk = 33; + else if(pci_clk < 45) + pci_clk = 40; + else if(pci_clk < 55) + pci_clk = 50; + else + pci_clk = 66; + + printk(KERN_INFO "%s %s: DPLL base: %d MHz, f_CNT: %d, " + "assuming %d MHz PCI\n", name, pci_name(dev), + dpll_clk, f_cnt, pci_clk); + } else { + u32 itr1 = 0; + + pci_read_config_dword(dev, 0x40, &itr1); + + /* Detect PCI clock by looking at cmd_high_time. */ + switch((itr1 >> 8) & 0x07) { + case 0x09: + pci_clk = 40; + break; + case 0x05: + pci_clk = 25; + break; + case 0x07: + default: + pci_clk = 33; + break; + } + } + + /* Let's assume we'll use PCI clock for the ATA clock... */ + switch (pci_clk) { + case 25: + clock = ATA_CLOCK_25MHZ; + break; + case 33: + default: + clock = ATA_CLOCK_33MHZ; + break; + case 40: + clock = ATA_CLOCK_40MHZ; + break; + case 50: + clock = ATA_CLOCK_50MHZ; + break; + case 66: + clock = ATA_CLOCK_66MHZ; + break; + } + + /* + * Only try the DPLL if we don't have a table for the PCI clock that + * we are running at for HPT370/A, always use it for anything newer... + * + * NOTE: Using the internal DPLL results in slow reads on 33 MHz PCI. + * We also don't like using the DPLL because this causes glitches + * on PRST-/SRST- when the state engine gets reset... + */ + if (chip_type >= HPT374 || info->timings->clock_table[clock] == NULL) { + u16 f_low, delta = pci_clk < 50 ? 2 : 4; + int adjust; + + /* + * Select 66 MHz DPLL clock only if UltraATA/133 mode is + * supported/enabled, use 50 MHz DPLL clock otherwise... + */ + if (info->udma_mask == ATA_UDMA6) { + dpll_clk = 66; + clock = ATA_CLOCK_66MHZ; + } else if (dpll_clk) { /* HPT36x chips don't have DPLL */ + dpll_clk = 50; + clock = ATA_CLOCK_50MHZ; + } + + if (info->timings->clock_table[clock] == NULL) { + printk(KERN_ERR "%s %s: unknown bus timing!\n", + name, pci_name(dev)); + return -EIO; + } + + /* Select the DPLL clock. */ + pci_write_config_byte(dev, 0x5b, 0x21); + + /* + * Adjust the DPLL based upon PCI clock, enable it, + * and wait for stabilization... + */ + f_low = (pci_clk * 48) / dpll_clk; + + for (adjust = 0; adjust < 8; adjust++) { + if(hpt37x_calibrate_dpll(dev, f_low, f_low + delta)) + break; + + /* + * See if it'll settle at a fractionally different clock + */ + if (adjust & 1) + f_low -= adjust >> 1; + else + f_low += adjust >> 1; + } + if (adjust == 8) { + printk(KERN_ERR "%s %s: DPLL did not stabilize!\n", + name, pci_name(dev)); + return -EIO; + } + + printk(KERN_INFO "%s %s: using %d MHz DPLL clock\n", + name, pci_name(dev), dpll_clk); + } else { + /* Mark the fact that we're not using the DPLL. */ + dpll_clk = 0; + + printk(KERN_INFO "%s %s: using %d MHz PCI clock\n", + name, pci_name(dev), pci_clk); + } + + /* Store the clock frequencies. */ + info->dpll_clk = dpll_clk; + info->pci_clk = pci_clk; + info->clock = clock; + + if (chip_type >= HPT370) { + u8 mcr1, mcr4; + + /* + * Reset the state engines. + * NOTE: Avoid accidentally enabling the disabled channels. + */ + pci_read_config_byte (dev, 0x50, &mcr1); + pci_read_config_byte (dev, 0x54, &mcr4); + pci_write_config_byte(dev, 0x50, (mcr1 | 0x32)); + pci_write_config_byte(dev, 0x54, (mcr4 | 0x32)); + udelay(100); + } + + /* + * On HPT371N, if ATA clock is 66 MHz we must set bit 2 in + * the MISC. register to stretch the UltraDMA Tss timing. + * NOTE: This register is only writeable via I/O space. + */ + if (chip_type == HPT371N && clock == ATA_CLOCK_66MHZ) + outb(inb(io_base + 0x9c) | 0x04, io_base + 0x9c); + + hpt3xx_disable_fast_irq(dev, 0x50); + hpt3xx_disable_fast_irq(dev, 0x54); + + return 0; +} + +static u8 hpt3xx_cable_detect(ide_hwif_t *hwif) +{ + struct pci_dev *dev = to_pci_dev(hwif->dev); + struct hpt_info *info = hpt3xx_get_info(hwif->dev); + u8 chip_type = info->chip_type; + u8 scr1 = 0, ata66 = hwif->channel ? 0x01 : 0x02; + + /* + * The HPT37x uses the CBLID pins as outputs for MA15/MA16 + * address lines to access an external EEPROM. To read valid + * cable detect state the pins must be enabled as inputs. + */ + if (chip_type == HPT374 && (PCI_FUNC(dev->devfn) & 1)) { + /* + * HPT374 PCI function 1 + * - set bit 15 of reg 0x52 to enable TCBLID as input + * - set bit 15 of reg 0x56 to enable FCBLID as input + */ + u8 mcr_addr = hwif->select_data + 2; + u16 mcr; + + pci_read_config_word(dev, mcr_addr, &mcr); + pci_write_config_word(dev, mcr_addr, mcr | 0x8000); + /* Debounce, then read cable ID register */ + udelay(10); + pci_read_config_byte(dev, 0x5a, &scr1); + pci_write_config_word(dev, mcr_addr, mcr); + } else if (chip_type >= HPT370) { + /* + * HPT370/372 and 374 pcifn 0 + * - clear bit 0 of reg 0x5b to enable P/SCBLID as inputs + */ + u8 scr2 = 0; + + pci_read_config_byte(dev, 0x5b, &scr2); + pci_write_config_byte(dev, 0x5b, scr2 & ~1); + /* Debounce, then read cable ID register */ + udelay(10); + pci_read_config_byte(dev, 0x5a, &scr1); + pci_write_config_byte(dev, 0x5b, scr2); + } else + pci_read_config_byte(dev, 0x5a, &scr1); + + return (scr1 & ata66) ? ATA_CBL_PATA40 : ATA_CBL_PATA80; +} + +static void init_hwif_hpt366(ide_hwif_t *hwif) +{ + struct hpt_info *info = hpt3xx_get_info(hwif->dev); + u8 chip_type = info->chip_type; + + /* Cache the channel's MISC. control registers' offset */ + hwif->select_data = hwif->channel ? 0x54 : 0x50; + + /* + * HPT3xxN chips have some complications: + * + * - on 33 MHz PCI we must clock switch + * - on 66 MHz PCI we must NOT use the PCI clock + */ + if (chip_type >= HPT372N && info->dpll_clk && info->pci_clk < 66) { + /* + * Clock is shared between the channels, + * so we'll have to serialize them... :-( + */ + hwif->host->host_flags |= IDE_HFLAG_SERIALIZE; + hwif->rw_disk = &hpt3xxn_rw_disk; + } +} + +static int init_dma_hpt366(ide_hwif_t *hwif, + const struct ide_port_info *d) +{ + struct pci_dev *dev = to_pci_dev(hwif->dev); + unsigned long flags, base = ide_pci_dma_base(hwif, d); + u8 dma_old, dma_new, masterdma = 0, slavedma = 0; + + if (base == 0) + return -1; + + hwif->dma_base = base; + + if (ide_pci_check_simplex(hwif, d) < 0) + return -1; + + if (ide_pci_set_master(dev, d->name) < 0) + return -1; + + dma_old = inb(base + 2); + + local_irq_save(flags); + + dma_new = dma_old; + pci_read_config_byte(dev, hwif->channel ? 0x4b : 0x43, &masterdma); + pci_read_config_byte(dev, hwif->channel ? 0x4f : 0x47, &slavedma); + + if (masterdma & 0x30) dma_new |= 0x20; + if ( slavedma & 0x30) dma_new |= 0x40; + if (dma_new != dma_old) + outb(dma_new, base + 2); + + local_irq_restore(flags); + + printk(KERN_INFO " %s: BM-DMA at 0x%04lx-0x%04lx\n", + hwif->name, base, base + 7); + + hwif->extra_base = base + (hwif->channel ? 8 : 16); + + if (ide_allocate_dma_engine(hwif)) + return -1; + + return 0; +} + +static void hpt374_init(struct pci_dev *dev, struct pci_dev *dev2) +{ + if (dev2->irq != dev->irq) { + /* FIXME: we need a core pci_set_interrupt() */ + dev2->irq = dev->irq; + printk(KERN_INFO DRV_NAME " %s: PCI config space interrupt " + "fixed\n", pci_name(dev2)); + } +} + +static void hpt371_init(struct pci_dev *dev) +{ + u8 mcr1 = 0; + + /* + * HPT371 chips physically have only one channel, the secondary one, + * but the primary channel registers do exist! Go figure... + * So, we manually disable the non-existing channel here + * (if the BIOS hasn't done this already). + */ + pci_read_config_byte(dev, 0x50, &mcr1); + if (mcr1 & 0x04) + pci_write_config_byte(dev, 0x50, mcr1 & ~0x04); +} + +static int hpt36x_init(struct pci_dev *dev, struct pci_dev *dev2) +{ + u8 mcr1 = 0, pin1 = 0, pin2 = 0; + + /* + * Now we'll have to force both channels enabled if + * at least one of them has been enabled by BIOS... + */ + pci_read_config_byte(dev, 0x50, &mcr1); + if (mcr1 & 0x30) + pci_write_config_byte(dev, 0x50, mcr1 | 0x30); + + pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin1); + pci_read_config_byte(dev2, PCI_INTERRUPT_PIN, &pin2); + + if (pin1 != pin2 && dev->irq == dev2->irq) { + printk(KERN_INFO DRV_NAME " %s: onboard version of chipset, " + "pin1=%d pin2=%d\n", pci_name(dev), pin1, pin2); + return 1; + } + + return 0; +} + +#define IDE_HFLAGS_HPT3XX \ + (IDE_HFLAG_NO_ATAPI_DMA | \ + IDE_HFLAG_OFF_BOARD) + +static const struct ide_port_ops hpt3xx_port_ops = { + .set_pio_mode = hpt3xx_set_pio_mode, + .set_dma_mode = hpt3xx_set_mode, + .maskproc = hpt3xx_maskproc, + .mdma_filter = hpt3xx_mdma_filter, + .udma_filter = hpt3xx_udma_filter, + .cable_detect = hpt3xx_cable_detect, +}; + +static const struct ide_dma_ops hpt37x_dma_ops = { + .dma_host_set = ide_dma_host_set, + .dma_setup = ide_dma_setup, + .dma_start = ide_dma_start, + .dma_end = hpt374_dma_end, + .dma_test_irq = hpt374_dma_test_irq, + .dma_lost_irq = ide_dma_lost_irq, + .dma_timer_expiry = ide_dma_sff_timer_expiry, + .dma_sff_read_status = ide_dma_sff_read_status, +}; + +static const struct ide_dma_ops hpt370_dma_ops = { + .dma_host_set = ide_dma_host_set, + .dma_setup = ide_dma_setup, + .dma_start = hpt370_dma_start, + .dma_end = hpt370_dma_end, + .dma_test_irq = ide_dma_test_irq, + .dma_lost_irq = ide_dma_lost_irq, + .dma_timer_expiry = ide_dma_sff_timer_expiry, + .dma_clear = hpt370_irq_timeout, + .dma_sff_read_status = ide_dma_sff_read_status, +}; + +static const struct ide_dma_ops hpt36x_dma_ops = { + .dma_host_set = ide_dma_host_set, + .dma_setup = ide_dma_setup, + .dma_start = ide_dma_start, + .dma_end = ide_dma_end, + .dma_test_irq = ide_dma_test_irq, + .dma_lost_irq = hpt366_dma_lost_irq, + .dma_timer_expiry = ide_dma_sff_timer_expiry, + .dma_sff_read_status = ide_dma_sff_read_status, +}; + +static const struct ide_port_info hpt366_chipsets[] = { + { /* 0: HPT36x */ + .name = DRV_NAME, + .init_chipset = init_chipset_hpt366, + .init_hwif = init_hwif_hpt366, + .init_dma = init_dma_hpt366, + /* + * HPT36x chips have one channel per function and have + * both channel enable bits located differently and visible + * to both functions -- really stupid design decision... :-( + * Bit 4 is for the primary channel, bit 5 for the secondary. + */ + .enablebits = {{0x50,0x10,0x10}, {0x54,0x04,0x04}}, + .port_ops = &hpt3xx_port_ops, + .dma_ops = &hpt36x_dma_ops, + .host_flags = IDE_HFLAGS_HPT3XX | IDE_HFLAG_SINGLE, + .pio_mask = ATA_PIO4, + .mwdma_mask = ATA_MWDMA2, + }, + { /* 1: HPT3xx */ + .name = DRV_NAME, + .init_chipset = init_chipset_hpt366, + .init_hwif = init_hwif_hpt366, + .init_dma = init_dma_hpt366, + .enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}}, + .port_ops = &hpt3xx_port_ops, + .dma_ops = &hpt37x_dma_ops, + .host_flags = IDE_HFLAGS_HPT3XX, + .pio_mask = ATA_PIO4, + .mwdma_mask = ATA_MWDMA2, + } +}; + +/** + * hpt366_init_one - called when an HPT366 is found + * @dev: the hpt366 device + * @id: the matching pci id + * + * Called when the PCI registration layer (or the IDE initialization) + * finds a device matching our IDE device tables. + */ +static int hpt366_init_one(struct pci_dev *dev, const struct pci_device_id *id) +{ + const struct hpt_info *info = NULL; + struct hpt_info *dyn_info; + struct pci_dev *dev2 = NULL; + struct ide_port_info d; + u8 idx = id->driver_data; + u8 rev = dev->revision; + int ret; + + if ((idx == 0 || idx == 4) && (PCI_FUNC(dev->devfn) & 1)) + return -ENODEV; + + switch (idx) { + case 0: + if (rev < 3) + info = &hpt36x; + else { + switch (min_t(u8, rev, 6)) { + case 3: info = &hpt370; break; + case 4: info = &hpt370a; break; + case 5: info = &hpt372; break; + case 6: info = &hpt372n; break; + } + idx++; + } + break; + case 1: + info = (rev > 1) ? &hpt372n : &hpt372a; + break; + case 2: + info = (rev > 1) ? &hpt302n : &hpt302; + break; + case 3: + hpt371_init(dev); + info = (rev > 1) ? &hpt371n : &hpt371; + break; + case 4: + info = &hpt374; + break; + case 5: + info = &hpt372n; + break; + } + + printk(KERN_INFO DRV_NAME ": %s chipset detected\n", info->chip_name); + + d = hpt366_chipsets[min_t(u8, idx, 1)]; + + d.udma_mask = info->udma_mask; + + /* fixup ->dma_ops for HPT370/HPT370A */ + if (info == &hpt370 || info == &hpt370a) + d.dma_ops = &hpt370_dma_ops; + + if (info == &hpt36x || info == &hpt374) + dev2 = pci_get_slot(dev->bus, dev->devfn + 1); + + dyn_info = kzalloc(sizeof(*dyn_info) * (dev2 ? 2 : 1), GFP_KERNEL); + if (dyn_info == NULL) { + printk(KERN_ERR "%s %s: out of memory!\n", + d.name, pci_name(dev)); + pci_dev_put(dev2); + return -ENOMEM; + } + + /* + * Copy everything from a static "template" structure + * to just allocated per-chip hpt_info structure. + */ + memcpy(dyn_info, info, sizeof(*dyn_info)); + + if (dev2) { + memcpy(dyn_info + 1, info, sizeof(*dyn_info)); + + if (info == &hpt374) + hpt374_init(dev, dev2); + else { + if (hpt36x_init(dev, dev2)) + d.host_flags &= ~IDE_HFLAG_NON_BOOTABLE; + } + + ret = ide_pci_init_two(dev, dev2, &d, dyn_info); + if (ret < 0) { + pci_dev_put(dev2); + kfree(dyn_info); + } + return ret; + } + + ret = ide_pci_init_one(dev, &d, dyn_info); + if (ret < 0) + kfree(dyn_info); + + return ret; +} + +static void hpt366_remove(struct pci_dev *dev) +{ + struct ide_host *host = pci_get_drvdata(dev); + struct ide_info *info = host->host_priv; + struct pci_dev *dev2 = host->dev[1] ? to_pci_dev(host->dev[1]) : NULL; + + ide_pci_remove(dev); + pci_dev_put(dev2); + kfree(info); +} + +static const struct pci_device_id hpt366_pci_tbl[] = { + { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT366), 0 }, + { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT372), 1 }, + { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT302), 2 }, + { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT371), 3 }, + { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT374), 4 }, + { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT372N), 5 }, + { 0, }, +}; +MODULE_DEVICE_TABLE(pci, hpt366_pci_tbl); + +static struct pci_driver hpt366_pci_driver = { + .name = "HPT366_IDE", + .id_table = hpt366_pci_tbl, + .probe = hpt366_init_one, + .remove = hpt366_remove, + .suspend = ide_pci_suspend, + .resume = ide_pci_resume, +}; + +static int __init hpt366_ide_init(void) +{ + return ide_pci_register_driver(&hpt366_pci_driver); +} + +static void __exit hpt366_ide_exit(void) +{ + pci_unregister_driver(&hpt366_pci_driver); +} + +module_init(hpt366_ide_init); +module_exit(hpt366_ide_exit); + +MODULE_AUTHOR("Andre Hedrick"); +MODULE_DESCRIPTION("PCI driver module for Highpoint HPT366 IDE"); +MODULE_LICENSE("GPL"); diff --git a/drivers/ide/legacy/ht6560b.c b/drivers/ide/ht6560b.c index c48e87e512d..1e0fd3aa962 100644 --- a/drivers/ide/legacy/ht6560b.c +++ b/drivers/ide/ht6560b.c @@ -1,42 +1,19 @@ /* - * linux/drivers/ide/legacy/ht6560b.c Version 0.07 Feb 1, 2000 - * * Copyright (C) 1995-2000 Linus Torvalds & author (see below) */ /* - * - * Version 0.01 Initial version hacked out of ide.c - * - * Version 0.02 Added support for PIO modes, auto-tune - * - * Version 0.03 Some cleanups - * - * Version 0.05 PIO mode cycle timings auto-tune using bus-speed - * - * Version 0.06 Prefetch mode now defaults no OFF. To set - * prefetch mode OFF/ON use "hdparm -p8/-p9". - * Unmask irq is disabled when prefetch mode - * is enabled. - * - * Version 0.07 Trying to fix CD-ROM detection problem. - * "Prefetch" mode bit OFF for ide disks and - * ON for anything else. - * - * * HT-6560B EIDE-controller support * To activate controller support use kernel parameter "ide0=ht6560b". * Use hdparm utility to enable PIO mode support. * * Author: Mikko Ala-Fossi <maf@iki.fi> - * Jan Evert van Grootheest <janevert@iae.nl> + * Jan Evert van Grootheest <j.e.van.grootheest@caiway.nl> * - * Try: http://www.maf.iki.fi/~maf/ht6560b/ */ -#define HT6560B_VERSION "v0.07" - -#undef REALLY_SLOW_IO /* most systems can safely undef this */ +#define DRV_NAME "ht6560b" +#define HT6560B_VERSION "v0.08" #include <linux/module.h> #include <linux/types.h> @@ -46,7 +23,6 @@ #include <linux/mm.h> #include <linux/ioport.h> #include <linux/blkdev.h> -#include <linux/hdreg.h> #include <linux/ide.h> #include <linux/init.h> @@ -67,7 +43,12 @@ * bit3 (0x08): "1" 3 cycle time, "0" 2 cycle time (?) */ #define HT_CONFIG_PORT 0x3e6 -#define HT_CONFIG(drivea) (u8)(((drivea)->drive_data & 0xff00) >> 8) + +static inline u8 HT_CONFIG(ide_drive_t *drive) +{ + return ((unsigned long)ide_get_drivedata(drive) & 0xff00) >> 8; +} + /* * FIFO + PREFETCH (both a/b-model) */ @@ -83,7 +64,7 @@ * out how they setup those cycle time interfacing values, as they at Holtek * call them. IDESETUP.COM that is supplied with the drivers figures out * optimal values and fetches those values to drivers. I found out that - * they use IDE_SELECT_REG to fetch timings to the ide board right after + * they use Select register to fetch timings to the ide board right after * interface switching. After that it was quite easy to add code to * ht6560b.c. * @@ -113,7 +94,11 @@ * Active Time for each drive. Smaller value gives higher speed. * In case of failures you should probably fall back to a higher value. */ -#define HT_TIMING(drivea) (u8)((drivea)->drive_data & 0x00ff) +static inline u8 HT_TIMING(ide_drive_t *drive) +{ + return (unsigned long)ide_get_drivedata(drive) & 0x00ff; +} + #define HT_TIMING_DEFAULT 0xff /* @@ -126,39 +111,48 @@ /* * This routine is invoked from ide.c to prepare for access to a given drive. */ -static void ht6560b_selectproc (ide_drive_t *drive) +static void ht6560b_dev_select(ide_drive_t *drive) { + ide_hwif_t *hwif = drive->hwif; unsigned long flags; static u8 current_select = 0; static u8 current_timing = 0; u8 select, timing; local_irq_save(flags); - + select = HT_CONFIG(drive); timing = HT_TIMING(drive); - + + /* + * Need to enforce prefetch sometimes because otherwise + * it'll hang (hard). + */ + if (drive->media != ide_disk || + (drive->dev_flags & IDE_DFLAG_PRESENT) == 0) + select |= HT_PREFETCH_MODE; + if (select != current_select || timing != current_timing) { current_select = select; current_timing = timing; - if (drive->media != ide_disk || !drive->present) - select |= HT_PREFETCH_MODE; - (void) HWIF(drive)->INB(HT_CONFIG_PORT); - (void) HWIF(drive)->INB(HT_CONFIG_PORT); - (void) HWIF(drive)->INB(HT_CONFIG_PORT); - (void) HWIF(drive)->INB(HT_CONFIG_PORT); - HWIF(drive)->OUTB(select, HT_CONFIG_PORT); + (void)inb(HT_CONFIG_PORT); + (void)inb(HT_CONFIG_PORT); + (void)inb(HT_CONFIG_PORT); + (void)inb(HT_CONFIG_PORT); + outb(select, HT_CONFIG_PORT); /* * Set timing for this drive: */ - HWIF(drive)->OUTB(timing, IDE_SELECT_REG); - (void) HWIF(drive)->INB(IDE_STATUS_REG); + outb(timing, hwif->io_ports.device_addr); + (void)inb(hwif->io_ports.status_addr); #ifdef DEBUG printk("ht6560b: %s: select=%#x timing=%#x\n", drive->name, select, timing); #endif } local_irq_restore(flags); + + outb(drive->select | ATA_DEVICE_OBS, hwif->io_ports.device_addr); } /* @@ -189,37 +183,38 @@ static int __init try_to_init_ht6560b(void) * Ht6560b autodetected */ outb(HT_CONFIG_DEFAULT, HT_CONFIG_PORT); - outb(HT_TIMING_DEFAULT, 0x1f6); /* IDE_SELECT_REG */ - (void) inb(0x1f7); /* IDE_STATUS_REG */ - - printk("\nht6560b " HT6560B_VERSION + outb(HT_TIMING_DEFAULT, 0x1f6); /* Select register */ + (void)inb(0x1f7); /* Status register */ + + printk("ht6560b " HT6560B_VERSION ": chipset detected and initialized" #ifdef DEBUG " with debug enabled" #endif + "\n" ); return 1; } -static u8 ht_pio2timings(ide_drive_t *drive, u8 pio) +static u8 ht_pio2timings(ide_drive_t *drive, const u8 pio) { int active_time, recovery_time; int active_cycles, recovery_cycles; - ide_pio_data_t d; - int bus_speed = system_bus_clock(); - + int bus_speed = ide_vlb_clk ? ide_vlb_clk : 50; + if (pio) { - pio = ide_get_best_pio_mode(drive, pio, 5, &d); - + unsigned int cycle_time; + struct ide_timing *t = ide_timing_find_mode(XFER_PIO_0 + pio); + + cycle_time = ide_pio_cycle_time(drive, pio); + /* * Just like opti621.c we try to calculate the * actual cycle time for recovery and activity * according system bus speed. */ - active_time = ide_pio_timings[pio].active_time; - recovery_time = d.cycle_time - - active_time - - ide_pio_timings[pio].setup_time; + active_time = t->active; + recovery_time = cycle_time - active_time - t->setup; /* * Cycle times should be Vesa bus cycles */ @@ -248,38 +243,45 @@ static u8 ht_pio2timings(ide_drive_t *drive, u8 pio) } } +static DEFINE_SPINLOCK(ht6560b_lock); + /* * Enable/Disable so called prefetch mode */ static void ht_set_prefetch(ide_drive_t *drive, u8 state) { - unsigned long flags; + unsigned long flags, config; int t = HT_PREFETCH_MODE << 8; - - spin_lock_irqsave(&ide_lock, flags); - + + spin_lock_irqsave(&ht6560b_lock, flags); + + config = (unsigned long)ide_get_drivedata(drive); + /* * Prefetch mode and unmask irq seems to conflict */ if (state) { - drive->drive_data |= t; /* enable prefetch mode */ - drive->no_unmask = 1; - drive->unmask = 0; + config |= t; /* enable prefetch mode */ + drive->dev_flags |= IDE_DFLAG_NO_UNMASK; + drive->dev_flags &= ~IDE_DFLAG_UNMASK; } else { - drive->drive_data &= ~t; /* disable prefetch mode */ - drive->no_unmask = 0; + config &= ~t; /* disable prefetch mode */ + drive->dev_flags &= ~IDE_DFLAG_NO_UNMASK; } - - spin_unlock_irqrestore(&ide_lock, flags); - + + ide_set_drivedata(drive, (void *)config); + + spin_unlock_irqrestore(&ht6560b_lock, flags); + #ifdef DEBUG printk("ht6560b: drive %s prefetch mode %sabled\n", drive->name, (state ? "en" : "dis")); #endif } -static void tune_ht6560b (ide_drive_t *drive, u8 pio) +static void ht6560b_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) { - unsigned long flags; + unsigned long flags, config; + const u8 pio = drive->pio_mode - XFER_PIO_0; u8 timing; switch (pio) { @@ -288,81 +290,92 @@ static void tune_ht6560b (ide_drive_t *drive, u8 pio) ht_set_prefetch(drive, pio & 1); return; } - + timing = ht_pio2timings(drive, pio); - - spin_lock_irqsave(&ide_lock, flags); - - drive->drive_data &= 0xff00; - drive->drive_data |= timing; - - spin_unlock_irqrestore(&ide_lock, flags); - + + spin_lock_irqsave(&ht6560b_lock, flags); + config = (unsigned long)ide_get_drivedata(drive); + config &= 0xff00; + config |= timing; + ide_set_drivedata(drive, (void *)config); + spin_unlock_irqrestore(&ht6560b_lock, flags); + #ifdef DEBUG printk("ht6560b: drive %s tuned to pio mode %#x timing=%#x\n", drive->name, pio, timing); #endif } -/* Can be called directly from ide.c. */ -int __init ht6560b_init(void) +static void __init ht6560b_init_dev(ide_drive_t *drive) { - ide_hwif_t *hwif, *mate; - int t; + ide_hwif_t *hwif = drive->hwif; + /* Setting default configurations for drives. */ + int t = (HT_CONFIG_DEFAULT << 8) | HT_TIMING_DEFAULT; - hwif = &ide_hwifs[0]; - mate = &ide_hwifs[1]; + if (hwif->channel) + t |= (HT_SECONDARY_IF << 8); - if (!request_region(HT_CONFIG_PORT, 1, hwif->name)) { - printk(KERN_NOTICE "%s: HT_CONFIG_PORT not found\n", - __FUNCTION__); - return -ENODEV; - } + ide_set_drivedata(drive, (void *)t); +} - if (!try_to_init_ht6560b()) { - printk(KERN_NOTICE "%s: HBA not found\n", __FUNCTION__); - goto release_region; - } +static bool probe_ht6560b; - hwif->chipset = ide_ht6560b; - hwif->selectproc = &ht6560b_selectproc; - hwif->tuneproc = &tune_ht6560b; - hwif->serialized = 1; /* is this needed? */ - hwif->mate = mate; +module_param_named(probe, probe_ht6560b, bool, 0); +MODULE_PARM_DESC(probe, "probe for HT6560B chipset"); - mate->chipset = ide_ht6560b; - mate->selectproc = &ht6560b_selectproc; - mate->tuneproc = &tune_ht6560b; - mate->serialized = 1; /* is this needed? */ - mate->mate = hwif; - mate->channel = 1; +static const struct ide_tp_ops ht6560b_tp_ops = { + .exec_command = ide_exec_command, + .read_status = ide_read_status, + .read_altstatus = ide_read_altstatus, + .write_devctl = ide_write_devctl, - /* - * Setting default configurations for drives - */ - t = (HT_CONFIG_DEFAULT << 8); - t |= HT_TIMING_DEFAULT; - hwif->drives[0].drive_data = t; - hwif->drives[1].drive_data = t; + .dev_select = ht6560b_dev_select, + .tf_load = ide_tf_load, + .tf_read = ide_tf_read, + + .input_data = ide_input_data, + .output_data = ide_output_data, +}; + +static const struct ide_port_ops ht6560b_port_ops = { + .init_dev = ht6560b_init_dev, + .set_pio_mode = ht6560b_set_pio_mode, +}; + +static const struct ide_port_info ht6560b_port_info __initconst = { + .name = DRV_NAME, + .chipset = ide_ht6560b, + .tp_ops = &ht6560b_tp_ops, + .port_ops = &ht6560b_port_ops, + .host_flags = IDE_HFLAG_SERIALIZE | /* is this needed? */ + IDE_HFLAG_NO_DMA | + IDE_HFLAG_ABUSE_PREFETCH, + .pio_mask = ATA_PIO4, +}; - t |= (HT_SECONDARY_IF << 8); - mate->drives[0].drive_data = t; - mate->drives[1].drive_data = t; +static int __init ht6560b_init(void) +{ + if (probe_ht6560b == 0) + return -ENODEV; - probe_hwif_init(hwif); - probe_hwif_init(mate); + if (!request_region(HT_CONFIG_PORT, 1, DRV_NAME)) { + printk(KERN_NOTICE "%s: HT_CONFIG_PORT not found\n", + __func__); + return -ENODEV; + } - create_proc_ide_interfaces(); + if (!try_to_init_ht6560b()) { + printk(KERN_NOTICE "%s: HBA not found\n", __func__); + goto release_region; + } - return 0; + return ide_legacy_device_add(&ht6560b_port_info, 0); release_region: release_region(HT_CONFIG_PORT, 1); return -ENODEV; } -#ifdef MODULE module_init(ht6560b_init); -#endif MODULE_AUTHOR("See Local File"); MODULE_DESCRIPTION("HT-6560B EIDE-controller support"); diff --git a/drivers/ide/arm/icside.c b/drivers/ide/icside.c index 8a1c27f2869..9f0a48e39b8 100644 --- a/drivers/ide/arm/icside.c +++ b/drivers/ide/icside.c @@ -1,6 +1,4 @@ /* - * linux/drivers/ide/arm/icside.c - * * Copyright (c) 1996-2004 Russell King. * * Please note that this platform does not support 32-bit IDE IO. @@ -12,16 +10,17 @@ #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 <linux/io.h> #include <asm/dma.h> #include <asm/ecard.h> -#include <asm/io.h> + +#define DRV_NAME "icside" #define ICS_IDENT_OFFSET 0x2280 @@ -70,10 +69,9 @@ struct icside_state { unsigned int enabled; void __iomem *irq_port; void __iomem *ioc_base; + unsigned int sel; unsigned int type; - /* parent device... until the IDE core gets one of its own */ - struct device *dev; - ide_hwif_t *hwif[2]; + struct ide_host *host; }; #define ICS_TYPE_A3IN 0 @@ -168,8 +166,9 @@ static const expansioncard_ops_t icside_ops_arcin_v6 = { */ static void icside_maskproc(ide_drive_t *drive, int mask) { - ide_hwif_t *hwif = HWIF(drive); - struct icside_state *state = hwif->hwif_data; + ide_hwif_t *hwif = drive->hwif; + struct expansion_card *ec = ECARD_DEV(hwif->dev); + struct icside_state *state = ecard_get_drvdata(ec); unsigned long flags; local_irq_save(flags); @@ -195,12 +194,11 @@ static void icside_maskproc(ide_drive_t *drive, int mask) 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 +static const struct ide_port_ops icside_v6_no_dma_port_ops = { + .maskproc = icside_maskproc, +}; +#ifdef CONFIG_BLK_DEV_IDEDMA_ICS /* * SG-DMA support. * @@ -211,23 +209,6 @@ static void icside_maskproc(ide_drive_t *drive, int mask) * 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 @@ -253,15 +234,11 @@ static void icside_build_sglist(ide_drive_t *drive, struct request *rq) * MW1 80 50 50 150 C * MW2 70 25 25 120 C */ -static int icside_set_speed(ide_drive_t *drive, u8 xfer_mode) +static void icside_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive) { - 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; + unsigned long cycle_time = 0; + int use_dma_info = 0; + const u8 xfer_mode = drive->dma_mode; switch (xfer_mode) { case XFER_MW_DMA_2: @@ -289,120 +266,53 @@ static int icside_set_speed(ide_drive_t *drive, u8 xfer_mode) * 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; + if (use_dma_info && drive->id[ATA_ID_EIDE_DMA_TIME] > cycle_time) + cycle_time = drive->id[ATA_ID_EIDE_DMA_TIME]; - drive->drive_data = cycle_time; - - 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; -} + ide_set_drivedata(drive, (void *)cycle_time); -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; + printk(KERN_INFO "%s: %s selected (peak %luMB/s)\n", + drive->name, ide_xfer_verbose(xfer_mode), + 2000 / (cycle_time ? cycle_time : (unsigned long) -1)); } -static int icside_dma_on(ide_drive_t *drive) -{ - drive->using_dma = 1; - return icside_dma_host_on(drive); -} +static const struct ide_port_ops icside_v6_port_ops = { + .set_dma_mode = icside_set_dma_mode, + .maskproc = icside_maskproc, +}; -static int icside_dma_check(ide_drive_t *drive) +static void icside_dma_host_set(ide_drive_t *drive, int on) { - 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); + ide_hwif_t *hwif = drive->hwif; + struct expansion_card *ec = ECARD_DEV(hwif->dev); - /* Teardown mappings after DMA has completed. */ - dma_unmap_sg(state->dev, hwif->sg_table, hwif->sg_nents, - hwif->sg_dma_direction); + disable_dma(ec->dma); - return get_dma_residue(hwif->hw.dma) != 0; + return get_dma_residue(ec->dma) != 0; } static void icside_dma_start(ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; + struct expansion_card *ec = ECARD_DEV(hwif->dev); /* We can not enable DMA on both channels simultaneously. */ - BUG_ON(dma_channel_active(hwif->hw.dma)); - enable_dma(hwif->hw.dma); + BUG_ON(dma_channel_active(ec->dma)); + enable_dma(ec->dma); } -static int icside_dma_setup(ide_drive_t *drive) +static int icside_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd) { - ide_hwif_t *hwif = HWIF(drive); - struct request *rq = hwif->hwgroup->rq; + ide_hwif_t *hwif = drive->hwif; + struct expansion_card *ec = ECARD_DEV(hwif->dev); + struct icside_state *state = ecard_get_drvdata(ec); unsigned int dma_mode; - if (rq_data_dir(rq)) + if (cmd->tf_flags & IDE_TFLAG_WRITE) dma_mode = DMA_MODE_WRITE; else dma_mode = DMA_MODE_READ; @@ -410,9 +320,7 @@ static int icside_dma_setup(ide_drive_t *drive) /* * We can not enable DMA on both channels. */ - BUG_ON(dma_channel_active(hwif->hw.dma)); - - icside_build_sglist(drive, rq); + BUG_ON(dma_channel_active(ec->dma)); /* * Ensure that we have the right interrupt routed. @@ -422,35 +330,28 @@ static int icside_dma_setup(ide_drive_t *drive) /* * Route the DMA signals to the correct interface. */ - writeb(hwif->select_data, hwif->config_data); + writeb(state->sel | hwif->channel, state->ioc_base); /* * Select the correct timing for this drive. */ - set_dma_speed(hwif->hw.dma, drive->drive_data); + set_dma_speed(ec->dma, (unsigned long)ide_get_drivedata(drive)); /* * 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; + set_dma_sg(ec->dma, hwif->sg_table, cmd->sg_nents); + set_dma_mode(ec->dma, dma_mode); 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; + ide_hwif_t *hwif = drive->hwif; + struct expansion_card *ec = ECARD_DEV(hwif->dev); + struct icside_state *state = ecard_get_drvdata(ec); return readb(state->irq_port + (hwif->channel ? @@ -458,131 +359,62 @@ static int icside_dma_test_irq(ide_drive_t *drive) 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) +static int icside_dma_init(ide_hwif_t *hwif, const struct ide_port_info *d) { - 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" : ""); + + return 0; } -#else -#define icside_dma_init(hwif) (0) + +static const struct ide_dma_ops icside_v6_dma_ops = { + .dma_host_set = icside_dma_host_set, + .dma_setup = icside_dma_setup, + .dma_start = icside_dma_start, + .dma_end = icside_dma_end, + .dma_test_irq = icside_dma_test_irq, + .dma_lost_irq = ide_dma_lost_irq, +}; #endif -static ide_hwif_t *icside_find_hwif(unsigned long dataport) +static int icside_dma_off_init(ide_hwif_t *hwif, const struct ide_port_info *d) { - 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; + return -EOPNOTSUPP; } -static ide_hwif_t * -icside_setup(void __iomem *base, struct cardinfo *info, struct expansion_card *ec) +static void icside_setup_ports(struct ide_hw *hw, 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; + hw->io_ports.data_addr = port; + hw->io_ports.error_addr = port + (1 << info->stepping); + hw->io_ports.nsect_addr = port + (2 << info->stepping); + hw->io_ports.lbal_addr = port + (3 << info->stepping); + hw->io_ports.lbam_addr = port + (4 << info->stepping); + hw->io_ports.lbah_addr = port + (5 << info->stepping); + hw->io_ports.device_addr = port + (6 << info->stepping); + hw->io_ports.status_addr = port + (7 << info->stepping); + hw->io_ports.ctl_addr = (unsigned long)base + info->ctrloffset; + + hw->irq = ec->irq; + hw->dev = &ec->dev; } -static int __init -icside_register_v5(struct icside_state *state, struct expansion_card *ec) +static const struct ide_port_info icside_v5_port_info = { + .host_flags = IDE_HFLAG_NO_DMA, + .chipset = ide_acorn, +}; + +static int icside_register_v5(struct icside_state *state, + struct expansion_card *ec) { - ide_hwif_t *hwif; void __iomem *base; + struct ide_host *host; + struct ide_hw hw, *hws[] = { &hw }; + int ret; - base = ioremap(ecard_resource_start(ec, ECARD_RES_MEMC), - ecard_resource_len(ec, ECARD_RES_MEMC)); + base = ecardm_iomap(ec, ECARD_RES_MEMC, 0, 0); if (!base) return -ENOMEM; @@ -590,38 +422,55 @@ icside_register_v5(struct icside_state *state, struct expansion_card *ec) ec->irqaddr = base + ICS_ARCIN_V5_INTRSTAT; ec->irqmask = 1; - ec->irq_data = state; - ec->ops = &icside_ops_arcin_v5; + + ecard_setirq(ec, &icside_ops_arcin_v5, state); /* * 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); + icside_setup_ports(&hw, base, &icside_cardinfo_v5, ec); + + host = ide_host_alloc(&icside_v5_port_info, hws, 1); + if (host == NULL) return -ENODEV; - } - state->hwif[0] = hwif; + state->host = host; + + ecard_set_drvdata(ec, state); - probe_hwif_init(hwif); - create_proc_ide_interfaces(); + ret = ide_host_register(host, &icside_v5_port_info, hws); + if (ret) + goto err_free; return 0; +err_free: + ide_host_free(host); + ecard_set_drvdata(ec, NULL); + return ret; } -static int __init -icside_register_v6(struct icside_state *state, struct expansion_card *ec) +static const struct ide_port_info icside_v6_port_info __initconst = { + .init_dma = icside_dma_off_init, + .port_ops = &icside_v6_no_dma_port_ops, + .host_flags = IDE_HFLAG_SERIALIZE | IDE_HFLAG_MMIO, + .mwdma_mask = ATA_MWDMA2, + .swdma_mask = ATA_SWDMA2, + .chipset = ide_acorn, +}; + +static int icside_register_v6(struct icside_state *state, + struct expansion_card *ec) { - ide_hwif_t *hwif, *mate; void __iomem *ioc_base, *easi_base; + struct ide_host *host; unsigned int sel = 0; int ret; + struct ide_hw hw[2], *hws[] = { &hw[0], &hw[1] }; + struct ide_port_info d = icside_v6_port_info; - ioc_base = ioremap(ecard_resource_start(ec, ECARD_RES_IOCFAST), - ecard_resource_len(ec, ECARD_RES_IOCFAST)); + ioc_base = ecardm_iomap(ec, ECARD_RES_IOCFAST, 0, 0); if (!ioc_base) { ret = -ENOMEM; goto out; @@ -630,11 +479,10 @@ icside_register_v6(struct icside_state *state, struct expansion_card *ec) 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)); + easi_base = ecardm_iomap(ec, ECARD_RES_EASI, 0, 0); if (!easi_base) { ret = -ENOMEM; - goto unmap_slot; + goto out; } /* @@ -645,71 +493,51 @@ icside_register_v6(struct icside_state *state, struct expansion_card *ec) writeb(sel, ioc_base); - ec->irq_data = state; - ec->ops = &icside_ops_arcin_v6; + ecard_setirq(ec, &icside_ops_arcin_v6, state); state->irq_port = easi_base; state->ioc_base = ioc_base; + state->sel = sel; /* * Be on the safe side - disable interrupts */ icside_irqdisable_arcin_v6(ec, 0); - /* - * 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); + icside_setup_ports(&hw[0], easi_base, &icside_cardinfo_v6_1, ec); + icside_setup_ports(&hw[1], easi_base, &icside_cardinfo_v6_2, ec); - if (!hwif || !mate) { - ret = -ENODEV; - goto unmap_port; - } + host = ide_host_alloc(&d, hws, 2); + if (host == NULL) + return -ENODEV; + + state->host = host; - 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); + ecard_set_drvdata(ec, state); + +#ifdef CONFIG_BLK_DEV_IDEDMA_ICS + if (ec->dma != NO_DMA && !request_dma(ec->dma, DRV_NAME)) { + d.init_dma = icside_dma_init; + d.port_ops = &icside_v6_port_ops; + d.dma_ops = &icside_v6_dma_ops; } +#endif - probe_hwif_init(hwif); - probe_hwif_init(mate); - create_proc_ide_interfaces(); + ret = ide_host_register(host, &d, hws); + if (ret) + goto err_free; return 0; - - unmap_port: - if (easi_base != ioc_base) - iounmap(easi_base); - unmap_slot: - iounmap(ioc_base); - out: +err_free: + ide_host_free(host); + if (d.dma_ops) + free_dma(ec->dma); + ecard_set_drvdata(ec, NULL); +out: return ret; } -static int __devinit -icside_probe(struct expansion_card *ec, const struct ecard_id *id) +static int icside_probe(struct expansion_card *ec, const struct ecard_id *id) { struct icside_state *state; void __iomem *idmem; @@ -719,18 +547,15 @@ icside_probe(struct expansion_card *ec, const struct ecard_id *id) if (ret) goto out; - state = kmalloc(sizeof(struct icside_state), GFP_KERNEL); + state = kzalloc(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)); + idmem = ecardm_iomap(ec, ECARD_RES_IOCFAST, 0, 0); if (idmem) { unsigned int type; @@ -738,7 +563,7 @@ icside_probe(struct expansion_card *ec, const struct ecard_id *id) 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); + ecardm_iounmap(ec, idmem); state->type = type; } @@ -768,10 +593,8 @@ icside_probe(struct expansion_card *ec, const struct ecard_id *id) break; } - if (ret == 0) { - ecard_set_drvdata(ec, state); + if (ret == 0) goto out; - } kfree(state); release: @@ -780,7 +603,7 @@ icside_probe(struct expansion_card *ec, const struct ecard_id *id) return ret; } -static void __devexit icside_remove(struct expansion_card *ec) +static void icside_remove(struct expansion_card *ec) { struct icside_state *state = ecard_get_drvdata(ec); @@ -806,13 +629,6 @@ static void __devexit icside_remove(struct expansion_card *ec) } 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); @@ -849,7 +665,7 @@ static const struct ecard_id icside_ids[] = { static struct ecard_driver icside_driver = { .probe = icside_probe, - .remove = __devexit_p(icside_remove), + .remove = icside_remove, .shutdown = icside_shutdown, .id_table = icside_ids, .drv = { @@ -862,8 +678,14 @@ static int __init icside_init(void) return ecard_register_driver(&icside_driver); } +static void __exit icside_exit(void) +{ + ecard_remove_driver(&icside_driver); +} + MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("ICS IDE driver"); module_init(icside_init); +module_exit(icside_exit); diff --git a/drivers/ide/ide-4drives.c b/drivers/ide/ide-4drives.c new file mode 100644 index 00000000000..547d7cf2e01 --- /dev/null +++ b/drivers/ide/ide-4drives.c @@ -0,0 +1,64 @@ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/ide.h> + +#define DRV_NAME "ide-4drives" + +static bool probe_4drives; + +module_param_named(probe, probe_4drives, bool, 0); +MODULE_PARM_DESC(probe, "probe for generic IDE chipset with 4 drives/port"); + +static void ide_4drives_init_dev(ide_drive_t *drive) +{ + if (drive->hwif->channel) + drive->select ^= 0x20; +} + +static const struct ide_port_ops ide_4drives_port_ops = { + .init_dev = ide_4drives_init_dev, +}; + +static const struct ide_port_info ide_4drives_port_info = { + .port_ops = &ide_4drives_port_ops, + .host_flags = IDE_HFLAG_SERIALIZE | IDE_HFLAG_NO_DMA | + IDE_HFLAG_4DRIVES, + .chipset = ide_4drives, +}; + +static int __init ide_4drives_init(void) +{ + unsigned long base = 0x1f0, ctl = 0x3f6; + struct ide_hw hw, *hws[] = { &hw, &hw }; + + if (probe_4drives == 0) + return -ENODEV; + + if (!request_region(base, 8, DRV_NAME)) { + printk(KERN_ERR "%s: I/O resource 0x%lX-0x%lX not free.\n", + DRV_NAME, base, base + 7); + return -EBUSY; + } + + if (!request_region(ctl, 1, DRV_NAME)) { + printk(KERN_ERR "%s: I/O resource 0x%lX not free.\n", + DRV_NAME, ctl); + release_region(base, 8); + return -EBUSY; + } + + memset(&hw, 0, sizeof(hw)); + + ide_std_init_ports(&hw, base, ctl); + hw.irq = 14; + + return ide_host_add(&ide_4drives_port_info, hws, 2, NULL); +} + +module_init(ide_4drives_init); + +MODULE_AUTHOR("Bartlomiej Zolnierkiewicz"); +MODULE_DESCRIPTION("generic IDE chipset with 4 drives/port support"); +MODULE_LICENSE("GPL"); diff --git a/drivers/ide/ide-acpi.c b/drivers/ide/ide-acpi.c new file mode 100644 index 00000000000..b6940992a6f --- /dev/null +++ b/drivers/ide/ide-acpi.c @@ -0,0 +1,621 @@ +/* + * Provides ACPI support for IDE drives. + * + * Copyright (C) 2005 Intel Corp. + * Copyright (C) 2005 Randy Dunlap + * Copyright (C) 2006 SUSE Linux Products GmbH + * Copyright (C) 2006 Hannes Reinecke + */ + +#include <linux/acpi.h> +#include <linux/ata.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/ide.h> +#include <linux/pci.h> +#include <linux/dmi.h> +#include <linux/module.h> + +#define REGS_PER_GTF 7 + +struct GTM_buffer { + u32 PIO_speed0; + u32 DMA_speed0; + u32 PIO_speed1; + u32 DMA_speed1; + u32 GTM_flags; +}; + +struct ide_acpi_drive_link { + acpi_handle obj_handle; + u8 idbuff[512]; +}; + +struct ide_acpi_hwif_link { + ide_hwif_t *hwif; + acpi_handle obj_handle; + struct GTM_buffer gtm; + struct ide_acpi_drive_link master; + struct ide_acpi_drive_link slave; +}; + +#undef DEBUGGING +/* note: adds function name and KERN_DEBUG */ +#ifdef DEBUGGING +#define DEBPRINT(fmt, args...) \ + printk(KERN_DEBUG "%s: " fmt, __func__, ## args) +#else +#define DEBPRINT(fmt, args...) do {} while (0) +#endif /* DEBUGGING */ + +static bool ide_noacpi; +module_param_named(noacpi, ide_noacpi, bool, 0); +MODULE_PARM_DESC(noacpi, "disable IDE ACPI support"); + +static bool ide_acpigtf; +module_param_named(acpigtf, ide_acpigtf, bool, 0); +MODULE_PARM_DESC(acpigtf, "enable IDE ACPI _GTF support"); + +static bool ide_acpionboot; +module_param_named(acpionboot, ide_acpionboot, bool, 0); +MODULE_PARM_DESC(acpionboot, "call IDE ACPI methods on boot"); + +static bool ide_noacpi_psx; +static int no_acpi_psx(const struct dmi_system_id *id) +{ + ide_noacpi_psx = true; + printk(KERN_NOTICE"%s detected - disable ACPI _PSx.\n", id->ident); + return 0; +} + +static const struct dmi_system_id ide_acpi_dmi_table[] = { + /* Bug 9673. */ + /* We should check if this is because ACPI NVS isn't save/restored. */ + { + .callback = no_acpi_psx, + .ident = "HP nx9005", + .matches = { + DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies Ltd."), + DMI_MATCH(DMI_BIOS_VERSION, "KAM1.60") + }, + }, + + { } /* terminate list */ +}; + +int ide_acpi_init(void) +{ + dmi_check_system(ide_acpi_dmi_table); + return 0; +} + +bool ide_port_acpi(ide_hwif_t *hwif) +{ + return ide_noacpi == 0 && hwif->acpidata; +} + +static acpi_handle acpi_get_child(acpi_handle handle, u64 addr) +{ + struct acpi_device *adev; + + if (!handle || acpi_bus_get_device(handle, &adev)) + return NULL; + + adev = acpi_find_child_device(adev, addr, false); + return adev ? adev->handle : NULL; +} + +/** + * ide_get_dev_handle - finds acpi_handle and PCI device.function + * @dev: device to locate + * @handle: returned acpi_handle for @dev + * @pcidevfn: return PCI device.func for @dev + * + * Returns the ACPI object handle to the corresponding PCI device. + * + * Returns 0 on success, <0 on error. + */ +static int ide_get_dev_handle(struct device *dev, acpi_handle *handle, + u64 *pcidevfn) +{ + struct pci_dev *pdev = to_pci_dev(dev); + unsigned int bus, devnum, func; + u64 addr; + acpi_handle dev_handle; + acpi_status status; + struct acpi_device_info *dinfo = NULL; + int ret = -ENODEV; + + bus = pdev->bus->number; + devnum = PCI_SLOT(pdev->devfn); + func = PCI_FUNC(pdev->devfn); + /* ACPI _ADR encoding for PCI bus: */ + addr = (u64)(devnum << 16 | func); + + DEBPRINT("ENTER: pci %02x:%02x.%01x\n", bus, devnum, func); + + dev_handle = ACPI_HANDLE(dev); + if (!dev_handle) { + DEBPRINT("no acpi handle for device\n"); + goto err; + } + + status = acpi_get_object_info(dev_handle, &dinfo); + if (ACPI_FAILURE(status)) { + DEBPRINT("get_object_info for device failed\n"); + goto err; + } + if (dinfo && (dinfo->valid & ACPI_VALID_ADR) && + dinfo->address == addr) { + *pcidevfn = addr; + *handle = dev_handle; + } else { + DEBPRINT("get_object_info for device has wrong " + " address: %llu, should be %u\n", + dinfo ? (unsigned long long)dinfo->address : -1ULL, + (unsigned int)addr); + goto err; + } + + DEBPRINT("for dev=0x%x.%x, addr=0x%llx, *handle=0x%p\n", + devnum, func, (unsigned long long)addr, *handle); + ret = 0; +err: + kfree(dinfo); + return ret; +} + +/** + * ide_acpi_hwif_get_handle - Get ACPI object handle for a given hwif + * @hwif: device to locate + * + * Retrieves the object handle for a given hwif. + * + * Returns handle on success, 0 on error. + */ +static acpi_handle ide_acpi_hwif_get_handle(ide_hwif_t *hwif) +{ + struct device *dev = hwif->gendev.parent; + acpi_handle uninitialized_var(dev_handle); + u64 pcidevfn; + acpi_handle chan_handle; + int err; + + DEBPRINT("ENTER: device %s\n", hwif->name); + + if (!dev) { + DEBPRINT("no PCI device for %s\n", hwif->name); + return NULL; + } + + err = ide_get_dev_handle(dev, &dev_handle, &pcidevfn); + if (err < 0) { + DEBPRINT("ide_get_dev_handle failed (%d)\n", err); + return NULL; + } + + /* get child objects of dev_handle == channel objects, + * + _their_ children == drive objects */ + /* channel is hwif->channel */ + chan_handle = acpi_get_child(dev_handle, hwif->channel); + DEBPRINT("chan adr=%d: handle=0x%p\n", + hwif->channel, chan_handle); + + return chan_handle; +} + +/** + * do_drive_get_GTF - get the drive bootup default taskfile settings + * @drive: the drive for which the taskfile settings should be retrieved + * @gtf_length: number of bytes of _GTF data returned at @gtf_address + * @gtf_address: buffer containing _GTF taskfile arrays + * + * The _GTF method has no input parameters. + * It returns a variable number of register set values (registers + * hex 1F1..1F7, taskfiles). + * The <variable number> is not known in advance, so have ACPI-CA + * allocate the buffer as needed and return it, then free it later. + * + * The returned @gtf_length and @gtf_address are only valid if the + * function return value is 0. + */ +static int do_drive_get_GTF(ide_drive_t *drive, + unsigned int *gtf_length, unsigned long *gtf_address, + unsigned long *obj_loc) +{ + acpi_status status; + struct acpi_buffer output; + union acpi_object *out_obj; + int err = -ENODEV; + + *gtf_length = 0; + *gtf_address = 0UL; + *obj_loc = 0UL; + + if (!drive->acpidata->obj_handle) { + DEBPRINT("No ACPI object found for %s\n", drive->name); + goto out; + } + + /* Setting up output buffer */ + output.length = ACPI_ALLOCATE_BUFFER; + output.pointer = NULL; /* ACPI-CA sets this; save/free it later */ + + /* _GTF has no input parameters */ + err = -EIO; + status = acpi_evaluate_object(drive->acpidata->obj_handle, "_GTF", + NULL, &output); + if (ACPI_FAILURE(status)) { + printk(KERN_DEBUG + "%s: Run _GTF error: status = 0x%x\n", + __func__, status); + goto out; + } + + if (!output.length || !output.pointer) { + DEBPRINT("Run _GTF: " + "length or ptr is NULL (0x%llx, 0x%p)\n", + (unsigned long long)output.length, + output.pointer); + goto out; + } + + out_obj = output.pointer; + if (out_obj->type != ACPI_TYPE_BUFFER) { + DEBPRINT("Run _GTF: error: " + "expected object type of ACPI_TYPE_BUFFER, " + "got 0x%x\n", out_obj->type); + err = -ENOENT; + kfree(output.pointer); + goto out; + } + + if (!out_obj->buffer.length || !out_obj->buffer.pointer || + out_obj->buffer.length % REGS_PER_GTF) { + printk(KERN_ERR + "%s: unexpected GTF length (%d) or addr (0x%p)\n", + __func__, out_obj->buffer.length, + out_obj->buffer.pointer); + err = -ENOENT; + kfree(output.pointer); + goto out; + } + + *gtf_length = out_obj->buffer.length; + *gtf_address = (unsigned long)out_obj->buffer.pointer; + *obj_loc = (unsigned long)out_obj; + DEBPRINT("returning gtf_length=%d, gtf_address=0x%lx, obj_loc=0x%lx\n", + *gtf_length, *gtf_address, *obj_loc); + err = 0; +out: + return err; +} + +/** + * do_drive_set_taskfiles - write the drive taskfile settings from _GTF + * @drive: the drive to which the taskfile command should be sent + * @gtf_length: total number of bytes of _GTF taskfiles + * @gtf_address: location of _GTF taskfile arrays + * + * Write {gtf_address, length gtf_length} in groups of + * REGS_PER_GTF bytes. + */ +static int do_drive_set_taskfiles(ide_drive_t *drive, + unsigned int gtf_length, + unsigned long gtf_address) +{ + int rc = 0, err; + int gtf_count = gtf_length / REGS_PER_GTF; + int ix; + + DEBPRINT("total GTF bytes=%u (0x%x), gtf_count=%d, addr=0x%lx\n", + gtf_length, gtf_length, gtf_count, gtf_address); + + /* send all taskfile registers (0x1f1-0x1f7) *in*that*order* */ + for (ix = 0; ix < gtf_count; ix++) { + u8 *gtf = (u8 *)(gtf_address + ix * REGS_PER_GTF); + struct ide_cmd cmd; + + DEBPRINT("(0x1f1-1f7): " + "hex: %02x %02x %02x %02x %02x %02x %02x\n", + gtf[0], gtf[1], gtf[2], + gtf[3], gtf[4], gtf[5], gtf[6]); + + if (!ide_acpigtf) { + DEBPRINT("_GTF execution disabled\n"); + continue; + } + + /* convert GTF to taskfile */ + memset(&cmd, 0, sizeof(cmd)); + memcpy(&cmd.tf.feature, gtf, REGS_PER_GTF); + cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE; + cmd.valid.in.tf = IDE_VALID_IN_TF | IDE_VALID_DEVICE; + + err = ide_no_data_taskfile(drive, &cmd); + if (err) { + printk(KERN_ERR "%s: ide_no_data_taskfile failed: %u\n", + __func__, err); + rc = err; + } + } + + return rc; +} + +/** + * ide_acpi_exec_tfs - get then write drive taskfile settings + * @drive: the drive for which the taskfile settings should be + * written. + * + * According to the ACPI spec this should be called after _STM + * has been evaluated for the interface. Some ACPI vendors interpret + * that as a hard requirement and modify the taskfile according + * to the Identify Drive information passed down with _STM. + * So one should really make sure to call this only after _STM has + * been executed. + */ +int ide_acpi_exec_tfs(ide_drive_t *drive) +{ + int ret; + unsigned int gtf_length; + unsigned long gtf_address; + unsigned long obj_loc; + + DEBPRINT("call get_GTF, drive=%s port=%d\n", drive->name, drive->dn); + + ret = do_drive_get_GTF(drive, >f_length, >f_address, &obj_loc); + if (ret < 0) { + DEBPRINT("get_GTF error (%d)\n", ret); + return ret; + } + + DEBPRINT("call set_taskfiles, drive=%s\n", drive->name); + + ret = do_drive_set_taskfiles(drive, gtf_length, gtf_address); + kfree((void *)obj_loc); + if (ret < 0) { + DEBPRINT("set_taskfiles error (%d)\n", ret); + } + + DEBPRINT("ret=%d\n", ret); + + return ret; +} + +/** + * ide_acpi_get_timing - get the channel (controller) timings + * @hwif: target IDE interface (channel) + * + * This function executes the _GTM ACPI method for the target channel. + * + */ +void ide_acpi_get_timing(ide_hwif_t *hwif) +{ + acpi_status status; + struct acpi_buffer output; + union acpi_object *out_obj; + + /* Setting up output buffer for _GTM */ + output.length = ACPI_ALLOCATE_BUFFER; + output.pointer = NULL; /* ACPI-CA sets this; save/free it later */ + + /* _GTM has no input parameters */ + status = acpi_evaluate_object(hwif->acpidata->obj_handle, "_GTM", + NULL, &output); + + DEBPRINT("_GTM status: %d, outptr: 0x%p, outlen: 0x%llx\n", + status, output.pointer, + (unsigned long long)output.length); + + if (ACPI_FAILURE(status)) { + DEBPRINT("Run _GTM error: status = 0x%x\n", status); + return; + } + + if (!output.length || !output.pointer) { + DEBPRINT("Run _GTM: length or ptr is NULL (0x%llx, 0x%p)\n", + (unsigned long long)output.length, + output.pointer); + kfree(output.pointer); + return; + } + + out_obj = output.pointer; + if (out_obj->type != ACPI_TYPE_BUFFER) { + DEBPRINT("Run _GTM: error: " + "expected object type of ACPI_TYPE_BUFFER, " + "got 0x%x\n", out_obj->type); + kfree(output.pointer); + return; + } + + if (!out_obj->buffer.length || !out_obj->buffer.pointer || + out_obj->buffer.length != sizeof(struct GTM_buffer)) { + printk(KERN_ERR + "%s: unexpected _GTM length (0x%x)[should be 0x%zx] or " + "addr (0x%p)\n", + __func__, out_obj->buffer.length, + sizeof(struct GTM_buffer), out_obj->buffer.pointer); + kfree(output.pointer); + return; + } + + memcpy(&hwif->acpidata->gtm, out_obj->buffer.pointer, + sizeof(struct GTM_buffer)); + + DEBPRINT("_GTM info: ptr: 0x%p, len: 0x%x, exp.len: 0x%Zx\n", + out_obj->buffer.pointer, out_obj->buffer.length, + sizeof(struct GTM_buffer)); + + DEBPRINT("_GTM fields: 0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n", + hwif->acpidata->gtm.PIO_speed0, + hwif->acpidata->gtm.DMA_speed0, + hwif->acpidata->gtm.PIO_speed1, + hwif->acpidata->gtm.DMA_speed1, + hwif->acpidata->gtm.GTM_flags); + + kfree(output.pointer); +} + +/** + * ide_acpi_push_timing - set the channel (controller) timings + * @hwif: target IDE interface (channel) + * + * This function executes the _STM ACPI method for the target channel. + * + * _STM requires Identify Drive data, which has to passed as an argument. + * Unfortunately drive->id is a mangled version which we can't readily + * use; hence we'll get the information afresh. + */ +void ide_acpi_push_timing(ide_hwif_t *hwif) +{ + acpi_status status; + struct acpi_object_list input; + union acpi_object in_params[3]; + struct ide_acpi_drive_link *master = &hwif->acpidata->master; + struct ide_acpi_drive_link *slave = &hwif->acpidata->slave; + + /* Give the GTM buffer + drive Identify data to the channel via the + * _STM method: */ + /* setup input parameters buffer for _STM */ + input.count = 3; + input.pointer = in_params; + in_params[0].type = ACPI_TYPE_BUFFER; + in_params[0].buffer.length = sizeof(struct GTM_buffer); + in_params[0].buffer.pointer = (u8 *)&hwif->acpidata->gtm; + in_params[1].type = ACPI_TYPE_BUFFER; + in_params[1].buffer.length = ATA_ID_WORDS * 2; + in_params[1].buffer.pointer = (u8 *)&master->idbuff; + in_params[2].type = ACPI_TYPE_BUFFER; + in_params[2].buffer.length = ATA_ID_WORDS * 2; + in_params[2].buffer.pointer = (u8 *)&slave->idbuff; + /* Output buffer: _STM has no output */ + + status = acpi_evaluate_object(hwif->acpidata->obj_handle, "_STM", + &input, NULL); + + if (ACPI_FAILURE(status)) { + DEBPRINT("Run _STM error: status = 0x%x\n", status); + } + DEBPRINT("_STM status: %d\n", status); +} + +/** + * ide_acpi_set_state - set the channel power state + * @hwif: target IDE interface + * @on: state, on/off + * + * This function executes the _PS0/_PS3 ACPI method to set the power state. + * ACPI spec requires _PS0 when IDE power on and _PS3 when power off + */ +void ide_acpi_set_state(ide_hwif_t *hwif, int on) +{ + ide_drive_t *drive; + int i; + + if (ide_noacpi_psx) + return; + + DEBPRINT("ENTER:\n"); + + /* channel first and then drives for power on and verse versa for power off */ + if (on) + acpi_bus_set_power(hwif->acpidata->obj_handle, ACPI_STATE_D0); + + ide_port_for_each_present_dev(i, drive, hwif) { + if (drive->acpidata->obj_handle) + acpi_bus_set_power(drive->acpidata->obj_handle, + on ? ACPI_STATE_D0 : ACPI_STATE_D3_COLD); + } + + if (!on) + acpi_bus_set_power(hwif->acpidata->obj_handle, + ACPI_STATE_D3_COLD); +} + +/** + * ide_acpi_init_port - initialize the ACPI link for an IDE interface + * @hwif: target IDE interface (channel) + * + * The ACPI spec is not quite clear when the drive identify buffer + * should be obtained. Calling IDENTIFY DEVICE during shutdown + * is not the best of ideas as the drive might already being put to + * sleep. And obviously we can't call it during resume. + * So we get the information during startup; but this means that + * any changes during run-time will be lost after resume. + */ +void ide_acpi_init_port(ide_hwif_t *hwif) +{ + hwif->acpidata = kzalloc(sizeof(struct ide_acpi_hwif_link), GFP_KERNEL); + if (!hwif->acpidata) + return; + + hwif->acpidata->obj_handle = ide_acpi_hwif_get_handle(hwif); + if (!hwif->acpidata->obj_handle) { + DEBPRINT("no ACPI object for %s found\n", hwif->name); + kfree(hwif->acpidata); + hwif->acpidata = NULL; + } +} + +void ide_acpi_port_init_devices(ide_hwif_t *hwif) +{ + ide_drive_t *drive; + int i, err; + + if (hwif->acpidata == NULL) + return; + + /* + * The ACPI spec mandates that we send information + * for both drives, regardless whether they are connected + * or not. + */ + hwif->devices[0]->acpidata = &hwif->acpidata->master; + hwif->devices[1]->acpidata = &hwif->acpidata->slave; + + /* get _ADR info for each device */ + ide_port_for_each_present_dev(i, drive, hwif) { + acpi_handle dev_handle; + + DEBPRINT("ENTER: %s at channel#: %d port#: %d\n", + drive->name, hwif->channel, drive->dn & 1); + + /* TBD: could also check ACPI object VALID bits */ + dev_handle = acpi_get_child(hwif->acpidata->obj_handle, + drive->dn & 1); + + DEBPRINT("drive %s handle 0x%p\n", drive->name, dev_handle); + + drive->acpidata->obj_handle = dev_handle; + } + + /* send IDENTIFY for each device */ + ide_port_for_each_present_dev(i, drive, hwif) { + err = taskfile_lib_get_identify(drive, drive->acpidata->idbuff); + if (err) + DEBPRINT("identify device %s failed (%d)\n", + drive->name, err); + } + + if (ide_noacpi || ide_acpionboot == 0) { + DEBPRINT("ACPI methods disabled on boot\n"); + return; + } + + /* ACPI _PS0 before _STM */ + ide_acpi_set_state(hwif, 1); + /* + * ACPI requires us to call _STM on startup + */ + ide_acpi_get_timing(hwif); + ide_acpi_push_timing(hwif); + + ide_port_for_each_present_dev(i, drive, hwif) { + ide_acpi_exec_tfs(drive); + } +} diff --git a/drivers/ide/ide-atapi.c b/drivers/ide/ide-atapi.c new file mode 100644 index 00000000000..fac3d9da2e0 --- /dev/null +++ b/drivers/ide/ide-atapi.c @@ -0,0 +1,729 @@ +/* + * ATAPI support. + */ + +#include <linux/kernel.h> +#include <linux/cdrom.h> +#include <linux/delay.h> +#include <linux/export.h> +#include <linux/ide.h> +#include <linux/scatterlist.h> +#include <linux/gfp.h> + +#include <scsi/scsi.h> + +#define DRV_NAME "ide-atapi" +#define PFX DRV_NAME ": " + +#ifdef DEBUG +#define debug_log(fmt, args...) \ + printk(KERN_INFO "ide: " fmt, ## args) +#else +#define debug_log(fmt, args...) do {} while (0) +#endif + +#define ATAPI_MIN_CDB_BYTES 12 + +static inline int dev_is_idecd(ide_drive_t *drive) +{ + return drive->media == ide_cdrom || drive->media == ide_optical; +} + +/* + * Check whether we can support a device, + * based on the ATAPI IDENTIFY command results. + */ +int ide_check_atapi_device(ide_drive_t *drive, const char *s) +{ + u16 *id = drive->id; + u8 gcw[2], protocol, device_type, removable, drq_type, packet_size; + + *((u16 *)&gcw) = id[ATA_ID_CONFIG]; + + protocol = (gcw[1] & 0xC0) >> 6; + device_type = gcw[1] & 0x1F; + removable = (gcw[0] & 0x80) >> 7; + drq_type = (gcw[0] & 0x60) >> 5; + packet_size = gcw[0] & 0x03; + +#ifdef CONFIG_PPC + /* kludge for Apple PowerBook internal zip */ + if (drive->media == ide_floppy && device_type == 5 && + !strstr((char *)&id[ATA_ID_PROD], "CD-ROM") && + strstr((char *)&id[ATA_ID_PROD], "ZIP")) + device_type = 0; +#endif + + if (protocol != 2) + printk(KERN_ERR "%s: %s: protocol (0x%02x) is not ATAPI\n", + s, drive->name, protocol); + else if ((drive->media == ide_floppy && device_type != 0) || + (drive->media == ide_tape && device_type != 1)) + printk(KERN_ERR "%s: %s: invalid device type (0x%02x)\n", + s, drive->name, device_type); + else if (removable == 0) + printk(KERN_ERR "%s: %s: the removable flag is not set\n", + s, drive->name); + else if (drive->media == ide_floppy && drq_type == 3) + printk(KERN_ERR "%s: %s: sorry, DRQ type (0x%02x) not " + "supported\n", s, drive->name, drq_type); + else if (packet_size != 0) + printk(KERN_ERR "%s: %s: packet size (0x%02x) is not 12 " + "bytes\n", s, drive->name, packet_size); + else + return 1; + return 0; +} +EXPORT_SYMBOL_GPL(ide_check_atapi_device); + +void ide_init_pc(struct ide_atapi_pc *pc) +{ + memset(pc, 0, sizeof(*pc)); +} +EXPORT_SYMBOL_GPL(ide_init_pc); + +/* + * Add a special packet command request to the tail of the request queue, + * and wait for it to be serviced. + */ +int ide_queue_pc_tail(ide_drive_t *drive, struct gendisk *disk, + struct ide_atapi_pc *pc, void *buf, unsigned int bufflen) +{ + struct request *rq; + int error; + + rq = blk_get_request(drive->queue, READ, __GFP_WAIT); + rq->cmd_type = REQ_TYPE_SPECIAL; + rq->special = (char *)pc; + + if (buf && bufflen) { + error = blk_rq_map_kern(drive->queue, rq, buf, bufflen, + GFP_NOIO); + if (error) + goto put_req; + } + + memcpy(rq->cmd, pc->c, 12); + if (drive->media == ide_tape) + rq->cmd[13] = REQ_IDETAPE_PC1; + error = blk_execute_rq(drive->queue, disk, rq, 0); +put_req: + blk_put_request(rq); + return error; +} +EXPORT_SYMBOL_GPL(ide_queue_pc_tail); + +int ide_do_test_unit_ready(ide_drive_t *drive, struct gendisk *disk) +{ + struct ide_atapi_pc pc; + + ide_init_pc(&pc); + pc.c[0] = TEST_UNIT_READY; + + return ide_queue_pc_tail(drive, disk, &pc, NULL, 0); +} +EXPORT_SYMBOL_GPL(ide_do_test_unit_ready); + +int ide_do_start_stop(ide_drive_t *drive, struct gendisk *disk, int start) +{ + struct ide_atapi_pc pc; + + ide_init_pc(&pc); + pc.c[0] = START_STOP; + pc.c[4] = start; + + if (drive->media == ide_tape) + pc.flags |= PC_FLAG_WAIT_FOR_DSC; + + return ide_queue_pc_tail(drive, disk, &pc, NULL, 0); +} +EXPORT_SYMBOL_GPL(ide_do_start_stop); + +int ide_set_media_lock(ide_drive_t *drive, struct gendisk *disk, int on) +{ + struct ide_atapi_pc pc; + + if ((drive->dev_flags & IDE_DFLAG_DOORLOCKING) == 0) + return 0; + + ide_init_pc(&pc); + pc.c[0] = ALLOW_MEDIUM_REMOVAL; + pc.c[4] = on; + + return ide_queue_pc_tail(drive, disk, &pc, NULL, 0); +} +EXPORT_SYMBOL_GPL(ide_set_media_lock); + +void ide_create_request_sense_cmd(ide_drive_t *drive, struct ide_atapi_pc *pc) +{ + ide_init_pc(pc); + pc->c[0] = REQUEST_SENSE; + if (drive->media == ide_floppy) { + pc->c[4] = 255; + pc->req_xfer = 18; + } else { + pc->c[4] = 20; + pc->req_xfer = 20; + } +} +EXPORT_SYMBOL_GPL(ide_create_request_sense_cmd); + +void ide_prep_sense(ide_drive_t *drive, struct request *rq) +{ + struct request_sense *sense = &drive->sense_data; + struct request *sense_rq = &drive->sense_rq; + unsigned int cmd_len, sense_len; + int err; + + switch (drive->media) { + case ide_floppy: + cmd_len = 255; + sense_len = 18; + break; + case ide_tape: + cmd_len = 20; + sense_len = 20; + break; + default: + cmd_len = 18; + sense_len = 18; + } + + BUG_ON(sense_len > sizeof(*sense)); + + if (rq->cmd_type == REQ_TYPE_SENSE || drive->sense_rq_armed) + return; + + memset(sense, 0, sizeof(*sense)); + + blk_rq_init(rq->q, sense_rq); + + err = blk_rq_map_kern(drive->queue, sense_rq, sense, sense_len, + GFP_NOIO); + if (unlikely(err)) { + if (printk_ratelimit()) + printk(KERN_WARNING PFX "%s: failed to map sense " + "buffer\n", drive->name); + return; + } + + sense_rq->rq_disk = rq->rq_disk; + sense_rq->cmd[0] = GPCMD_REQUEST_SENSE; + sense_rq->cmd[4] = cmd_len; + sense_rq->cmd_type = REQ_TYPE_SENSE; + sense_rq->cmd_flags |= REQ_PREEMPT; + + if (drive->media == ide_tape) + sense_rq->cmd[13] = REQ_IDETAPE_PC1; + + drive->sense_rq_armed = true; +} +EXPORT_SYMBOL_GPL(ide_prep_sense); + +int ide_queue_sense_rq(ide_drive_t *drive, void *special) +{ + /* deferred failure from ide_prep_sense() */ + if (!drive->sense_rq_armed) { + printk(KERN_WARNING PFX "%s: error queuing a sense request\n", + drive->name); + return -ENOMEM; + } + + drive->sense_rq.special = special; + drive->sense_rq_armed = false; + + drive->hwif->rq = NULL; + + elv_add_request(drive->queue, &drive->sense_rq, ELEVATOR_INSERT_FRONT); + return 0; +} +EXPORT_SYMBOL_GPL(ide_queue_sense_rq); + +/* + * Called when an error was detected during the last packet command. + * We queue a request sense packet command at the head of the request + * queue. + */ +void ide_retry_pc(ide_drive_t *drive) +{ + struct request *failed_rq = drive->hwif->rq; + struct request *sense_rq = &drive->sense_rq; + struct ide_atapi_pc *pc = &drive->request_sense_pc; + + (void)ide_read_error(drive); + + /* init pc from sense_rq */ + ide_init_pc(pc); + memcpy(pc->c, sense_rq->cmd, 12); + + if (drive->media == ide_tape) + drive->atapi_flags |= IDE_AFLAG_IGNORE_DSC; + + /* + * Push back the failed request and put request sense on top + * of it. The failed command will be retried after sense data + * is acquired. + */ + drive->hwif->rq = NULL; + ide_requeue_and_plug(drive, failed_rq); + if (ide_queue_sense_rq(drive, pc)) { + blk_start_request(failed_rq); + ide_complete_rq(drive, -EIO, blk_rq_bytes(failed_rq)); + } +} +EXPORT_SYMBOL_GPL(ide_retry_pc); + +int ide_cd_expiry(ide_drive_t *drive) +{ + struct request *rq = drive->hwif->rq; + unsigned long wait = 0; + + debug_log("%s: rq->cmd[0]: 0x%x\n", __func__, rq->cmd[0]); + + /* + * Some commands are *slow* and normally take a long time to complete. + * Usually we can use the ATAPI "disconnect" to bypass this, but not all + * commands/drives support that. Let ide_timer_expiry keep polling us + * for these. + */ + switch (rq->cmd[0]) { + case GPCMD_BLANK: + case GPCMD_FORMAT_UNIT: + case GPCMD_RESERVE_RZONE_TRACK: + case GPCMD_CLOSE_TRACK: + case GPCMD_FLUSH_CACHE: + wait = ATAPI_WAIT_PC; + break; + default: + if (!(rq->cmd_flags & REQ_QUIET)) + printk(KERN_INFO PFX "cmd 0x%x timed out\n", + rq->cmd[0]); + wait = 0; + break; + } + return wait; +} +EXPORT_SYMBOL_GPL(ide_cd_expiry); + +int ide_cd_get_xferlen(struct request *rq) +{ + switch (rq->cmd_type) { + case REQ_TYPE_FS: + return 32768; + case REQ_TYPE_SENSE: + case REQ_TYPE_BLOCK_PC: + case REQ_TYPE_ATA_PC: + return blk_rq_bytes(rq); + default: + return 0; + } +} +EXPORT_SYMBOL_GPL(ide_cd_get_xferlen); + +void ide_read_bcount_and_ireason(ide_drive_t *drive, u16 *bcount, u8 *ireason) +{ + struct ide_taskfile tf; + + drive->hwif->tp_ops->tf_read(drive, &tf, IDE_VALID_NSECT | + IDE_VALID_LBAM | IDE_VALID_LBAH); + + *bcount = (tf.lbah << 8) | tf.lbam; + *ireason = tf.nsect & 3; +} +EXPORT_SYMBOL_GPL(ide_read_bcount_and_ireason); + +/* + * Check the contents of the interrupt reason register and attempt to recover if + * there are problems. + * + * Returns: + * - 0 if everything's ok + * - 1 if the request has to be terminated. + */ +int ide_check_ireason(ide_drive_t *drive, struct request *rq, int len, + int ireason, int rw) +{ + ide_hwif_t *hwif = drive->hwif; + + debug_log("ireason: 0x%x, rw: 0x%x\n", ireason, rw); + + if (ireason == (!rw << 1)) + return 0; + else if (ireason == (rw << 1)) { + printk(KERN_ERR PFX "%s: %s: wrong transfer direction!\n", + drive->name, __func__); + + if (dev_is_idecd(drive)) + ide_pad_transfer(drive, rw, len); + } else if (!rw && ireason == ATAPI_COD) { + if (dev_is_idecd(drive)) { + /* + * Some drives (ASUS) seem to tell us that status info + * is available. Just get it and ignore. + */ + (void)hwif->tp_ops->read_status(hwif); + return 0; + } + } else { + if (ireason & ATAPI_COD) + printk(KERN_ERR PFX "%s: CoD != 0 in %s\n", drive->name, + __func__); + + /* drive wants a command packet, or invalid ireason... */ + printk(KERN_ERR PFX "%s: %s: bad interrupt reason 0x%02x\n", + drive->name, __func__, ireason); + } + + if (dev_is_idecd(drive) && rq->cmd_type == REQ_TYPE_ATA_PC) + rq->cmd_flags |= REQ_FAILED; + + return 1; +} +EXPORT_SYMBOL_GPL(ide_check_ireason); + +/* + * This is the usual interrupt handler which will be called during a packet + * command. We will transfer some of the data (as requested by the drive) + * and will re-point interrupt handler to us. + */ +static ide_startstop_t ide_pc_intr(ide_drive_t *drive) +{ + struct ide_atapi_pc *pc = drive->pc; + ide_hwif_t *hwif = drive->hwif; + struct ide_cmd *cmd = &hwif->cmd; + struct request *rq = hwif->rq; + const struct ide_tp_ops *tp_ops = hwif->tp_ops; + unsigned int timeout, done; + u16 bcount; + u8 stat, ireason, dsc = 0; + u8 write = !!(pc->flags & PC_FLAG_WRITING); + + debug_log("Enter %s - interrupt handler\n", __func__); + + timeout = (drive->media == ide_floppy) ? WAIT_FLOPPY_CMD + : WAIT_TAPE_CMD; + + /* Clear the interrupt */ + stat = tp_ops->read_status(hwif); + + if (pc->flags & PC_FLAG_DMA_IN_PROGRESS) { + int rc; + + drive->waiting_for_dma = 0; + rc = hwif->dma_ops->dma_end(drive); + ide_dma_unmap_sg(drive, cmd); + + if (rc || (drive->media == ide_tape && (stat & ATA_ERR))) { + if (drive->media == ide_floppy) + printk(KERN_ERR PFX "%s: DMA %s error\n", + drive->name, rq_data_dir(pc->rq) + ? "write" : "read"); + pc->flags |= PC_FLAG_DMA_ERROR; + } else + rq->resid_len = 0; + debug_log("%s: DMA finished\n", drive->name); + } + + /* No more interrupts */ + if ((stat & ATA_DRQ) == 0) { + int uptodate, error; + + debug_log("Packet command completed, %d bytes transferred\n", + blk_rq_bytes(rq)); + + pc->flags &= ~PC_FLAG_DMA_IN_PROGRESS; + + local_irq_enable_in_hardirq(); + + if (drive->media == ide_tape && + (stat & ATA_ERR) && rq->cmd[0] == REQUEST_SENSE) + stat &= ~ATA_ERR; + + if ((stat & ATA_ERR) || (pc->flags & PC_FLAG_DMA_ERROR)) { + /* Error detected */ + debug_log("%s: I/O error\n", drive->name); + + if (drive->media != ide_tape) + pc->rq->errors++; + + if (rq->cmd[0] == REQUEST_SENSE) { + printk(KERN_ERR PFX "%s: I/O error in request " + "sense command\n", drive->name); + return ide_do_reset(drive); + } + + debug_log("[cmd %x]: check condition\n", rq->cmd[0]); + + /* Retry operation */ + ide_retry_pc(drive); + + /* queued, but not started */ + return ide_stopped; + } + pc->error = 0; + + if ((pc->flags & PC_FLAG_WAIT_FOR_DSC) && (stat & ATA_DSC) == 0) + dsc = 1; + + /* + * ->pc_callback() might change rq->data_len for + * residual count, cache total length. + */ + done = blk_rq_bytes(rq); + + /* Command finished - Call the callback function */ + uptodate = drive->pc_callback(drive, dsc); + + if (uptodate == 0) + drive->failed_pc = NULL; + + if (rq->cmd_type == REQ_TYPE_SPECIAL) { + rq->errors = 0; + error = 0; + } else { + + if (rq->cmd_type != REQ_TYPE_FS && uptodate <= 0) { + if (rq->errors == 0) + rq->errors = -EIO; + } + + error = uptodate ? 0 : -EIO; + } + + ide_complete_rq(drive, error, blk_rq_bytes(rq)); + return ide_stopped; + } + + if (pc->flags & PC_FLAG_DMA_IN_PROGRESS) { + pc->flags &= ~PC_FLAG_DMA_IN_PROGRESS; + printk(KERN_ERR PFX "%s: The device wants to issue more " + "interrupts in DMA mode\n", drive->name); + ide_dma_off(drive); + return ide_do_reset(drive); + } + + /* Get the number of bytes to transfer on this interrupt. */ + ide_read_bcount_and_ireason(drive, &bcount, &ireason); + + if (ide_check_ireason(drive, rq, bcount, ireason, write)) + return ide_do_reset(drive); + + done = min_t(unsigned int, bcount, cmd->nleft); + ide_pio_bytes(drive, cmd, write, done); + + /* Update transferred byte count */ + rq->resid_len -= done; + + bcount -= done; + + if (bcount) + ide_pad_transfer(drive, write, bcount); + + debug_log("[cmd %x] transferred %d bytes, padded %d bytes, resid: %u\n", + rq->cmd[0], done, bcount, rq->resid_len); + + /* And set the interrupt handler again */ + ide_set_handler(drive, ide_pc_intr, timeout); + return ide_started; +} + +static void ide_init_packet_cmd(struct ide_cmd *cmd, u8 valid_tf, + u16 bcount, u8 dma) +{ + cmd->protocol = dma ? ATAPI_PROT_DMA : ATAPI_PROT_PIO; + cmd->valid.out.tf = IDE_VALID_LBAH | IDE_VALID_LBAM | + IDE_VALID_FEATURE | valid_tf; + cmd->tf.command = ATA_CMD_PACKET; + cmd->tf.feature = dma; /* Use PIO/DMA */ + cmd->tf.lbam = bcount & 0xff; + cmd->tf.lbah = (bcount >> 8) & 0xff; +} + +static u8 ide_read_ireason(ide_drive_t *drive) +{ + struct ide_taskfile tf; + + drive->hwif->tp_ops->tf_read(drive, &tf, IDE_VALID_NSECT); + + return tf.nsect & 3; +} + +static u8 ide_wait_ireason(ide_drive_t *drive, u8 ireason) +{ + int retries = 100; + + while (retries-- && ((ireason & ATAPI_COD) == 0 || + (ireason & ATAPI_IO))) { + printk(KERN_ERR PFX "%s: (IO,CoD != (0,1) while issuing " + "a packet command, retrying\n", drive->name); + udelay(100); + ireason = ide_read_ireason(drive); + if (retries == 0) { + printk(KERN_ERR PFX "%s: (IO,CoD != (0,1) while issuing" + " a packet command, ignoring\n", + drive->name); + ireason |= ATAPI_COD; + ireason &= ~ATAPI_IO; + } + } + + return ireason; +} + +static int ide_delayed_transfer_pc(ide_drive_t *drive) +{ + /* Send the actual packet */ + drive->hwif->tp_ops->output_data(drive, NULL, drive->pc->c, 12); + + /* Timeout for the packet command */ + return WAIT_FLOPPY_CMD; +} + +static ide_startstop_t ide_transfer_pc(ide_drive_t *drive) +{ + struct ide_atapi_pc *uninitialized_var(pc); + ide_hwif_t *hwif = drive->hwif; + struct request *rq = hwif->rq; + ide_expiry_t *expiry; + unsigned int timeout; + int cmd_len; + ide_startstop_t startstop; + u8 ireason; + + if (ide_wait_stat(&startstop, drive, ATA_DRQ, ATA_BUSY, WAIT_READY)) { + printk(KERN_ERR PFX "%s: Strange, packet command initiated yet " + "DRQ isn't asserted\n", drive->name); + return startstop; + } + + if (drive->atapi_flags & IDE_AFLAG_DRQ_INTERRUPT) { + if (drive->dma) + drive->waiting_for_dma = 1; + } + + if (dev_is_idecd(drive)) { + /* 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; + + timeout = rq->timeout; + expiry = ide_cd_expiry; + } else { + pc = drive->pc; + + cmd_len = ATAPI_MIN_CDB_BYTES; + + /* + * If necessary schedule the packet transfer to occur 'timeout' + * milliseconds later in ide_delayed_transfer_pc() after the + * device says it's ready for a packet. + */ + if (drive->atapi_flags & IDE_AFLAG_ZIP_DRIVE) { + timeout = drive->pc_delay; + expiry = &ide_delayed_transfer_pc; + } else { + timeout = (drive->media == ide_floppy) ? WAIT_FLOPPY_CMD + : WAIT_TAPE_CMD; + expiry = NULL; + } + + ireason = ide_read_ireason(drive); + if (drive->media == ide_tape) + ireason = ide_wait_ireason(drive, ireason); + + if ((ireason & ATAPI_COD) == 0 || (ireason & ATAPI_IO)) { + printk(KERN_ERR PFX "%s: (IO,CoD) != (0,1) while " + "issuing a packet command\n", drive->name); + + return ide_do_reset(drive); + } + } + + hwif->expiry = expiry; + + /* Set the interrupt routine */ + ide_set_handler(drive, + (dev_is_idecd(drive) ? drive->irq_handler + : ide_pc_intr), + timeout); + + /* Send the actual packet */ + if ((drive->atapi_flags & IDE_AFLAG_ZIP_DRIVE) == 0) + hwif->tp_ops->output_data(drive, NULL, rq->cmd, cmd_len); + + /* Begin DMA, if necessary */ + if (dev_is_idecd(drive)) { + if (drive->dma) + hwif->dma_ops->dma_start(drive); + } else { + if (pc->flags & PC_FLAG_DMA_OK) { + pc->flags |= PC_FLAG_DMA_IN_PROGRESS; + hwif->dma_ops->dma_start(drive); + } + } + + return ide_started; +} + +ide_startstop_t ide_issue_pc(ide_drive_t *drive, struct ide_cmd *cmd) +{ + struct ide_atapi_pc *pc; + ide_hwif_t *hwif = drive->hwif; + ide_expiry_t *expiry = NULL; + struct request *rq = hwif->rq; + unsigned int timeout, bytes; + u16 bcount; + u8 valid_tf; + u8 drq_int = !!(drive->atapi_flags & IDE_AFLAG_DRQ_INTERRUPT); + + if (dev_is_idecd(drive)) { + valid_tf = IDE_VALID_NSECT | IDE_VALID_LBAL; + bcount = ide_cd_get_xferlen(rq); + expiry = ide_cd_expiry; + timeout = ATAPI_WAIT_PC; + + if (drive->dma) + drive->dma = !ide_dma_prepare(drive, cmd); + } else { + pc = drive->pc; + + valid_tf = IDE_VALID_DEVICE; + bytes = blk_rq_bytes(rq); + bcount = ((drive->media == ide_tape) ? bytes + : min_t(unsigned int, + bytes, 63 * 1024)); + + /* We haven't transferred any data yet */ + rq->resid_len = bcount; + + if (pc->flags & PC_FLAG_DMA_ERROR) { + pc->flags &= ~PC_FLAG_DMA_ERROR; + ide_dma_off(drive); + } + + if (pc->flags & PC_FLAG_DMA_OK) + drive->dma = !ide_dma_prepare(drive, cmd); + + if (!drive->dma) + pc->flags &= ~PC_FLAG_DMA_OK; + + timeout = (drive->media == ide_floppy) ? WAIT_FLOPPY_CMD + : WAIT_TAPE_CMD; + } + + ide_init_packet_cmd(cmd, valid_tf, bcount, drive->dma); + + (void)do_rw_taskfile(drive, cmd); + + if (drq_int) { + if (drive->dma) + drive->waiting_for_dma = 0; + hwif->expiry = expiry; + } + + ide_execute_command(drive, cmd, ide_transfer_pc, timeout); + + return drq_int ? ide_started : ide_transfer_pc(drive); +} +EXPORT_SYMBOL_GPL(ide_issue_pc); diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c index 654d4cd0984..0b510bafd90 100644 --- a/drivers/ide/ide-cd.c +++ b/drivers/ide/ide-cd.c @@ -1,311 +1,36 @@ /* - * linux/drivers/ide/ide-cd.c + * ATAPI CD-ROM driver. * - * 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> + * Copyright (C) 1994-1996 Scott Snyder <snyder@fnald0.fnal.gov> + * Copyright (C) 1996-1998 Erik Andersen <andersee@debian.org> + * Copyright (C) 1998-2000 Jens Axboe <axboe@suse.de> + * Copyright (C) 2005, 2007-2009 Bartlomiej Zolnierkiewicz * * 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... + * Documentation: + * Mt. Fuji (SFF8090 version 4) and ATAPI (SFF-8020i rev 2.6) standards. * - * ---------------------------------- - * 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" + * For historical changelog please see: + * Documentation/ide/ChangeLog.ide-cd.1994-2004 + */ + +#define DRV_NAME "ide-cd" +#define PFX DRV_NAME ": " + +#define IDECD_VERSION "5.00" #include <linux/module.h> #include <linux/types.h> #include <linux/kernel.h> #include <linux/delay.h> #include <linux/timer.h> +#include <linux/seq_file.h> #include <linux/slab.h> #include <linux/interrupt.h> #include <linux/errno.h> @@ -313,1668 +38,726 @@ #include <linux/ide.h> #include <linux/completion.h> #include <linux/mutex.h> +#include <linux/bcd.h> -#include <scsi/scsi.h> /* For SCSI -> ATAPI command conversion */ +/* For SCSI -> ATAPI command conversion */ +#include <scsi/scsi.h> -#include <asm/irq.h> -#include <asm/io.h> +#include <linux/io.h> #include <asm/byteorder.h> -#include <asm/uaccess.h> +#include <linux/uaccess.h> #include <asm/unaligned.h> #include "ide-cd.h" +static DEFINE_MUTEX(ide_cd_mutex); static DEFINE_MUTEX(idecd_ref_mutex); -#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 void ide_cd_release(struct device *); static struct cdrom_info *ide_cd_get(struct gendisk *disk) { struct cdrom_info *cd = NULL; mutex_lock(&idecd_ref_mutex); - cd = ide_cd_g(disk); - if (cd) - kref_get(&cd->kref); + cd = ide_drv_g(disk, cdrom_info); + if (cd) { + if (ide_device_get(cd->drive)) + cd = NULL; + else + get_device(&cd->dev); + + } mutex_unlock(&idecd_ref_mutex); return cd; } -static void ide_cd_release(struct kref *); - static void ide_cd_put(struct cdrom_info *cd) { + ide_drive_t *drive = cd->drive; + mutex_lock(&idecd_ref_mutex); - kref_put(&cd->kref, ide_cd_release); + put_device(&cd->dev); + ide_device_put(drive); mutex_unlock(&idecd_ref_mutex); } -/**************************************************************************** +/* * Generic packet command support and error handling routines. */ -/* Mark that we've seen a media change, and invalidate our internal - buffers. */ -static void cdrom_saw_media_change (ide_drive_t *drive) +/* 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; + drive->dev_flags |= IDE_DFLAG_MEDIA_CHANGED; + drive->atapi_flags &= ~IDE_AFLAG_TOC_VALID; } -static int cdrom_log_sense(ide_drive_t *drive, struct request *rq, - struct request_sense *sense) +static int cdrom_log_sense(ide_drive_t *drive, struct request *rq) { + struct request_sense *sense = &drive->sense_data; int log = 0; - if (!sense || !rq || (rq->flags & REQ_QUIET)) + if (!sense || !rq || (rq->cmd_flags & REQ_QUIET)) return 0; + ide_debug_log(IDE_DBG_SENSE, "sense_key: 0x%x", sense->sense_key); + switch (sense->sense_key) { - case NO_SENSE: case RECOVERED_ERROR: - break; - case NOT_READY: - /* - * don't care about tray state messages for - * e.g. capacity commands or in-progress or - * becoming ready - */ - if (sense->asc == 0x3a || sense->asc == 0x04) - break; - log = 1; - break; - case ILLEGAL_REQUEST: - /* - * don't log START_STOP unit with LoEj set, since - * we cannot reliably check if drive can auto-close - */ - if (rq->cmd[0] == GPCMD_START_STOP_UNIT && sense->asc == 0x24) - break; - log = 1; - break; - case UNIT_ATTENTION: - /* - * Make good and sure we've seen this potential media - * change. Some drives (i.e. Creative) fail to present - * the correct sense key in the error register. - */ - cdrom_saw_media_change(drive); + 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; - default: - log = 1; + log = 1; + break; + case ILLEGAL_REQUEST: + /* + * don't log START_STOP unit with LoEj set, since we cannot + * reliably check if drive can auto-close + */ + if (rq->cmd[0] == GPCMD_START_STOP_UNIT && sense->asc == 0x24) break; + log = 1; + break; + case UNIT_ATTENTION: + /* + * Make good and sure we've seen this potential media change. + * Some drives (i.e. Creative) fail to present the correct sense + * key in the error register. + */ + cdrom_saw_media_change(drive); + break; + default: + log = 1; + break; } return log; } -static -void cdrom_analyze_sense_data(ide_drive_t *drive, - struct request *failed_command, - struct request_sense *sense) +static void cdrom_analyze_sense_data(ide_drive_t *drive, + struct request *failed_command) { + struct request_sense *sense = &drive->sense_data; + struct cdrom_info *info = drive->driver_data; unsigned long sector; unsigned long bio_sectors; - unsigned long valid; - struct cdrom_info *info = drive->driver_data; - if (!cdrom_log_sense(drive, failed_command, sense)) + ide_debug_log(IDE_DBG_SENSE, "error_code: 0x%x, sense_key: 0x%x", + sense->error_code, sense->sense_key); + + if (failed_command) + ide_debug_log(IDE_DBG_SENSE, "failed cmd: 0x%x", + failed_command->cmd[0]); + + if (!cdrom_log_sense(drive, failed_command)) 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 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 (sense->error_code == 0x70) { /* Current Error */ - switch(sense->sense_key) { + /* current error */ + if (sense->error_code == 0x70) { + switch (sense->sense_key) { case MEDIUM_ERROR: case VOLUME_OVERFLOW: case ILLEGAL_REQUEST: if (!sense->valid) break; if (failed_command == NULL || - !blk_fs_request(failed_command)) + failed_command->cmd_type != REQ_TYPE_FS) break; sector = (sense->information[0] << 24) | (sense->information[1] << 16) | (sense->information[2] << 8) | (sense->information[3]); - bio_sectors = bio_sectors(failed_command->bio); - if (bio_sectors < 4) - bio_sectors = 4; - if (drive->queue->hardsect_size == 2048) - sector <<= 2; /* Device sector size is 2K */ - sector &= ~(bio_sectors -1); - valid = (sector - failed_command->sector) << 9; + if (queue_logical_block_size(drive->queue) == 2048) + /* device sector size is 2K */ + sector <<= 2; + + bio_sectors = max(bio_sectors(failed_command->bio), 4U); + sector &= ~(bio_sectors - 1); - if (valid < 0) - valid = 0; + /* + * The SCSI specification allows for the value + * returned by READ CAPACITY to be up to 75 2K + * sectors past the last readable block. + * Therefore, if we hit a medium error within the + * last 75 2K sectors, we decrease the saved size + * value. + */ if (sector < get_capacity(info->disk) && - drive->probed_capacity - sector < 4 * 75) { + drive->probed_capacity - sector < 4 * 75) set_capacity(info->disk, sector); - } - } - } -#if VERBOSE_IDE_CD_ERRORS - { - int i; - const char *s = "bad sense key!"; - 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]; - - 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 */ + ide_cd_log_error(drive->name, failed_command, sense); +} - /* Suppress printing unit attention and `in progress of becoming ready' - errors when we're not being verbose. */ +static void ide_cd_complete_failed_rq(ide_drive_t *drive, struct request *rq) +{ + /* + * For REQ_TYPE_SENSE, "rq->special" points to the original + * failed request. Also, the sense data should be read + * directly from rq which might be different from the original + * sense buffer if it got copied during mapping. + */ + struct request *failed = (struct request *)rq->special; + void *sense = bio_data(rq->bio); - if (sense->sense_key == UNIT_ATTENTION || - (sense->sense_key == NOT_READY && (sense->asc == 4 || - sense->asc == 0x3a))) - return; + if (failed) { + if (failed->sense) { + /* + * Sense is always read into drive->sense_data. + * Copy back if the failed request has its + * sense pointer set. + */ + memcpy(failed->sense, sense, 18); + failed->sense_len = rq->sense_len; + } + cdrom_analyze_sense_data(drive, failed); - 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 */ + if (ide_end_rq(drive, failed, -EIO, blk_rq_bytes(failed))) + BUG(); + } else + cdrom_analyze_sense_data(drive, NULL); } + /* - * Initialize a ide-cd packet command request + * Allow the drive 5 seconds to recover; some devices will return NOT_READY + * while flushing data from cache. + * + * returns: 0 failed (write timeout expired) + * 1 success */ -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) +static int ide_cd_breathe(ide_drive_t *drive, struct request *rq) { - 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; + struct cdrom_info *info = drive->driver_data; - (void) ide_do_drive_cmd(drive, rq, ide_preempt); -} + if (!rq->errors) + info->write_timeout = jiffies + ATAPI_WAIT_WRITE_BUSY; -static void cdrom_end_request (ide_drive_t *drive, int uptodate) -{ - struct request *rq = HWGROUP(drive)->rq; - int nsectors = rq->hard_cur_sectors; + rq->errors = 1; - if ((rq->flags & REQ_SENSE) && uptodate) { + if (time_after(jiffies, info->write_timeout)) + return 0; + else { /* - * For REQ_SENSE, "rq->buffer" points to the original failed - * request + * take a breather */ - struct request *failed = (struct request *) rq->buffer; - struct cdrom_info *info = drive->driver_data; - void *sense = &info->sense_data; - unsigned long flags; - - if (failed) { - if (failed->sense) { - sense = failed->sense; - failed->sense_len = rq->sense_len; - } - cdrom_analyze_sense_data(drive, failed, sense); - /* - * now end failed request - */ - if (blk_fs_request(failed)) { - if (ide_end_dequeued_request(drive, failed, 0, - failed->hard_nr_sectors)) - BUG(); - } else { - spin_lock_irqsave(&ide_lock, flags); - end_that_request_chunk(failed, 0, - failed->data_len); - end_that_request_last(failed, 0); - spin_unlock_irqrestore(&ide_lock, flags); - } - } else - cdrom_analyze_sense_data(drive, NULL, sense); + blk_delay_queue(drive->queue, 1); + return 1; } - - 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); -} - -static void ide_dump_status_no_sense(ide_drive_t *drive, const char *msg, u8 stat) -{ - if (stat & 0x80) - return; - ide_dump_status(drive, msg, stat); } -/* 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) +/** + * Returns: + * 0: if the request should be continued. + * 1: if the request will be going through error recovery. + * 2: if the request should be ended. + */ +static int cdrom_decode_status(ide_drive_t *drive, u8 stat) { - 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; + ide_hwif_t *hwif = drive->hwif; + struct request *rq = hwif->rq; + int err, sense_key, do_end_request = 0; - /* Get the IDE error register. */ - err = HWIF(drive)->INB(IDE_ERROR_REG); + /* get the IDE error register */ + err = ide_read_error(drive); 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; + ide_debug_log(IDE_DBG_RQ, "cmd: 0x%x, rq->cmd_type: 0x%x, err: 0x%x, " + "stat 0x%x", + rq->cmd[0], rq->cmd_type, err, stat); + if (rq->cmd_type == REQ_TYPE_SENSE) { /* - * if we have an error, pass back CHECK_CONDITION as the - * scsi status byte + * We got an error trying to get sense info from the drive + * (probably while trying to recover from a former error). + * Just give up. */ - 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); + rq->cmd_flags |= REQ_FAILED; + return 2; + } - cdrom_queue_request_sense(drive, rq->sense, rq); - } else - cdrom_end_request(drive, 0); + /* if we have an error, pass CHECK_CONDITION as the SCSI status byte */ + if (rq->cmd_type == REQ_TYPE_BLOCK_PC && !rq->errors) + rq->errors = SAM_STAT_CHECK_CONDITION; - } else if (blk_fs_request(rq)) { - int do_end_request = 0; + if (blk_noretry_request(rq)) + do_end_request = 1; - /* Handle errors from READ and WRITE requests. */ + switch (sense_key) { + case NOT_READY: + if (rq->cmd_type == REQ_TYPE_FS && rq_data_dir(rq) == WRITE) { + if (ide_cd_breathe(drive, rq)) + return 1; + } else { + cdrom_saw_media_change(drive); - if (blk_noretry_request(rq)) - do_end_request = 1; + if (rq->cmd_type == REQ_TYPE_FS && + !(rq->cmd_flags & REQ_QUIET)) + printk(KERN_ERR PFX "%s: tray open\n", + drive->name); + } + do_end_request = 1; + break; + case UNIT_ATTENTION: + cdrom_saw_media_change(drive); - if (sense_key == NOT_READY) { - /* Tray open. */ - if (rq_data_dir(rq) == READ) { - cdrom_saw_media_change (drive); + if (rq->cmd_type != REQ_TYPE_FS) + return 0; - /* 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_no_sense (drive, "command error", stat); - do_end_request = 1; - } else if (sense_key == MEDIUM_ERROR) { - /* No point in re-trying a zillion times on a bad - * sector... If we got here the error is not correctable */ - ide_dump_status_no_sense (drive, "media error (bad sector)", stat); - do_end_request = 1; - } else if (sense_key == BLANK_CHECK) { - /* Disk appears blank ?? */ - ide_dump_status_no_sense (drive, "media error (blank)", stat); + /* + * 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 ((err & ~ABRT_ERR) != 0) { - /* Go to the default handler - for other errors. */ + break; + case ILLEGAL_REQUEST: + /* + * Don't print error message for this condition -- SFF8090i + * indicates that 5/24/00 is the correct response to a request + * to close the tray if the drive doesn't have that capability. + * + * cdrom_log_sense() knows this! + */ + if (rq->cmd[0] == GPCMD_START_STOP_UNIT) + break; + /* fall-through */ + case DATA_PROTECT: + /* + * No point in retrying after an illegal request or data + * protect error. + */ + if (!(rq->cmd_flags & REQ_QUIET)) + ide_dump_status(drive, "command error", stat); + do_end_request = 1; + break; + case MEDIUM_ERROR: + /* + * No point in re-trying a zillion times on a bad sector. + * If we got here the error is not correctable. + */ + if (!(rq->cmd_flags & REQ_QUIET)) + ide_dump_status(drive, "media error " + "(bad sector)", stat); + do_end_request = 1; + break; + case BLANK_CHECK: + /* disk appears blank? */ + if (!(rq->cmd_flags & REQ_QUIET)) + ide_dump_status(drive, "media error (blank)", + stat); + do_end_request = 1; + break; + default: + if (rq->cmd_type != REQ_TYPE_FS) + break; + if (err & ~ATA_ABORTED) { + /* 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. */ + } else if (++rq->errors > ERROR_MAX) + /* we've racked up too many retries, abort */ do_end_request = 1; - } - - /* End a request through request sense analysis when we have - sense data. We need this in order to perform end of media - processing */ - - if (do_end_request) { - if (stat & ERR_STAT) { - unsigned long flags; - spin_lock_irqsave(&ide_lock, flags); - blkdev_dequeue_request(rq); - HWGROUP(drive)->rq = NULL; - spin_unlock_irqrestore(&ide_lock, flags); - - cdrom_queue_request_sense(drive, rq->sense, rq); - } else - cdrom_end_request(drive, 0); - } else { - /* If we got a CHECK_CONDITION status, - queue a request sense command. */ - if (stat & ERR_STAT) - 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; + if (rq->cmd_type != REQ_TYPE_FS) { + rq->cmd_flags |= REQ_FAILED; + do_end_request = 1; + } /* - * 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. + * End a request through request sense analysis when we have sense data. + * We need this in order to perform end of media processing. */ - 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; - } -} + if (do_end_request) + goto end_request; -/* - * Check the contents of the interrupt reason register from the cdrom - * and attempt to recover if there are problems. Returns 0 if everything's - * ok; nonzero if the request has been terminated. - */ -static -int 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); - } + /* if we got a CHECK_CONDITION status, queue a request sense command */ + if (stat & ATA_ERR) + return ide_queue_sense_rq(drive, NULL) ? 2 : 1; + return 1; - cdrom_end_request(drive, 0); - return -1; +end_request: + if (stat & ATA_ERR) { + hwif->rq = NULL; + return ide_queue_sense_rq(drive, rq) ? 2 : 1; + } else + return 2; } -/* - * Interrupt routine. Called when a read request has completed. - */ -static ide_startstop_t cdrom_read_intr (ide_drive_t *drive) +static void ide_cd_request_sense_fixup(ide_drive_t *drive, struct ide_cmd *cmd) { - 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 = cmd->rq; - struct request *rq = HWGROUP(drive)->rq; + ide_debug_log(IDE_DBG_FUNC, "rq->cmd[0]: 0x%x", rq->cmd[0]); /* - * handle dma case + * Some of the trailing request sense fields are optional, + * and some drives don't send them. Sigh. */ - 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; + if (rq->cmd[0] == GPCMD_REQUEST_SENSE && + cmd->nleft > 0 && cmd->nleft <= 5) + cmd->nleft = 0; } -/* - * 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) +int ide_cd_queue_pc(ide_drive_t *drive, const unsigned char *cmd, + int write, void *buffer, unsigned *bufflen, + struct request_sense *sense, int timeout, + unsigned int cmd_flags) { struct cdrom_info *info = drive->driver_data; - struct request *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; - } + struct request_sense local_sense; + int retries = 10; + unsigned int flags = 0; - /* If we've satisfied the current request, - terminate it successfully. */ - if (rq->nr_sectors == 0) { - cdrom_end_request(drive, 1); - return -1; - } + if (!sense) + sense = &local_sense; - /* 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; - } + ide_debug_log(IDE_DBG_PC, "cmd[0]: 0x%x, write: 0x%x, timeout: %d, " + "cmd_flags: 0x%x", + cmd[0], write, timeout, cmd_flags); - return 0; -} + /* start of retry loop */ + do { + struct request *rq; + int error; -/* - * 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 = blk_get_request(drive->queue, write, __GFP_WAIT); + + memcpy(rq->cmd, cmd, BLK_MAX_CDB); + rq->cmd_type = REQ_TYPE_ATA_PC; + rq->sense = sense; + rq->cmd_flags |= cmd_flags; + rq->timeout = timeout; + if (buffer) { + error = blk_rq_map_kern(drive->queue, rq, buffer, + *bufflen, GFP_NOIO); + if (error) { + blk_put_request(rq); + return error; + } } - 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); -} + error = blk_execute_rq(drive->queue, info->disk, rq, 0); + if (buffer) + *bufflen = rq->resid_len; -#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 */ + flags = rq->cmd_flags; + blk_put_request(rq); -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) { + /* + * FIXME: we should probably abort/retry or something in case of + * failure. + */ + if (flags & REQ_FAILED) { /* - * this condition is far too common, to bother - * users about it + * The request failed. Retry if it was due to a unit + * attention status (usually means media was changed). */ - /* 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->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; - - /* 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; - - /* 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). " - "Trying to recover by ending request.\n", - drive->name, ireason); - rq->flags |= REQ_FAILED; - cdrom_end_request(drive, 0); - return ide_stopped; - } - - /* 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; - 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; + struct request_sense *reqbuf = sense; if (reqbuf->sense_key == UNIT_ATTENTION) cdrom_saw_media_change(drive); else if (reqbuf->sense_key == NOT_READY && reqbuf->asc == 4 && reqbuf->ascq != 4) { - /* The drive is in the process of loading - a disk. Retry, but wait a little to give - the drive time to complete the load. */ + /* + * 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. */ + /* otherwise, don't retry */ retries = 0; } --retries; } - /* End of retry loop. */ - } while ((rq->flags & REQ_FAILED) && retries >= 0); + /* end of retry loop */ + } while ((flags & REQ_FAILED) && retries >= 0); - /* Return an error if the command failed. */ - return (rq->flags & REQ_FAILED) ? -EIO : 0; + /* return an error if the command failed */ + return (flags & REQ_FAILED) ? -EIO : 0; } /* - * Write handling + * returns true if rq has been completed */ -static 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) +static bool ide_cd_error_cmd(ide_drive_t *drive, struct ide_cmd *cmd) { - u8 *c = req->cmd; - char *ibuf; - - if (!blk_pc_request(req)) - return; + unsigned int nr_bytes = cmd->nbytes - cmd->nleft; - if (req->bio) - ibuf = bio_data(req->bio); - else - ibuf = req->data; + if (cmd->tf_flags & IDE_TFLAG_WRITE) + nr_bytes -= cmd->last_xfer_len; - 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; + if (nr_bytes > 0) { + ide_complete_rq(drive, 0, nr_bytes); + return true; } -} -typedef void (xfer_func_t)(ide_drive_t *, void *, u32); + return false; +} -/* - * 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; + ide_hwif_t *hwif = drive->hwif; + struct ide_cmd *cmd = &hwif->cmd; + struct request *rq = hwif->rq; + ide_expiry_t *expiry = NULL; + int dma_error = 0, dma, thislen, uptodate = 0; + int write = (rq_data_dir(rq) == WRITE) ? 1 : 0, rc = 0; + int sense = (rq->cmd_type == REQ_TYPE_SENSE); + unsigned int timeout; + u16 len; + u8 ireason, stat; + + ide_debug_log(IDE_DBG_PC, "cmd: 0x%x, write: 0x%x", rq->cmd[0], write); + + /* check for errors */ + dma = drive->dma; if (dma) { - info->dma = 0; - dma_error = HWIF(drive)->ide_dma_end(drive); + drive->dma = 0; + drive->waiting_for_dma = 0; + dma_error = hwif->dma_ops->dma_end(drive); + ide_dma_unmap_sg(drive, cmd); + if (dma_error) { + printk(KERN_ERR PFX "%s: DMA %s error\n", drive->name, + write ? "write" : "read"); + ide_dma_off(drive); + } } - if (cdrom_decode_status(drive, 0, &stat)) - return ide_stopped; + /* check status */ + stat = hwif->tp_ops->read_status(hwif); - /* - * 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); + if (!OK_STAT(stat, 0, BAD_R_STAT)) { + rc = cdrom_decode_status(drive, stat); + if (rc) { + if (rc == 2) + goto out_end; + return ide_stopped; } + } - end_that_request_chunk(rq, 1, rq->data_len); - rq->data_len = 0; - goto end_request; + /* using dma, transfer is complete now */ + if (dma) { + if (dma_error) + return ide_error(drive, "dma error", stat); + uptodate = 1; + goto out_end; } - /* - * 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); + ide_read_bcount_and_ireason(drive, &len, &ireason); - len = lowcyl + (256 * highcyl); - thislen = rq->data_len; + thislen = (rq->cmd_type == REQ_TYPE_FS) ? len : cmd->nleft; if (thislen > len) thislen = len; - /* - * If DRQ is clear, the command has completed. - */ - if ((stat & DRQ_STAT) == 0) - goto end_request; + ide_debug_log(IDE_DBG_PC, "DRQ: stat: 0x%x, thislen: %d", + stat, thislen); - /* - * 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; + /* If DRQ is clear, the command has completed. */ + if ((stat & ATA_DRQ) == 0) { + if (rq->cmd_type == REQ_TYPE_FS) { + /* + * If we're not done reading/writing, complain. + * Otherwise, complete the command normally. + */ + uptodate = 1; + if (cmd->nleft > 0) { + printk(KERN_ERR PFX "%s: %s: data underrun " + "(%u bytes)\n", drive->name, __func__, + cmd->nleft); + if (!write) + rq->cmd_flags |= REQ_FAILED; + uptodate = 0; + } + } else if (rq->cmd_type != REQ_TYPE_BLOCK_PC) { + ide_cd_request_sense_fixup(drive, cmd); - xferfunc = HWIF(drive)->atapi_output_bytes; - } else { - /* - * read from drive - */ - if (cdrom_read_check_ireason(drive, len, ireason)) - return ide_stopped; + uptodate = cmd->nleft ? 0 : 1; + + /* + * suck out the remaining bytes from the drive in an + * attempt to complete the data xfer. (see BZ#13399) + */ + if (!(stat & ATA_ERR) && !uptodate && thislen) { + ide_pio_bytes(drive, cmd, write, thislen); + uptodate = cmd->nleft ? 0 : 1; + } - xferfunc = HWIF(drive)->atapi_input_bytes; + if (!uptodate) + rq->cmd_flags |= REQ_FAILED; + } + goto out_end; } - /* - * transfer data - */ - while (thislen > 0) { - int blen = blen = rq->data_len; - char *ptr = rq->data; + rc = ide_check_ireason(drive, rq, len, ireason, write); + if (rc) + goto out_end; - /* - * bio backed? - */ - if (rq->bio) { - ptr = bio_data(rq->bio); - blen = bio_iovec(rq->bio)->bv_len; - } + cmd->last_xfer_len = 0; - if (!ptr) { - printk(KERN_ERR "%s: confused, missing data\n", drive->name); - break; - } + ide_debug_log(IDE_DBG_PC, "data transfer, rq->cmd_type: 0x%x, " + "ireason: 0x%x", + rq->cmd_type, ireason); - if (blen > thislen) - blen = thislen; + /* transfer data */ + while (thislen > 0) { + int blen = min_t(int, thislen, cmd->nleft); - xferfunc(drive, ptr, blen); + if (cmd->nleft == 0) + break; + + ide_pio_bytes(drive, cmd, write, blen); + cmd->last_xfer_len += blen; thislen -= blen; len -= blen; - rq->data_len -= blen; - if (rq->bio) - end_that_request_chunk(rq, 1, blen); - else - rq->data += blen; + if (sense && write == 0) + rq->sense_len += blen; } - /* - * pad, if necessary - */ + /* pad, if necessary */ if (len > 0) { - while (len > 0) { - int pad = 0; - - xferfunc(drive, &pad, sizeof(pad)); - len -= sizeof(pad); - } - } - - BUG_ON(HWGROUP(drive)->handler != NULL); - - 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, 1); - 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 (rq->cmd_type != REQ_TYPE_FS || write == 0) + ide_pad_transfer(drive, write, len); + else { + printk(KERN_ERR PFX "%s: confused, missing data\n", + drive->name); + blk_dump_rq_flags(rq, "cdrom_newpc_intr"); } } - 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; + if (rq->cmd_type == REQ_TYPE_BLOCK_PC) { + timeout = rq->timeout; + } else { + timeout = ATAPI_WAIT_PC; + if (rq->cmd_type != REQ_TYPE_FS) + expiry = ide_cd_expiry; } - /* 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); + hwif->expiry = expiry; + ide_set_handler(drive, cdrom_newpc_intr, timeout); + return ide_started; - len = lowcyl + (256 * highcyl); +out_end: + if (rq->cmd_type == REQ_TYPE_BLOCK_PC && rc == 0) { + rq->resid_len = 0; + blk_end_request_all(rq, 0); + hwif->rq = NULL; + } else { + if (sense && uptodate) + ide_cd_complete_failed_rq(drive, rq); - /* 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; + if (rq->cmd_type == REQ_TYPE_FS) { + if (cmd->nleft == 0) + uptodate = 1; + } else { + if (uptodate <= 0 && rq->errors == 0) + rq->errors = -EIO; } - 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; + if (uptodate == 0 && rq->bio) + if (ide_cd_error_cmd(drive, cmd)) + 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; + /* make sure it's fully ended */ + if (rq->cmd_type != REQ_TYPE_FS) { + rq->resid_len -= cmd->nbytes - cmd->nleft; + if (uptodate == 0 && (cmd->tf_flags & IDE_TFLAG_WRITE)) + rq->resid_len += cmd->last_xfer_len; } - /* - * 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; - } + ide_complete_rq(drive, uptodate ? 0 : -EIO, blk_rq_bytes(rq)); - /* - * current buffer complete, move on - */ - if (rq->current_nr_sectors == 0 && rq->nr_sectors) - cdrom_end_request(drive, 1); + if (sense && rc == 2) + ide_error(drive, "request sense failure", stat); } - - /* 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); + return ide_stopped; } -static ide_startstop_t cdrom_start_write(ide_drive_t *drive, struct request *rq) +static ide_startstop_t cdrom_start_rw(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; + struct cdrom_info *cd = drive->driver_data; + struct request_queue *q = drive->queue; + int write = rq_data_dir(rq) == WRITE; + unsigned short sectors_per_frame = + queue_logical_block_size(q) >> SECTOR_BITS; + + ide_debug_log(IDE_DBG_RQ, "rq->cmd[0]: 0x%x, rq->cmd_flags: 0x%x, " + "secs_per_frame: %u", + rq->cmd[0], rq->cmd_flags, sectors_per_frame); + + if (write) { + /* disk has become write protected */ + if (get_disk_ro(cd->disk)) + return ide_stopped; + } else { + /* + * We may be retrying this request after an error. Fix up any + * weirdness which might be present in the request packet. + */ + q->prep_rq_fn(q, rq); } - /* - * disk has become write protected - */ - if (g->policy) { - cdrom_end_request(drive, 0); + /* fs requests *must* be hardware frame aligned */ + if ((blk_rq_sectors(rq) & (sectors_per_frame - 1)) || + (blk_rq_pos(rq) & (sectors_per_frame - 1))) return ide_stopped; - } - info->nsectors_buffered = 0; + /* use DMA, if possible */ + drive->dma = !!(drive->dev_flags & IDE_DFLAG_USING_DMA); - /* 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; + if (write) + cd->devinfo.media_written = 1; - info->devinfo.media_written = 1; + rq->timeout = ATAPI_WAIT_PC; - /* Start sending the write request to the drive. */ - return cdrom_start_packet_command(drive, 32768, cdrom_start_write_cont); + return ide_started; } -static ide_startstop_t cdrom_do_newpc_cont(ide_drive_t *drive) +static void cdrom_do_block_pc(ide_drive_t *drive, struct request *rq) { - struct request *rq = HWGROUP(drive)->rq; - if (!rq->timeout) - rq->timeout = ATAPI_WAIT_PC; + ide_debug_log(IDE_DBG_PC, "rq->cmd[0]: 0x%x, rq->cmd_type: 0x%x", + rq->cmd[0], rq->cmd_type); - 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; + if (rq->cmd_type == REQ_TYPE_BLOCK_PC) + rq->cmd_flags |= REQ_QUIET; + else + rq->cmd_flags &= ~REQ_FAILED; - info->dma = 0; + drive->dma = 0; - /* - * sg request - */ + /* sg request */ if (rq->bio) { - int mask = drive->queue->dma_alignment; - unsigned long addr = (unsigned long) page_address(bio_page(rq->bio)); + struct request_queue *q = drive->queue; + char *buf = bio_data(rq->bio); + unsigned int alignment; - info->dma = drive->using_dma; + drive->dma = !!(drive->dev_flags & IDE_DFLAG_USING_DMA); /* * check if dma is safe @@ -1982,211 +765,109 @@ static ide_startstop_t cdrom_do_block_pc(ide_drive_t *drive, struct request *rq) * NOTE! The "len" and "addr" checks should possibly have * separate masks. */ - if ((rq->data_len & 15) || (addr & mask)) - info->dma = 0; + alignment = queue_dma_alignment(q) | q->dma_pad_mask; + if ((unsigned long)buf & alignment + || blk_rq_bytes(rq) & q->dma_pad_mask + || object_is_on_stack(buf)) + drive->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) +static ide_startstop_t ide_cd_do_request(ide_drive_t *drive, struct request *rq, + sector_t block) { - ide_startstop_t action; - struct cdrom_info *info = drive->driver_data; + struct ide_cmd cmd; + int uptodate = 0; + unsigned int nsectors; - 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; - } + ide_debug_log(IDE_DBG_RQ, "cmd: 0x%x, block: %llu", + rq->cmd[0], (unsigned long long)block); - blk_dump_rq_flags(rq, "ide-cd bad flags"); - cdrom_end_request(drive, 0); - return ide_stopped; -} + if (drive->debug_mask & IDE_DBG_RQ) + blk_dump_rq_flags(rq, "ide_cd_do_request"); + switch (rq->cmd_type) { + case REQ_TYPE_FS: + if (cdrom_start_rw(drive, rq) == ide_stopped) + goto out_end; + break; + case REQ_TYPE_SENSE: + case REQ_TYPE_BLOCK_PC: + case REQ_TYPE_ATA_PC: + if (!rq->timeout) + rq->timeout = ATAPI_WAIT_PC; + cdrom_do_block_pc(drive, rq); + break; + case REQ_TYPE_SPECIAL: + /* right now this can only be a reset... */ + uptodate = 1; + goto out_end; + default: + BUG(); + } -/**************************************************************************** - * 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. - */ + /* prepare sense request for this command */ + ide_prep_sense(drive, rq); -#if ! STANDARD_ATAPI -static inline -int bin2bcd (int x) -{ - return (x%10) | ((x/10) << 4); -} + memset(&cmd, 0, sizeof(cmd)); + if (rq_data_dir(rq)) + cmd.tf_flags |= IDE_TFLAG_WRITE; -static inline -int bcd2bin (int x) -{ - return (x >> 4) * 10 + (x & 0x0f); -} + cmd.rq = rq; -static -void msf_from_bcd (struct atapi_msf *msf) -{ - msf->minute = bcd2bin (msf->minute); - msf->second = bcd2bin (msf->second); - msf->frame = bcd2bin (msf->frame); -} + if (rq->cmd_type == REQ_TYPE_FS || blk_rq_bytes(rq)) { + ide_init_sg_cmd(&cmd, blk_rq_bytes(rq)); + ide_map_sg(drive, &cmd); + } -#endif /* not STANDARD_ATAPI */ + return ide_issue_pc(drive, &cmd); +out_end: + nsectors = blk_rq_sectors(rq); + if (nsectors == 0) + nsectors = 1; -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; -} + ide_complete_rq(drive, uptodate ? 0 : -EIO, nsectors << 9); + return ide_stopped; +} -static inline -int msf_to_lba (byte m, byte s, byte f) +/* + * Ioctl handling. + * + * Routines which queue packet commands take as a final argument a pointer to a + * request_sense struct. If execution of the command results in an error with a + * CHECK CONDITION status, this structure will be filled with the results of the + * subsequent request sense command. The pointer can also be NULL, in which case + * no sense information is returned. + */ +static void msf_from_bcd(struct atapi_msf *msf) { - return (((m * CD_SECS) + s) * CD_FRAMES + f) - CD_MSF_OFFSET; + msf->minute = bcd2bin(msf->minute); + msf->second = bcd2bin(msf->second); + msf->frame = bcd2bin(msf->frame); } -static int cdrom_check_status(ide_drive_t *drive, struct request_sense *sense) +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; + unsigned char cmd[BLK_MAX_CDB]; - 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); -} + ide_debug_log(IDE_DBG_FUNC, "enter"); + memset(cmd, 0, BLK_MAX_CDB); + cmd[0] = GPCMD_TEST_UNIT_READY; -/* 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; + /* + * Sanyo 3 CD changer uses byte 7 of TEST_UNIT_READY to switch CDs + * instead of supporting the LOAD_UNLOAD opcode. + */ + cmd[7] = cdi->sanyo_slot % 3; - req.sense = sense; - req.cmd[0] = GPCMD_START_STOP_UNIT; - req.cmd[4] = loej | (ejectflag != 0); - return cdrom_queue_packet_command(drive, &req); + return ide_cd_queue_pc(drive, cmd, 0, NULL, NULL, sense, 0, REQ_QUIET); } static int cdrom_read_capacity(ide_drive_t *drive, unsigned long *capacity, @@ -2194,58 +875,79 @@ static int cdrom_read_capacity(ide_drive_t *drive, unsigned long *capacity, struct request_sense *sense) { struct { - __u32 lba; - __u32 blocklen; + __be32 lba; + __be32 blocklen; } capbuf; int stat; - struct request req; + unsigned char cmd[BLK_MAX_CDB]; + unsigned len = sizeof(capbuf); + u32 blocklen; - cdrom_prepare_request(drive, &req); + ide_debug_log(IDE_DBG_FUNC, "enter"); - req.sense = sense; - req.cmd[0] = GPCMD_READ_CDVD_CAPACITY; - req.data = (char *)&capbuf; - req.data_len = sizeof(capbuf); - req.flags |= REQ_QUIET; + memset(cmd, 0, BLK_MAX_CDB); + cmd[0] = GPCMD_READ_CDVD_CAPACITY; - 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; + stat = ide_cd_queue_pc(drive, cmd, 0, &capbuf, &len, sense, 0, + REQ_QUIET); + if (stat) + return stat; + + /* + * Sanity check the given block size, in so far as making + * sure the sectors_per_frame we give to the caller won't + * end up being bogus. + */ + blocklen = be32_to_cpu(capbuf.blocklen); + blocklen = (blocklen >> SECTOR_BITS) << SECTOR_BITS; + switch (blocklen) { + case 512: + case 1024: + case 2048: + case 4096: + break; + default: + printk_once(KERN_ERR PFX "%s: weird block size %u; " + "setting default block size to 2048\n", + drive->name, blocklen); + blocklen = 2048; + break; } - return stat; + *capacity = 1 + be32_to_cpu(capbuf.lba); + *sectors_per_frame = blocklen >> SECTOR_BITS; + + ide_debug_log(IDE_DBG_PROBE, "cap: %lu, sectors_per_frame: %lu", + *capacity, *sectors_per_frame); + + return 0; } static int cdrom_read_tocentry(ide_drive_t *drive, int trackno, int msf_flag, int format, char *buf, int buflen, struct request_sense *sense) { - struct request req; + unsigned char cmd[BLK_MAX_CDB]; - cdrom_prepare_request(drive, &req); + ide_debug_log(IDE_DBG_FUNC, "enter"); - 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); + memset(cmd, 0, BLK_MAX_CDB); + + cmd[0] = GPCMD_READ_TOC_PMA_ATIP; + cmd[6] = trackno; + cmd[7] = (buflen >> 8); + cmd[8] = (buflen & 0xff); + cmd[9] = (format << 6); if (msf_flag) - req.cmd[1] = 2; + cmd[1] = 2; - return cdrom_queue_packet_command(drive, &req); + return ide_cd_queue_pc(drive, cmd, 0, buf, &buflen, sense, 0, REQ_QUIET); } - /* Try to read the entire TOC for the disk into our internal buffer. */ -static int cdrom_read_toc(ide_drive_t *drive, struct request_sense *sense) +int ide_cd_read_toc(ide_drive_t *drive, struct request_sense *sense) { int stat, ntracks, i; struct cdrom_info *info = drive->driver_data; @@ -2258,48 +960,51 @@ static int cdrom_read_toc(ide_drive_t *drive, struct request_sense *sense) long last_written; unsigned long sectors_per_frame = SECTORS_PER_FRAME; + ide_debug_log(IDE_DBG_FUNC, "enter"); + if (toc == NULL) { - /* Try to allocate space. */ + /* try to allocate space */ toc = kmalloc(sizeof(struct atapi_toc), GFP_KERNEL); if (toc == NULL) { - printk (KERN_ERR "%s: No cdrom TOC buffer!\n", drive->name); + printk(KERN_ERR PFX "%s: No cdrom TOC buffer!\n", + drive->name); return -ENOMEM; } info->toc = toc; } - /* Check to see if the existing data is still valid. - If it is, just return. */ + /* + * 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) + if (drive->atapi_flags & IDE_AFLAG_TOC_VALID) return 0; - /* Try to get the total cdrom capacity and sector size. */ + /* try to get the total cdrom capacity and sector size */ stat = cdrom_read_capacity(drive, &toc->capacity, §ors_per_frame, sense); if (stat) toc->capacity = 0x1fffff; set_capacity(info->disk, toc->capacity * sectors_per_frame); - /* Save a private copy of te TOC capacity for error handling */ + /* save a private copy of the TOC capacity for error handling */ drive->probed_capacity = toc->capacity * sectors_per_frame; - blk_queue_hardsect_size(drive->queue, - sectors_per_frame << SECTOR_BITS); + blk_queue_logical_block_size(drive->queue, + sectors_per_frame << SECTOR_BITS); - /* First read just the header, so we know how long the TOC is. */ + /* 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) { + if (drive->atapi_flags & IDE_AFLAG_TOCTRACKS_AS_BCD) { toc->hdr.first_track = bcd2bin(toc->hdr.first_track); toc->hdr.last_track = bcd2bin(toc->hdr.last_track); } -#endif /* not STANDARD_ATAPI */ ntracks = toc->hdr.last_track - toc->hdr.first_track + 1; if (ntracks <= 0) @@ -2307,7 +1012,7 @@ static int cdrom_read_toc(ide_drive_t *drive, struct request_sense *sense) if (ntracks > MAX_TRACKS) ntracks = MAX_TRACKS; - /* Now read the whole schmeer. */ + /* now read the whole schmeer */ stat = cdrom_read_tocentry(drive, toc->hdr.first_track, 1, 0, (char *)&toc->hdr, sizeof(struct atapi_toc_header) + @@ -2315,15 +1020,18 @@ static int cdrom_read_toc(ide_drive_t *drive, struct request_sense *sense) 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 */ + /* + * 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, @@ -2331,16 +1039,13 @@ static int cdrom_read_toc(ide_drive_t *drive, struct request_sense *sense) (ntracks + 1) * sizeof(struct atapi_toc_entry), sense); - if (stat) { + 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 */ - { + + if (drive->atapi_flags & IDE_AFLAG_TOCTRACKS_AS_BCD) { + toc->hdr.first_track = (u8)bin2bcd(CDROM_LEADOUT); + toc->hdr.last_track = (u8)bin2bcd(CDROM_LEADOUT); + } else { toc->hdr.first_track = CDROM_LEADOUT; toc->hdr.last_track = CDROM_LEADOUT; } @@ -2349,31 +1054,26 @@ static int cdrom_read_toc(ide_drive_t *drive, struct request_sense *sense) if (stat) return stat; - toc->hdr.toc_length = ntohs (toc->hdr.toc_length); + toc->hdr.toc_length = be16_to_cpu(toc->hdr.toc_length); -#if ! STANDARD_ATAPI - if (CDROM_CONFIG_FLAGS(drive)->toctracks_as_bcd) { + if (drive->atapi_flags & IDE_AFLAG_TOCTRACKS_AS_BCD) { toc->hdr.first_track = bcd2bin(toc->hdr.first_track); toc->hdr.last_track = bcd2bin(toc->hdr.last_track); } -#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) + for (i = 0; i <= ntracks; i++) { + if (drive->atapi_flags & IDE_AFLAG_TOCADDR_AS_BCD) { + if (drive->atapi_flags & IDE_AFLAG_TOCTRACKS_AS_BCD) toc->ent[i].track = bcd2bin(toc->ent[i].track); msf_from_bcd(&toc->ent[i].addr.msf); } -#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); + 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. */ + /* read the multisession information */ stat = cdrom_read_tocentry(drive, 0, 0, 1, (char *)&ms_tmp, sizeof(ms_tmp), sense); if (stat) @@ -2381,28 +1081,27 @@ static int cdrom_read_toc(ide_drive_t *drive, struct request_sense *sense) 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; + ms_tmp.hdr.last_track = CDROM_LEADOUT; + ms_tmp.hdr.first_track = ms_tmp.hdr.last_track; toc->last_session_lba = msf_to_lba(0, 2, 0); /* 0m 2s 0f */ } -#if ! STANDARD_ATAPI - if (CDROM_CONFIG_FLAGS(drive)->tocaddr_as_bcd) { - /* Re-read multisession information using MSF format */ + if (drive->atapi_flags & IDE_AFLAG_TOCADDR_AS_BCD) { + /* re-read multisession information using MSF format */ stat = cdrom_read_tocentry(drive, 0, 1, 1, (char *)&ms_tmp, sizeof(ms_tmp), sense); if (stat) return stat; - msf_from_bcd (&ms_tmp.ent.addr.msf); + 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.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. */ + /* 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; @@ -2411,278 +1110,26 @@ static int cdrom_read_toc(ide_drive_t *drive, struct request_sense *sense) } /* 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]; + drive->atapi_flags |= IDE_AFLAG_TOC_VALID; 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 = 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_audio_ioctl (struct cdrom_device_info *cdi, - unsigned int cmd, void *arg) - -{ - ide_drive_t *drive = 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 = 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 = 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 = 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 = 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 = 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 = cdi->handle; - return cdrom_lockdoor(drive, lock, NULL); -} - -static -int ide_cdrom_get_capabilities(ide_drive_t *drive, struct atapi_capabilities_page *cap) +int ide_cdrom_get_capabilities(ide_drive_t *drive, u8 *buf) { struct cdrom_info *info = drive->driver_data; struct cdrom_device_info *cdi = &info->devinfo; struct packet_command cgc; - int stat, attempts = 3, size = sizeof(*cap); + int stat, attempts = 3, size = ATAPI_CAPABILITIES_PAGE_SIZE; - /* - * 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); + ide_debug_log(IDE_DBG_FUNC, "enter"); + + if ((drive->atapi_flags & IDE_AFLAG_FULL_CAPS_PAGE) == 0) + size -= ATAPI_CAPABILITIES_PAGE_PAD_SIZE; - init_cdrom_command(&cgc, cap, size, CGC_DATA_UNKNOWN); - do { /* we seem to get stat=0x01,err=0x00 the first time (??) */ + init_cdrom_command(&cgc, buf, size, CGC_DATA_UNKNOWN); + do { + /* we seem to get stat=0x01,err=0x00 the first time (??) */ stat = cdrom_mode_sense(cdi, &cgc, GPMODE_CAPABILITIES_PAGE, 0); if (!stat) break; @@ -2690,182 +1137,40 @@ int ide_cdrom_get_capabilities(ide_drive_t *drive, struct atapi_capabilities_pag return stat; } -static -void ide_cdrom_update_speed (ide_drive_t *drive, struct atapi_capabilities_page *cap) +void ide_cdrom_update_speed(ide_drive_t *drive, u8 *buf) { - /* 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; - } -} - -static -int ide_cdrom_select_speed (struct cdrom_device_info *cdi, int speed) -{ - ide_drive_t *drive = cdi->handle; - struct request_sense sense; - struct atapi_capabilities_page cap; - int stat; - - if ((stat = cdrom_select_speed(drive, speed, &sense)) < 0) - return stat; - - if (!ide_cdrom_get_capabilities(drive, &cap)) { - ide_cdrom_update_speed(drive, &cap); - 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 = cdi->handle; - struct media_event_desc med; - struct request_sense sense; - int stat; - - if (slot_nr != CDSL_CURRENT) - return -EINVAL; - - stat = cdrom_check_status(drive, &sense); - if (!stat || sense.sense_key == UNIT_ATTENTION) - return CDS_DISC_OK; - - if (!cdrom_get_media_event(cdi, &med)) { - if (med.media_present) - return CDS_DISC_OK; - else if (med.door_open) - return CDS_TRAY_OPEN; - else - return CDS_NO_DISC; - } - - if (sense.sense_key == NOT_READY && sense.asc == 0x04 && sense.ascq == 0x04) - return CDS_DISC_OK; - - /* - * If not using Mt Fuji extended media tray reports, - * just return TRAY_OPEN since ATAPI doesn't provide - * any other way to detect this... - */ - if (sense.sense_key == NOT_READY) { - if (sense.asc == 0x3a && sense.ascq == 1) - return CDS_NO_DISC; - else - return CDS_TRAY_OPEN; - } - return CDS_DRIVE_NOT_READY; -} - -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 = 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 = 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; -} - - + struct cdrom_info *cd = drive->driver_data; + u16 curspeed, maxspeed; -/**************************************************************************** - * Other driver requests (open, close, check media change). - */ + ide_debug_log(IDE_DBG_FUNC, "enter"); -static -int ide_cdrom_check_media_change_real (struct cdrom_device_info *cdi, - int slot_nr) -{ - ide_drive_t *drive = cdi->handle; - int retval; - - if (slot_nr == CDSL_CURRENT) { - (void) cdrom_check_status(drive, NULL); - retval = CDROM_STATE_FLAGS(drive)->media_changed; - CDROM_STATE_FLAGS(drive)->media_changed = 0; - return retval; + if (drive->atapi_flags & IDE_AFLAG_LE_SPEED_FIELDS) { + curspeed = le16_to_cpup((__le16 *)&buf[8 + 14]); + maxspeed = le16_to_cpup((__le16 *)&buf[8 + 8]); } else { - return -EINVAL; + curspeed = be16_to_cpup((__be16 *)&buf[8 + 14]); + maxspeed = be16_to_cpup((__be16 *)&buf[8 + 8]); } -} - - -static -int ide_cdrom_open_real (struct cdrom_device_info *cdi, int purpose) -{ - return 0; -} -/* - * Close down the device. Invalidate all cached blocks. - */ + ide_debug_log(IDE_DBG_PROBE, "curspeed: %u, maxspeed: %u", + curspeed, maxspeed); -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; + cd->current_speed = DIV_ROUND_CLOSEST(curspeed, 176); + cd->max_speed = DIV_ROUND_CLOSEST(maxspeed, 176); } +#define IDE_CD_CAPABILITIES \ + (CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK | CDC_SELECT_SPEED | \ + CDC_SELECT_DISC | CDC_MULTI_SESSION | CDC_MCN | CDC_MEDIA_CHANGED | \ + CDC_PLAY_AUDIO | CDC_RESET | CDC_DRIVE_STATUS | CDC_CD_R | \ + CDC_CD_RW | CDC_DVD | CDC_DVD_R | CDC_DVD_RAM | CDC_GENERIC_PACKET | \ + CDC_MO_DRIVE | CDC_MRW | CDC_MRW_W | CDC_RAM) - -/**************************************************************************** - * 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, + .check_events = ide_cdrom_check_events_real, .tray_move = ide_cdrom_tray_move, .lock_door = ide_cdrom_lock_door, .select_speed = ide_cdrom_select_speed, @@ -2873,188 +1178,142 @@ static struct cdrom_device_ops ide_cdrom_dops = { .get_mcn = ide_cdrom_get_mcn, .reset = ide_cdrom_reset, .audio_ioctl = ide_cdrom_audio_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_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, + .capability = IDE_CD_CAPABILITIES, .generic_packet = ide_cdrom_packet, }; -static int ide_cdrom_register (ide_drive_t *drive, int nslots) +static int ide_cdrom_register(ide_drive_t *drive, int nslots) { struct cdrom_info *info = drive->driver_data; struct cdrom_device_info *devinfo = &info->devinfo; + ide_debug_log(IDE_DBG_PROBE, "nslots: %d", nslots); + devinfo->ops = &ide_cdrom_dops; - devinfo->mask = 0; - devinfo->speed = CDROM_STATE_FLAGS(drive)->current_speed; + devinfo->speed = info->current_speed; devinfo->capacity = nslots; devinfo->handle = 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; - if (!CDROM_CONFIG_FLAGS(drive)->ram) - devinfo->mask |= CDC_RAM; + + if (drive->atapi_flags & IDE_AFLAG_NO_SPEED_SELECT) + devinfo->mask |= CDC_SELECT_SPEED; devinfo->disk = info->disk; return register_cdrom(devinfo); } -static -int ide_cdrom_probe_capabilities (ide_drive_t *drive) +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; + struct cdrom_info *cd = drive->driver_data; + struct cdrom_device_info *cdi = &cd->devinfo; + u8 buf[ATAPI_CAPABILITIES_PAGE_SIZE]; + mechtype_t mechtype; int nslots = 1; + ide_debug_log(IDE_DBG_PROBE, "media: 0x%x, atapi_flags: 0x%lx", + drive->media, drive->atapi_flags); + + cdi->mask = (CDC_CD_R | CDC_CD_RW | CDC_DVD | CDC_DVD_R | + CDC_DVD_RAM | CDC_SELECT_DISC | CDC_PLAY_AUDIO | + CDC_MO_DRIVE | CDC_RAM); + if (drive->media == ide_optical) { - CDROM_CONFIG_FLAGS(drive)->mo_drive = 1; - CDROM_CONFIG_FLAGS(drive)->ram = 1; - printk(KERN_ERR "%s: ATAPI magneto-optical drive\n", drive->name); + cdi->mask &= ~(CDC_MO_DRIVE | CDC_RAM); + printk(KERN_ERR PFX "%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; + if (drive->atapi_flags & IDE_AFLAG_PRE_ATAPI12) { + drive->atapi_flags &= ~IDE_AFLAG_NO_EJECT; + cdi->mask &= ~CDC_PLAY_AUDIO; return nslots; } /* - * we have to cheat a little here. the packet will eventually - * be queued with ide_cdrom_packet(), which extracts the - * drive from cdi->handle. Since this device hasn't been - * registered with the Uniform layer yet, it can't do this. - * Same goes for cdi->ops. + * We have to cheat a little here. the packet will eventually be queued + * with ide_cdrom_packet(), which extracts the drive from cdi->handle. + * Since this device hasn't been registered with the Uniform layer yet, + * it can't do this. Same goes for cdi->ops. */ cdi->handle = drive; cdi->ops = &ide_cdrom_dops; - if (ide_cdrom_get_capabilities(drive, &cap)) + if (ide_cdrom_get_capabilities(drive, buf)) 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 ((buf[8 + 6] & 0x01) == 0) + drive->dev_flags &= ~IDE_DFLAG_DOORLOCKING; + if (buf[8 + 6] & 0x08) + drive->atapi_flags &= ~IDE_AFLAG_NO_EJECT; + if (buf[8 + 3] & 0x01) + cdi->mask &= ~CDC_CD_R; + if (buf[8 + 3] & 0x02) + cdi->mask &= ~(CDC_CD_RW | CDC_RAM); + if (buf[8 + 2] & 0x38) + cdi->mask &= ~CDC_DVD; + if (buf[8 + 3] & 0x20) + cdi->mask &= ~(CDC_DVD_RAM | CDC_RAM); + if (buf[8 + 3] & 0x10) + cdi->mask &= ~CDC_DVD_R; + if ((buf[8 + 4] & 0x01) || (drive->atapi_flags & IDE_AFLAG_PLAY_AUDIO_OK)) + cdi->mask &= ~CDC_PLAY_AUDIO; + + mechtype = buf[8 + 6] >> 5; + if (mechtype == mechtype_caddy || + mechtype == mechtype_popup || + (drive->atapi_flags & IDE_AFLAG_NO_AUTOCLOSE)) + cdi->mask |= CDC_CLOSE_TRAY; -#if ! STANDARD_ATAPI if (cdi->sanyo_slot > 0) { - CDROM_CONFIG_FLAGS(drive)->is_changer = 1; + cdi->mask &= ~CDC_SELECT_DISC; nslots = 3; + } else if (mechtype == mechtype_individual_changer || + mechtype == mechtype_cartridge_changer) { + nslots = cdrom_number_of_slots(cdi); + if (nslots > 1) + cdi->mask &= ~CDC_SELECT_DISC; } - 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; - } - } + ide_cdrom_update_speed(drive, buf); - ide_cdrom_update_speed(drive, &cap); - /* 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"); + printk(KERN_INFO PFX "%s: ATAPI", drive->name); - 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" : ""); + /* don't print speed if the drive reported 0 */ + if (cd->max_speed) + printk(KERN_CONT " %dX", cd->max_speed); - 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" : ""); + printk(KERN_CONT " %s", (cdi->mask & CDC_DVD) ? "CD-ROM" : "DVD-ROM"); - if (CDROM_CONFIG_FLAGS(drive)->is_changer) - printk(" changer w/%d slots", nslots); - else - printk(" drive"); + if ((cdi->mask & CDC_DVD_R) == 0 || (cdi->mask & CDC_DVD_RAM) == 0) + printk(KERN_CONT " DVD%s%s", + (cdi->mask & CDC_DVD_R) ? "" : "-R", + (cdi->mask & CDC_DVD_RAM) ? "" : "/RAM"); - printk(", %dkB Cache", be16_to_cpu(cap.buffer_size)); + if ((cdi->mask & CDC_CD_R) == 0 || (cdi->mask & CDC_CD_RW) == 0) + printk(KERN_CONT " CD%s%s", + (cdi->mask & CDC_CD_R) ? "" : "-R", + (cdi->mask & CDC_CD_RW) ? "" : "/RW"); - if (drive->using_dma) - ide_dma_verbose(drive); + if ((cdi->mask & CDC_SELECT_DISC) == 0) + printk(KERN_CONT " changer w/%d slots", nslots); + else + printk(KERN_CONT " drive"); - printk("\n"); + printk(KERN_CONT ", %dkB Cache\n", + be16_to_cpup((__be16 *)&buf[8 + 12])); 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) +/* standard prep_rq_fn that builds 10 byte cmds */ +static int ide_cdrom_prep_fs(struct request_queue *q, struct request *rq) { - int hard_sect = queue_hardsect_size(q); - long block = (long)rq->hard_sector / (hard_sect >> 9); - unsigned long blocks = rq->hard_nr_sectors / (hard_sect >> 9); + int hard_sect = queue_logical_block_size(q); + long block = (long)blk_rq_pos(rq) / (hard_sect >> 9); + unsigned long blocks = blk_rq_sectors(rq) / (hard_sect >> 9); - memset(rq->cmd, 0, sizeof(rq->cmd)); + memset(rq->cmd, 0, BLK_MAX_CDB); if (rq_data_dir(rq) == READ) rq->cmd[0] = GPCMD_READ_10; @@ -3086,9 +1345,7 @@ static int ide_cdrom_prep_pc(struct request *rq) { u8 *c = rq->cmd; - /* - * Transform 6-byte read/write commands to the 10-byte version - */ + /* 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]; @@ -3110,197 +1367,202 @@ static int ide_cdrom_prep_pc(struct request *rq) rq->errors = ILLEGAL_REQUEST; return BLKPREP_KILL; } - + return BLKPREP_OK; } -static int ide_cdrom_prep_fn(request_queue_t *q, struct request *rq) +static int ide_cdrom_prep_fn(struct request_queue *q, struct request *rq) { - if (rq->flags & REQ_CMD) + if (rq->cmd_type == REQ_TYPE_FS) return ide_cdrom_prep_fs(q, rq); - else if (rq->flags & REQ_BLOCK_PC) + else if (rq->cmd_type == REQ_TYPE_BLOCK_PC) return ide_cdrom_prep_pc(rq); return 0; } -static -int ide_cdrom_setup (ide_drive_t *drive) +struct cd_list_entry { + const char *id_model; + const char *id_firmware; + unsigned int cd_flags; +}; + +#ifdef CONFIG_IDE_PROC_FS +static sector_t ide_cdrom_capacity(ide_drive_t *drive) { - struct cdrom_info *info = drive->driver_data; - struct cdrom_device_info *cdi = &info->devinfo; - int nslots; + unsigned long capacity, sectors_per_frame; - 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; + if (cdrom_read_capacity(drive, &capacity, §ors_per_frame, NULL)) + return 0; - drive->special.all = 0; + return capacity * sectors_per_frame; +} - CDROM_STATE_FLAGS(drive)->media_changed = 1; - CDROM_STATE_FLAGS(drive)->toc_valid = 0; - CDROM_STATE_FLAGS(drive)->door_locked = 0; +static int idecd_capacity_proc_show(struct seq_file *m, void *v) +{ + ide_drive_t *drive = m->private; -#if NO_DOOR_LOCKING - CDROM_CONFIG_FLAGS(drive)->no_doorlock = 1; -#else - CDROM_CONFIG_FLAGS(drive)->no_doorlock = 0; -#endif + seq_printf(m, "%llu\n", (long long)ide_cdrom_capacity(drive)); + return 0; +} - 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; - } +static int idecd_capacity_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, idecd_capacity_proc_show, PDE_DATA(inode)); +} - 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); +static const struct file_operations idecd_capacity_proc_fops = { + .owner = THIS_MODULE, + .open = idecd_capacity_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static ide_proc_entry_t idecd_proc[] = { + { "capacity", S_IFREG|S_IRUGO, &idecd_capacity_proc_fops }, + {} +}; + +static ide_proc_entry_t *ide_cd_proc_entries(ide_drive_t *drive) +{ + return idecd_proc; +} +static const struct ide_proc_devset *ide_cd_proc_devsets(ide_drive_t *drive) +{ + return NULL; +} +#endif + +static const struct cd_list_entry ide_cd_quirks_list[] = { + /* SCR-3231 doesn't support the SET_CD_SPEED command. */ + { "SAMSUNG CD-ROM SCR-3231", NULL, IDE_AFLAG_NO_SPEED_SELECT }, + /* Old NEC260 (not R) was released before ATAPI 1.2 spec. */ + { "NEC CD-ROM DRIVE:260", "1.01", IDE_AFLAG_TOCADDR_AS_BCD | + IDE_AFLAG_PRE_ATAPI12, }, + /* Vertos 300, some versions of this drive like to talk BCD. */ + { "V003S0DS", NULL, IDE_AFLAG_VERTOS_300_SSD, }, + /* Vertos 600 ESD. */ + { "V006E0DS", NULL, IDE_AFLAG_VERTOS_600_ESD, }, /* - * set correct block size + * Sanyo 3 CD changer uses a non-standard command for CD changing + * (by default standard ATAPI support for CD changers is used). */ - 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 + { "CD-ROM CDR-C3 G", NULL, IDE_AFLAG_SANYO_3CD }, + { "CD-ROM CDR-C3G", NULL, IDE_AFLAG_SANYO_3CD }, + { "CD-ROM CDR_C36", NULL, IDE_AFLAG_SANYO_3CD }, + /* Stingray 8X CD-ROM. */ + { "STINGRAY 8422 IDE 8X CD-ROM 7-27-95", NULL, IDE_AFLAG_PRE_ATAPI12 }, + /* + * ACER 50X CD-ROM and WPI 32X CD-ROM require the full spec length + * mode sense page capabilities size, but older drives break. + */ + { "ATAPI CD ROM DRIVE 50X MAX", NULL, IDE_AFLAG_FULL_CAPS_PAGE }, + { "WPI CDS-32X", NULL, IDE_AFLAG_FULL_CAPS_PAGE }, + /* ACER/AOpen 24X CD-ROM has the speed fields byte-swapped. */ + { "", "241N", IDE_AFLAG_LE_SPEED_FIELDS }, + /* + * Some drives used by Apple don't advertise audio play + * but they do support reading TOC & audio datas. + */ + { "MATSHITADVD-ROM SR-8187", NULL, IDE_AFLAG_PLAY_AUDIO_OK }, + { "MATSHITADVD-ROM SR-8186", NULL, IDE_AFLAG_PLAY_AUDIO_OK }, + { "MATSHITADVD-ROM SR-8176", NULL, IDE_AFLAG_PLAY_AUDIO_OK }, + { "MATSHITADVD-ROM SR-8174", NULL, IDE_AFLAG_PLAY_AUDIO_OK }, + { "Optiarc DVD RW AD-5200A", NULL, IDE_AFLAG_PLAY_AUDIO_OK }, + { "Optiarc DVD RW AD-7200A", NULL, IDE_AFLAG_PLAY_AUDIO_OK }, + { "Optiarc DVD RW AD-7543A", NULL, IDE_AFLAG_NO_AUTOCLOSE }, + { "TEAC CD-ROM CD-224E", NULL, IDE_AFLAG_NO_AUTOCLOSE }, + { NULL, NULL, 0 } +}; - 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; +static unsigned int ide_cd_flags(u16 *id) +{ + const struct cd_list_entry *cle = ide_cd_quirks_list; + + while (cle->id_model) { + if (strcmp(cle->id_model, (char *)&id[ATA_ID_PROD]) == 0 && + (cle->id_firmware == NULL || + strstr((char *)&id[ATA_ID_FW_REV], cle->id_firmware))) + return cle->cd_flags; + cle++; } - ide_cdrom_add_settings(drive); + return 0; } -#ifdef CONFIG_PROC_FS -static -sector_t ide_cdrom_capacity (ide_drive_t *drive) +static int ide_cdrom_setup(ide_drive_t *drive) { - unsigned long capacity, sectors_per_frame; + struct cdrom_info *cd = drive->driver_data; + struct cdrom_device_info *cdi = &cd->devinfo; + struct request_queue *q = drive->queue; + u16 *id = drive->id; + char *fw_rev = (char *)&id[ATA_ID_FW_REV]; + int nslots; - if (cdrom_read_capacity(drive, &capacity, §ors_per_frame, NULL)) - return 0; + ide_debug_log(IDE_DBG_PROBE, "enter"); - return capacity * sectors_per_frame; + blk_queue_prep_rq(q, ide_cdrom_prep_fn); + blk_queue_dma_alignment(q, 31); + blk_queue_update_dma_pad(q, 15); + + drive->dev_flags |= IDE_DFLAG_MEDIA_CHANGED; + drive->atapi_flags = IDE_AFLAG_NO_EJECT | ide_cd_flags(id); + + if ((drive->atapi_flags & IDE_AFLAG_VERTOS_300_SSD) && + fw_rev[4] == '1' && fw_rev[6] <= '2') + drive->atapi_flags |= (IDE_AFLAG_TOCTRACKS_AS_BCD | + IDE_AFLAG_TOCADDR_AS_BCD); + else if ((drive->atapi_flags & IDE_AFLAG_VERTOS_600_ESD) && + fw_rev[4] == '1' && fw_rev[6] <= '2') + drive->atapi_flags |= IDE_AFLAG_TOCTRACKS_AS_BCD; + else if (drive->atapi_flags & IDE_AFLAG_SANYO_3CD) + /* 3 => use CD in slot 0 */ + cdi->sanyo_slot = 3; + + nslots = ide_cdrom_probe_capabilities(drive); + + blk_queue_logical_block_size(q, CD_FRAMESIZE); + + if (ide_cdrom_register(drive, nslots)) { + printk(KERN_ERR PFX "%s: %s failed to register device with the" + " cdrom driver.\n", drive->name, __func__); + cd->devinfo.handle = NULL; + return 1; + } + + ide_proc_register_driver(drive, cd->driver); + return 0; } -#endif static void ide_cd_remove(ide_drive_t *drive) { struct cdrom_info *info = drive->driver_data; - ide_unregister_subdriver(drive, info->driver); + ide_debug_log(IDE_DBG_FUNC, "enter"); + ide_proc_unregister_driver(drive, info->driver); + device_del(&info->dev); del_gendisk(info->disk); - ide_cd_put(info); + mutex_lock(&idecd_ref_mutex); + put_device(&info->dev); + mutex_unlock(&idecd_ref_mutex); } -static void ide_cd_release(struct kref *kref) +static void ide_cd_release(struct device *dev) { - struct cdrom_info *info = to_ide_cd(kref); + struct cdrom_info *info = to_ide_drv(dev, cdrom_info); struct cdrom_device_info *devinfo = &info->devinfo; ide_drive_t *drive = info->drive; struct gendisk *g = info->disk; - kfree(info->buffer); + ide_debug_log(IDE_DBG_FUNC, "enter"); + kfree(info->toc); - 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; + if (devinfo->handle == drive) + unregister_cdrom(devinfo); drive->driver_data = NULL; blk_queue_prep_rq(drive->queue, NULL); g->private_data = NULL; @@ -3310,26 +1572,7 @@ static void ide_cd_release(struct kref *kref) static int ide_cd_probe(ide_drive_t *); -#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 = 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 = { +static struct ide_driver ide_cdrom_driver = { .gen_driver = { .owner = THIS_MODULE, .name = "ide-cdrom", @@ -3338,53 +1581,40 @@ static ide_driver_t ide_cdrom_driver = { .probe = ide_cd_probe, .remove = ide_cd_remove, .version = IDECD_VERSION, - .media = ide_cdrom, - .supports_dsc_overlap = 1, - .do_request = ide_do_rw_cdrom, - .end_request = ide_end_request, - .error = __ide_error, - .abort = __ide_abort, - .proc = idecd_proc, + .do_request = ide_cd_do_request, +#ifdef CONFIG_IDE_PROC_FS + .proc_entries = ide_cd_proc_entries, + .proc_devsets = ide_cd_proc_devsets, +#endif }; -static int idecd_open(struct inode * inode, struct file * file) +static int idecd_open(struct block_device *bdev, fmode_t mode) { - 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; + int rc = -ENXIO; - 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--; + mutex_lock(&ide_cd_mutex); + info = ide_cd_get(bdev->bd_disk); + if (!info) + goto out; + rc = cdrom_open(&info->devinfo, bdev, mode); if (rc < 0) ide_cd_put(info); - +out: + mutex_unlock(&ide_cd_mutex); return rc; } -static int idecd_release(struct inode * inode, struct file * file) +static void idecd_release(struct gendisk *disk, fmode_t mode) { - struct gendisk *disk = inode->i_bdev->bd_disk; - struct cdrom_info *info = ide_cd_g(disk); - ide_drive_t *drive = info->drive; + struct cdrom_info *info = ide_drv_g(disk, cdrom_info); - cdrom_release (&info->devinfo, file); - drive->usage--; + mutex_lock(&ide_cd_mutex); + cdrom_release(&info->devinfo, mode); ide_cd_put(info); - - return 0; + mutex_unlock(&ide_cd_mutex); } static int idecd_set_spindown(struct cdrom_device_info *cdi, unsigned long arg) @@ -3412,7 +1642,7 @@ static int idecd_get_spindown(struct cdrom_device_info *cdi, unsigned long arg) struct packet_command cgc; char buffer[16]; int stat; - char spindown; + char spindown; init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_UNKNOWN); @@ -3421,61 +1651,76 @@ static int idecd_get_spindown(struct cdrom_device_info *cdi, unsigned long arg) return stat; spindown = buffer[11] & 0x0f; - if (copy_to_user((void __user *)arg, &spindown, sizeof (char))) + if (copy_to_user((void __user *)arg, &spindown, sizeof(char))) return -EFAULT; return 0; } -static int idecd_ioctl (struct inode *inode, struct file *file, +static int idecd_locked_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, unsigned long arg) { - struct block_device *bdev = inode->i_bdev; - struct cdrom_info *info = ide_cd_g(bdev->bd_disk); + struct cdrom_info *info = ide_drv_g(bdev->bd_disk, cdrom_info); int err; switch (cmd) { - case CDROMSETSPINDOWN: + case CDROMSETSPINDOWN: return idecd_set_spindown(&info->devinfo, arg); - case CDROMGETSPINDOWN: + case CDROMGETSPINDOWN: return idecd_get_spindown(&info->devinfo, arg); default: break; - } + } - err = generic_ide_ioctl(info->drive, file, bdev, cmd, arg); + err = generic_ide_ioctl(info->drive, bdev, cmd, arg); if (err == -EINVAL) - err = cdrom_ioctl(file, &info->devinfo, inode, cmd, arg); + err = cdrom_ioctl(&info->devinfo, bdev, mode, cmd, arg); return err; } -static int idecd_media_changed(struct gendisk *disk) +static int idecd_ioctl(struct block_device *bdev, fmode_t mode, + unsigned int cmd, unsigned long arg) +{ + int ret; + + mutex_lock(&ide_cd_mutex); + ret = idecd_locked_ioctl(bdev, mode, cmd, arg); + mutex_unlock(&ide_cd_mutex); + + return ret; +} + + +static unsigned int idecd_check_events(struct gendisk *disk, + unsigned int clearing) { - struct cdrom_info *info = ide_cd_g(disk); - return cdrom_media_changed(&info->devinfo); + struct cdrom_info *info = ide_drv_g(disk, cdrom_info); + return cdrom_check_events(&info->devinfo, clearing); } static int idecd_revalidate_disk(struct gendisk *disk) { - struct cdrom_info *info = ide_cd_g(disk); + struct cdrom_info *info = ide_drv_g(disk, cdrom_info); struct request_sense sense; - cdrom_read_toc(info->drive, &sense); + + ide_cd_read_toc(info->drive, &sense); + return 0; } -static struct block_device_operations idecd_ops = { - .owner = THIS_MODULE, - .open = idecd_open, - .release = idecd_release, - .ioctl = idecd_ioctl, - .media_changed = idecd_media_changed, - .revalidate_disk= idecd_revalidate_disk +static const struct block_device_operations idecd_ops = { + .owner = THIS_MODULE, + .open = idecd_open, + .release = idecd_release, + .ioctl = idecd_ioctl, + .check_events = idecd_check_events, + .revalidate_disk = idecd_revalidate_disk }; -/* options */ -static char *ignore = NULL; +/* module options */ +static unsigned long debug_mask; +module_param(debug_mask, ulong, 0644); -module_param(ignore, charp, 0400); MODULE_DESCRIPTION("ATAPI CD-ROM Driver"); static int ide_cd_probe(ide_drive_t *drive) @@ -3484,26 +1729,22 @@ static int ide_cd_probe(ide_drive_t *drive) struct gendisk *g; struct request_sense sense; + ide_debug_log(IDE_DBG_PROBE, "driver_req: %s, media: 0x%x", + drive->driver_req, drive->media); + 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; - } + + drive->debug_mask = debug_mask; + drive->irq_handler = cdrom_newpc_intr; + info = kzalloc(sizeof(struct cdrom_info), GFP_KERNEL); if (info == NULL) { - printk(KERN_ERR "%s: Can't allocate a cdrom structure\n", drive->name); + printk(KERN_ERR PFX "%s: Can't allocate a cdrom structure\n", + drive->name); goto failed; } @@ -3513,9 +1754,12 @@ static int ide_cd_probe(ide_drive_t *drive) ide_init_disk(g, drive); - ide_register_subdriver(drive, &ide_cdrom_driver); + info->dev.parent = &drive->gendev; + info->dev.release = ide_cd_release; + dev_set_name(&info->dev, "%s", dev_name(&drive->gendev)); - kref_init(&info->kref); + if (device_register(&info->dev)) + goto out_free_disk; info->drive = drive; info->driver = &ide_cdrom_driver; @@ -3529,24 +1773,18 @@ static int ide_cd_probe(ide_drive_t *drive) 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; - ide_unregister_subdriver(drive, &ide_cdrom_driver); - kfree(info->buffer); - kfree(info->toc); - 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; + put_device(&info->dev); goto failed; } - cdrom_read_toc(drive, &sense); + ide_cd_read_toc(drive, &sense); g->fops = &idecd_ops; - g->flags |= GENHD_FL_REMOVABLE; + g->flags |= GENHD_FL_REMOVABLE | GENHD_FL_BLOCK_EVENTS_ON_EXCL_WRITE; add_disk(g); return 0; +out_free_disk: + put_disk(g); out_free_cd: kfree(info); failed: @@ -3560,10 +1798,12 @@ static void __exit ide_cdrom_exit(void) static int __init ide_cdrom_init(void) { + printk(KERN_INFO DRV_NAME " driver " IDECD_VERSION "\n"); return driver_register(&ide_cdrom_driver.gen_driver); } MODULE_ALIAS("ide:*m-cdrom*"); +MODULE_ALIAS("ide-cd"); module_init(ide_cdrom_init); module_exit(ide_cdrom_exit); MODULE_LICENSE("GPL"); diff --git a/drivers/ide/ide-cd.h b/drivers/ide/ide-cd.h index ad1f2ed14a3..1efc936f5b6 100644 --- a/drivers/ide/ide-cd.h +++ b/drivers/ide/ide-cd.h @@ -1,6 +1,4 @@ /* - * linux/drivers/ide/ide_cd.h - * * Copyright (C) 1996-98 Erik Andersen * Copyright (C) 1998-2000 Jens Axboe */ @@ -10,35 +8,14 @@ #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. */ +#define IDECD_DEBUG_LOG 0 -#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 +#if IDECD_DEBUG_LOG +#define ide_debug_log(lvl, fmt, args...) __ide_debug_log(lvl, fmt, ## args) +#else +#define ide_debug_log(lvl, fmt, args...) do {} while (0) #endif -/* - * typical timeout for packet command - */ -#define ATAPI_WAIT_PC (60 * HZ) #define ATAPI_WAIT_WRITE_BUSY (10 * HZ) /************************************************************************/ @@ -49,96 +26,40 @@ #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)) +/* Capabilities Page size including 8 bytes of Mode Page Header */ +#define ATAPI_CAPABILITIES_PAGE_SIZE (8 + 20) +#define ATAPI_CAPABILITIES_PAGE_PAD_SIZE 4 /* Structure of a MSF cdrom address. */ struct atapi_msf { - byte reserved; - byte minute; - byte second; - byte frame; + u8 reserved; + u8 minute; + u8 second; + u8 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; + u8 first_track; + u8 last_track; }; struct atapi_toc_entry { - byte reserved1; + u8 reserved1; #if defined(__BIG_ENDIAN_BITFIELD) - __u8 adr : 4; - __u8 control : 4; + u8 adr : 4; + u8 control : 4; #elif defined(__LITTLE_ENDIAN_BITFIELD) - __u8 control : 4; - __u8 adr : 4; + u8 control : 4; + u8 adr : 4; #else #error "Please fix <asm/byteorder.h>" #endif - byte track; - byte reserved2; + u8 track; + u8 reserved2; union { unsigned lba; struct atapi_msf msf; @@ -154,339 +75,20 @@ struct atapi_toc { /* 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; + ide_drive_t *drive; + struct ide_driver *driver; + struct gendisk *disk; + struct device dev; /* 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; - 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; + u8 max_speed; /* Max speed of the drive. */ + u8 current_speed; /* Current speed of the drive. */ /* Per-device info needed by cdrom.c generic driver. */ struct cdrom_device_info devinfo; @@ -494,252 +96,31 @@ struct cdrom_info { 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 - +/* ide-cd_verbose.c */ +void ide_cd_log_error(const char *, struct request *, struct request_sense *); + +/* ide-cd.c functions used by ide-cd_ioctl.c */ +int ide_cd_queue_pc(ide_drive_t *, const unsigned char *, int, void *, + unsigned *, struct request_sense *, int, unsigned int); +int ide_cd_read_toc(ide_drive_t *, struct request_sense *); +int ide_cdrom_get_capabilities(ide_drive_t *, u8 *); +void ide_cdrom_update_speed(ide_drive_t *, u8 *); +int cdrom_check_status(ide_drive_t *, struct request_sense *); + +/* ide-cd_ioctl.c */ +int ide_cdrom_open_real(struct cdrom_device_info *, int); +void ide_cdrom_release_real(struct cdrom_device_info *); +int ide_cdrom_drive_status(struct cdrom_device_info *, int); +unsigned int ide_cdrom_check_events_real(struct cdrom_device_info *, + unsigned int clearing, int slot_nr); +int ide_cdrom_tray_move(struct cdrom_device_info *, int); +int ide_cdrom_lock_door(struct cdrom_device_info *, int); +int ide_cdrom_select_speed(struct cdrom_device_info *, int); +int ide_cdrom_get_last_session(struct cdrom_device_info *, + struct cdrom_multisession *); +int ide_cdrom_get_mcn(struct cdrom_device_info *, struct cdrom_mcn *); +int ide_cdrom_reset(struct cdrom_device_info *cdi); +int ide_cdrom_audio_ioctl(struct cdrom_device_info *, unsigned int, void *); +int ide_cdrom_packet(struct cdrom_device_info *, struct packet_command *); #endif /* _IDE_CD_H */ diff --git a/drivers/ide/ide-cd_ioctl.c b/drivers/ide/ide-cd_ioctl.c new file mode 100644 index 00000000000..02caa7dd51c --- /dev/null +++ b/drivers/ide/ide-cd_ioctl.c @@ -0,0 +1,478 @@ +/* + * cdrom.c IOCTLs handling for ide-cd driver. + * + * Copyright (C) 1994-1996 Scott Snyder <snyder@fnald0.fnal.gov> + * Copyright (C) 1996-1998 Erik Andersen <andersee@debian.org> + * Copyright (C) 1998-2000 Jens Axboe <axboe@suse.de> + */ + +#include <linux/kernel.h> +#include <linux/cdrom.h> +#include <linux/gfp.h> +#include <linux/ide.h> +#include <scsi/scsi.h> + +#include "ide-cd.h" + +/**************************************************************************** + * Other driver requests (open, close, check media change). + */ +int ide_cdrom_open_real(struct cdrom_device_info *cdi, int purpose) +{ + return 0; +} + +/* + * Close down the device. Invalidate all cached blocks. + */ +void ide_cdrom_release_real(struct cdrom_device_info *cdi) +{ + ide_drive_t *drive = cdi->handle; + + if (!cdi->use_count) + drive->atapi_flags &= ~IDE_AFLAG_TOC_VALID; +} + +/* + * add logic to try GET_EVENT command first to check for media and tray + * status. this should be supported by newer cd-r/w and all DVD etc + * drives + */ +int ide_cdrom_drive_status(struct cdrom_device_info *cdi, int slot_nr) +{ + ide_drive_t *drive = cdi->handle; + struct media_event_desc med; + struct request_sense sense; + int stat; + + if (slot_nr != CDSL_CURRENT) + return -EINVAL; + + stat = cdrom_check_status(drive, &sense); + if (!stat || sense.sense_key == UNIT_ATTENTION) + return CDS_DISC_OK; + + if (!cdrom_get_media_event(cdi, &med)) { + if (med.media_present) + return CDS_DISC_OK; + else if (med.door_open) + return CDS_TRAY_OPEN; + else + return CDS_NO_DISC; + } + + if (sense.sense_key == NOT_READY && sense.asc == 0x04 + && sense.ascq == 0x04) + return CDS_DISC_OK; + + /* + * If not using Mt Fuji extended media tray reports, + * just return TRAY_OPEN since ATAPI doesn't provide + * any other way to detect this... + */ + if (sense.sense_key == NOT_READY) { + if (sense.asc == 0x3a && sense.ascq == 1) + return CDS_NO_DISC; + else + return CDS_TRAY_OPEN; + } + return CDS_DRIVE_NOT_READY; +} + +/* + * ide-cd always generates media changed event if media is missing, which + * makes it impossible to use for proper event reporting, so disk->events + * is cleared to 0 and the following function is used only to trigger + * revalidation and never propagated to userland. + */ +unsigned int ide_cdrom_check_events_real(struct cdrom_device_info *cdi, + unsigned int clearing, int slot_nr) +{ + ide_drive_t *drive = cdi->handle; + int retval; + + if (slot_nr == CDSL_CURRENT) { + (void) cdrom_check_status(drive, NULL); + retval = (drive->dev_flags & IDE_DFLAG_MEDIA_CHANGED) ? 1 : 0; + drive->dev_flags &= ~IDE_DFLAG_MEDIA_CHANGED; + return retval ? DISK_EVENT_MEDIA_CHANGE : 0; + } else { + return 0; + } +} + +/* Eject the disk if EJECTFLAG is 0. + If EJECTFLAG is 1, try to reload the disk. */ +static +int cdrom_eject(ide_drive_t *drive, int ejectflag, + struct request_sense *sense) +{ + struct cdrom_info *cd = drive->driver_data; + struct cdrom_device_info *cdi = &cd->devinfo; + char loej = 0x02; + unsigned char cmd[BLK_MAX_CDB]; + + if ((drive->atapi_flags & IDE_AFLAG_NO_EJECT) && !ejectflag) + return -EDRIVE_CANT_DO_THIS; + + /* reload fails on some drives, if the tray is locked */ + if ((drive->atapi_flags & IDE_AFLAG_DOOR_LOCKED) && ejectflag) + return 0; + + /* only tell drive to close tray if open, if it can do that */ + if (ejectflag && (cdi->mask & CDC_CLOSE_TRAY)) + loej = 0; + + memset(cmd, 0, BLK_MAX_CDB); + + cmd[0] = GPCMD_START_STOP_UNIT; + cmd[4] = loej | (ejectflag != 0); + + return ide_cd_queue_pc(drive, cmd, 0, NULL, NULL, sense, 0, 0); +} + +/* Lock the door if LOCKFLAG is nonzero; unlock it otherwise. */ +static +int ide_cd_lockdoor(ide_drive_t *drive, int lockflag, + struct request_sense *sense) +{ + struct request_sense my_sense; + int stat; + + if (sense == NULL) + sense = &my_sense; + + /* If the drive cannot lock the door, just pretend. */ + if ((drive->dev_flags & IDE_DFLAG_DOORLOCKING) == 0) { + stat = 0; + } else { + unsigned char cmd[BLK_MAX_CDB]; + + memset(cmd, 0, BLK_MAX_CDB); + + cmd[0] = GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL; + cmd[4] = lockflag ? 1 : 0; + + stat = ide_cd_queue_pc(drive, cmd, 0, NULL, NULL, + sense, 0, 0); + } + + /* If we got an illegal field error, the drive + probably cannot lock the door. */ + if (stat != 0 && + sense->sense_key == ILLEGAL_REQUEST && + (sense->asc == 0x24 || sense->asc == 0x20)) { + printk(KERN_ERR "%s: door locking not supported\n", + drive->name); + drive->dev_flags &= ~IDE_DFLAG_DOORLOCKING; + stat = 0; + } + + /* no medium, that's alright. */ + if (stat != 0 && sense->sense_key == NOT_READY && sense->asc == 0x3a) + stat = 0; + + if (stat == 0) { + if (lockflag) + drive->atapi_flags |= IDE_AFLAG_DOOR_LOCKED; + else + drive->atapi_flags &= ~IDE_AFLAG_DOOR_LOCKED; + } + + return stat; +} + +int ide_cdrom_tray_move(struct cdrom_device_info *cdi, int position) +{ + ide_drive_t *drive = cdi->handle; + struct request_sense sense; + + if (position) { + int stat = ide_cd_lockdoor(drive, 0, &sense); + + if (stat) + return stat; + } + + return cdrom_eject(drive, !position, &sense); +} + +int ide_cdrom_lock_door(struct cdrom_device_info *cdi, int lock) +{ + ide_drive_t *drive = cdi->handle; + + return ide_cd_lockdoor(drive, lock, NULL); +} + +/* + * ATAPI devices are free to select the speed you request or any slower + * rate. :-( Requesting too fast a speed will _not_ produce an error. + */ +int ide_cdrom_select_speed(struct cdrom_device_info *cdi, int speed) +{ + ide_drive_t *drive = cdi->handle; + struct cdrom_info *cd = drive->driver_data; + struct request_sense sense; + u8 buf[ATAPI_CAPABILITIES_PAGE_SIZE]; + int stat; + unsigned char cmd[BLK_MAX_CDB]; + + if (speed == 0) + speed = 0xffff; /* set to max */ + else + speed *= 177; /* Nx to kbytes/s */ + + memset(cmd, 0, BLK_MAX_CDB); + + cmd[0] = GPCMD_SET_SPEED; + /* Read Drive speed in kbytes/second MSB/LSB */ + cmd[2] = (speed >> 8) & 0xff; + cmd[3] = speed & 0xff; + if ((cdi->mask & (CDC_CD_R | CDC_CD_RW | CDC_DVD_R)) != + (CDC_CD_R | CDC_CD_RW | CDC_DVD_R)) { + /* Write Drive speed in kbytes/second MSB/LSB */ + cmd[4] = (speed >> 8) & 0xff; + cmd[5] = speed & 0xff; + } + + stat = ide_cd_queue_pc(drive, cmd, 0, NULL, NULL, &sense, 0, 0); + + if (!ide_cdrom_get_capabilities(drive, buf)) { + ide_cdrom_update_speed(drive, buf); + cdi->speed = cd->current_speed; + } + + return 0; +} + +int ide_cdrom_get_last_session(struct cdrom_device_info *cdi, + struct cdrom_multisession *ms_info) +{ + struct atapi_toc *toc; + ide_drive_t *drive = cdi->handle; + struct cdrom_info *info = drive->driver_data; + struct request_sense sense; + int ret; + + if ((drive->atapi_flags & IDE_AFLAG_TOC_VALID) == 0 || !info->toc) { + ret = ide_cd_read_toc(drive, &sense); + if (ret) + return ret; + } + + toc = info->toc; + ms_info->addr.lba = toc->last_session_lba; + ms_info->xa_flag = toc->xa_flag; + + return 0; +} + +int ide_cdrom_get_mcn(struct cdrom_device_info *cdi, + struct cdrom_mcn *mcn_info) +{ + ide_drive_t *drive = cdi->handle; + int stat, mcnlen; + char buf[24]; + unsigned char cmd[BLK_MAX_CDB]; + unsigned len = sizeof(buf); + + memset(cmd, 0, BLK_MAX_CDB); + + cmd[0] = GPCMD_READ_SUBCHANNEL; + cmd[1] = 2; /* MSF addressing */ + cmd[2] = 0x40; /* request subQ data */ + cmd[3] = 2; /* format */ + cmd[8] = len; + + stat = ide_cd_queue_pc(drive, cmd, 0, buf, &len, NULL, 0, 0); + if (stat) + return stat; + + mcnlen = sizeof(mcn_info->medium_catalog_number) - 1; + memcpy(mcn_info->medium_catalog_number, buf + 9, mcnlen); + mcn_info->medium_catalog_number[mcnlen] = '\0'; + + return 0; +} + +int ide_cdrom_reset(struct cdrom_device_info *cdi) +{ + ide_drive_t *drive = cdi->handle; + struct cdrom_info *cd = drive->driver_data; + struct request_sense sense; + struct request *rq; + int ret; + + rq = blk_get_request(drive->queue, READ, __GFP_WAIT); + rq->cmd_type = REQ_TYPE_SPECIAL; + rq->cmd_flags = REQ_QUIET; + ret = blk_execute_rq(drive->queue, cd->disk, rq, 0); + blk_put_request(rq); + /* + * A reset will unlock the door. If it was previously locked, + * lock it again. + */ + if (drive->atapi_flags & IDE_AFLAG_DOOR_LOCKED) + (void)ide_cd_lockdoor(drive, 1, &sense); + + return ret; +} + +static int ide_cd_get_toc_entry(ide_drive_t *drive, int track, + struct atapi_toc_entry **ent) +{ + struct cdrom_info *info = drive->driver_data; + struct atapi_toc *toc = info->toc; + int ntracks; + + /* + * don't serve cached data, if the toc isn't valid + */ + if ((drive->atapi_flags & IDE_AFLAG_TOC_VALID) == 0) + return -EINVAL; + + /* Check validity of requested track number. */ + ntracks = toc->hdr.last_track - toc->hdr.first_track + 1; + + if (toc->hdr.first_track == CDROM_LEADOUT) + ntracks = 0; + + if (track == CDROM_LEADOUT) + *ent = &toc->ent[ntracks]; + else if (track < toc->hdr.first_track || track > toc->hdr.last_track) + return -EINVAL; + else + *ent = &toc->ent[track - toc->hdr.first_track]; + + return 0; +} + +static int ide_cd_fake_play_trkind(ide_drive_t *drive, void *arg) +{ + struct cdrom_ti *ti = arg; + struct atapi_toc_entry *first_toc, *last_toc; + unsigned long lba_start, lba_end; + int stat; + struct request_sense sense; + unsigned char cmd[BLK_MAX_CDB]; + + stat = ide_cd_get_toc_entry(drive, ti->cdti_trk0, &first_toc); + if (stat) + return stat; + + stat = ide_cd_get_toc_entry(drive, ti->cdti_trk1, &last_toc); + if (stat) + return stat; + + if (ti->cdti_trk1 != CDROM_LEADOUT) + ++last_toc; + lba_start = first_toc->addr.lba; + lba_end = last_toc->addr.lba; + + if (lba_end <= lba_start) + return -EINVAL; + + memset(cmd, 0, BLK_MAX_CDB); + + cmd[0] = GPCMD_PLAY_AUDIO_MSF; + lba_to_msf(lba_start, &cmd[3], &cmd[4], &cmd[5]); + lba_to_msf(lba_end - 1, &cmd[6], &cmd[7], &cmd[8]); + + return ide_cd_queue_pc(drive, cmd, 0, NULL, NULL, &sense, 0, 0); +} + +static int ide_cd_read_tochdr(ide_drive_t *drive, void *arg) +{ + struct cdrom_info *cd = drive->driver_data; + struct cdrom_tochdr *tochdr = arg; + struct atapi_toc *toc; + int stat; + + /* Make sure our saved TOC is valid. */ + stat = ide_cd_read_toc(drive, NULL); + if (stat) + return stat; + + toc = cd->toc; + tochdr->cdth_trk0 = toc->hdr.first_track; + tochdr->cdth_trk1 = toc->hdr.last_track; + + return 0; +} + +static int ide_cd_read_tocentry(ide_drive_t *drive, void *arg) +{ + struct cdrom_tocentry *tocentry = arg; + struct atapi_toc_entry *toce; + int stat; + + stat = ide_cd_get_toc_entry(drive, tocentry->cdte_track, &toce); + if (stat) + return stat; + + tocentry->cdte_ctrl = toce->control; + tocentry->cdte_adr = toce->adr; + if (tocentry->cdte_format == CDROM_MSF) { + lba_to_msf(toce->addr.lba, + &tocentry->cdte_addr.msf.minute, + &tocentry->cdte_addr.msf.second, + &tocentry->cdte_addr.msf.frame); + } else + tocentry->cdte_addr.lba = toce->addr.lba; + + return 0; +} + +int ide_cdrom_audio_ioctl(struct cdrom_device_info *cdi, + unsigned int cmd, void *arg) +{ + ide_drive_t *drive = cdi->handle; + + switch (cmd) { + /* + * emulate PLAY_AUDIO_TI command with PLAY_AUDIO_10, since + * atapi doesn't support it + */ + case CDROMPLAYTRKIND: + return ide_cd_fake_play_trkind(drive, arg); + case CDROMREADTOCHDR: + return ide_cd_read_tochdr(drive, arg); + case CDROMREADTOCENTRY: + return ide_cd_read_tocentry(drive, arg); + default: + return -EINVAL; + } +} + +/* the generic packet interface to cdrom.c */ +int ide_cdrom_packet(struct cdrom_device_info *cdi, + struct packet_command *cgc) +{ + ide_drive_t *drive = cdi->handle; + unsigned int flags = 0; + unsigned len = cgc->buflen; + + if (cgc->timeout <= 0) + cgc->timeout = ATAPI_WAIT_PC; + + /* here we queue the commands from the uniform CD-ROM + layer. the packet must be complete, as we do not + touch it at all. */ + + if (cgc->data_direction == CGC_DATA_WRITE) + flags |= REQ_WRITE; + + if (cgc->sense) + memset(cgc->sense, 0, sizeof(struct request_sense)); + + if (cgc->quiet) + flags |= REQ_QUIET; + + cgc->stat = ide_cd_queue_pc(drive, cgc->cmd, + cgc->data_direction == CGC_DATA_WRITE, + cgc->buffer, &len, + cgc->sense, cgc->timeout, flags); + if (!cgc->stat) + cgc->buflen -= len; + return cgc->stat; +} diff --git a/drivers/ide/ide-cd_verbose.c b/drivers/ide/ide-cd_verbose.c new file mode 100644 index 00000000000..f079ca2f260 --- /dev/null +++ b/drivers/ide/ide-cd_verbose.c @@ -0,0 +1,361 @@ +/* + * Verbose error logging for ATAPI CD/DVD devices. + * + * Copyright (C) 1994-1996 Scott Snyder <snyder@fnald0.fnal.gov> + * Copyright (C) 1996-1998 Erik Andersen <andersee@debian.org> + * Copyright (C) 1998-2000 Jens Axboe <axboe@suse.de> + */ + +#include <linux/kernel.h> +#include <linux/blkdev.h> +#include <linux/cdrom.h> +#include <linux/ide.h> +#include <scsi/scsi.h> +#include "ide-cd.h" + +#ifndef CONFIG_BLK_DEV_IDECD_VERBOSE_ERRORS +void ide_cd_log_error(const char *name, struct request *failed_command, + struct request_sense *sense) +{ + /* Suppress printing unit attention and `in progress of becoming ready' + errors when we're not being verbose. */ + if (sense->sense_key == UNIT_ATTENTION || + (sense->sense_key == NOT_READY && (sense->asc == 4 || + sense->asc == 0x3a))) + return; + + printk(KERN_ERR "%s: error code: 0x%02x sense_key: 0x%02x " + "asc: 0x%02x ascq: 0x%02x\n", + name, sense->error_code, sense->sense_key, + sense->asc, sense->ascq); +} +#else +/* The generic packet command opcodes for CD/DVD Logical Units, + * From Table 57 of the SFF8090 Ver. 3 (Mt. Fuji) draft standard. */ +static const struct { + unsigned short packet_command; + const char * const text; +} packet_command_texts[] = { + { GPCMD_TEST_UNIT_READY, "Test Unit Ready" }, + { GPCMD_REQUEST_SENSE, "Request Sense" }, + { GPCMD_FORMAT_UNIT, "Format Unit" }, + { GPCMD_INQUIRY, "Inquiry" }, + { GPCMD_START_STOP_UNIT, "Start/Stop Unit" }, + { GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL, "Prevent/Allow Medium Removal" }, + { GPCMD_READ_FORMAT_CAPACITIES, "Read Format Capacities" }, + { GPCMD_READ_CDVD_CAPACITY, "Read Cd/Dvd Capacity" }, + { GPCMD_READ_10, "Read 10" }, + { GPCMD_WRITE_10, "Write 10" }, + { GPCMD_SEEK, "Seek" }, + { GPCMD_WRITE_AND_VERIFY_10, "Write and Verify 10" }, + { GPCMD_VERIFY_10, "Verify 10" }, + { GPCMD_FLUSH_CACHE, "Flush Cache" }, + { GPCMD_READ_SUBCHANNEL, "Read Subchannel" }, + { GPCMD_READ_TOC_PMA_ATIP, "Read Table of Contents" }, + { GPCMD_READ_HEADER, "Read Header" }, + { GPCMD_PLAY_AUDIO_10, "Play Audio 10" }, + { GPCMD_GET_CONFIGURATION, "Get Configuration" }, + { GPCMD_PLAY_AUDIO_MSF, "Play Audio MSF" }, + { GPCMD_PLAYAUDIO_TI, "Play Audio TrackIndex" }, + { GPCMD_GET_EVENT_STATUS_NOTIFICATION, + "Get Event Status Notification" }, + { GPCMD_PAUSE_RESUME, "Pause/Resume" }, + { GPCMD_STOP_PLAY_SCAN, "Stop Play/Scan" }, + { GPCMD_READ_DISC_INFO, "Read Disc Info" }, + { GPCMD_READ_TRACK_RZONE_INFO, "Read Track Rzone Info" }, + { GPCMD_RESERVE_RZONE_TRACK, "Reserve Rzone Track" }, + { GPCMD_SEND_OPC, "Send OPC" }, + { GPCMD_MODE_SELECT_10, "Mode Select 10" }, + { GPCMD_REPAIR_RZONE_TRACK, "Repair Rzone Track" }, + { GPCMD_MODE_SENSE_10, "Mode Sense 10" }, + { GPCMD_CLOSE_TRACK, "Close Track" }, + { GPCMD_BLANK, "Blank" }, + { GPCMD_SEND_EVENT, "Send Event" }, + { GPCMD_SEND_KEY, "Send Key" }, + { GPCMD_REPORT_KEY, "Report Key" }, + { GPCMD_LOAD_UNLOAD, "Load/Unload" }, + { GPCMD_SET_READ_AHEAD, "Set Read-ahead" }, + { GPCMD_READ_12, "Read 12" }, + { GPCMD_GET_PERFORMANCE, "Get Performance" }, + { GPCMD_SEND_DVD_STRUCTURE, "Send DVD Structure" }, + { GPCMD_READ_DVD_STRUCTURE, "Read DVD Structure" }, + { GPCMD_SET_STREAMING, "Set Streaming" }, + { GPCMD_READ_CD_MSF, "Read CD MSF" }, + { GPCMD_SCAN, "Scan" }, + { GPCMD_SET_SPEED, "Set Speed" }, + { GPCMD_PLAY_CD, "Play CD" }, + { GPCMD_MECHANISM_STATUS, "Mechanism Status" }, + { GPCMD_READ_CD, "Read CD" }, +}; + +/* From Table 303 of the SFF8090 Ver. 3 (Mt. Fuji) draft standard. */ +static const char * const sense_key_texts[16] = { + "No sense data", + "Recovered error", + "Not ready", + "Medium error", + "Hardware error", + "Illegal request", + "Unit attention", + "Data protect", + "Blank check", + "(reserved)", + "(reserved)", + "Aborted command", + "(reserved)", + "(reserved)", + "Miscompare", + "(reserved)", +}; + +/* From Table 304 of the SFF8090 Ver. 3 (Mt. Fuji) draft standard. */ +static const struct { + unsigned long asc_ascq; + const char * const text; +} sense_data_texts[] = { + { 0x000000, "No additional sense information" }, + { 0x000011, "Play operation in progress" }, + { 0x000012, "Play operation paused" }, + { 0x000013, "Play operation successfully completed" }, + { 0x000014, "Play operation stopped due to error" }, + { 0x000015, "No current audio status to return" }, + { 0x010c0a, "Write error - padding blocks added" }, + { 0x011700, "Recovered data with no error correction applied" }, + { 0x011701, "Recovered data with retries" }, + { 0x011702, "Recovered data with positive head offset" }, + { 0x011703, "Recovered data with negative head offset" }, + { 0x011704, "Recovered data with retries and/or CIRC applied" }, + { 0x011705, "Recovered data using previous sector ID" }, + { 0x011800, "Recovered data with error correction applied" }, + { 0x011801, "Recovered data with error correction and retries applied"}, + { 0x011802, "Recovered data - the data was auto-reallocated" }, + { 0x011803, "Recovered data with CIRC" }, + { 0x011804, "Recovered data with L-EC" }, + { 0x015d00, "Failure prediction threshold exceeded" + " - Predicted logical unit failure" }, + { 0x015d01, "Failure prediction threshold exceeded" + " - Predicted media failure" }, + { 0x015dff, "Failure prediction threshold exceeded - False" }, + { 0x017301, "Power calibration area almost full" }, + { 0x020400, "Logical unit not ready - cause not reportable" }, + /* Following is misspelled in ATAPI 2.6, _and_ in Mt. Fuji */ + { 0x020401, "Logical unit not ready" + " - in progress [sic] of becoming ready" }, + { 0x020402, "Logical unit not ready - initializing command required" }, + { 0x020403, "Logical unit not ready - manual intervention required" }, + { 0x020404, "Logical unit not ready - format in progress" }, + { 0x020407, "Logical unit not ready - operation in progress" }, + { 0x020408, "Logical unit not ready - long write in progress" }, + { 0x020600, "No reference position found (media may be upside down)" }, + { 0x023000, "Incompatible medium installed" }, + { 0x023a00, "Medium not present" }, + { 0x025300, "Media load or eject failed" }, + { 0x025700, "Unable to recover table of contents" }, + { 0x030300, "Peripheral device write fault" }, + { 0x030301, "No write current" }, + { 0x030302, "Excessive write errors" }, + { 0x030c00, "Write error" }, + { 0x030c01, "Write error - Recovered with auto reallocation" }, + { 0x030c02, "Write error - auto reallocation failed" }, + { 0x030c03, "Write error - recommend reassignment" }, + { 0x030c04, "Compression check miscompare error" }, + { 0x030c05, "Data expansion occurred during compress" }, + { 0x030c06, "Block not compressible" }, + { 0x030c07, "Write error - recovery needed" }, + { 0x030c08, "Write error - recovery failed" }, + { 0x030c09, "Write error - loss of streaming" }, + { 0x031100, "Unrecovered read error" }, + { 0x031106, "CIRC unrecovered error" }, + { 0x033101, "Format command failed" }, + { 0x033200, "No defect spare location available" }, + { 0x033201, "Defect list update failure" }, + { 0x035100, "Erase failure" }, + { 0x037200, "Session fixation error" }, + { 0x037201, "Session fixation error writin lead-in" }, + { 0x037202, "Session fixation error writin lead-out" }, + { 0x037300, "CD control error" }, + { 0x037302, "Power calibration area is full" }, + { 0x037303, "Power calibration area error" }, + { 0x037304, "Program memory area / RMA update failure" }, + { 0x037305, "Program memory area / RMA is full" }, + { 0x037306, "Program memory area / RMA is (almost) full" }, + { 0x040200, "No seek complete" }, + { 0x040300, "Write fault" }, + { 0x040900, "Track following error" }, + { 0x040901, "Tracking servo failure" }, + { 0x040902, "Focus servo failure" }, + { 0x040903, "Spindle servo failure" }, + { 0x041500, "Random positioning error" }, + { 0x041501, "Mechanical positioning or changer error" }, + { 0x041502, "Positioning error detected by read of medium" }, + { 0x043c00, "Mechanical positioning or changer error" }, + { 0x044000, "Diagnostic failure on component (ASCQ)" }, + { 0x044400, "Internal CD/DVD logical unit failure" }, + { 0x04b600, "Media load mechanism failed" }, + { 0x051a00, "Parameter list length error" }, + { 0x052000, "Invalid command operation code" }, + { 0x052100, "Logical block address out of range" }, + { 0x052102, "Invalid address for write" }, + { 0x052400, "Invalid field in command packet" }, + { 0x052600, "Invalid field in parameter list" }, + { 0x052601, "Parameter not supported" }, + { 0x052602, "Parameter value invalid" }, + { 0x052700, "Write protected media" }, + { 0x052c00, "Command sequence error" }, + { 0x052c03, "Current program area is not empty" }, + { 0x052c04, "Current program area is empty" }, + { 0x053001, "Cannot read medium - unknown format" }, + { 0x053002, "Cannot read medium - incompatible format" }, + { 0x053900, "Saving parameters not supported" }, + { 0x054e00, "Overlapped commands attempted" }, + { 0x055302, "Medium removal prevented" }, + { 0x055500, "System resource failure" }, + { 0x056300, "End of user area encountered on this track" }, + { 0x056400, "Illegal mode for this track or incompatible medium" }, + { 0x056f00, "Copy protection key exchange failure" + " - Authentication failure" }, + { 0x056f01, "Copy protection key exchange failure - Key not present" }, + { 0x056f02, "Copy protection key exchange failure" + " - Key not established" }, + { 0x056f03, "Read of scrambled sector without authentication" }, + { 0x056f04, "Media region code is mismatched to logical unit" }, + { 0x056f05, "Drive region must be permanent" + " / region reset count error" }, + { 0x057203, "Session fixation error - incomplete track in session" }, + { 0x057204, "Empty or partially written reserved track" }, + { 0x057205, "No more RZONE reservations are allowed" }, + { 0x05bf00, "Loss of streaming" }, + { 0x062800, "Not ready to ready transition, medium may have changed" }, + { 0x062900, "Power on, reset or hardware reset occurred" }, + { 0x062a00, "Parameters changed" }, + { 0x062a01, "Mode parameters changed" }, + { 0x062e00, "Insufficient time for operation" }, + { 0x063f00, "Logical unit operating conditions have changed" }, + { 0x063f01, "Microcode has been changed" }, + { 0x065a00, "Operator request or state change input (unspecified)" }, + { 0x065a01, "Operator medium removal request" }, + { 0x0bb900, "Play operation aborted" }, + /* Here we use 0xff for the key (not a valid key) to signify + * that these can have _any_ key value associated with them... */ + { 0xff0401, "Logical unit is in process of becoming ready" }, + { 0xff0400, "Logical unit not ready, cause not reportable" }, + { 0xff0402, "Logical unit not ready, initializing command required" }, + { 0xff0403, "Logical unit not ready, manual intervention required" }, + { 0xff0500, "Logical unit does not respond to selection" }, + { 0xff0800, "Logical unit communication failure" }, + { 0xff0802, "Logical unit communication parity error" }, + { 0xff0801, "Logical unit communication time-out" }, + { 0xff2500, "Logical unit not supported" }, + { 0xff4c00, "Logical unit failed self-configuration" }, + { 0xff3e00, "Logical unit has not self-configured yet" }, +}; + +void ide_cd_log_error(const char *name, struct request *failed_command, + struct request_sense *sense) +{ + int i; + const char *s = "bad sense key!"; + char buf[80]; + + printk(KERN_ERR "ATAPI device %s:\n", name); + if (sense->error_code == 0x70) + printk(KERN_CONT " Error: "); + else if (sense->error_code == 0x71) + printk(" Deferred Error: "); + else if (sense->error_code == 0x7f) + printk(KERN_CONT " Vendor-specific Error: "); + else + printk(KERN_CONT " Unknown Error Type: "); + + if (sense->sense_key < ARRAY_SIZE(sense_key_texts)) + s = sense_key_texts[sense->sense_key]; + + printk(KERN_CONT "%s -- (Sense key=0x%02x)\n", s, sense->sense_key); + + if (sense->asc == 0x40) { + sprintf(buf, "Diagnostic failure on component 0x%02x", + sense->ascq); + s = buf; + } else { + int lo = 0, mid, hi = ARRAY_SIZE(sense_data_texts); + unsigned long key = (sense->sense_key << 16); + + key |= (sense->asc << 8); + if (!(sense->ascq >= 0x80 && sense->ascq <= 0xdd)) + key |= sense->ascq; + s = NULL; + + while (hi > lo) { + mid = (lo + hi) / 2; + if (sense_data_texts[mid].asc_ascq == key || + sense_data_texts[mid].asc_ascq == (0xff0000|key)) { + s = sense_data_texts[mid].text; + break; + } else if (sense_data_texts[mid].asc_ascq > key) + hi = mid; + else + lo = mid + 1; + } + } + + if (s == NULL) { + if (sense->asc > 0x80) + s = "(vendor-specific error)"; + else + s = "(reserved error code)"; + } + + printk(KERN_ERR " %s -- (asc=0x%02x, ascq=0x%02x)\n", + s, sense->asc, sense->ascq); + + if (failed_command != NULL) { + int lo = 0, mid, hi = ARRAY_SIZE(packet_command_texts); + s = NULL; + + while (hi > lo) { + mid = (lo + hi) / 2; + if (packet_command_texts[mid].packet_command == + failed_command->cmd[0]) { + s = packet_command_texts[mid].text; + break; + } + if (packet_command_texts[mid].packet_command > + failed_command->cmd[0]) + hi = mid; + else + lo = mid + 1; + } + + printk(KERN_ERR " The failed \"%s\" packet command " + "was: \n \"", s); + for (i = 0; i < BLK_MAX_CDB; i++) + printk(KERN_CONT "%02x ", failed_command->cmd[i]); + printk(KERN_CONT "\"\n"); + } + + /* The SKSV bit specifies validity of the sense_key_specific + * in the next two commands. It is bit 7 of the first byte. + * In the case of NOT_READY, if SKSV is set the drive can + * give us nice ETA readings. + */ + if (sense->sense_key == NOT_READY && (sense->sks[0] & 0x80)) { + int progress = (sense->sks[1] << 8 | sense->sks[2]) * 100; + + printk(KERN_ERR " Command is %02d%% complete\n", + progress / 0xffff); + } + + if (sense->sense_key == ILLEGAL_REQUEST && + (sense->sks[0] & 0x80) != 0) { + printk(KERN_ERR " Error in %s byte %d", + (sense->sks[0] & 0x40) != 0 ? + "command packet" : "command data", + (sense->sks[1] << 8) + sense->sks[2]); + + if ((sense->sks[0] & 0x40) != 0) + printk(KERN_CONT " bit %d", sense->sks[0] & 0x07); + + printk(KERN_CONT "\n"); + } +} +#endif diff --git a/drivers/ide/ide-cs.c b/drivers/ide/ide-cs.c new file mode 100644 index 00000000000..f1e922e2479 --- /dev/null +++ b/drivers/ide/ide-cs.c @@ -0,0 +1,364 @@ +/*====================================================================== + + A driver for PCMCIA IDE/ATA disk cards + + The contents of this file are subject to the Mozilla Public + License Version 1.1 (the "License"); you may not use this file + except in compliance with the License. You may obtain a copy of + the License at http://www.mozilla.org/MPL/ + + Software distributed under the License is distributed on an "AS + IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + implied. See the License for the specific language governing + rights and limitations under the License. + + The initial developer of the original code is David A. Hinds + <dahinds@users.sourceforge.net>. Portions created by David A. Hinds + are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + + Alternatively, the contents of this file may be used under the + terms of the GNU General Public License version 2 (the "GPL"), in + which case the provisions of the GPL are applicable instead of the + above. If you wish to allow the use of your version of this file + only under the terms of the GPL and not to allow others to use + your version of this file under the MPL, indicate your decision + by deleting the provisions above and replace them with the notice + and other provisions required by the GPL. If you do not delete + the provisions above, a recipient may use your version of this + file under either the MPL or the GPL. + +======================================================================*/ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/ptrace.h> +#include <linux/slab.h> +#include <linux/string.h> +#include <linux/timer.h> +#include <linux/ioport.h> +#include <linux/ide.h> +#include <linux/major.h> +#include <linux/delay.h> +#include <asm/io.h> + +#include <pcmcia/cistpl.h> +#include <pcmcia/ds.h> +#include <pcmcia/cisreg.h> +#include <pcmcia/ciscode.h> + +#define DRV_NAME "ide-cs" + +/*====================================================================*/ + +/* Module parameters */ + +MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>"); +MODULE_DESCRIPTION("PCMCIA ATA/IDE card driver"); +MODULE_LICENSE("Dual MPL/GPL"); + +/*====================================================================*/ + +typedef struct ide_info_t { + struct pcmcia_device *p_dev; + struct ide_host *host; + int ndev; +} ide_info_t; + +static void ide_release(struct pcmcia_device *); +static int ide_config(struct pcmcia_device *); + +static void ide_detach(struct pcmcia_device *p_dev); + +static int ide_probe(struct pcmcia_device *link) +{ + ide_info_t *info; + + dev_dbg(&link->dev, "ide_attach()\n"); + + /* Create new ide device */ + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + info->p_dev = link; + link->priv = info; + + link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO | + CONF_AUTO_SET_VPP | CONF_AUTO_CHECK_VCC; + + return ide_config(link); +} /* ide_attach */ + +static void ide_detach(struct pcmcia_device *link) +{ + ide_info_t *info = link->priv; + + dev_dbg(&link->dev, "ide_detach(0x%p)\n", link); + + ide_release(link); + + kfree(info); +} /* ide_detach */ + +static const struct ide_port_ops idecs_port_ops = { + .quirkproc = ide_undecoded_slave, +}; + +static const struct ide_port_info idecs_port_info = { + .port_ops = &idecs_port_ops, + .host_flags = IDE_HFLAG_NO_DMA, + .irq_flags = IRQF_SHARED, + .chipset = ide_pci, +}; + +static struct ide_host *idecs_register(unsigned long io, unsigned long ctl, + unsigned long irq, struct pcmcia_device *handle) +{ + struct ide_host *host; + ide_hwif_t *hwif; + int i, rc; + struct ide_hw hw, *hws[] = { &hw }; + + if (!request_region(io, 8, DRV_NAME)) { + printk(KERN_ERR "%s: I/O resource 0x%lX-0x%lX not free.\n", + DRV_NAME, io, io + 7); + return NULL; + } + + if (!request_region(ctl, 1, DRV_NAME)) { + printk(KERN_ERR "%s: I/O resource 0x%lX not free.\n", + DRV_NAME, ctl); + release_region(io, 8); + return NULL; + } + + memset(&hw, 0, sizeof(hw)); + ide_std_init_ports(&hw, io, ctl); + hw.irq = irq; + hw.dev = &handle->dev; + + rc = ide_host_add(&idecs_port_info, hws, 1, &host); + if (rc) + goto out_release; + + hwif = host->ports[0]; + + if (hwif->present) + return host; + + /* retry registration in case device is still spinning up */ + for (i = 0; i < 10; i++) { + msleep(100); + ide_port_scan(hwif); + if (hwif->present) + return host; + } + + return host; + +out_release: + release_region(ctl, 1); + release_region(io, 8); + return NULL; +} + +static int pcmcia_check_one_config(struct pcmcia_device *pdev, void *priv_data) +{ + int *is_kme = priv_data; + + if ((pdev->resource[0]->flags & IO_DATA_PATH_WIDTH) + != IO_DATA_PATH_WIDTH_8) { + pdev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; + pdev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO; + } + pdev->resource[1]->flags &= ~IO_DATA_PATH_WIDTH; + pdev->resource[1]->flags |= IO_DATA_PATH_WIDTH_8; + + if (pdev->resource[1]->end) { + pdev->resource[0]->end = 8; + pdev->resource[1]->end = (*is_kme) ? 2 : 1; + } else { + if (pdev->resource[0]->end < 16) + return -ENODEV; + } + + return pcmcia_request_io(pdev); +} + +static int ide_config(struct pcmcia_device *link) +{ + ide_info_t *info = link->priv; + int ret = 0, is_kme = 0; + unsigned long io_base, ctl_base; + struct ide_host *host; + + dev_dbg(&link->dev, "ide_config(0x%p)\n", link); + + is_kme = ((link->manf_id == MANFID_KME) && + ((link->card_id == PRODID_KME_KXLC005_A) || + (link->card_id == PRODID_KME_KXLC005_B))); + + if (pcmcia_loop_config(link, pcmcia_check_one_config, &is_kme)) { + link->config_flags &= ~CONF_AUTO_CHECK_VCC; + if (pcmcia_loop_config(link, pcmcia_check_one_config, &is_kme)) + goto failed; /* No suitable config found */ + } + io_base = link->resource[0]->start; + if (link->resource[1]->end) + ctl_base = link->resource[1]->start; + else + ctl_base = link->resource[0]->start + 0x0e; + + if (!link->irq) + goto failed; + + ret = pcmcia_enable_device(link); + if (ret) + goto failed; + + /* disable drive interrupts during IDE probe */ + outb(0x02, ctl_base); + + /* special setup for KXLC005 card */ + if (is_kme) + outb(0x81, ctl_base+1); + + host = idecs_register(io_base, ctl_base, link->irq, link); + if (host == NULL && resource_size(link->resource[0]) == 0x20) { + outb(0x02, ctl_base + 0x10); + host = idecs_register(io_base + 0x10, ctl_base + 0x10, + link->irq, link); + } + + if (host == NULL) + goto failed; + + info->ndev = 1; + info->host = host; + dev_info(&link->dev, "ide-cs: hd%c: Vpp = %d.%d\n", + 'a' + host->ports[0]->index * 2, + link->vpp / 10, link->vpp % 10); + + return 0; + +failed: + ide_release(link); + return -ENODEV; +} /* ide_config */ + +static void ide_release(struct pcmcia_device *link) +{ + ide_info_t *info = link->priv; + struct ide_host *host = info->host; + + dev_dbg(&link->dev, "ide_release(0x%p)\n", link); + + if (info->ndev) { + ide_hwif_t *hwif = host->ports[0]; + unsigned long data_addr, ctl_addr; + + data_addr = hwif->io_ports.data_addr; + ctl_addr = hwif->io_ports.ctl_addr; + + ide_host_remove(host); + info->ndev = 0; + + release_region(ctl_addr, 1); + release_region(data_addr, 8); + } + + pcmcia_disable_device(link); +} /* ide_release */ + + +static const struct pcmcia_device_id ide_ids[] = { + PCMCIA_DEVICE_FUNC_ID(4), + PCMCIA_DEVICE_MANF_CARD(0x0000, 0x0000), /* Corsair */ + PCMCIA_DEVICE_MANF_CARD(0x0007, 0x0000), /* Hitachi */ + PCMCIA_DEVICE_MANF_CARD(0x000a, 0x0000), /* I-O Data CFA */ + PCMCIA_DEVICE_MANF_CARD(0x001c, 0x0001), /* Mitsubishi CFA */ + PCMCIA_DEVICE_MANF_CARD(0x0032, 0x0704), + PCMCIA_DEVICE_MANF_CARD(0x0032, 0x2904), + PCMCIA_DEVICE_MANF_CARD(0x0045, 0x0401), /* SanDisk CFA */ + PCMCIA_DEVICE_MANF_CARD(0x004f, 0x0000), /* Kingston */ + PCMCIA_DEVICE_MANF_CARD(0x0097, 0x1620), /* TI emulated */ + PCMCIA_DEVICE_MANF_CARD(0x0098, 0x0000), /* Toshiba */ + PCMCIA_DEVICE_MANF_CARD(0x00a4, 0x002d), + PCMCIA_DEVICE_MANF_CARD(0x00ce, 0x0000), /* Samsung */ + PCMCIA_DEVICE_MANF_CARD(0x0319, 0x0000), /* Hitachi */ + PCMCIA_DEVICE_MANF_CARD(0x2080, 0x0001), + PCMCIA_DEVICE_MANF_CARD(0x4e01, 0x0100), /* Viking CFA */ + PCMCIA_DEVICE_MANF_CARD(0x4e01, 0x0200), /* Lexar, Viking CFA */ + PCMCIA_DEVICE_PROD_ID123("Caravelle", "PSC-IDE ", "PSC000", 0x8c36137c, 0xd0693ab8, 0x2768a9f0), + PCMCIA_DEVICE_PROD_ID123("CDROM", "IDE", "MCD-601p", 0x1b9179ca, 0xede88951, 0x0d902f74), + PCMCIA_DEVICE_PROD_ID123("PCMCIA", "IDE CARD", "F1", 0x281f1c5d, 0x1907960c, 0xf7fde8b9), + PCMCIA_DEVICE_PROD_ID12("ARGOSY", "CD-ROM", 0x78f308dc, 0x66536591), + PCMCIA_DEVICE_PROD_ID12("ARGOSY", "PnPIDE", 0x78f308dc, 0x0c694728), + PCMCIA_DEVICE_PROD_ID12("CNF ", "CD-ROM", 0x46d7db81, 0x66536591), + PCMCIA_DEVICE_PROD_ID12("CNF CD-M", "CD-ROM", 0x7d93b852, 0x66536591), + PCMCIA_DEVICE_PROD_ID12("Creative Technology Ltd.", "PCMCIA CD-ROM Interface Card", 0xff8c8a45, 0xfe8020c4), + PCMCIA_DEVICE_PROD_ID12("Digital Equipment Corporation.", "Digital Mobile Media CD-ROM", 0x17692a66, 0xef1dcbde), + PCMCIA_DEVICE_PROD_ID12("EXP", "CD+GAME", 0x6f58c983, 0x63c13aaf), + PCMCIA_DEVICE_PROD_ID12("EXP ", "CD-ROM", 0x0a5c52fd, 0x66536591), + PCMCIA_DEVICE_PROD_ID12("EXP ", "PnPIDE", 0x0a5c52fd, 0x0c694728), + PCMCIA_DEVICE_PROD_ID12("FREECOM", "PCCARD-IDE", 0x5714cbf7, 0x48e0ab8e), + PCMCIA_DEVICE_PROD_ID12("HITACHI", "FLASH", 0xf4f43949, 0x9eb86aae), + PCMCIA_DEVICE_PROD_ID12("HITACHI", "microdrive", 0xf4f43949, 0xa6d76178), + PCMCIA_DEVICE_PROD_ID12("Hyperstone", "Model1", 0x3d5b9ef5, 0xca6ab420), + PCMCIA_DEVICE_PROD_ID12("IBM", "microdrive", 0xb569a6e5, 0xa6d76178), + PCMCIA_DEVICE_PROD_ID12("IBM", "IBM17JSSFP20", 0xb569a6e5, 0xf2508753), + PCMCIA_DEVICE_PROD_ID12("KINGSTON", "CF CARD 1GB", 0x2e6d1829, 0x55d5bffb), + PCMCIA_DEVICE_PROD_ID12("KINGSTON", "CF CARD 4GB", 0x2e6d1829, 0x531e7d10), + PCMCIA_DEVICE_PROD_ID12("KINGSTON", "CF8GB", 0x2e6d1829, 0xacbe682e), + PCMCIA_DEVICE_PROD_ID12("IO DATA", "CBIDE2 ", 0x547e66dc, 0x8671043b), + PCMCIA_DEVICE_PROD_ID12("IO DATA", "PCIDE", 0x547e66dc, 0x5c5ab149), + PCMCIA_DEVICE_PROD_ID12("IO DATA", "PCIDEII", 0x547e66dc, 0xb3662674), + PCMCIA_DEVICE_PROD_ID12("LOOKMEET", "CBIDE2 ", 0xe37be2b5, 0x8671043b), + PCMCIA_DEVICE_PROD_ID12("M-Systems", "CF300", 0x7ed2ad87, 0x7e9e78ee), + PCMCIA_DEVICE_PROD_ID12("M-Systems", "CF500", 0x7ed2ad87, 0x7a13045c), + PCMCIA_DEVICE_PROD_ID2("NinjaATA-", 0xebe0bd79), + PCMCIA_DEVICE_PROD_ID12("PCMCIA", "CD-ROM", 0x281f1c5d, 0x66536591), + PCMCIA_DEVICE_PROD_ID12("PCMCIA", "PnPIDE", 0x281f1c5d, 0x0c694728), + PCMCIA_DEVICE_PROD_ID12("SHUTTLE TECHNOLOGY LTD.", "PCCARD-IDE/ATAPI Adapter", 0x4a3f0ba0, 0x322560e1), + PCMCIA_DEVICE_PROD_ID12("SEAGATE", "ST1", 0x87c1b330, 0xe1f30883), + PCMCIA_DEVICE_PROD_ID12("SAMSUNG", "04/05/06", 0x43d74cb4, 0x6a22777d), + PCMCIA_DEVICE_PROD_ID12("SMI VENDOR", "SMI PRODUCT", 0x30896c92, 0x703cc5f6), + PCMCIA_DEVICE_PROD_ID12("TOSHIBA", "MK2001MPL", 0xb4585a1a, 0x3489e003), + PCMCIA_DEVICE_PROD_ID1("TRANSCEND 512M ", 0xd0909443), + PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS1GCF45", 0x709b1bf1, 0xf68b6f32), + PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS1GCF80", 0x709b1bf1, 0x2a54d4b1), + PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS2GCF120", 0x709b1bf1, 0x969aa4f2), + PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS4GCF120", 0x709b1bf1, 0xf54a91c8), + PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS4GCF133", 0x709b1bf1, 0x7558f133), + PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS8GCF133", 0x709b1bf1, 0xb2f89b47), + PCMCIA_DEVICE_PROD_ID12("WIT", "IDE16", 0x244e5994, 0x3e232852), + PCMCIA_DEVICE_PROD_ID12("WEIDA", "TWTTI", 0xcc7cf69c, 0x212bb918), + PCMCIA_DEVICE_PROD_ID1("STI Flash", 0xe4a13209), + PCMCIA_DEVICE_PROD_ID12("STI", "Flash 5.0", 0xbf2df18d, 0x8cb57a0e), + PCMCIA_MFC_DEVICE_PROD_ID12(1, "SanDisk", "ConnectPlus", 0x7a954bd9, 0x74be00c6), + PCMCIA_DEVICE_PROD_ID2("Flash Card", 0x5a362506), + PCMCIA_DEVICE_NULL, +}; +MODULE_DEVICE_TABLE(pcmcia, ide_ids); + +static struct pcmcia_driver ide_cs_driver = { + .owner = THIS_MODULE, + .name = "ide-cs", + .probe = ide_probe, + .remove = ide_detach, + .id_table = ide_ids, +}; + +static int __init init_ide_cs(void) +{ + return pcmcia_register_driver(&ide_cs_driver); +} + +static void __exit exit_ide_cs(void) +{ + pcmcia_unregister_driver(&ide_cs_driver); +} + +late_initcall(init_ide_cs); +module_exit(exit_ide_cs); diff --git a/drivers/ide/ide-devsets.c b/drivers/ide/ide-devsets.c new file mode 100644 index 00000000000..9e98122f646 --- /dev/null +++ b/drivers/ide/ide-devsets.c @@ -0,0 +1,191 @@ + +#include <linux/kernel.h> +#include <linux/gfp.h> +#include <linux/ide.h> + +DEFINE_MUTEX(ide_setting_mtx); + +ide_devset_get(io_32bit, io_32bit); + +static int set_io_32bit(ide_drive_t *drive, int arg) +{ + if (drive->dev_flags & IDE_DFLAG_NO_IO_32BIT) + return -EPERM; + + if (arg < 0 || arg > 1 + (SUPPORT_VLB_SYNC << 1)) + return -EINVAL; + + drive->io_32bit = arg; + + return 0; +} + +ide_devset_get_flag(ksettings, IDE_DFLAG_KEEP_SETTINGS); + +static int set_ksettings(ide_drive_t *drive, int arg) +{ + if (arg < 0 || arg > 1) + return -EINVAL; + + if (arg) + drive->dev_flags |= IDE_DFLAG_KEEP_SETTINGS; + else + drive->dev_flags &= ~IDE_DFLAG_KEEP_SETTINGS; + + return 0; +} + +ide_devset_get_flag(using_dma, IDE_DFLAG_USING_DMA); + +static int set_using_dma(ide_drive_t *drive, int arg) +{ +#ifdef CONFIG_BLK_DEV_IDEDMA + int err = -EPERM; + + if (arg < 0 || arg > 1) + return -EINVAL; + + if (ata_id_has_dma(drive->id) == 0) + goto out; + + if (drive->hwif->dma_ops == NULL) + goto out; + + err = 0; + + if (arg) { + if (ide_set_dma(drive)) + err = -EIO; + } else + ide_dma_off(drive); + +out: + return err; +#else + if (arg < 0 || arg > 1) + return -EINVAL; + + return -EPERM; +#endif +} + +/* + * handle HDIO_SET_PIO_MODE ioctl abusers here, eventually it will go away + */ +static int set_pio_mode_abuse(ide_hwif_t *hwif, u8 req_pio) +{ + switch (req_pio) { + case 202: + case 201: + case 200: + case 102: + case 101: + case 100: + return (hwif->host_flags & IDE_HFLAG_ABUSE_DMA_MODES) ? 1 : 0; + case 9: + case 8: + return (hwif->host_flags & IDE_HFLAG_ABUSE_PREFETCH) ? 1 : 0; + case 7: + case 6: + return (hwif->host_flags & IDE_HFLAG_ABUSE_FAST_DEVSEL) ? 1 : 0; + default: + return 0; + } +} + +static int set_pio_mode(ide_drive_t *drive, int arg) +{ + ide_hwif_t *hwif = drive->hwif; + const struct ide_port_ops *port_ops = hwif->port_ops; + + if (arg < 0 || arg > 255) + return -EINVAL; + + if (port_ops == NULL || port_ops->set_pio_mode == NULL || + (hwif->host_flags & IDE_HFLAG_NO_SET_MODE)) + return -ENOSYS; + + if (set_pio_mode_abuse(drive->hwif, arg)) { + drive->pio_mode = arg + XFER_PIO_0; + + if (arg == 8 || arg == 9) { + unsigned long flags; + + /* take lock for IDE_DFLAG_[NO_]UNMASK/[NO_]IO_32BIT */ + spin_lock_irqsave(&hwif->lock, flags); + port_ops->set_pio_mode(hwif, drive); + spin_unlock_irqrestore(&hwif->lock, flags); + } else + port_ops->set_pio_mode(hwif, drive); + } else { + int keep_dma = !!(drive->dev_flags & IDE_DFLAG_USING_DMA); + + ide_set_pio(drive, arg); + + if (hwif->host_flags & IDE_HFLAG_SET_PIO_MODE_KEEP_DMA) { + if (keep_dma) + ide_dma_on(drive); + } + } + + return 0; +} + +ide_devset_get_flag(unmaskirq, IDE_DFLAG_UNMASK); + +static int set_unmaskirq(ide_drive_t *drive, int arg) +{ + if (drive->dev_flags & IDE_DFLAG_NO_UNMASK) + return -EPERM; + + if (arg < 0 || arg > 1) + return -EINVAL; + + if (arg) + drive->dev_flags |= IDE_DFLAG_UNMASK; + else + drive->dev_flags &= ~IDE_DFLAG_UNMASK; + + return 0; +} + +ide_ext_devset_rw_sync(io_32bit, io_32bit); +ide_ext_devset_rw_sync(keepsettings, ksettings); +ide_ext_devset_rw_sync(unmaskirq, unmaskirq); +ide_ext_devset_rw_sync(using_dma, using_dma); +__IDE_DEVSET(pio_mode, DS_SYNC, NULL, set_pio_mode); + +int ide_devset_execute(ide_drive_t *drive, const struct ide_devset *setting, + int arg) +{ + struct request_queue *q = drive->queue; + struct request *rq; + int ret = 0; + + if (!(setting->flags & DS_SYNC)) + return setting->set(drive, arg); + + rq = blk_get_request(q, READ, __GFP_WAIT); + rq->cmd_type = REQ_TYPE_SPECIAL; + rq->cmd_len = 5; + rq->cmd[0] = REQ_DEVSET_EXEC; + *(int *)&rq->cmd[1] = arg; + rq->special = setting->set; + + if (blk_execute_rq(q, NULL, rq, 0)) + ret = rq->errors; + blk_put_request(rq); + + return ret; +} + +ide_startstop_t ide_do_devset(ide_drive_t *drive, struct request *rq) +{ + int err, (*setfunc)(ide_drive_t *, int) = rq->special; + + err = setfunc(drive, *(int *)&rq->cmd[1]); + if (err) + rq->errors = err; + ide_complete_rq(drive, err, blk_rq_bytes(rq)); + return ide_stopped; +} diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c index 7cf3eb02352..ee880382e3b 100644 --- a/drivers/ide/ide-disk.c +++ b/drivers/ide/ide-disk.c @@ -1,10 +1,9 @@ /* - * 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> + * Copyright (C) 1994-1998 Linus Torvalds & authors (see below) + * Copyright (C) 1998-2002 Linux ATA Development + * Andre Hedrick <andre@linux-ide.org> + * Copyright (C) 2003 Red Hat + * Copyright (C) 2003-2005, 2007 Bartlomiej Zolnierkiewicz */ /* @@ -13,41 +12,8 @@ * 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 standby, 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/module.h> #include <linux/types.h> #include <linux/string.h> #include <linux/kernel.h> @@ -61,9 +27,6 @@ #include <linux/delay.h> #include <linux/mutex.h> #include <linux/leds.h> - -#define _IDE_DISK - #include <linux/ide.h> #include <asm/byteorder.h> @@ -72,231 +35,141 @@ #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; +#include "ide-disk.h" + +static const u8 ide_rw_cmds[] = { + ATA_CMD_READ_MULTI, + ATA_CMD_WRITE_MULTI, + ATA_CMD_READ_MULTI_EXT, + ATA_CMD_WRITE_MULTI_EXT, + ATA_CMD_PIO_READ, + ATA_CMD_PIO_WRITE, + ATA_CMD_PIO_READ_EXT, + ATA_CMD_PIO_WRITE_EXT, + ATA_CMD_READ, + ATA_CMD_WRITE, + ATA_CMD_READ_EXT, + ATA_CMD_WRITE_EXT, }; -static DEFINE_MUTEX(idedisk_ref_mutex); - -#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; - - mutex_lock(&idedisk_ref_mutex); - idkp = ide_disk_g(disk); - if (idkp) - kref_get(&idkp->kref); - mutex_unlock(&idedisk_ref_mutex); - return idkp; -} - -static void ide_disk_release(struct kref *); - -static void ide_disk_put(struct ide_disk_obj *idkp) -{ - mutex_lock(&idedisk_ref_mutex); - kref_put(&idkp->kref, ide_disk_release); - mutex_unlock(&idedisk_ref_mutex); -} - -/* - * 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) +static void ide_tf_set_cmd(ide_drive_t *drive, struct ide_cmd *cmd, u8 dma) { - unsigned long lba_sects, chs_sects, head, tail; + u8 index, lba48, write; - /* No non-LBA info .. so valid! */ - if (id->cyls == 0) - return 1; + lba48 = (cmd->tf_flags & IDE_TFLAG_LBA48) ? 2 : 0; + write = (cmd->tf_flags & IDE_TFLAG_WRITE) ? 1 : 0; - /* - * 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 */ + if (dma) { + cmd->protocol = ATA_PROT_DMA; + index = 8; + } else { + cmd->protocol = ATA_PROT_PIO; + if (drive->mult_count) { + cmd->tf_flags |= IDE_TFLAG_MULTI_PIO; + index = 0; + } else + index = 4; } - return 0; /* lba_capacity value may be bad */ + cmd->tf.command = ide_rw_cmds[index + lba48 + write]; } /* * __ide_do_rw_disk() issues READ and WRITE commands to a disk, * using LBA if supported, or CHS otherwise, to address sectors. */ -static ide_startstop_t __ide_do_rw_disk(ide_drive_t *drive, struct request *rq, sector_t block) -{ - ide_hwif_t *hwif = HWIF(drive); - 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) +static ide_startstop_t __ide_do_rw_disk(ide_drive_t *drive, struct request *rq, + sector_t block) +{ + ide_hwif_t *hwif = drive->hwif; + u16 nsectors = (u16)blk_rq_sectors(rq); + u8 lba48 = !!(drive->dev_flags & IDE_DFLAG_LBA48); + u8 dma = !!(drive->dev_flags & IDE_DFLAG_USING_DMA); + struct ide_cmd cmd; + struct ide_taskfile *tf = &cmd.tf; + ide_startstop_t rc; + + if ((hwif->host_flags & IDE_HFLAG_NO_LBA48_DMA) && lba48 && dma) { + if (block + blk_rq_sectors(rq) > 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); + memset(&cmd, 0, sizeof(cmd)); + cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE; + cmd.valid.in.tf = IDE_VALID_IN_TF | IDE_VALID_DEVICE; - /* FIXME: SELECT_MASK(drive, 0) ? */ - - if (drive->select.b.lba) { + if (drive->dev_flags & IDE_DFLAG_LBA) { if (lba48) { - task_ioreg_t tasklets[10]; - pr_debug("%s: LBA=0x%012llx\n", drive->name, (unsigned long long)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); + tf->nsect = nsectors & 0xff; + tf->lbal = (u8) block; + tf->lbam = (u8)(block >> 8); + tf->lbah = (u8)(block >> 16); + tf->device = ATA_LBA; + + tf = &cmd.hob; + tf->nsect = (nsectors >> 8) & 0xff; + tf->lbal = (u8)(block >> 24); + if (sizeof(block) != 4) { + tf->lbam = (u8)((u64)block >> 32); + tf->lbah = (u8)((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); + + cmd.valid.out.hob = IDE_VALID_OUT_HOB; + cmd.valid.in.hob = IDE_VALID_IN_HOB; + cmd.tf_flags |= IDE_TFLAG_LBA48; } 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); + tf->nsect = nsectors & 0xff; + tf->lbal = block; + tf->lbam = block >>= 8; + tf->lbah = block >>= 8; + tf->device = ((block >> 8) & 0xf) | ATA_LBA; } } else { - unsigned int sect,head,cyl,track; + 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); + tf->nsect = nsectors & 0xff; + tf->lbal = sect; + tf->lbam = cyl; + tf->lbah = cyl >> 8; + tf->device = head; } - 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); - } + cmd.tf_flags |= IDE_TFLAG_FS; - if (rq_data_dir(rq) == READ) { + if (rq_data_dir(rq)) + cmd.tf_flags |= IDE_TFLAG_WRITE; - 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_tf_set_cmd(drive, &cmd, dma); + cmd.rq = rq; - 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; - } + if (dma == 0) { + ide_init_sg_cmd(&cmd, nsectors << 9); + ide_map_sg(drive, &cmd); + } - /* FIXME: ->OUTBSYNC ? */ - hwif->OUTB(command, IDE_COMMAND_REG); + rc = do_rw_taskfile(drive, &cmd); - return pre_task_out_intr(drive, rq); + if (rc == ide_stopped && dma) { + /* fallback to PIO */ + cmd.tf_flags |= IDE_TFLAG_DMA_PIO_FALLBACK; + ide_tf_set_cmd(drive, &cmd, 0); + ide_init_sg_cmd(&cmd, nsectors << 9); + rc = do_rw_taskfile(drive, &cmd); } + + return rc; } /* @@ -305,24 +178,19 @@ static ide_startstop_t __ide_do_rw_disk(ide_drive_t *drive, struct request *rq, * 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) +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); + ide_hwif_t *hwif = drive->hwif; - 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; - } + BUG_ON(drive->dev_flags & IDE_DFLAG_BLOCKED); + BUG_ON(rq->cmd_type != REQ_TYPE_FS); ledtrig_ide_activity(); - pr_debug("%s: %sing: block=%llu, sectors=%lu, buffer=0x%08lx\n", + pr_debug("%s: %sing: block=%llu, sectors=%u\n", drive->name, rq_data_dir(rq) == READ ? "read" : "writ", - (unsigned long long)block, rq->nr_sectors, - (unsigned long)rq->buffer); + (unsigned long long)block, blk_rq_sectors(rq)); if (hwif->rw_disk) hwif->rw_disk(drive, rq); @@ -334,57 +202,33 @@ static ide_startstop_t ide_do_rw_disk (ide_drive_t *drive, struct request *rq, s * 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) +static u64 idedisk_read_native_max_address(ide_drive_t *drive, int lba48) { - 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); + struct ide_cmd cmd; + struct ide_taskfile *tf = &cmd.tf; + u64 addr = 0; - /* 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 */ + memset(&cmd, 0, sizeof(cmd)); + if (lba48) + tf->command = ATA_CMD_READ_NATIVE_MAX_EXT; + else + tf->command = ATA_CMD_READ_NATIVE_MAX; + tf->device = ATA_LBA; + + cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE; + cmd.valid.in.tf = IDE_VALID_IN_TF | IDE_VALID_DEVICE; + if (lba48) { + cmd.valid.out.hob = IDE_VALID_OUT_HOB; + cmd.valid.in.hob = IDE_VALID_IN_HOB; + cmd.tf_flags = IDE_TFLAG_LBA48; } - 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); + ide_no_data_taskfile(drive, &cmd); /* 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 */ - } + if (!(tf->status & ATA_ERR)) + addr = ide_get_lba_addr(&cmd, lba48) + 1; + return addr; } @@ -392,67 +236,43 @@ static unsigned long long idedisk_read_native_max_address_ext(ide_drive_t *drive * 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) +static u64 idedisk_set_max_address(ide_drive_t *drive, u64 addr_req, int lba48) { - ide_task_t args; - unsigned long addr_set = 0; - + struct ide_cmd cmd; + struct ide_taskfile *tf = &cmd.tf; + u64 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++; + + memset(&cmd, 0, sizeof(cmd)); + tf->lbal = (addr_req >> 0) & 0xff; + tf->lbam = (addr_req >>= 8) & 0xff; + tf->lbah = (addr_req >>= 8) & 0xff; + if (lba48) { + cmd.hob.lbal = (addr_req >>= 8) & 0xff; + cmd.hob.lbam = (addr_req >>= 8) & 0xff; + cmd.hob.lbah = (addr_req >>= 8) & 0xff; + tf->command = ATA_CMD_SET_MAX_EXT; + } else { + tf->device = (addr_req >>= 8) & 0x0f; + tf->command = ATA_CMD_SET_MAX; + } + tf->device |= ATA_LBA; + + cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE; + cmd.valid.in.tf = IDE_VALID_IN_TF | IDE_VALID_DEVICE; + if (lba48) { + cmd.valid.out.hob = IDE_VALID_OUT_HOB; + cmd.valid.in.hob = IDE_VALID_IN_HOB; + cmd.tf_flags = IDE_TFLAG_LBA48; } - 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; + ide_no_data_taskfile(drive, &cmd); - 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++; - } + if (!(tf->status & ATA_ERR)) + addr_set = ide_get_lba_addr(&cmd, lba48) + 1; + return addr_set; } @@ -464,38 +284,57 @@ static unsigned long long sectors_to_MB(unsigned long long 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. + * Some disks report total number of sectors instead of + * maximum sector address. We list them here. */ -static inline int idedisk_supports_hpa(const struct hd_driveid *id) +static const struct drive_list_entry hpa_list[] = { + { "ST340823A", NULL }, + { "ST320413A", NULL }, + { "ST310211A", NULL }, + { NULL, NULL } +}; + +static u64 ide_disk_hpa_get_native_capacity(ide_drive_t *drive, int lba48) { - return (id->command_set_1 & 0x0400) && (id->cfs_enable_1 & 0x0400); + u64 capacity, set_max; + + capacity = drive->capacity64; + set_max = idedisk_read_native_max_address(drive, lba48); + + if (ide_in_drive_list(drive->id, hpa_list)) { + /* + * Since we are inclusive wrt to firmware revisions do this + * extra check and apply the workaround only when needed. + */ + if (set_max == capacity + 1) + set_max--; + } + + return set_max; } -/* - * The same here. - */ -static inline int idedisk_supports_lba48(const struct hd_driveid *id) +static u64 ide_disk_hpa_set_capacity(ide_drive_t *drive, u64 set_max, int lba48) { - return (id->command_set_2 & 0x0400) && (id->cfs_enable_2 & 0x0400) - && id->lba_capacity_2; + set_max = idedisk_set_max_address(drive, set_max, lba48); + if (set_max) + drive->capacity64 = set_max; + + return set_max; } static void idedisk_check_hpa(ide_drive_t *drive) { - unsigned long long capacity, set_max; - int lba48 = idedisk_supports_lba48(drive->id); + u64 capacity, set_max; + int lba48 = ata_id_lba48_enabled(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); + set_max = ide_disk_hpa_get_native_capacity(drive, lba48); if (set_max <= capacity) return; + drive->probed_capacity = set_max; + 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", @@ -503,268 +342,189 @@ static void idedisk_check_hpa(ide_drive_t *drive) 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; + if ((drive->dev_flags & IDE_DFLAG_NOHPA) == 0) + return; + + set_max = ide_disk_hpa_set_capacity(drive, set_max, lba48); + if (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) +static int ide_disk_get_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); + u16 *id = drive->id; + int lba; - if (idedisk_supports_lba48(id)) { + if (ata_id_lba48_enabled(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)) { + lba = 1; + drive->capacity64 = ata_id_u64(id, ATA_ID_LBA_CAPACITY_2); + } else if (ata_id_has_lba(id) && ata_id_is_lba_capacity_ok(id)) { /* drive speaks 28-bit LBA */ - drive->select.b.lba = 1; - drive->capacity64 = id->lba_capacity; - if (hpa) - idedisk_check_hpa(drive); + lba = 1; + drive->capacity64 = ata_id_u32(id, ATA_ID_LBA_CAPACITY); } else { /* drive speaks boring old 28-bit CHS */ + lba = 0; drive->capacity64 = drive->cyl * drive->head * drive->sect; } -} -static sector_t idedisk_capacity (ide_drive_t *drive) -{ - return drive->capacity64 - drive->sect0; -} + drive->probed_capacity = drive->capacity64; -#ifdef CONFIG_PROC_FS + if (lba) { + drive->dev_flags |= IDE_DFLAG_LBA; -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; + /* + * If this device supports the Host Protected Area feature set, + * then we may need to change our opinion about its capacity. + */ + if (ata_id_hpa_enabled(id)) + idedisk_check_hpa(drive); } - 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; + /* limit drive capacity to 137GB if LBA48 cannot be used */ + if ((drive->dev_flags & IDE_DFLAG_LBA48) == 0 && + drive->capacity64 > 1ULL << 28) { + printk(KERN_WARNING "%s: cannot use LBA48 - full capacity " + "%llu sectors (%llu MB)\n", + drive->name, (unsigned long long)drive->capacity64, + sectors_to_MB(drive->capacity64)); + drive->probed_capacity = drive->capacity64 = 1ULL << 28; } - 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 + if ((drive->hwif->host_flags & IDE_HFLAG_NO_LBA48_DMA) && + (drive->dev_flags & IDE_DFLAG_LBA48)) { + if (drive->capacity64 > 1ULL << 28) { + printk(KERN_INFO "%s: cannot use LBA48 DMA - PIO mode" + " will be used for accessing sectors " + "> %u\n", drive->name, 1 << 28); + } else + drive->dev_flags &= ~IDE_DFLAG_LBA48; + } -#endif /* CONFIG_PROC_FS */ + return 0; +} -static void idedisk_prepare_flush(request_queue_t *q, struct request *rq) +static void ide_disk_unlock_native_capacity(ide_drive_t *drive) { - ide_drive_t *drive = q->queuedata; + u16 *id = drive->id; + int lba48 = ata_id_lba48_enabled(id); - 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; + if ((drive->dev_flags & IDE_DFLAG_LBA) == 0 || + ata_id_hpa_enabled(id) == 0) + return; + /* + * according to the spec the SET MAX ADDRESS command shall be + * immediately preceded by a READ NATIVE MAX ADDRESS command + */ + if (!ide_disk_hpa_get_native_capacity(drive, lba48)) + return; - rq->flags |= REQ_DRIVE_TASK; - rq->buffer = rq->cmd; + if (ide_disk_hpa_set_capacity(drive, drive->probed_capacity, lba48)) + drive->dev_flags |= IDE_DFLAG_NOHPA; /* disable HPA on resume */ } -static int idedisk_issue_flush(request_queue_t *q, struct gendisk *disk, - sector_t *error_sector) +static int idedisk_prep_fn(struct request_queue *q, struct request *rq) { ide_drive_t *drive = q->queuedata; - struct request *rq; - int ret; + struct ide_cmd *cmd; - if (!drive->wcache) - return 0; + if (!(rq->cmd_flags & REQ_FLUSH)) + return BLKPREP_OK; - rq = blk_get_request(q, WRITE, __GFP_WAIT); + if (rq->special) { + cmd = rq->special; + memset(cmd, 0, sizeof(*cmd)); + } else { + cmd = kzalloc(sizeof(*cmd), GFP_ATOMIC); + } - idedisk_prepare_flush(q, rq); + /* FIXME: map struct ide_taskfile on rq->cmd[] */ + BUG_ON(cmd == NULL); - ret = blk_execute_rq(q, disk, rq, 0); + if (ata_id_flush_ext_enabled(drive->id) && + (drive->capacity64 >= (1UL << 28))) + cmd->tf.command = ATA_CMD_FLUSH_EXT; + else + cmd->tf.command = ATA_CMD_FLUSH; + cmd->valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE; + cmd->tf_flags = IDE_TFLAG_DYN; + cmd->protocol = ATA_PROT_NODATA; - /* - * if we failed and caller wants error offset, get it - */ - if (ret && error_sector) - *error_sector = ide_get_error_location(drive, rq->cmd); + rq->cmd_type = REQ_TYPE_ATA_TASKFILE; + rq->special = cmd; + cmd->rq = rq; - blk_put_request(rq); - return ret; + return BLKPREP_OK; } +ide_devset_get(multcount, mult_count); + /* * This is tightly woven into the driver->do_special can not touch. * DON'T do it again until a total personality rewrite is committed. */ static int set_multcount(ide_drive_t *drive, int arg) { - struct request rq; + struct request *rq; + int error; - if (drive->special.b.set_multmode) + if (arg < 0 || arg > (drive->id[ATA_ID_MAX_MULTSECT] & 0xff)) + return -EINVAL; + + if (drive->special_flags & IDE_SFLAG_SET_MULTMODE) return -EBUSY; - ide_init_drive_cmd (&rq); - rq.flags = REQ_DRIVE_CMD; + + rq = blk_get_request(drive->queue, READ, __GFP_WAIT); + rq->cmd_type = REQ_TYPE_ATA_TASKFILE; + drive->mult_req = arg; - drive->special.b.set_multmode = 1; - (void) ide_do_drive_cmd (drive, &rq, ide_wait); + drive->special_flags |= IDE_SFLAG_SET_MULTMODE; + error = blk_execute_rq(drive->queue, NULL, rq, 0); + blk_put_request(rq); + return (drive->mult_count == arg) ? 0 : -EIO; } +ide_devset_get_flag(nowerr, IDE_DFLAG_NOWERR); + static int set_nowerr(ide_drive_t *drive, int arg) { - if (ide_spin_wait_hwgroup(drive)) - return -EBUSY; - drive->nowerr = arg; + if (arg < 0 || arg > 1) + return -EINVAL; + + if (arg) + drive->dev_flags |= IDE_DFLAG_NOWERR; + else + drive->dev_flags &= ~IDE_DFLAG_NOWERR; + drive->bad_wstat = arg ? BAD_R_STAT : BAD_W_STAT; - spin_unlock_irq(&ide_lock); + return 0; } -static void update_ordered(ide_drive_t *drive) +static int ide_do_setfeature(ide_drive_t *drive, u8 feature, u8 nsect) { - struct hd_driveid *id = drive->id; - unsigned ordered = QUEUE_ORDERED_NONE; - prepare_flush_fn *prep_fn = NULL; - issue_flush_fn *issue_fn = NULL; + struct ide_cmd cmd; - if (drive->wcache) { + memset(&cmd, 0, sizeof(cmd)); + cmd.tf.feature = feature; + cmd.tf.nsect = nsect; + cmd.tf.command = ATA_CMD_SET_FEATURES; + cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE; + cmd.valid.in.tf = IDE_VALID_IN_TF | IDE_VALID_DEVICE; + + return ide_no_data_taskfile(drive, &cmd); +} + +static void update_flush(ide_drive_t *drive) +{ + u16 *id = drive->id; + unsigned flush = 0; + + if (drive->dev_flags & IDE_DFLAG_WCACHE) { unsigned long long capacity; int barrier; /* @@ -775,177 +535,170 @@ static void update_ordered(ide_drive_t *drive) * time we have trimmed the drive capacity if LBA48 is * not available so we don't need to recheck that. */ - capacity = idedisk_capacity(drive); - barrier = ide_id_has_flush_cache(id) && !drive->noflush && - (drive->addressing == 0 || capacity <= (1ULL << 28) || - ide_id_has_flush_cache_ext(id)); + capacity = ide_gd_capacity(drive); + barrier = ata_id_flush_enabled(id) && + (drive->dev_flags & IDE_DFLAG_NOFLUSH) == 0 && + ((drive->dev_flags & IDE_DFLAG_LBA48) == 0 || + capacity <= (1ULL << 28) || + ata_id_flush_ext_enabled(id)); printk(KERN_INFO "%s: cache flushes %ssupported\n", drive->name, barrier ? "" : "not "); if (barrier) { - ordered = QUEUE_ORDERED_DRAIN_FLUSH; - prep_fn = idedisk_prepare_flush; - issue_fn = idedisk_issue_flush; + flush = REQ_FLUSH; + blk_queue_prep_rq(drive->queue, idedisk_prep_fn); } - } else - ordered = QUEUE_ORDERED_DRAIN; + } - blk_queue_ordered(drive->queue, ordered, prep_fn); - blk_queue_issue_flush_fn(drive->queue, issue_fn); + blk_queue_flush(drive->queue, flush); } -static int write_cache(ide_drive_t *drive, int arg) +ide_devset_get_flag(wcache, IDE_DFLAG_WCACHE); + +static int set_wcache(ide_drive_t *drive, int arg) { - ide_task_t args; int err = 1; - if (ide_id_has_flush_cache(drive->id)) { - 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 == 0) - drive->wcache = arg; + if (arg < 0 || arg > 1) + return -EINVAL; + + if (ata_id_flush_enabled(drive->id)) { + err = ide_do_setfeature(drive, + arg ? SETFEATURES_WC_ON : SETFEATURES_WC_OFF, 0); + if (err == 0) { + if (arg) + drive->dev_flags |= IDE_DFLAG_WCACHE; + else + drive->dev_flags &= ~IDE_DFLAG_WCACHE; + } } - update_ordered(drive); + update_flush(drive); return err; } -static int do_idedisk_flushcache (ide_drive_t *drive) +static int do_idedisk_flushcache(ide_drive_t *drive) { - ide_task_t args; + struct ide_cmd cmd; - 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; + memset(&cmd, 0, sizeof(cmd)); + if (ata_id_flush_ext_enabled(drive->id)) + cmd.tf.command = ATA_CMD_FLUSH_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); + cmd.tf.command = ATA_CMD_FLUSH; + cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE; + cmd.valid.in.tf = IDE_VALID_IN_TF | IDE_VALID_DEVICE; + + return ide_no_data_taskfile(drive, &cmd); } -static int set_acoustic (ide_drive_t *drive, int arg) +ide_devset_get(acoustic, acoustic); + +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); + if (arg < 0 || arg > 254) + return -EINVAL; + + ide_do_setfeature(drive, + arg ? SETFEATURES_AAM_ON : SETFEATURES_AAM_OFF, arg); + drive->acoustic = arg; + return 0; } +ide_devset_get_flag(addressing, IDE_DFLAG_LBA48); + /* * drive->addressing: * 0: 28-bit * 1: 48-bit * 2: 48-bit capable doing 28-bit */ -static int set_lba_addressing(ide_drive_t *drive, int arg) +static int set_addressing(ide_drive_t *drive, int arg) { - drive->addressing = 0; + if (arg < 0 || arg > 2) + return -EINVAL; - if (HWIF(drive)->no_lba48) - return 0; + if (arg && ((drive->hwif->host_flags & IDE_HFLAG_NO_LBA48) || + ata_id_lba48_enabled(drive->id) == 0)) + return -EIO; + + if (arg == 2) + arg = 0; + + if (arg) + drive->dev_flags |= IDE_DFLAG_LBA48; + else + drive->dev_flags &= ~IDE_DFLAG_LBA48; - if (!idedisk_supports_lba48(drive->id)) - return -EIO; - drive->addressing = arg; return 0; } -static void idedisk_add_settings(ide_drive_t *drive) +ide_ext_devset_rw(acoustic, acoustic); +ide_ext_devset_rw(address, addressing); +ide_ext_devset_rw(multcount, multcount); +ide_ext_devset_rw(wcache, wcache); + +ide_ext_devset_rw_sync(nowerr, nowerr); + +static int ide_disk_check(ide_drive_t *drive, const char *s) { - 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); + return 1; } -static void idedisk_setup (ide_drive_t *drive) +static void ide_disk_setup(ide_drive_t *drive) { - struct hd_driveid *id = drive->id; + struct ide_disk_obj *idkp = drive->driver_data; + struct request_queue *q = drive->queue; + ide_hwif_t *hwif = drive->hwif; + u16 *id = drive->id; + char *m = (char *)&id[ATA_ID_PROD]; unsigned long long capacity; - idedisk_add_settings(drive); + ide_proc_register_driver(drive, idkp->driver); - if (drive->id_read == 0) + if ((drive->dev_flags & IDE_DFLAG_ID_READ) == 0) return; - if (drive->removable) { + if (drive->dev_flags & IDE_DFLAG_REMOVABLE) { /* - * Removable disks (eg. SYQUEST); ignore 'WD' drives + * Removable disks (eg. SYQUEST); ignore 'WD' drives */ - if (id->model[0] != 'W' || id->model[1] != 'D') { - drive->doorlocking = 1; - } + if (m[0] != 'W' || m[1] != 'D') + drive->dev_flags |= IDE_DFLAG_DOORLOCKING; } - (void)set_lba_addressing(drive, 1); + (void)set_addressing(drive, 1); - if (drive->addressing == 1) { - ide_hwif_t *hwif = HWIF(drive); + if (drive->dev_flags & IDE_DFLAG_LBA48) { int max_s = 2048; if (max_s > hwif->rqsize) max_s = hwif->rqsize; - blk_queue_max_sectors(drive->queue, max_s); + blk_queue_max_hw_sectors(q, max_s); } - printk(KERN_INFO "%s: max request size: %dKiB\n", drive->name, drive->queue->max_sectors / 2); + printk(KERN_INFO "%s: max request size: %dKiB\n", drive->name, + queue_max_sectors(q) / 2); - /* calculate drive capacity, and select LBA if possible */ - init_idedisk_capacity (drive); + if (ata_id_is_ssd(id)) + queue_flag_set_unlocked(QUEUE_FLAG_NONROT, q); - /* 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; - } + /* calculate drive capacity, and select LBA if possible */ + ide_disk_get_capacity(drive); /* * if possible, give fdisk access to more of the drive, * by correcting bios_cyls: */ - capacity = idedisk_capacity (drive); - if (!drive->forced_geom) { + capacity = ide_gd_capacity(drive); - if (idedisk_supports_lba48(drive->id)) { + if ((drive->dev_flags & IDE_DFLAG_FORCED_GEOM) == 0) { + if (ata_id_lba48_enabled(drive->id)) { /* compatibility */ drive->bios_sect = 63; drive->bios_head = 255; @@ -971,279 +724,72 @@ static void idedisk_setup (ide_drive_t *drive) 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); + if (id[ATA_ID_BUF_SIZE]) + printk(KERN_CONT " w/%dKiB Cache", id[ATA_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"); + printk(KERN_CONT ", CHS=%d/%d/%d\n", + drive->bios_cyl, drive->bios_head, drive->bios_sect); /* write cache enabled? */ - if ((id->csfo & 1) || (id->cfs_enable_1 & (1 << 5))) - drive->wcache = 1; + if ((id[ATA_ID_CSFO] & 1) || ata_id_wcache_enabled(id)) + drive->dev_flags |= IDE_DFLAG_WCACHE; - write_cache(drive, 1); + set_wcache(drive, 1); + + if ((drive->dev_flags & IDE_DFLAG_LBA) == 0 && + (drive->head == 0 || drive->head > 16)) { + printk(KERN_ERR "%s: invalid geometry: %d physical heads?\n", + drive->name, drive->head); + drive->dev_flags &= ~IDE_DFLAG_ATTACH; + } else + drive->dev_flags |= IDE_DFLAG_ATTACH; } -static void ide_cacheflush_p(ide_drive_t *drive) +static void ide_disk_flush(ide_drive_t *drive) { - if (!drive->wcache || !ide_id_has_flush_cache(drive->id)) + if (ata_id_flush_enabled(drive->id) == 0 || + (drive->dev_flags & IDE_DFLAG_WCACHE) == 0) return; if (do_idedisk_flushcache(drive)) printk(KERN_INFO "%s: wcache flush failed!\n", drive->name); } -static void ide_disk_remove(ide_drive_t *drive) -{ - struct ide_disk_obj *idkp = drive->driver_data; - struct gendisk *g = idkp->disk; - - ide_unregister_subdriver(drive, idkp->driver); - - del_gendisk(g); - - ide_cacheflush_p(drive); - - ide_disk_put(idkp); -} - -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; - g->private_data = NULL; - put_disk(g); - kfree(idkp); -} - -static int ide_disk_probe(ide_drive_t *drive); - -static void ide_device_shutdown(ide_drive_t *drive) -{ -#ifdef CONFIG_ALPHA - /* On Alpha, halt(8) doesn't actually turn the machine off, - it puts you into the sort of firmware monitor. Typically, - it's used to boot another kernel image, so it's not much - different from reboot(8). Therefore, we don't need to - spin down the disk in this case, especially since Alpha - firmware doesn't handle disks in standby mode properly. - On the other hand, it's reasonably safe to turn the power - off when the shutdown process reaches the firmware prompt, - as the firmware initialization takes rather long time - - at least 10 seconds, which should be sufficient for - the disk to expire its write cache. */ - if (system_state != SYSTEM_POWER_OFF) { -#else - if (system_state == SYSTEM_RESTART) { -#endif - ide_cacheflush_p(drive); - return; - } - - printk("Shutdown: %s\n", drive->name); - drive->gendev.bus->suspend(&drive->gendev, PMSG_SUSPEND); -} - -static ide_driver_t idedisk_driver = { - .gen_driver = { - .owner = THIS_MODULE, - .name = "ide-disk", - .bus = &ide_bus_type, - }, - .probe = ide_disk_probe, - .remove = ide_disk_remove, - .shutdown = ide_device_shutdown, - .version = IDEDISK_VERSION, - .media = ide_disk, - .supports_dsc_overlap = 0, - .do_request = ide_do_rw_disk, - .end_request = ide_end_request, - .error = __ide_error, - .abort = __ide_abort, - .proc = idedisk_proc, -}; - -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) +static int ide_disk_init_media(ide_drive_t *drive, struct gendisk *disk) { - 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_getgeo(struct block_device *bdev, struct hd_geometry *geo) +static int ide_disk_set_doorlock(ide_drive_t *drive, struct gendisk *disk, + int on) { - struct ide_disk_obj *idkp = ide_disk_g(bdev->bd_disk); - ide_drive_t *drive = idkp->drive; - - geo->heads = drive->bios_head; - geo->sectors = drive->bios_sect; - geo->cylinders = (u16)drive->bios_cyl; /* truncate */ - return 0; -} - -static int 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; + struct ide_cmd cmd; + int ret; - /* do not scan partitions twice if this is a removable device */ - if (drive->attach) { - drive->attach = 0; + if ((drive->dev_flags & IDE_DFLAG_DOORLOCKING) == 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, - .getgeo = idedisk_getgeo, - .media_changed = idedisk_media_changed, - .revalidate_disk= idedisk_revalidate_disk -}; - -MODULE_DESCRIPTION("ATA DISK Driver"); - -static int ide_disk_probe(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 = kzalloc(sizeof(*idkp), GFP_KERNEL); - if (!idkp) - goto failed; - g = alloc_disk_node(1 << PARTN_BITS, - hwif_to_node(drive->hwif)); - if (!g) - goto out_free_idkp; + memset(&cmd, 0, sizeof(cmd)); + cmd.tf.command = on ? ATA_CMD_MEDIA_LOCK : ATA_CMD_MEDIA_UNLOCK; + cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE; + cmd.valid.in.tf = IDE_VALID_IN_TF | IDE_VALID_DEVICE; - ide_init_disk(g, drive); + ret = ide_no_data_taskfile(drive, &cmd); - ide_register_subdriver(drive, &idedisk_driver); + if (ret) + drive->dev_flags &= ~IDE_DFLAG_DOORLOCKING; - kref_init(&idkp->kref); - - idkp->drive = drive; - idkp->driver = &idedisk_driver; - idkp->disk = g; - - g->private_data = &idkp->driver; - - drive->driver_data = idkp; - - 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; - - g->minors = 1 << PARTN_BITS; - 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_free_idkp: - kfree(idkp); -failed: - return -ENODEV; -} - -static void __exit idedisk_exit (void) -{ - driver_unregister(&idedisk_driver.gen_driver); -} - -static int __init idedisk_init(void) -{ - return driver_register(&idedisk_driver.gen_driver); + return ret; } -MODULE_ALIAS("ide:*m-disk*"); -module_init(idedisk_init); -module_exit(idedisk_exit); -MODULE_LICENSE("GPL"); +const struct ide_disk_ops ide_ata_disk_ops = { + .check = ide_disk_check, + .unlock_native_capacity = ide_disk_unlock_native_capacity, + .get_capacity = ide_disk_get_capacity, + .setup = ide_disk_setup, + .flush = ide_disk_flush, + .init_media = ide_disk_init_media, + .set_doorlock = ide_disk_set_doorlock, + .do_request = ide_do_rw_disk, + .ioctl = ide_disk_ioctl, +}; diff --git a/drivers/ide/ide-disk.h b/drivers/ide/ide-disk.h new file mode 100644 index 00000000000..d511dab7c4a --- /dev/null +++ b/drivers/ide/ide-disk.h @@ -0,0 +1,29 @@ +#ifndef __IDE_DISK_H +#define __IDE_DISK_H + +#include "ide-gd.h" + +#ifdef CONFIG_IDE_GD_ATA +/* ide-disk.c */ +extern const struct ide_disk_ops ide_ata_disk_ops; +ide_decl_devset(address); +ide_decl_devset(multcount); +ide_decl_devset(nowerr); +ide_decl_devset(wcache); +ide_decl_devset(acoustic); + +/* ide-disk_ioctl.c */ +int ide_disk_ioctl(ide_drive_t *, struct block_device *, fmode_t, unsigned int, + unsigned long); + +#ifdef CONFIG_IDE_PROC_FS +/* ide-disk_proc.c */ +extern ide_proc_entry_t ide_disk_proc[]; +extern const struct ide_proc_devset ide_disk_settings[]; +#endif +#else +#define ide_disk_proc NULL +#define ide_disk_settings NULL +#endif + +#endif /* __IDE_DISK_H */ diff --git a/drivers/ide/ide-disk_ioctl.c b/drivers/ide/ide-disk_ioctl.c new file mode 100644 index 00000000000..da36f729ff3 --- /dev/null +++ b/drivers/ide/ide-disk_ioctl.c @@ -0,0 +1,32 @@ +#include <linux/kernel.h> +#include <linux/ide.h> +#include <linux/hdreg.h> +#include <linux/mutex.h> + +#include "ide-disk.h" + +static DEFINE_MUTEX(ide_disk_ioctl_mutex); +static const struct ide_ioctl_devset ide_disk_ioctl_settings[] = { +{ HDIO_GET_ADDRESS, HDIO_SET_ADDRESS, &ide_devset_address }, +{ HDIO_GET_MULTCOUNT, HDIO_SET_MULTCOUNT, &ide_devset_multcount }, +{ HDIO_GET_NOWERR, HDIO_SET_NOWERR, &ide_devset_nowerr }, +{ HDIO_GET_WCACHE, HDIO_SET_WCACHE, &ide_devset_wcache }, +{ HDIO_GET_ACOUSTIC, HDIO_SET_ACOUSTIC, &ide_devset_acoustic }, +{ 0 } +}; + +int ide_disk_ioctl(ide_drive_t *drive, struct block_device *bdev, fmode_t mode, + unsigned int cmd, unsigned long arg) +{ + int err; + + mutex_lock(&ide_disk_ioctl_mutex); + err = ide_setting_ioctl(drive, bdev, cmd, arg, ide_disk_ioctl_settings); + if (err != -EOPNOTSUPP) + goto out; + + err = generic_ide_ioctl(drive, bdev, cmd, arg); +out: + mutex_unlock(&ide_disk_ioctl_mutex); + return err; +} diff --git a/drivers/ide/ide-disk_proc.c b/drivers/ide/ide-disk_proc.c new file mode 100644 index 00000000000..0d1fae6cba6 --- /dev/null +++ b/drivers/ide/ide-disk_proc.c @@ -0,0 +1,176 @@ +#include <linux/kernel.h> +#include <linux/ide.h> +#include <linux/slab.h> +#include <linux/export.h> +#include <linux/seq_file.h> + +#include "ide-disk.h" + +static int smart_enable(ide_drive_t *drive) +{ + struct ide_cmd cmd; + struct ide_taskfile *tf = &cmd.tf; + + memset(&cmd, 0, sizeof(cmd)); + tf->feature = ATA_SMART_ENABLE; + tf->lbam = ATA_SMART_LBAM_PASS; + tf->lbah = ATA_SMART_LBAH_PASS; + tf->command = ATA_CMD_SMART; + cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE; + cmd.valid.in.tf = IDE_VALID_IN_TF | IDE_VALID_DEVICE; + + return ide_no_data_taskfile(drive, &cmd); +} + +static int get_smart_data(ide_drive_t *drive, u8 *buf, u8 sub_cmd) +{ + struct ide_cmd cmd; + struct ide_taskfile *tf = &cmd.tf; + + memset(&cmd, 0, sizeof(cmd)); + tf->feature = sub_cmd; + tf->nsect = 0x01; + tf->lbam = ATA_SMART_LBAM_PASS; + tf->lbah = ATA_SMART_LBAH_PASS; + tf->command = ATA_CMD_SMART; + cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE; + cmd.valid.in.tf = IDE_VALID_IN_TF | IDE_VALID_DEVICE; + cmd.protocol = ATA_PROT_PIO; + + return ide_raw_taskfile(drive, &cmd, buf, 1); +} + +static int idedisk_cache_proc_show(struct seq_file *m, void *v) +{ + ide_drive_t *drive = (ide_drive_t *) m->private; + + if (drive->dev_flags & IDE_DFLAG_ID_READ) + seq_printf(m, "%i\n", drive->id[ATA_ID_BUF_SIZE] / 2); + else + seq_printf(m, "(none)\n"); + return 0; +} + +static int idedisk_cache_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, idedisk_cache_proc_show, PDE_DATA(inode)); +} + +static const struct file_operations idedisk_cache_proc_fops = { + .owner = THIS_MODULE, + .open = idedisk_cache_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int idedisk_capacity_proc_show(struct seq_file *m, void *v) +{ + ide_drive_t*drive = (ide_drive_t *)m->private; + + seq_printf(m, "%llu\n", (long long)ide_gd_capacity(drive)); + return 0; +} + +static int idedisk_capacity_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, idedisk_capacity_proc_show, PDE_DATA(inode)); +} + +static const struct file_operations idedisk_capacity_proc_fops = { + .owner = THIS_MODULE, + .open = idedisk_capacity_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int __idedisk_proc_show(struct seq_file *m, ide_drive_t *drive, u8 sub_cmd) +{ + u8 *buf; + + buf = kmalloc(SECTOR_SIZE, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + (void)smart_enable(drive); + + if (get_smart_data(drive, buf, sub_cmd) == 0) { + __le16 *val = (__le16 *)buf; + int i; + + for (i = 0; i < SECTOR_SIZE / 2; i++) { + seq_printf(m, "%04x%c", le16_to_cpu(val[i]), + (i % 8) == 7 ? '\n' : ' '); + } + } + kfree(buf); + return 0; +} + +static int idedisk_sv_proc_show(struct seq_file *m, void *v) +{ + return __idedisk_proc_show(m, m->private, ATA_SMART_READ_VALUES); +} + +static int idedisk_sv_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, idedisk_sv_proc_show, PDE_DATA(inode)); +} + +static const struct file_operations idedisk_sv_proc_fops = { + .owner = THIS_MODULE, + .open = idedisk_sv_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int idedisk_st_proc_show(struct seq_file *m, void *v) +{ + return __idedisk_proc_show(m, m->private, ATA_SMART_READ_THRESHOLDS); +} + +static int idedisk_st_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, idedisk_st_proc_show, PDE_DATA(inode)); +} + +static const struct file_operations idedisk_st_proc_fops = { + .owner = THIS_MODULE, + .open = idedisk_st_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +ide_proc_entry_t ide_disk_proc[] = { + { "cache", S_IFREG|S_IRUGO, &idedisk_cache_proc_fops }, + { "capacity", S_IFREG|S_IRUGO, &idedisk_capacity_proc_fops }, + { "geometry", S_IFREG|S_IRUGO, &ide_geometry_proc_fops }, + { "smart_values", S_IFREG|S_IRUSR, &idedisk_sv_proc_fops }, + { "smart_thresholds", S_IFREG|S_IRUSR, &idedisk_st_proc_fops }, + {} +}; + +ide_devset_rw_field(bios_cyl, bios_cyl); +ide_devset_rw_field(bios_head, bios_head); +ide_devset_rw_field(bios_sect, bios_sect); +ide_devset_rw_field(failures, failures); +ide_devset_rw_field(lun, lun); +ide_devset_rw_field(max_failures, max_failures); + +const struct ide_proc_devset ide_disk_settings[] = { + IDE_PROC_DEVSET(acoustic, 0, 254), + IDE_PROC_DEVSET(address, 0, 2), + IDE_PROC_DEVSET(bios_cyl, 0, 65535), + IDE_PROC_DEVSET(bios_head, 0, 255), + IDE_PROC_DEVSET(bios_sect, 0, 63), + IDE_PROC_DEVSET(failures, 0, 65535), + IDE_PROC_DEVSET(lun, 0, 7), + IDE_PROC_DEVSET(max_failures, 0, 65535), + IDE_PROC_DEVSET(multcount, 0, 16), + IDE_PROC_DEVSET(nowerr, 0, 1), + IDE_PROC_DEVSET(wcache, 0, 1), + { NULL }, +}; diff --git a/drivers/ide/ide-dma-sff.c b/drivers/ide/ide-dma-sff.c new file mode 100644 index 00000000000..289d16c87b8 --- /dev/null +++ b/drivers/ide/ide-dma-sff.c @@ -0,0 +1,335 @@ +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/export.h> +#include <linux/ide.h> +#include <linux/scatterlist.h> +#include <linux/dma-mapping.h> +#include <linux/io.h> + +/** + * config_drive_for_dma - attempt to activate IDE DMA + * @drive: the drive to place in DMA mode + * + * If the drive supports at least mode 2 DMA or UDMA of any kind + * then attempt to place it into DMA mode. Drives that are known to + * support DMA but predate the DMA properties or that are known + * to have DMA handling bugs are also set up appropriately based + * on the good/bad drive lists. + */ + +int config_drive_for_dma(ide_drive_t *drive) +{ + ide_hwif_t *hwif = drive->hwif; + u16 *id = drive->id; + + if (drive->media != ide_disk) { + if (hwif->host_flags & IDE_HFLAG_NO_ATAPI_DMA) + return 0; + } + + /* + * Enable DMA on any drive that has + * UltraDMA (mode 0/1/2/3/4/5/6) enabled + */ + if ((id[ATA_ID_FIELD_VALID] & 4) && + ((id[ATA_ID_UDMA_MODES] >> 8) & 0x7f)) + return 1; + + /* + * Enable DMA on any drive that has mode2 DMA + * (multi or single) enabled + */ + if ((id[ATA_ID_MWDMA_MODES] & 0x404) == 0x404 || + (id[ATA_ID_SWDMA_MODES] & 0x404) == 0x404) + return 1; + + /* Consult the list of known "good" drives */ + if (ide_dma_good_drive(drive)) + return 1; + + return 0; +} + +u8 ide_dma_sff_read_status(ide_hwif_t *hwif) +{ + unsigned long addr = hwif->dma_base + ATA_DMA_STATUS; + + if (hwif->host_flags & IDE_HFLAG_MMIO) + return readb((void __iomem *)addr); + else + return inb(addr); +} +EXPORT_SYMBOL_GPL(ide_dma_sff_read_status); + +static void ide_dma_sff_write_status(ide_hwif_t *hwif, u8 val) +{ + unsigned long addr = hwif->dma_base + ATA_DMA_STATUS; + + if (hwif->host_flags & IDE_HFLAG_MMIO) + writeb(val, (void __iomem *)addr); + else + outb(val, addr); +} + +/** + * ide_dma_host_set - Enable/disable DMA on a host + * @drive: drive to control + * + * Enable/disable DMA on an IDE controller following generic + * bus-mastering IDE controller behaviour. + */ + +void ide_dma_host_set(ide_drive_t *drive, int on) +{ + ide_hwif_t *hwif = drive->hwif; + u8 unit = drive->dn & 1; + u8 dma_stat = hwif->dma_ops->dma_sff_read_status(hwif); + + if (on) + dma_stat |= (1 << (5 + unit)); + else + dma_stat &= ~(1 << (5 + unit)); + + ide_dma_sff_write_status(hwif, dma_stat); +} +EXPORT_SYMBOL_GPL(ide_dma_host_set); + +/** + * ide_build_dmatable - build IDE DMA table + * + * ide_build_dmatable() prepares a dma request. We map the command + * to get the pci bus addresses of the buffers and then build up + * the PRD table that the IDE layer wants to be fed. + * + * Most chipsets correctly interpret a length of 0x0000 as 64KB, + * but at least one (e.g. CS5530) misinterprets it as zero (!). + * So we break the 64KB entry into two 32KB entries instead. + * + * Returns the number of built PRD entries if all went okay, + * returns 0 otherwise. + * + * May also be invoked from trm290.c + */ + +int ide_build_dmatable(ide_drive_t *drive, struct ide_cmd *cmd) +{ + ide_hwif_t *hwif = drive->hwif; + __le32 *table = (__le32 *)hwif->dmatable_cpu; + unsigned int count = 0; + int i; + struct scatterlist *sg; + u8 is_trm290 = !!(hwif->host_flags & IDE_HFLAG_TRM290); + + for_each_sg(hwif->sg_table, sg, cmd->sg_nents, i) { + u32 cur_addr, cur_len, xcount, bcount; + + cur_addr = sg_dma_address(sg); + cur_len = sg_dma_len(sg); + + /* + * Fill in the dma table, without crossing any 64kB boundaries. + * Most hardware requires 16-bit alignment of all blocks, + * but the trm290 requires 32-bit alignment. + */ + + while (cur_len) { + if (count++ >= PRD_ENTRIES) + goto use_pio_instead; + + bcount = 0x10000 - (cur_addr & 0xffff); + if (bcount > cur_len) + bcount = cur_len; + *table++ = cpu_to_le32(cur_addr); + xcount = bcount & 0xffff; + if (is_trm290) + xcount = ((xcount >> 2) - 1) << 16; + else if (xcount == 0x0000) { + if (count++ >= PRD_ENTRIES) + goto use_pio_instead; + *table++ = cpu_to_le32(0x8000); + *table++ = cpu_to_le32(cur_addr + 0x8000); + xcount = 0x8000; + } + *table++ = cpu_to_le32(xcount); + cur_addr += bcount; + cur_len -= bcount; + } + } + + if (count) { + if (!is_trm290) + *--table |= cpu_to_le32(0x80000000); + return count; + } + +use_pio_instead: + printk(KERN_ERR "%s: %s\n", drive->name, + count ? "DMA table too small" : "empty DMA table?"); + + return 0; /* revert to PIO for this request */ +} +EXPORT_SYMBOL_GPL(ide_build_dmatable); + +/** + * ide_dma_setup - begin a DMA phase + * @drive: target device + * @cmd: command + * + * 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, struct ide_cmd *cmd) +{ + ide_hwif_t *hwif = drive->hwif; + u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0; + u8 rw = (cmd->tf_flags & IDE_TFLAG_WRITE) ? 0 : ATA_DMA_WR; + u8 dma_stat; + + /* fall back to pio! */ + if (ide_build_dmatable(drive, cmd) == 0) { + ide_map_sg(drive, cmd); + return 1; + } + + /* PRD table */ + if (mmio) + writel(hwif->dmatable_dma, + (void __iomem *)(hwif->dma_base + ATA_DMA_TABLE_OFS)); + else + outl(hwif->dmatable_dma, hwif->dma_base + ATA_DMA_TABLE_OFS); + + /* specify r/w */ + if (mmio) + writeb(rw, (void __iomem *)(hwif->dma_base + ATA_DMA_CMD)); + else + outb(rw, hwif->dma_base + ATA_DMA_CMD); + + /* read DMA status for INTR & ERROR flags */ + dma_stat = hwif->dma_ops->dma_sff_read_status(hwif); + + /* clear INTR & ERROR flags */ + ide_dma_sff_write_status(hwif, dma_stat | ATA_DMA_ERR | ATA_DMA_INTR); + + return 0; +} +EXPORT_SYMBOL_GPL(ide_dma_setup); + +/** + * ide_dma_sff_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. + */ + +int ide_dma_sff_timer_expiry(ide_drive_t *drive) +{ + ide_hwif_t *hwif = drive->hwif; + u8 dma_stat = hwif->dma_ops->dma_sff_read_status(hwif); + + printk(KERN_WARNING "%s: %s: DMA status (0x%02x)\n", + drive->name, __func__, dma_stat); + + if ((dma_stat & 0x18) == 0x18) /* BUSY Stupid Early Timer !! */ + return WAIT_CMD; + + hwif->expiry = NULL; /* one free ride for now */ + + if (dma_stat & ATA_DMA_ERR) /* ERROR */ + return -1; + + if (dma_stat & ATA_DMA_ACTIVE) /* DMAing */ + return WAIT_CMD; + + if (dma_stat & ATA_DMA_INTR) /* Got an Interrupt */ + return WAIT_CMD; + + return 0; /* Status is unknown -- reset the bus */ +} +EXPORT_SYMBOL_GPL(ide_dma_sff_timer_expiry); + +void ide_dma_start(ide_drive_t *drive) +{ + ide_hwif_t *hwif = drive->hwif; + u8 dma_cmd; + + /* Note that this is done *after* the cmd has + * been issued to the drive, as per the BM-IDE spec. + * The Promise Ultra33 doesn't work correctly when + * we do this part before issuing the drive cmd. + */ + if (hwif->host_flags & IDE_HFLAG_MMIO) { + dma_cmd = readb((void __iomem *)(hwif->dma_base + ATA_DMA_CMD)); + writeb(dma_cmd | ATA_DMA_START, + (void __iomem *)(hwif->dma_base + ATA_DMA_CMD)); + } else { + dma_cmd = inb(hwif->dma_base + ATA_DMA_CMD); + outb(dma_cmd | ATA_DMA_START, hwif->dma_base + ATA_DMA_CMD); + } +} +EXPORT_SYMBOL_GPL(ide_dma_start); + +/* returns 1 on error, 0 otherwise */ +int ide_dma_end(ide_drive_t *drive) +{ + ide_hwif_t *hwif = drive->hwif; + u8 dma_stat = 0, dma_cmd = 0; + + /* stop DMA */ + if (hwif->host_flags & IDE_HFLAG_MMIO) { + dma_cmd = readb((void __iomem *)(hwif->dma_base + ATA_DMA_CMD)); + writeb(dma_cmd & ~ATA_DMA_START, + (void __iomem *)(hwif->dma_base + ATA_DMA_CMD)); + } else { + dma_cmd = inb(hwif->dma_base + ATA_DMA_CMD); + outb(dma_cmd & ~ATA_DMA_START, hwif->dma_base + ATA_DMA_CMD); + } + + /* get DMA status */ + dma_stat = hwif->dma_ops->dma_sff_read_status(hwif); + + /* clear INTR & ERROR bits */ + ide_dma_sff_write_status(hwif, dma_stat | ATA_DMA_ERR | ATA_DMA_INTR); + +#define CHECK_DMA_MASK (ATA_DMA_ACTIVE | ATA_DMA_ERR | ATA_DMA_INTR) + + /* verify good DMA status */ + if ((dma_stat & CHECK_DMA_MASK) != ATA_DMA_INTR) + return 0x10 | dma_stat; + return 0; +} +EXPORT_SYMBOL_GPL(ide_dma_end); + +/* returns 1 if dma irq issued, 0 otherwise */ +int ide_dma_test_irq(ide_drive_t *drive) +{ + ide_hwif_t *hwif = drive->hwif; + u8 dma_stat = hwif->dma_ops->dma_sff_read_status(hwif); + + return (dma_stat & ATA_DMA_INTR) ? 1 : 0; +} +EXPORT_SYMBOL_GPL(ide_dma_test_irq); + +const struct ide_dma_ops sff_dma_ops = { + .dma_host_set = ide_dma_host_set, + .dma_setup = ide_dma_setup, + .dma_start = ide_dma_start, + .dma_end = ide_dma_end, + .dma_test_irq = ide_dma_test_irq, + .dma_lost_irq = ide_dma_lost_irq, + .dma_timer_expiry = ide_dma_sff_timer_expiry, + .dma_sff_read_status = ide_dma_sff_read_status, +}; +EXPORT_SYMBOL_GPL(sff_dma_ops); diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c index 7c3a13e1cf6..17a65ac5649 100644 --- a/drivers/ide/ide-dma.c +++ b/drivers/ide/ide-dma.c @@ -1,61 +1,20 @@ /* - * linux/drivers/ide/ide-dma.c Version 4.10 June 9, 2000 + * IDE DMA support (including IDE PCI BM-DMA). + * + * Copyright (C) 1995-1998 Mark Lord + * Copyright (C) 1999-2000 Andre Hedrick <andre@linux-ide.org> + * Copyright (C) 2004, 2007 Bartlomiej Zolnierkiewicz * - * Copyright (c) 1999-2000 Andre Hedrick <andre@linux-ide.org> * May be copied or modified under the terms of the GNU General Public License + * + * DMA is supported for all IDE devices (disk drives, cdroms, tapes, floppies). */ /* * Special Thanks to Mark for his Six years of work. - * - * 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. * @@ -67,255 +26,132 @@ * * 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/module.h> #include <linux/types.h> +#include <linux/gfp.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/export.h> #include <linux/ide.h> -#include <linux/delay.h> #include <linux/scatterlist.h> +#include <linux/dma-mapping.h> -#include <asm/io.h> -#include <asm/irq.h> - -static const struct drive_list_entry drive_whitelist [] = { - - { "Micropolis 2112A" , "ALL" }, - { "CONNER CTMA 4000" , "ALL" }, - { "CONNER CTT8000-A" , "ALL" }, - { "ST34342A" , "ALL" }, +static const struct drive_list_entry drive_whitelist[] = { + { "Micropolis 2112A" , NULL }, + { "CONNER CTMA 4000" , NULL }, + { "CONNER CTT8000-A" , NULL }, + { "ST34342A" , NULL }, { NULL , NULL } }; -static const struct drive_list_entry drive_blacklist [] = { - - { "WDC AC11000H" , "ALL" }, - { "WDC AC22100H" , "ALL" }, - { "WDC AC32500H" , "ALL" }, - { "WDC AC33100H" , "ALL" }, - { "WDC AC31600H" , "ALL" }, +static const struct drive_list_entry drive_blacklist[] = { + { "WDC AC11000H" , NULL }, + { "WDC AC22100H" , NULL }, + { "WDC AC32500H" , NULL }, + { "WDC AC33100H" , NULL }, + { "WDC AC31600H" , NULL }, { "WDC AC32100H" , "24.09P07" }, { "WDC AC23200L" , "21.10N21" }, - { "Compaq CRD-8241B" , "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" }, - { "ATAPI CD-ROM DRIVE 40X MAXIMUM", "ALL" }, - { "_NEC DV5800A", "ALL" }, + { "Compaq CRD-8241B" , NULL }, + { "CRD-8400B" , NULL }, + { "CRD-8480B", NULL }, + { "CRD-8482B", NULL }, + { "CRD-84" , NULL }, + { "SanDisk SDP3B" , NULL }, + { "SanDisk SDP3B-64" , NULL }, + { "SANYO CD-ROM CRD" , NULL }, + { "HITACHI CDR-8" , NULL }, + { "HITACHI CDR-8335" , NULL }, + { "HITACHI CDR-8435" , NULL }, + { "Toshiba CD-ROM XM-6202B" , NULL }, + { "TOSHIBA CD-ROM XM-1702BC", NULL }, + { "CD-532E-A" , NULL }, + { "E-IDE CD-ROM CR-840", NULL }, + { "CD-ROM Drive/F5A", NULL }, + { "WPI CDD-820", NULL }, + { "SAMSUNG CD-ROM SC-148C", NULL }, + { "SAMSUNG CD-ROM SC", NULL }, + { "ATAPI CD-ROM DRIVE 40X MAXIMUM", NULL }, + { "_NEC DV5800A", NULL }, + { "SAMSUNG CD-ROM SN-124", "N001" }, + { "Seagate STT20000A", NULL }, + { "CD-ROM CDR_U200", "1.09" }, { NULL , NULL } }; /** - * ide_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. - */ - -int ide_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; -} - -EXPORT_SYMBOL_GPL(ide_in_drive_list); - -/** * 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 + * Handle an interrupt completing a read/write DMA transfer on an * IDE device */ - -ide_startstop_t ide_dma_intr (ide_drive_t *drive) + +ide_startstop_t ide_dma_intr(ide_drive_t *drive) { + ide_hwif_t *hwif = drive->hwif; + struct ide_cmd *cmd = &hwif->cmd; 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; + drive->waiting_for_dma = 0; + dma_stat = hwif->dma_ops->dma_end(drive); + ide_dma_unmap_sg(drive, cmd); + stat = hwif->tp_ops->read_status(hwif); - 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); + if (OK_STAT(stat, DRIVE_READY, drive->bad_wstat | ATA_DRQ)) { + if (!dma_stat) { + if ((cmd->tf_flags & IDE_TFLAG_FS) == 0) + ide_finish_cmd(drive, cmd, stat); + else + ide_complete_rq(drive, 0, + blk_rq_sectors(cmd->rq) << 9); return ide_stopped; } - printk(KERN_ERR "%s: dma_intr: bad DMA status (dma_stat=%x)\n", - drive->name, dma_stat); + printk(KERN_ERR "%s: %s: bad DMA status (0x%02x)\n", + drive->name, __func__, dma_stat); } return ide_error(drive, "dma_intr", stat); } -EXPORT_SYMBOL_GPL(ide_dma_intr); +int ide_dma_good_drive(ide_drive_t *drive) +{ + return ide_in_drive_list(drive->id, drive_whitelist); +} -#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 + * ide_dma_map_sg - map IDE scatter gather for DMA I/O + * @drive: the drive to map the DMA table for + * @cmd: command * - * Perform the PCI mapping magic necessary to access the source or - * target buffers of a request via PCI DMA. The lower layers of the + * Perform the DMA mapping magic necessary to access the source or + * target buffers of a request via DMA. The lower layers of the * kernel provide the necessary cache management so that we can - * operate in a portable fashion + * operate in a portable fashion. */ -int ide_build_sglist(ide_drive_t *drive, struct request *rq) +static int ide_dma_map_sg(ide_drive_t *drive, struct ide_cmd *cmd) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; struct scatterlist *sg = hwif->sg_table; - - BUG_ON((rq->flags & REQ_DRIVE_TASKFILE) && rq->nr_sectors > 256); - - 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; - } - } + if (cmd->tf_flags & IDE_TFLAG_WRITE) + cmd->sg_dma_direction = DMA_TO_DEVICE; + else + cmd->sg_dma_direction = DMA_FROM_DEVICE; - sg++; - i--; + i = dma_map_sg(hwif->dev, sg, cmd->sg_nents, cmd->sg_dma_direction); + if (i) { + cmd->orig_sg_nents = cmd->sg_nents; + cmd->sg_nents = 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 */ + return i; } -EXPORT_SYMBOL_GPL(ide_build_dmatable); - /** - * ide_destroy_dmatable - clean up DMA mapping + * ide_dma_unmap_sg - clean up DMA mapping * @drive: The drive to unmap * * Teardown mappings after DMA has completed. This must be called @@ -324,629 +160,394 @@ EXPORT_SYMBOL_GPL(ide_build_dmatable); * 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) +void ide_dma_unmap_sg(ide_drive_t *drive, struct ide_cmd *cmd) { - ide_hwif_t *hwif = HWIF(drive); - u8 unit = (drive->select.b.unit & 0x01); - u8 dma_stat = hwif->INB(hwif->dma_status); + ide_hwif_t *hwif = drive->hwif; - hwif->OUTB((dma_stat & ~(1<<(5+unit))), hwif->dma_status); - return 0; + dma_unmap_sg(hwif->dev, hwif->sg_table, cmd->orig_sg_nents, + cmd->sg_dma_direction); } - -EXPORT_SYMBOL(__ide_dma_host_off); +EXPORT_SYMBOL_GPL(ide_dma_unmap_sg); /** - * __ide_dma_host_off_quietly - Generic DMA kill + * ide_dma_off_quietly - Generic DMA kill * @drive: drive to control * - * Turn off the current DMA on this IDE controller. + * Turn off the current DMA on this IDE controller. */ -int __ide_dma_off_quietly (ide_drive_t *drive) +void ide_dma_off_quietly(ide_drive_t *drive) { - drive->using_dma = 0; + drive->dev_flags &= ~IDE_DFLAG_USING_DMA; ide_toggle_bounce(drive, 0); - if (HWIF(drive)->ide_dma_host_off(drive)) - return 1; - - return 0; + drive->hwif->dma_ops->dma_host_set(drive, 0); } - -EXPORT_SYMBOL(__ide_dma_off_quietly); -#endif /* CONFIG_BLK_DEV_IDEDMA_PCI */ +EXPORT_SYMBOL(ide_dma_off_quietly); /** - * __ide_dma_off - disable DMA on a device + * 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) +void ide_dma_off(ide_drive_t *drive) { printk(KERN_INFO "%s: DMA disabled\n", drive->name); - return HWIF(drive)->ide_dma_off_quietly(drive); + ide_dma_off_quietly(drive); } +EXPORT_SYMBOL(ide_dma_off); -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 + * ide_dma_on - Enable DMA on a device + * @drive: drive to enable DMA on * - * Enable DMA on an IDE controller following generic bus mastering - * IDE controller behaviour + * Enable IDE DMA for a device on this IDE controller. */ - -int __ide_dma_host_on (ide_drive_t *drive) + +void ide_dma_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); + drive->dev_flags |= IDE_DFLAG_USING_DMA; + ide_toggle_bounce(drive, 1); - hwif->OUTB((dma_stat|(1<<(5+unit))), hwif->dma_status); - return 0; + drive->hwif->dma_ops->dma_host_set(drive, 1); +} + +int __ide_dma_bad_drive(ide_drive_t *drive) +{ + u16 *id = drive->id; + + int blacklist = ide_in_drive_list(id, drive_blacklist); + if (blacklist) { + printk(KERN_WARNING "%s: Disabling (U)DMA for %s (blacklisted)\n", + drive->name, (char *)&id[ATA_ID_PROD]); + return blacklist; } - return 1; + return 0; } +EXPORT_SYMBOL(__ide_dma_bad_drive); -EXPORT_SYMBOL(__ide_dma_host_on); +static const u8 xfer_mode_bases[] = { + XFER_UDMA_0, + XFER_MW_DMA_0, + XFER_SW_DMA_0, +}; -/** - * __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) +static unsigned int ide_get_mode_mask(ide_drive_t *drive, u8 base, u8 req_mode) { - /* consult the list of known "bad" drives */ - if (__ide_dma_bad_drive(drive)) - return 1; + u16 *id = drive->id; + ide_hwif_t *hwif = drive->hwif; + const struct ide_port_ops *port_ops = hwif->port_ops; + unsigned int mask = 0; + + switch (base) { + case XFER_UDMA_0: + if ((id[ATA_ID_FIELD_VALID] & 4) == 0) + break; + mask = id[ATA_ID_UDMA_MODES]; + if (port_ops && port_ops->udma_filter) + mask &= port_ops->udma_filter(drive); + else + mask &= hwif->ultra_mask; - drive->using_dma = 1; - ide_toggle_bounce(drive, 1); + /* + * avoid false cable warning from eighty_ninty_three() + */ + if (req_mode > XFER_UDMA_2) { + if ((mask & 0x78) && (eighty_ninty_three(drive) == 0)) + mask &= 0x07; + } + break; + case XFER_MW_DMA_0: + mask = id[ATA_ID_MWDMA_MODES]; - if (HWIF(drive)->ide_dma_host_on(drive)) - return 1; + /* Also look for the CF specific MWDMA modes... */ + if (ata_id_is_cfa(id) && (id[ATA_ID_CFA_MODES] & 0x38)) { + u8 mode = ((id[ATA_ID_CFA_MODES] & 0x38) >> 3) - 1; - return 0; -} + mask |= ((2 << mode) - 1) << 3; + } -EXPORT_SYMBOL(__ide_dma_on); + if (port_ops && port_ops->mdma_filter) + mask &= port_ops->mdma_filter(drive); + else + mask &= hwif->mwdma_mask; + break; + case XFER_SW_DMA_0: + mask = id[ATA_ID_SWDMA_MODES]; + if (!(mask & ATA_SWDMA2) && (id[ATA_ID_OLD_DMA_MODES] >> 8)) { + u8 mode = id[ATA_ID_OLD_DMA_MODES] >> 8; + + /* + * if the mode is valid convert it to the mask + * (the maximum allowed mode is XFER_SW_DMA_2) + */ + if (mode <= 2) + mask = (2 << mode) - 1; + } + mask &= hwif->swdma_mask; + break; + default: + BUG(); + break; + } -/** - * __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); + return mask; } -EXPORT_SYMBOL(__ide_dma_check); - /** - * ide_dma_setup - begin a DMA phase - * @drive: target device + * ide_find_dma_mode - compute DMA speed + * @drive: IDE device + * @req_mode: requested mode * - * 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 + * Checks the drive/host capabilities and finds the speed to use for + * the DMA transfer. The speed is then limited by the requested mode. * - * Returns 0 on success. If a PIO fallback is required then 1 - * is returned. + * Returns 0 if the drive/host combination is incapable of DMA transfers + * or if the requested mode is not a DMA mode. */ -int ide_dma_setup(ide_drive_t *drive) +u8 ide_find_dma_mode(ide_drive_t *drive, u8 req_mode) { 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; + unsigned int mask; + int x, i; + u8 mode = 0; - /* fall back to pio! */ - if (!ide_build_dmatable(drive, rq)) { - ide_map_sg(drive, rq); - return 1; + if (drive->media != ide_disk) { + if (hwif->host_flags & IDE_HFLAG_NO_ATAPI_DMA) + return 0; } - /* 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; -} + for (i = 0; i < ARRAY_SIZE(xfer_mode_bases); i++) { + if (req_mode < xfer_mode_bases[i]) + continue; + mask = ide_get_mode_mask(drive, xfer_mode_bases[i], req_mode); + x = fls(mask) - 1; + if (x >= 0) { + mode = xfer_mode_bases[i] + x; + break; + } + } -EXPORT_SYMBOL_GPL(ide_dma_setup); + if (hwif->chipset == ide_acorn && mode == 0) { + /* + * is this correct? + */ + if (ide_dma_good_drive(drive) && + drive->id[ATA_ID_EIDE_DMA_TIME] < 150) + mode = XFER_MW_DMA_1; + } -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); -} + mode = min(mode, req_mode); -void ide_dma_start(ide_drive_t *drive) -{ - ide_hwif_t *hwif = HWIF(drive); - u8 dma_cmd = hwif->INB(hwif->dma_command); + printk(KERN_INFO "%s: %s mode selected\n", drive->name, + mode ? ide_xfer_verbose(mode) : "no DMA"); - /* 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(); + return mode; } -EXPORT_SYMBOL_GPL(ide_dma_start); - -/* returns 1 on error, 0 otherwise */ -int __ide_dma_end (ide_drive_t *drive) +static int ide_tune_dma(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; -} + ide_hwif_t *hwif = drive->hwif; + u8 speed; -EXPORT_SYMBOL(__ide_dma_end); + if (ata_id_has_dma(drive->id) == 0 || + (drive->dev_flags & IDE_DFLAG_NODMA)) + return 0; -/* 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); + /* consult the list of known "bad" drives */ + if (__ide_dma_bad_drive(drive)) + return 0; -#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 */ + if (hwif->host_flags & IDE_HFLAG_TRUST_BIOS_FOR_DMA) + return config_drive_for_dma(drive); -int __ide_dma_bad_drive (ide_drive_t *drive) -{ - struct hd_driveid *id = drive->id; + speed = ide_max_dma_mode(drive); - int blacklist = ide_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; -} + if (!speed) + return 0; -EXPORT_SYMBOL(__ide_dma_bad_drive); + if (ide_set_dma_mode(drive, speed)) + return 0; -int __ide_dma_good_drive (ide_drive_t *drive) -{ - struct hd_driveid *id = drive->id; - return ide_in_drive_list(id, drive_whitelist); + return 1; } -EXPORT_SYMBOL(__ide_dma_good_drive); - -int ide_use_dma(ide_drive_t *drive) +static int ide_dma_check(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)) + if (ide_tune_dma(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; - } + /* TODO: always do PIO fallback */ + if (hwif->host_flags & IDE_HFLAG_TRUST_BIOS_FOR_DMA) + return -1; - /* consult the list of known "good" drives */ - if (__ide_dma_good_drive(drive) && id->eide_dma_time < 150) - return 1; + ide_set_max_pio(drive); - return 0; + return -1; } -EXPORT_SYMBOL_GPL(ide_use_dma); - -void ide_dma_verbose(ide_drive_t *drive) +int ide_set_dma(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) { - goto bug_dma_off; - } - return; -bug_dma_off: - printk(", BUG DMA OFF"); - hwif->ide_dma_off_quietly(drive); - return; -} - -EXPORT_SYMBOL(ide_dma_verbose); + int rc; -#ifdef CONFIG_BLK_DEV_IDEDMA_PCI -int __ide_dma_lostirq (ide_drive_t *drive) -{ - printk("%s: DMA interrupt recovery\n", drive->name); - return 1; -} + /* + * Force DMAing for the beginning of the check. + * Some chipsets appear to do interesting + * things, if not checked and cleared. + * PARANOIA!!! + */ + ide_dma_off_quietly(drive); -EXPORT_SYMBOL(__ide_dma_lostirq); + rc = ide_dma_check(drive); + if (rc) + return rc; -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; + ide_dma_on(drive); - return HWIF(drive)->ide_dma_end(drive); + return 0; } -EXPORT_SYMBOL(__ide_dma_timeout); - -/* - * Needed for allowing full modular support of ide-driver - */ -static int ide_release_dma_engine(ide_hwif_t *hwif) +void ide_check_dma_crc(ide_drive_t *drive) { - 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; + u8 mode; + + ide_dma_off_quietly(drive); + drive->crc_count = 0; + mode = drive->current_speed; + /* + * Don't try non Ultra-DMA modes without iCRC's. Force the + * device to PIO and make the user enable SWDMA/MWDMA modes. + */ + if (mode > XFER_UDMA_0 && mode <= XFER_UDMA_7) + mode--; + else + mode = XFER_PIO_4; + ide_set_xfer_rate(drive, mode); + if (drive->current_speed >= XFER_SW_DMA_0) + ide_dma_on(drive); } -static int ide_release_iomio_dma(ide_hwif_t *hwif) +void ide_dma_lost_irq(ide_drive_t *drive) { - 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; + printk(KERN_ERR "%s: DMA interrupt recovery\n", drive->name); } +EXPORT_SYMBOL_GPL(ide_dma_lost_irq); /* - * Needed for allowing full modular support of ide-driver + * un-busy the port etc, and clear any pending DMA status. we want to + * retry the current request in pio mode instead of risking tossing it + * all away */ -int ide_release_dma (ide_hwif_t *hwif) +ide_startstop_t ide_dma_timeout_retry(ide_drive_t *drive, int error) { - if (hwif->mmio == 2) - return 1; - if (hwif->chipset == ide_etrax100) - return 1; - - ide_release_dma_engine(hwif); - return ide_release_iomio_dma(hwif); -} + ide_hwif_t *hwif = drive->hwif; + const struct ide_dma_ops *dma_ops = hwif->dma_ops; + struct ide_cmd *cmd = &hwif->cmd; + ide_startstop_t ret = ide_stopped; -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); + /* + * end current dma transaction + */ - if (hwif->dmatable_cpu) - return 0; + if (error < 0) { + printk(KERN_WARNING "%s: DMA timeout error\n", drive->name); + drive->waiting_for_dma = 0; + (void)dma_ops->dma_end(drive); + ide_dma_unmap_sg(drive, cmd); + ret = ide_error(drive, "dma timeout error", + hwif->tp_ops->read_status(hwif)); + } else { + printk(KERN_WARNING "%s: DMA timeout retry\n", drive->name); + if (dma_ops->dma_clear) + dma_ops->dma_clear(drive); + printk(KERN_ERR "%s: timeout waiting for DMA\n", drive->name); + if (dma_ops->dma_test_irq(drive) == 0) { + ide_dump_status(drive, "DMA timeout", + hwif->tp_ops->read_status(hwif)); + drive->waiting_for_dma = 0; + (void)dma_ops->dma_end(drive); + ide_dma_unmap_sg(drive, cmd); + } + } - printk(KERN_ERR "%s: -- Error, unable to allocate%s DMA table(s).\n", - hwif->cds->name, !hwif->dmatable_cpu ? " CPU" : ""); + /* + * disable dma for now, but remember that we did so because of + * a timeout -- we'll reenable after we finish this next request + * (or rather the first chunk of it) in pio. + */ + drive->dev_flags |= IDE_DFLAG_DMA_PIO_RETRY; + drive->retry_pio++; + ide_dma_off_quietly(drive); - ide_release_dma_engine(hwif); - return 1; + /* + * make sure request is sane + */ + if (hwif->rq) + hwif->rq->errors = 0; + return ret; } -static int ide_mapped_mmio_dma(ide_hwif_t *hwif, unsigned long base, unsigned int ports) +void ide_release_dma_engine(ide_hwif_t *hwif) { - 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; -} + if (hwif->dmatable_cpu) { + int prd_size = hwif->prd_max_nents * hwif->prd_ent_size; -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; - } + dma_free_coherent(hwif->dev, prd_size, + hwif->dmatable_cpu, hwif->dmatable_dma); + hwif->dmatable_cpu = NULL; } - return 0; } +EXPORT_SYMBOL_GPL(ide_release_dma_engine); -static int ide_dma_iobase(ide_hwif_t *hwif, unsigned long base, unsigned int ports) +int ide_allocate_dma_engine(ide_hwif_t *hwif) { - if (hwif->mmio == 2) - return ide_mapped_mmio_dma(hwif, base,ports); - BUG_ON(hwif->mmio == 1); - return ide_iomio_dma(hwif, base, ports); -} + int prd_size; -/* - * 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 (hwif->prd_max_nents == 0) + hwif->prd_max_nents = PRD_ENTRIES; + if (hwif->prd_ent_size == 0) + hwif->prd_ent_size = PRD_BYTES; - if (ide_allocate_dma_engine(hwif)) { - ide_release_dma(hwif); - return; - } + prd_size = hwif->prd_max_nents * hwif->prd_ent_size; - 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"); + hwif->dmatable_cpu = dma_alloc_coherent(hwif->dev, prd_size, + &hwif->dmatable_dma, + GFP_ATOMIC); + if (hwif->dmatable_cpu == NULL) { + printk(KERN_ERR "%s: unable to allocate PRD table\n", + hwif->name); + return -ENOMEM; } - printk("\n"); - BUG_ON(!hwif->dma_master); + return 0; } +EXPORT_SYMBOL_GPL(ide_allocate_dma_engine); + +int ide_dma_prepare(ide_drive_t *drive, struct ide_cmd *cmd) +{ + const struct ide_dma_ops *dma_ops = drive->hwif->dma_ops; -EXPORT_SYMBOL_GPL(ide_setup_dma); -#endif /* CONFIG_BLK_DEV_IDEDMA_PCI */ + if ((drive->dev_flags & IDE_DFLAG_USING_DMA) == 0 || + (dma_ops->dma_check && dma_ops->dma_check(drive, cmd))) + goto out; + ide_map_sg(drive, cmd); + if (ide_dma_map_sg(drive, cmd) == 0) + goto out_map; + if (dma_ops->dma_setup(drive, cmd)) + goto out_dma_unmap; + drive->waiting_for_dma = 1; + return 0; +out_dma_unmap: + ide_dma_unmap_sg(drive, cmd); +out_map: + ide_map_sg(drive, cmd); +out: + return 1; +} diff --git a/drivers/ide/ide-eh.c b/drivers/ide/ide-eh.c new file mode 100644 index 00000000000..32970664c27 --- /dev/null +++ b/drivers/ide/ide-eh.c @@ -0,0 +1,442 @@ + +#include <linux/kernel.h> +#include <linux/export.h> +#include <linux/ide.h> +#include <linux/delay.h> + +static ide_startstop_t ide_ata_error(ide_drive_t *drive, struct request *rq, + u8 stat, u8 err) +{ + ide_hwif_t *hwif = drive->hwif; + + if ((stat & ATA_BUSY) || + ((stat & ATA_DF) && (drive->dev_flags & IDE_DFLAG_NOWERR) == 0)) { + /* other bits are useless when BUSY */ + rq->errors |= ERROR_RESET; + } else if (stat & ATA_ERR) { + /* err has different meaning on cdrom and tape */ + if (err == ATA_ABORTED) { + if ((drive->dev_flags & IDE_DFLAG_LBA) && + /* some newer drives don't support ATA_CMD_INIT_DEV_PARAMS */ + hwif->tp_ops->read_status(hwif) == ATA_CMD_INIT_DEV_PARAMS) + return ide_stopped; + } else if ((err & BAD_CRC) == BAD_CRC) { + /* UDMA crc error, just retry the operation */ + drive->crc_count++; + } else if (err & (ATA_BBK | ATA_UNC)) { + /* retries won't help these */ + rq->errors = ERROR_MAX; + } else if (err & ATA_TRK0NF) { + /* help it find track zero */ + rq->errors |= ERROR_RECAL; + } + } + + if ((stat & ATA_DRQ) && rq_data_dir(rq) == READ && + (hwif->host_flags & IDE_HFLAG_ERROR_STOPS_FIFO) == 0) { + int nsect = drive->mult_count ? drive->mult_count : 1; + + ide_pad_transfer(drive, READ, nsect * SECTOR_SIZE); + } + + if (rq->errors >= ERROR_MAX || blk_noretry_request(rq)) { + ide_kill_rq(drive, rq); + return ide_stopped; + } + + if (hwif->tp_ops->read_status(hwif) & (ATA_BUSY | ATA_DRQ)) + rq->errors |= ERROR_RESET; + + if ((rq->errors & ERROR_RESET) == ERROR_RESET) { + ++rq->errors; + return ide_do_reset(drive); + } + + if ((rq->errors & ERROR_RECAL) == ERROR_RECAL) + drive->special_flags |= IDE_SFLAG_RECALIBRATE; + + ++rq->errors; + + return ide_stopped; +} + +static ide_startstop_t ide_atapi_error(ide_drive_t *drive, struct request *rq, + u8 stat, u8 err) +{ + ide_hwif_t *hwif = drive->hwif; + + if ((stat & ATA_BUSY) || + ((stat & ATA_DF) && (drive->dev_flags & IDE_DFLAG_NOWERR) == 0)) { + /* other bits are useless when BUSY */ + rq->errors |= ERROR_RESET; + } else { + /* add decoding error stuff */ + } + + if (hwif->tp_ops->read_status(hwif) & (ATA_BUSY | ATA_DRQ)) + /* force an abort */ + hwif->tp_ops->exec_command(hwif, ATA_CMD_IDLEIMMEDIATE); + + if (rq->errors >= ERROR_MAX) { + ide_kill_rq(drive, rq); + } else { + if ((rq->errors & ERROR_RESET) == ERROR_RESET) { + ++rq->errors; + return ide_do_reset(drive); + } + ++rq->errors; + } + + return ide_stopped; +} + +static 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); +} + +/** + * 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); + + rq = drive->hwif->rq; + if (rq == NULL) + return ide_stopped; + + /* retry only "normal" I/O: */ + if (rq->cmd_type != REQ_TYPE_FS) { + if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) { + struct ide_cmd *cmd = rq->special; + + if (cmd) + ide_complete_cmd(drive, cmd, stat, err); + } else if (blk_pm_request(rq)) { + rq->errors = 1; + ide_complete_pm_rq(drive, rq); + return ide_stopped; + } + rq->errors = err; + ide_complete_rq(drive, err ? -EIO : 0, blk_rq_bytes(rq)); + return ide_stopped; + } + + return __ide_error(drive, rq, stat, err); +} +EXPORT_SYMBOL_GPL(ide_error); + +static inline void ide_complete_drive_reset(ide_drive_t *drive, int err) +{ + struct request *rq = drive->hwif->rq; + + if (rq && rq->cmd_type == REQ_TYPE_SPECIAL && + rq->cmd[0] == REQ_DRIVE_RESET) { + if (err <= 0 && rq->errors == 0) + rq->errors = -EIO; + ide_complete_rq(drive, err ? err : 0, blk_rq_bytes(rq)); + } +} + +/* needed below */ +static ide_startstop_t do_reset1(ide_drive_t *, int); + +/* + * atapi_reset_pollfunc() gets invoked to poll the interface for completion + * every 50ms during an atapi drive reset operation. If the drive has not yet + * responded, and we have not yet hit our maximum waiting time, then the timer + * is restarted for another 50ms. + */ +static ide_startstop_t atapi_reset_pollfunc(ide_drive_t *drive) +{ + ide_hwif_t *hwif = drive->hwif; + const struct ide_tp_ops *tp_ops = hwif->tp_ops; + u8 stat; + + tp_ops->dev_select(drive); + udelay(10); + stat = tp_ops->read_status(hwif); + + if (OK_STAT(stat, 0, ATA_BUSY)) + printk(KERN_INFO "%s: ATAPI reset complete\n", drive->name); + else { + if (time_before(jiffies, hwif->poll_timeout)) { + ide_set_handler(drive, &atapi_reset_pollfunc, HZ/20); + /* continue polling */ + return ide_started; + } + /* end of polling */ + hwif->polling = 0; + printk(KERN_ERR "%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 */ + hwif->polling = 0; + ide_complete_drive_reset(drive, 0); + return ide_stopped; +} + +static void ide_reset_report_error(ide_hwif_t *hwif, u8 err) +{ + static const char *err_master_vals[] = + { NULL, "passed", "formatter device error", + "sector buffer error", "ECC circuitry error", + "controlling MPU error" }; + + u8 err_master = err & 0x7f; + + printk(KERN_ERR "%s: reset: master: ", hwif->name); + if (err_master && err_master < 6) + printk(KERN_CONT "%s", err_master_vals[err_master]); + else + printk(KERN_CONT "error (0x%02x?)", err); + if (err & 0x80) + printk(KERN_CONT "; slave: failed"); + printk(KERN_CONT "\n"); +} + +/* + * reset_pollfunc() gets invoked to poll the interface for completion every 50ms + * during an ide reset operation. If the drives have not yet responded, + * and we have not yet hit our maximum waiting time, then the timer is restarted + * for another 50ms. + */ +static ide_startstop_t reset_pollfunc(ide_drive_t *drive) +{ + ide_hwif_t *hwif = drive->hwif; + const struct ide_port_ops *port_ops = hwif->port_ops; + u8 tmp; + int err = 0; + + if (port_ops && port_ops->reset_poll) { + err = port_ops->reset_poll(drive); + if (err) { + printk(KERN_ERR "%s: host reset_poll failure for %s.\n", + hwif->name, drive->name); + goto out; + } + } + + tmp = hwif->tp_ops->read_status(hwif); + + if (!OK_STAT(tmp, 0, ATA_BUSY)) { + if (time_before(jiffies, hwif->poll_timeout)) { + ide_set_handler(drive, &reset_pollfunc, HZ/20); + /* continue polling */ + return ide_started; + } + printk(KERN_ERR "%s: reset timed-out, status=0x%02x\n", + hwif->name, tmp); + drive->failures++; + err = -EIO; + } else { + tmp = ide_read_error(drive); + + if (tmp == 1) { + printk(KERN_INFO "%s: reset: success\n", hwif->name); + drive->failures = 0; + } else { + ide_reset_report_error(hwif, tmp); + drive->failures++; + err = -EIO; + } + } +out: + hwif->polling = 0; /* done polling */ + ide_complete_drive_reset(drive, err); + return ide_stopped; +} + +static void ide_disk_pre_reset(ide_drive_t *drive) +{ + int legacy = (drive->id[ATA_ID_CFS_ENABLE_2] & 0x0400) ? 0 : 1; + + drive->special_flags = + legacy ? (IDE_SFLAG_SET_GEOMETRY | IDE_SFLAG_RECALIBRATE) : 0; + + drive->mult_count = 0; + drive->dev_flags &= ~IDE_DFLAG_PARKED; + + if ((drive->dev_flags & IDE_DFLAG_KEEP_SETTINGS) == 0 && + (drive->dev_flags & IDE_DFLAG_USING_DMA) == 0) + drive->mult_req = 0; + + if (drive->mult_req != drive->mult_count) + drive->special_flags |= IDE_SFLAG_SET_MULTMODE; +} + +static void pre_reset(ide_drive_t *drive) +{ + const struct ide_port_ops *port_ops = drive->hwif->port_ops; + + if (drive->media == ide_disk) + ide_disk_pre_reset(drive); + else + drive->dev_flags |= IDE_DFLAG_POST_RESET; + + if (drive->dev_flags & IDE_DFLAG_USING_DMA) { + if (drive->crc_count) + ide_check_dma_crc(drive); + else + ide_dma_off(drive); + } + + if ((drive->dev_flags & IDE_DFLAG_KEEP_SETTINGS) == 0) { + if ((drive->dev_flags & IDE_DFLAG_USING_DMA) == 0) { + drive->dev_flags &= ~IDE_DFLAG_UNMASK; + drive->io_32bit = 0; + } + return; + } + + if (port_ops && port_ops->pre_reset) + port_ops->pre_reset(drive); + + if (drive->current_speed != 0xff) + drive->desired_speed = drive->current_speed; + drive->current_speed = 0xff; +} + +/* + * do_reset1() attempts to recover a confused drive by resetting it. + * Unfortunately, resetting a disk drive actually resets all devices on + * the same interface, so it can really be thought of as resetting the + * interface rather than resetting the drive. + * + * ATAPI devices have their own reset mechanism which allows them to be + * individually reset without clobbering other devices on the same interface. + * + * Unfortunately, the IDE interface does not generate an interrupt to let + * us know when the reset operation has finished, so we must poll for this. + * Equally poor, though, is the fact that this may a very long time to complete, + * (up to 30 seconds worstcase). So, instead of busy-waiting here for it, + * we set a timer to poll at 50ms intervals. + */ +static ide_startstop_t do_reset1(ide_drive_t *drive, int do_not_try_atapi) +{ + ide_hwif_t *hwif = drive->hwif; + struct ide_io_ports *io_ports = &hwif->io_ports; + const struct ide_tp_ops *tp_ops = hwif->tp_ops; + const struct ide_port_ops *port_ops; + ide_drive_t *tdrive; + unsigned long flags, timeout; + int i; + DEFINE_WAIT(wait); + + spin_lock_irqsave(&hwif->lock, flags); + + /* We must not reset with running handlers */ + BUG_ON(hwif->handler != NULL); + + /* For an ATAPI device, first try an ATAPI SRST. */ + if (drive->media != ide_disk && !do_not_try_atapi) { + pre_reset(drive); + tp_ops->dev_select(drive); + udelay(20); + tp_ops->exec_command(hwif, ATA_CMD_DEV_RESET); + ndelay(400); + hwif->poll_timeout = jiffies + WAIT_WORSTCASE; + hwif->polling = 1; + __ide_set_handler(drive, &atapi_reset_pollfunc, HZ/20); + spin_unlock_irqrestore(&hwif->lock, flags); + return ide_started; + } + + /* We must not disturb devices in the IDE_DFLAG_PARKED state. */ + do { + unsigned long now; + + prepare_to_wait(&ide_park_wq, &wait, TASK_UNINTERRUPTIBLE); + timeout = jiffies; + ide_port_for_each_present_dev(i, tdrive, hwif) { + if ((tdrive->dev_flags & IDE_DFLAG_PARKED) && + time_after(tdrive->sleep, timeout)) + timeout = tdrive->sleep; + } + + now = jiffies; + if (time_before_eq(timeout, now)) + break; + + spin_unlock_irqrestore(&hwif->lock, flags); + timeout = schedule_timeout_uninterruptible(timeout - now); + spin_lock_irqsave(&hwif->lock, flags); + } while (timeout); + finish_wait(&ide_park_wq, &wait); + + /* + * First, reset any device state data we were maintaining + * for any of the drives on this interface. + */ + ide_port_for_each_dev(i, tdrive, hwif) + pre_reset(tdrive); + + if (io_ports->ctl_addr == 0) { + spin_unlock_irqrestore(&hwif->lock, flags); + ide_complete_drive_reset(drive, -ENXIO); + return ide_stopped; + } + + /* + * Note that we also set nIEN while resetting the device, + * to mask unwanted interrupts from the interface during the reset. + * However, due to the design of PC hardware, this will cause an + * immediate interrupt due to the edge transition it produces. + * This single interrupt gives us a "fast poll" for drives that + * recover from reset very quickly, saving us the first 50ms wait time. + */ + /* set SRST and nIEN */ + tp_ops->write_devctl(hwif, ATA_SRST | ATA_NIEN | ATA_DEVCTL_OBS); + /* more than enough time */ + udelay(10); + /* clear SRST, leave nIEN (unless device is on the quirk list) */ + tp_ops->write_devctl(hwif, + ((drive->dev_flags & IDE_DFLAG_NIEN_QUIRK) ? 0 : ATA_NIEN) | + ATA_DEVCTL_OBS); + /* more than enough time */ + udelay(10); + hwif->poll_timeout = jiffies + WAIT_WORSTCASE; + hwif->polling = 1; + __ide_set_handler(drive, &reset_pollfunc, HZ/20); + + /* + * Some weird controller like resetting themselves to a strange + * state when the disks are reset this way. At least, the Winbond + * 553 documentation says that + */ + port_ops = hwif->port_ops; + if (port_ops && port_ops->resetproc) + port_ops->resetproc(drive); + + spin_unlock_irqrestore(&hwif->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); diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c index adbe9f76a50..3d42043fec5 100644 --- a/drivers/ide/ide-floppy.c +++ b/drivers/ide/ide-floppy.c @@ -1,15 +1,9 @@ /* - * 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. + * Copyright (C) 1996-1999 Gadi Oxman <gadio@netvision.net.il> + * Copyright (C) 2000-2002 Paul Bristow <paul@paulbristow.net> + * Copyright (C) 2005 Bartlomiej Zolnierkiewicz * * This driver supports the following IDE floppy drives: * @@ -17,72 +11,10 @@ * 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 + * For a historical changelog see + * Documentation/ide/ChangeLog.ide-floppy.1996-2002 */ -#define IDEFLOPPY_VERSION "0.99.newide" - -#include <linux/module.h> #include <linux/types.h> #include <linux/string.h> #include <linux/kernel.h> @@ -93,1393 +25,426 @@ #include <linux/major.h> #include <linux/errno.h> #include <linux/genhd.h> -#include <linux/slab.h> #include <linux/cdrom.h> #include <linux/ide.h> +#include <linux/hdreg.h> #include <linux/bitops.h> #include <linux/mutex.h> +#include <linux/scatterlist.h> + +#include <scsi/scsi_ioctl.h> #include <asm/byteorder.h> -#include <asm/irq.h> -#include <asm/uaccess.h> -#include <asm/io.h> +#include <linux/uaccess.h> +#include <linux/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) +#include "ide-floppy.h" /* - * After each failed packet command we issue a request sense command - * and retry the packet command IDEFLOPPY_MAX_PC_RETRIES times. + * 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; - +/* format capacities descriptor codes */ #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 HZ/20 /* default delay for ZIP 100 (50ms) */ - -/* - * Floppy flag bits values. + * The following delay solves a problem with ATAPI Zip 100 drive where BSY bit + * was apparently being deasserted before the unit was ready to receive data. */ -#define IDEFLOPPY_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 */ +#define IDEFLOPPY_PC_DELAY (HZ/20) /* default delay for ZIP 100 (50ms) */ -/* - * 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 DEFINE_MUTEX(idefloppy_ref_mutex); - -#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; - - mutex_lock(&idefloppy_ref_mutex); - floppy = ide_floppy_g(disk); - if (floppy) - kref_get(&floppy->kref); - mutex_unlock(&idefloppy_ref_mutex); - return floppy; -} - -static void ide_floppy_release(struct kref *); - -static void ide_floppy_put(struct ide_floppy_obj *floppy) -{ - mutex_lock(&idefloppy_ref_mutex); - kref_put(&floppy->kref, ide_floppy_release); - mutex_unlock(&idefloppy_ref_mutex); -} - -/* - * 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) +static int ide_floppy_callback(ide_drive_t *drive, int dsc) { + struct ide_disk_obj *floppy = drive->driver_data; + struct ide_atapi_pc *pc = drive->pc; 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; + int uptodate = pc->error ? 0 : 1; - count = min(bvec->bv_len, bcount); + ide_debug_log(IDE_DBG_FUNC, "enter"); - data = bvec_kmap_irq(bvec, &flags); - drive->hwif->atapi_input_bytes(drive, data, count); - bvec_kunmap_irq(data, &flags); + if (drive->failed_pc == pc) + drive->failed_pc = NULL; - bcount -= count; - pc->b_count += count; - done += count; - } - } + if (pc->c[0] == GPCMD_READ_10 || pc->c[0] == GPCMD_WRITE_10 || + rq->cmd_type == REQ_TYPE_BLOCK_PC) + uptodate = 1; /* FIXME */ + else if (pc->c[0] == GPCMD_REQUEST_SENSE) { - idefloppy_do_end_request(drive, 1, done >> 9); + u8 *buf = bio_data(rq->bio); - if (bcount) { - printk(KERN_ERR "%s: leftover data in idefloppy_input_buffers, bcount == %d\n", drive->name, bcount); - idefloppy_discard_data(drive, bcount); - } -} + if (!pc->error) { + floppy->sense_key = buf[2] & 0x0F; + floppy->asc = buf[12]; + floppy->ascq = buf[13]; + floppy->progress_indication = buf[15] & 0x80 ? + (u16)get_unaligned((u16 *)&buf[16]) : 0x10000; -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); + if (drive->failed_pc) + ide_debug_log(IDE_DBG_PC, "pc = %x", + drive->failed_pc->c[0]); - bcount -= count; - pc->b_count += count; - done += count; - } + ide_debug_log(IDE_DBG_SENSE, "sense key = %x, asc = %x," + "ascq = %x", floppy->sense_key, + floppy->asc, floppy->ascq); + } else + printk(KERN_ERR PFX "Error in REQUEST SENSE itself - " + "Aborting request!\n"); } - idefloppy_do_end_request(drive, 1, done >> 9); + if (rq->cmd_type == REQ_TYPE_SPECIAL) + rq->errors = uptodate ? 0 : IDE_DRV_ERROR_GENERAL; -#if IDEFLOPPY_DEBUG_BUGS - if (bcount) { - printk(KERN_ERR "%s: leftover data in idefloppy_output_buffers, bcount == %d\n", drive->name, bcount); - idefloppy_write_zeros(drive, bcount); - } -#endif + return uptodate; } -static void idefloppy_update_buffers (ide_drive_t *drive, idefloppy_pc_t *pc) +static void ide_floppy_report_error(struct ide_disk_obj *floppy, + struct ide_atapi_pc *pc) { - struct request *rq = pc->rq; - struct bio *bio = rq->bio; - - while ((bio = rq->bio) != NULL) - idefloppy_do_end_request(drive, 1, 0); -} + /* suppress error messages resulting from Medium not present */ + if (floppy->sense_key == 0x02 && + floppy->asc == 0x3a && + floppy->ascq == 0x00) + return; -/* - * 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; + printk(KERN_ERR PFX "%s: I/O error, pc = %2x, key = %2x, " + "asc = %2x, ascq = %2x\n", + floppy->drive->name, pc->c[0], floppy->sense_key, + floppy->asc, floppy->ascq); - 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) +static ide_startstop_t ide_floppy_issue_pc(ide_drive_t *drive, + struct ide_cmd *cmd, + struct ide_atapi_pc *pc) { - idefloppy_floppy_t *floppy = drive->driver_data; + struct ide_disk_obj *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++]); -} + if (drive->failed_pc == NULL && + pc->c[0] != GPCMD_REQUEST_SENSE) + drive->failed_pc = pc; -static struct request *idefloppy_next_rq_storage (ide_drive_t *drive) -{ - idefloppy_floppy_t *floppy = drive->driver_data; + /* Set the current packet command */ + drive->pc = pc; - if (floppy->rq_stack_index == IDEFLOPPY_PC_STACK) - floppy->rq_stack_index = 0; - return (&floppy->rq_stack[floppy->rq_stack_index++]); -} + if (pc->retries > IDEFLOPPY_MAX_PC_RETRIES) { + unsigned int done = blk_rq_bytes(drive->hwif->rq); -/* - * 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); -} + if (!(pc->flags & PC_FLAG_SUPPRESS_ERROR)) + ide_floppy_report_error(floppy, pc); -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); - } -} + /* Giving up */ + pc->error = IDE_DRV_ERROR_GENERAL; -/* - * 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__); + drive->failed_pc = NULL; + drive->pc_callback(drive, 0); + ide_complete_rq(drive, -EIO, done); + return ide_stopped; + } - idefloppy_do_end_request(drive, floppy->pc->error ? 0 : 1, 0); -} + ide_debug_log(IDE_DBG_FUNC, "retry #%d", pc->retries); -/* - * 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; -} + pc->retries++; -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; + return ide_issue_pc(drive, cmd); } -/* - * 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) +void ide_floppy_create_read_capacity_cmd(struct ide_atapi_pc *pc) { - 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); + ide_init_pc(pc); + pc->c[0] = GPCMD_READ_FORMAT_CAPACITIES; + pc->c[7] = 255; + pc->c[8] = 255; + pc->req_xfer = 255; } -/* - * 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) +/* A mode sense command is used to "sense" floppy parameters. */ +void ide_floppy_create_mode_sense_cmd(struct ide_atapi_pc *pc, u8 page_code) { - 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; + u16 length = 8; /* sizeof(Mode Parameter Header) = 8 Bytes */ - debug_log(KERN_INFO "ide-floppy: Reached %s interrupt handler\n", - __FUNCTION__); + ide_init_pc(pc); + pc->c[0] = GPCMD_MODE_SENSE_10; + pc->c[1] = 0; + pc->c[2] = page_code; - 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"); + switch (page_code) { + case IDEFLOPPY_CAPABILITIES_PAGE: + length += 12; + break; + case IDEFLOPPY_FLEXIBLE_DISK_PAGE: + length += 32; + break; + default: + printk(KERN_ERR PFX "unsupported page code in %s\n", __func__); } + put_unaligned(cpu_to_be16(length), (u16 *) &pc->c[7]); + pc->req_xfer = length; +} - /* 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_in_hardirq(); +static void idefloppy_create_rw_cmd(ide_drive_t *drive, + struct ide_atapi_pc *pc, struct request *rq, + unsigned long sector) +{ + struct ide_disk_obj *floppy = drive->driver_data; + int block = sector / floppy->bs_factor; + int blocks = blk_rq_sectors(rq) / floppy->bs_factor; + int cmd = rq_data_dir(rq); - 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; - } + ide_debug_log(IDE_DBG_FUNC, "block: %d, blocks: %d", block, blocks); - 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); - } + ide_init_pc(pc); + pc->c[0] = cmd == READ ? GPCMD_READ_10 : GPCMD_WRITE_10; + put_unaligned(cpu_to_be16(blocks), (unsigned short *)&pc->c[7]); + put_unaligned(cpu_to_be32(block), (unsigned int *) &pc->c[2]); - /* 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); + memcpy(rq->cmd, pc->c, 12); - 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); - BUG_ON(HWGROUP(drive)->handler != NULL); - 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; + pc->rq = rq; + if (rq->cmd_flags & REQ_WRITE) + pc->flags |= PC_FLAG_WRITING; - BUG_ON(HWGROUP(drive)->handler != NULL); - ide_set_handler(drive, &idefloppy_pc_intr, IDEFLOPPY_WAIT_CMD, NULL); /* And set the interrupt handler again */ - return ide_started; + pc->flags |= PC_FLAG_DMA_OK; } -/* - * 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) +static void idefloppy_blockpc_cmd(struct ide_disk_obj *floppy, + struct ide_atapi_pc *pc, struct request *rq) { - 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); + ide_init_pc(pc); + memcpy(pc->c, rq->cmd, sizeof(pc->c)); + pc->rq = rq; + if (blk_rq_bytes(rq)) { + pc->flags |= PC_FLAG_DMA_OK; + if (rq_data_dir(rq) == WRITE) + pc->flags |= PC_FLAG_WRITING; } - BUG_ON(HWGROUP(drive)->handler != NULL); - /* 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) +static ide_startstop_t ide_floppy_do_request(ide_drive_t *drive, + struct request *rq, sector_t block) { - 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; -} + struct ide_disk_obj *floppy = drive->driver_data; + struct ide_cmd cmd; + struct ide_atapi_pc *pc; -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. - */ - BUG_ON(HWGROUP(drive)->handler != NULL); - 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; -} + ide_debug_log(IDE_DBG_FUNC, "enter, cmd: 0x%x\n", rq->cmd[0]); -/** - * 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; -} + if (drive->debug_mask & IDE_DBG_RQ) + blk_dump_rq_flags(rq, (rq->rq_disk + ? rq->rq_disk->disk_name + : "dev?")); -/* - * 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 0 /* Accessing floppy->pc is not valid here, the previous pc may be gone - and have lived on another thread's stack; that stack may have become - unmapped meanwhile (CONFIG_DEBUG_PAGEALLOC). */ -#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"); + if (rq->errors >= ERROR_MAX) { + if (drive->failed_pc) { + ide_floppy_report_error(floppy, drive->failed_pc); + drive->failed_pc = NULL; + } else + printk(KERN_ERR PFX "%s: I/O error\n", drive->name); + + if (rq->cmd_type == REQ_TYPE_SPECIAL) { + rq->errors = 0; + ide_complete_rq(drive, 0, blk_rq_bytes(rq)); + return ide_stopped; + } else + goto out_end; } -#endif /* IDEFLOPPY_DEBUG_BUGS */ -#endif - - 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; + switch (rq->cmd_type) { + case REQ_TYPE_FS: + if (((long)blk_rq_pos(rq) % floppy->bs_factor) || + (blk_rq_sectors(rq) % floppy->bs_factor)) { + printk(KERN_ERR PFX "%s: unsupported r/w rq size\n", + drive->name); + goto out_end; } - 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); + pc = &floppy->queued_pc; + idefloppy_create_rw_cmd(drive, pc, rq, (unsigned long)block); + break; + case REQ_TYPE_SPECIAL: + case REQ_TYPE_SENSE: + pc = (struct ide_atapi_pc *)rq->special; + break; + case REQ_TYPE_BLOCK_PC: + pc = &floppy->queued_pc; + idefloppy_blockpc_cmd(floppy, pc, rq); + break; + default: + BUG(); } - 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); + ide_prep_sense(drive, rq); - idefloppy_init_pc(pc); - pc->c[0] = IDEFLOPPY_PREVENT_REMOVAL_CMD; - pc->c[4] = prevent; -} + memset(&cmd, 0, sizeof(cmd)); -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; -} + if (rq_data_dir(rq)) + cmd.tf_flags |= IDE_TFLAG_WRITE; -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); + cmd.rq = rq; - 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"); + if (rq->cmd_type == REQ_TYPE_FS || blk_rq_bytes(rq)) { + ide_init_sg_cmd(&cmd, blk_rq_bytes(rq)); + ide_map_sg(drive, &cmd); } - 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; + return ide_floppy_issue_pc(drive, &cmd, pc); +out_end: + drive->failed_pc = NULL; + if (rq->cmd_type != REQ_TYPE_FS && rq->errors == 0) + rq->errors = -EIO; + ide_complete_rq(drive, -EIO, blk_rq_bytes(rq)); + return ide_stopped; } /* - * idefloppy_do_request is our request handling function. + * Look at the flexible disk page parameters. We ignore the CHS capacity + * parameters and use the LBA parameters instead. */ -static ide_startstop_t idefloppy_do_request (ide_drive_t *drive, struct request *rq, sector_t block_s) +static int ide_floppy_get_flexible_disk_page(ide_drive_t *drive, + struct ide_atapi_pc *pc) { - 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); + struct ide_disk_obj *floppy = drive->driver_data; + struct gendisk *disk = floppy->disk; + u8 *page, buf[40]; + int capacity, lba_capacity; + u16 transfer_rate, sector_size, cyls, rpm; + u8 heads, 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; + ide_floppy_create_mode_sense_cmd(pc, IDEFLOPPY_FLEXIBLE_DISK_PAGE); + + if (ide_queue_pc_tail(drive, disk, pc, buf, pc->req_xfer)) { + printk(KERN_ERR PFX "Can't get flexible disk page params\n"); + return 1; } - pc->rq = rq; - return idefloppy_issue_pc(drive, pc); -} + if (buf[3] & 0x80) + drive->dev_flags |= IDE_DFLAG_WP; + else + drive->dev_flags &= ~IDE_DFLAG_WP; -/* - * 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; + set_disk_ro(disk, !!(drive->dev_flags & IDE_DFLAG_WP)); - ide_init_drive_cmd (&rq); - rq.buffer = (char *) pc; - rq.flags = REQ_SPECIAL; // rq.cmd = IDEFLOPPY_PC_RQ; - rq.rq_disk = floppy->disk; + page = &buf[8]; - return ide_do_drive_cmd(drive, &rq, ide_wait); -} + transfer_rate = be16_to_cpup((__be16 *)&buf[8 + 2]); + sector_size = be16_to_cpup((__be16 *)&buf[8 + 6]); + cyls = be16_to_cpup((__be16 *)&buf[8 + 8]); + rpm = be16_to_cpup((__be16 *)&buf[8 + 28]); + heads = buf[8 + 4]; + sectors = buf[8 + 5]; -/* - * 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; + capacity = cyls * heads * sectors * sector_size; - 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, " + if (memcmp(page, &floppy->flexible_disk_page, 32)) + printk(KERN_INFO PFX "%s: %dkB, %d/%d/%d CHS, %d kBps, " "%d sector size, %d rpm\n", - drive->name, capacity / 1024, 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; + drive->name, capacity / 1024, cyls, heads, + sectors, transfer_rate / 8, sector_size, rpm); + + memcpy(&floppy->flexible_disk_page, page, 32); + drive->bios_cyl = cyls; + drive->bios_head = heads; + drive->bios_sect = sectors; lba_capacity = floppy->blocks * floppy->block_size; + if (capacity < lba_capacity) { - printk(KERN_NOTICE "%s: The disk reports a capacity of %d " + printk(KERN_NOTICE PFX "%s: The disk reports a capacity of %d " "bytes, but the drive only handles %d\n", drive->name, lba_capacity, capacity); - floppy->blocks = floppy->block_size ? capacity / floppy->block_size : 0; + floppy->blocks = floppy->block_size ? + capacity / floppy->block_size : 0; + drive->capacity64 = floppy->blocks * floppy->bs_factor; } - 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); + return 0; } /* - * Determine if a media is present in the floppy drive, and if so, - * its LBA capacity. + * 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) +static int ide_floppy_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; - + struct ide_disk_obj *floppy = drive->driver_data; + struct gendisk *disk = floppy->disk; + struct ide_atapi_pc pc; + u8 *cap_desc; + u8 pc_buf[256], header_len, desc_cnt; + int i, rc = 1, blocks, length; + + ide_debug_log(IDE_DBG_FUNC, "enter"); + drive->bios_cyl = 0; drive->bios_head = drive->bios_sect = 0; - floppy->blocks = floppy->bs_factor = 0; - set_capacity(floppy->disk, 0); + floppy->blocks = 0; + floppy->bs_factor = 1; + drive->capacity64 = 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"); + ide_floppy_create_read_capacity_cmd(&pc); + if (ide_queue_pc_tail(drive, disk, &pc, pc_buf, pc.req_xfer)) { + printk(KERN_ERR PFX "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); + header_len = pc_buf[3]; + cap_desc = &pc_buf[4]; + desc_cnt = header_len / 8; /* capacity descriptor of 8 bytes */ + + for (i = 0; i < desc_cnt; i++) { + unsigned int desc_start = 4 + i*8; + + blocks = be32_to_cpup((__be32 *)&pc_buf[desc_start]); + length = be16_to_cpup((__be16 *)&pc_buf[desc_start + 6]); + + ide_debug_log(IDE_DBG_PROBE, "Descriptor %d: %dkB, %d blocks, " + "%d sector size", + i, blocks * length / 1024, + blocks, length); - for (i = 0; i < descriptors; i++, descriptor++) { - blocks = descriptor->blocks = ntohl(descriptor->blocks); - length = descriptor->length = ntohs(descriptor->length); + if (i) + continue; + /* + * the code below is valid only for the 1st descriptor, ie i=0 + */ - if (!i) - { - switch (descriptor->dc) { + switch (pc_buf[desc_start + 4] & 0x03) { /* Clik! drive returns this instead of CAPACITY_CURRENT */ case CAPACITY_UNFORMATTED: - if (!test_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags)) - /* + if (!(drive->atapi_flags & IDE_AFLAG_CLIK_DRIVE)) + /* * If it is not a clik drive, break out * (maintains previous driver behaviour) */ break; case CAPACITY_CURRENT: /* Normal Zip/LS-120 disks */ - if (memcmp(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 (memcmp(cap_desc, &floppy->cap_desc, 8)) + printk(KERN_INFO PFX "%s: %dkB, %d blocks, %d " + "sector size\n", + drive->name, blocks * length / 1024, + blocks, length); + memcpy(&floppy->cap_desc, cap_desc, 8); + if (!length || length % 512) { - printk(KERN_NOTICE "%s: %d bytes block size " - "not supported\n", drive->name, length); + printk(KERN_NOTICE PFX "%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; + floppy->blocks = blocks; + floppy->block_size = length; + floppy->bs_factor = length / 512; + if (floppy->bs_factor != 1) + printk(KERN_NOTICE PFX "%s: Warning: " + "non 512 bytes block size not " + "fully supported\n", + drive->name); + drive->capacity64 = + floppy->blocks * floppy->bs_factor; + rc = 0; } break; case CAPACITY_NO_CARTRIDGE: @@ -1487,720 +452,91 @@ static int idefloppy_get_capacity (ide_drive_t *drive) * 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); + printk(KERN_ERR PFX "%s: No disk in drive\n", + drive->name); break; case CAPACITY_INVALID: - printk(KERN_ERR "%s: Invalid capacity for disk " + printk(KERN_ERR PFX "%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); + ide_debug_log(IDE_DBG_PROBE, "Descriptor 0 Code: %d", + pc_buf[desc_start + 4] & 0x03); } /* Clik! disk does not support get_flexible_disk_page */ - if (!test_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags)) { - (void) idefloppy_get_flexible_disk_page(drive); - } + if (!(drive->atapi_flags & IDE_AFLAG_CLIK_DRIVE)) + (void) ide_floppy_get_flexible_disk_page(drive, &pc); - 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) +static void ide_floppy_setup(ide_drive_t *drive) { - 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); - } + struct ide_disk_obj *floppy = drive->driver_data; + u16 *id = drive->id; - /* 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); - } + drive->pc_callback = ide_floppy_callback; - 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. + * 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. + * 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); + if (!strncmp((char *)&id[ATA_ID_PROD], "IOMEGA ZIP 100 ATAPI", 20)) { + drive->atapi_flags |= IDE_AFLAG_ZIP_DRIVE; /* This value will be visible in the /proc/ide/hdx/settings */ - floppy->ticks = IDEFLOPPY_TICKS_DELAY; - blk_queue_max_sectors(drive->queue, 64); + drive->pc_delay = IDEFLOPPY_PC_DELAY; + blk_queue_max_hw_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); + * Guess what? The IOMEGA Clik! drive also needs the above fix. It makes + * nasty clicking noises without it, so please don't remove this. + */ + if (strncmp((char *)&id[ATA_ID_PROD], "IOMEGA Clik!", 11) == 0) { + blk_queue_max_hw_sectors(drive->queue, 64); + drive->atapi_flags |= IDE_AFLAG_CLIK_DRIVE; + /* IOMEGA Clik! drives do not support lock/unlock commands */ + drive->dev_flags &= ~IDE_DFLAG_DOORLOCKING; } + (void) ide_floppy_get_capacity(drive); - (void) idefloppy_get_capacity(drive); - idefloppy_add_settings(drive); -} - -static void ide_floppy_remove(ide_drive_t *drive) -{ - idefloppy_floppy_t *floppy = drive->driver_data; - struct gendisk *g = floppy->disk; - - ide_unregister_subdriver(drive, floppy->driver); - - del_gendisk(g); + ide_proc_register_driver(drive, floppy->driver); - ide_floppy_put(floppy); + drive->dev_flags |= IDE_DFLAG_ATTACH; } -static void ide_floppy_release(struct kref *kref) +static void ide_floppy_flush(ide_drive_t *drive) { - 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) +static int ide_floppy_init_media(ide_drive_t *drive, struct gendisk *disk) { - 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 ide_floppy_probe(ide_drive_t *); - -static ide_driver_t idefloppy_driver = { - .gen_driver = { - .owner = THIS_MODULE, - .name = "ide-floppy", - .bus = &ide_bus_type, - }, - .probe = ide_floppy_probe, - .remove = ide_floppy_remove, - .version = IDEFLOPPY_VERSION, - .media = ide_floppy, - .supports_dsc_overlap = 0, - .do_request = idefloppy_do_request, - .end_request = idefloppy_do_end_request, - .error = __ide_error, - .abort = __ide_abort, - .proc = idefloppy_proc, -}; - -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 (ide_do_test_unit_ready(drive, disk)) + ide_do_start_stop(drive, disk, 1); - 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; - } + ret = ide_floppy_get_capacity(drive); - 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; + set_capacity(disk, ide_gd_capacity(drive)); -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_getgeo(struct block_device *bdev, struct hd_geometry *geo) -{ - struct ide_floppy_obj *floppy = ide_floppy_g(bdev->bd_disk); - ide_drive_t *drive = floppy->drive; - - geo->heads = drive->bios_head; - geo->sectors = drive->bios_sect; - geo->cylinders = (u16)drive->bios_cyl; /* truncate */ - 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; - int prevent = (arg) ? 1 : 0; - idefloppy_pc_t pc; - - 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 generic_ide_ioctl(drive, file, bdev, cmd, arg); -} - -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, - .getgeo = idefloppy_getgeo, - .media_changed = idefloppy_media_changed, - .revalidate_disk= idefloppy_revalidate_disk +const struct ide_disk_ops ide_atapi_disk_ops = { + .check = ide_check_atapi_device, + .get_capacity = ide_floppy_get_capacity, + .setup = ide_floppy_setup, + .flush = ide_floppy_flush, + .init_media = ide_floppy_init_media, + .set_doorlock = ide_set_media_lock, + .do_request = ide_floppy_do_request, + .ioctl = ide_floppy_ioctl, }; - -static int ide_floppy_probe(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 *) kzalloc (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); - - ide_register_subdriver(drive, &idefloppy_driver); - - kref_init(&floppy->kref); - - floppy->drive = drive; - floppy->driver = &idefloppy_driver; - floppy->disk = g; - - g->private_data = &floppy->driver; - - drive->driver_data = floppy; - - idefloppy_setup (drive, floppy); - - g->minors = 1 << PARTN_BITS; - g->driverfs_dev = &drive->gendev; - g->flags = drive->removable ? GENHD_FL_REMOVABLE : 0; - g->fops = &idefloppy_ops; - drive->attach = 1; - add_disk(g); - return 0; - -out_free_floppy: - kfree(floppy); -failed: - return -ENODEV; -} - -MODULE_DESCRIPTION("ATAPI FLOPPY Driver"); - -static void __exit idefloppy_exit (void) -{ - driver_unregister(&idefloppy_driver.gen_driver); -} - -static int __init idefloppy_init(void) -{ - printk("ide-floppy driver " IDEFLOPPY_VERSION "\n"); - return driver_register(&idefloppy_driver.gen_driver); -} - -MODULE_ALIAS("ide:*m-floppy*"); -module_init(idefloppy_init); -module_exit(idefloppy_exit); -MODULE_LICENSE("GPL"); diff --git a/drivers/ide/ide-floppy.h b/drivers/ide/ide-floppy.h new file mode 100644 index 00000000000..6dd2beb4843 --- /dev/null +++ b/drivers/ide/ide-floppy.h @@ -0,0 +1,39 @@ +#ifndef __IDE_FLOPPY_H +#define __IDE_FLOPPY_H + +#include "ide-gd.h" + +#ifdef CONFIG_IDE_GD_ATAPI +/* + * Pages of the SELECT SENSE / MODE SENSE packet commands. + * See SFF-8070i spec. + */ +#define IDEFLOPPY_CAPABILITIES_PAGE 0x1b +#define IDEFLOPPY_FLEXIBLE_DISK_PAGE 0x05 + +/* IOCTLs used in low-level formatting. */ +#define IDEFLOPPY_IOCTL_FORMAT_SUPPORTED 0x4600 +#define IDEFLOPPY_IOCTL_FORMAT_GET_CAPACITY 0x4601 +#define IDEFLOPPY_IOCTL_FORMAT_START 0x4602 +#define IDEFLOPPY_IOCTL_FORMAT_GET_PROGRESS 0x4603 + +/* ide-floppy.c */ +extern const struct ide_disk_ops ide_atapi_disk_ops; +void ide_floppy_create_mode_sense_cmd(struct ide_atapi_pc *, u8); +void ide_floppy_create_read_capacity_cmd(struct ide_atapi_pc *); + +/* ide-floppy_ioctl.c */ +int ide_floppy_ioctl(ide_drive_t *, struct block_device *, fmode_t, + unsigned int, unsigned long); + +#ifdef CONFIG_IDE_PROC_FS +/* ide-floppy_proc.c */ +extern ide_proc_entry_t ide_floppy_proc[]; +extern const struct ide_proc_devset ide_floppy_settings[]; +#endif +#else +#define ide_floppy_proc NULL +#define ide_floppy_settings NULL +#endif + +#endif /*__IDE_FLOPPY_H */ diff --git a/drivers/ide/ide-floppy_ioctl.c b/drivers/ide/ide-floppy_ioctl.c new file mode 100644 index 00000000000..a22ca846701 --- /dev/null +++ b/drivers/ide/ide-floppy_ioctl.c @@ -0,0 +1,303 @@ +/* + * ide-floppy IOCTLs handling. + */ + +#include <linux/kernel.h> +#include <linux/ide.h> +#include <linux/cdrom.h> +#include <linux/mutex.h> + +#include <asm/unaligned.h> + +#include <scsi/scsi_ioctl.h> + +#include "ide-floppy.h" + +/* + * Obtain the list of formattable capacities. + * Very similar to ide_floppy_get_capacity, except that we push the capacity + * descriptors to userland, instead of our own structures. + * + * Userland gives us the following structure: + * + * struct idefloppy_format_capacities { + * int nformats; + * struct { + * int nblocks; + * int blocksize; + * } formats[]; + * }; + * + * userland initializes nformats to the number of allocated formats[] records. + * On exit we set nformats to the number of records we've actually initialized. + */ + +static DEFINE_MUTEX(ide_floppy_ioctl_mutex); +static int ide_floppy_get_format_capacities(ide_drive_t *drive, + struct ide_atapi_pc *pc, + int __user *arg) +{ + struct ide_disk_obj *floppy = drive->driver_data; + int i, blocks, length, u_array_size, u_index; + int __user *argp; + u8 pc_buf[256], header_len, desc_cnt; + + if (get_user(u_array_size, arg)) + return -EFAULT; + + if (u_array_size <= 0) + return -EINVAL; + + ide_floppy_create_read_capacity_cmd(pc); + + if (ide_queue_pc_tail(drive, floppy->disk, pc, pc_buf, pc->req_xfer)) { + printk(KERN_ERR "ide-floppy: Can't get floppy parameters\n"); + return -EIO; + } + + header_len = pc_buf[3]; + desc_cnt = header_len / 8; /* capacity descriptor of 8 bytes */ + + u_index = 0; + argp = arg + 1; + + /* + * We always skip the first capacity descriptor. That's the current + * capacity. We are interested in the remaining descriptors, the + * formattable capacities. + */ + for (i = 1; i < desc_cnt; i++) { + unsigned int desc_start = 4 + i*8; + + if (u_index >= u_array_size) + break; /* User-supplied buffer too small */ + + blocks = be32_to_cpup((__be32 *)&pc_buf[desc_start]); + length = be16_to_cpup((__be16 *)&pc_buf[desc_start + 6]); + + if (put_user(blocks, argp)) + return -EFAULT; + + ++argp; + + if (put_user(length, argp)) + return -EFAULT; + + ++argp; + + ++u_index; + } + + if (put_user(u_index, arg)) + return -EFAULT; + + return 0; +} + +static void ide_floppy_create_format_unit_cmd(struct ide_atapi_pc *pc, + u8 *buf, int b, int l, + int flags) +{ + ide_init_pc(pc); + pc->c[0] = GPCMD_FORMAT_UNIT; + pc->c[1] = 0x17; + + memset(buf, 0, 12); + buf[1] = 0xA2; + /* Default format list header, u8 1: FOV/DCRT/IMM bits set */ + + if (flags & 1) /* Verify bit on... */ + buf[1] ^= 0x20; /* ... turn off DCRT bit */ + buf[3] = 8; + + put_unaligned(cpu_to_be32(b), (unsigned int *)(&buf[4])); + put_unaligned(cpu_to_be32(l), (unsigned int *)(&buf[8])); + pc->req_xfer = 12; + pc->flags |= PC_FLAG_WRITING; +} + +static int ide_floppy_get_sfrp_bit(ide_drive_t *drive, struct ide_atapi_pc *pc) +{ + struct ide_disk_obj *floppy = drive->driver_data; + u8 buf[20]; + + drive->atapi_flags &= ~IDE_AFLAG_SRFP; + + ide_floppy_create_mode_sense_cmd(pc, IDEFLOPPY_CAPABILITIES_PAGE); + pc->flags |= PC_FLAG_SUPPRESS_ERROR; + + if (ide_queue_pc_tail(drive, floppy->disk, pc, buf, pc->req_xfer)) + return 1; + + if (buf[8 + 2] & 0x40) + drive->atapi_flags |= IDE_AFLAG_SRFP; + + return 0; +} + +static int ide_floppy_format_unit(ide_drive_t *drive, struct ide_atapi_pc *pc, + int __user *arg) +{ + struct ide_disk_obj *floppy = drive->driver_data; + u8 buf[12]; + int blocks, length, flags, err = 0; + + if (floppy->openers > 1) { + /* Don't format if someone is using the disk */ + drive->dev_flags &= ~IDE_DFLAG_FORMAT_IN_PROGRESS; + return -EBUSY; + } + + drive->dev_flags |= IDE_DFLAG_FORMAT_IN_PROGRESS; + + /* + * Send ATAPI_FORMAT_UNIT to the drive. + * + * Userland gives us the following structure: + * + * struct idefloppy_format_command { + * int nblocks; + * int blocksize; + * int flags; + * } ; + * + * flags is a bitmask, currently, the only defined flag is: + * + * 0x01 - verify media after format. + */ + if (get_user(blocks, arg) || + get_user(length, arg+1) || + get_user(flags, arg+2)) { + err = -EFAULT; + goto out; + } + + ide_floppy_get_sfrp_bit(drive, pc); + ide_floppy_create_format_unit_cmd(pc, buf, blocks, length, flags); + + if (ide_queue_pc_tail(drive, floppy->disk, pc, buf, pc->req_xfer)) + err = -EIO; + +out: + if (err) + drive->dev_flags &= ~IDE_DFLAG_FORMAT_IN_PROGRESS; + return err; +} + +/* + * Get ATAPI_FORMAT_UNIT progress indication. + * + * Userland gives a pointer to an int. The int is set to a progress + * indicator 0-65536, with 65536=100%. + * + * If the drive does not support format progress indication, we just check + * the dsc bit, and return either 0 or 65536. + */ + +static int ide_floppy_get_format_progress(ide_drive_t *drive, + struct ide_atapi_pc *pc, + int __user *arg) +{ + struct ide_disk_obj *floppy = drive->driver_data; + u8 sense_buf[18]; + int progress_indication = 0x10000; + + if (drive->atapi_flags & IDE_AFLAG_SRFP) { + ide_create_request_sense_cmd(drive, pc); + if (ide_queue_pc_tail(drive, floppy->disk, pc, sense_buf, + pc->req_xfer)) + return -EIO; + + if (floppy->sense_key == 2 && + floppy->asc == 4 && + floppy->ascq == 4) + progress_indication = floppy->progress_indication; + + /* Else assume format_unit has finished, and we're at 0x10000 */ + } else { + ide_hwif_t *hwif = drive->hwif; + unsigned long flags; + u8 stat; + + local_irq_save(flags); + stat = hwif->tp_ops->read_status(hwif); + local_irq_restore(flags); + + progress_indication = ((stat & ATA_DSC) == 0) ? 0 : 0x10000; + } + + if (put_user(progress_indication, arg)) + return -EFAULT; + + return 0; +} + +static int ide_floppy_lockdoor(ide_drive_t *drive, struct ide_atapi_pc *pc, + unsigned long arg, unsigned int cmd) +{ + struct ide_disk_obj *floppy = drive->driver_data; + struct gendisk *disk = floppy->disk; + int prevent = (arg && cmd != CDROMEJECT) ? 1 : 0; + + if (floppy->openers > 1) + return -EBUSY; + + ide_set_media_lock(drive, disk, prevent); + + if (cmd == CDROMEJECT) + ide_do_start_stop(drive, disk, 2); + + return 0; +} + +static int ide_floppy_format_ioctl(ide_drive_t *drive, struct ide_atapi_pc *pc, + fmode_t mode, unsigned int cmd, + void __user *argp) +{ + switch (cmd) { + case IDEFLOPPY_IOCTL_FORMAT_SUPPORTED: + return 0; + case IDEFLOPPY_IOCTL_FORMAT_GET_CAPACITY: + return ide_floppy_get_format_capacities(drive, pc, argp); + case IDEFLOPPY_IOCTL_FORMAT_START: + if (!(mode & FMODE_WRITE)) + return -EPERM; + return ide_floppy_format_unit(drive, pc, (int __user *)argp); + case IDEFLOPPY_IOCTL_FORMAT_GET_PROGRESS: + return ide_floppy_get_format_progress(drive, pc, argp); + default: + return -ENOTTY; + } +} + +int ide_floppy_ioctl(ide_drive_t *drive, struct block_device *bdev, + fmode_t mode, unsigned int cmd, unsigned long arg) +{ + struct ide_atapi_pc pc; + void __user *argp = (void __user *)arg; + int err; + + mutex_lock(&ide_floppy_ioctl_mutex); + if (cmd == CDROMEJECT || cmd == CDROM_LOCKDOOR) { + err = ide_floppy_lockdoor(drive, &pc, arg, cmd); + goto out; + } + + err = ide_floppy_format_ioctl(drive, &pc, mode, cmd, argp); + if (err != -ENOTTY) + goto out; + + /* + * skip SCSI_IOCTL_SEND_COMMAND (deprecated) + * and CDROM_SEND_PACKET (legacy) ioctls + */ + if (cmd != CDROM_SEND_PACKET && cmd != SCSI_IOCTL_SEND_COMMAND) + err = scsi_cmd_blk_ioctl(bdev, mode, cmd, argp); + + if (err == -ENOTTY) + err = generic_ide_ioctl(drive, bdev, cmd, arg); + +out: + mutex_unlock(&ide_floppy_ioctl_mutex); + return err; +} diff --git a/drivers/ide/ide-floppy_proc.c b/drivers/ide/ide-floppy_proc.c new file mode 100644 index 00000000000..e7a25ea757d --- /dev/null +++ b/drivers/ide/ide-floppy_proc.c @@ -0,0 +1,46 @@ +#include <linux/kernel.h> +#include <linux/export.h> +#include <linux/ide.h> +#include <linux/seq_file.h> + +#include "ide-floppy.h" + +static int idefloppy_capacity_proc_show(struct seq_file *m, void *v) +{ + ide_drive_t*drive = (ide_drive_t *)m->private; + + seq_printf(m, "%llu\n", (long long)ide_gd_capacity(drive)); + return 0; +} + +static int idefloppy_capacity_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, idefloppy_capacity_proc_show, PDE_DATA(inode)); +} + +static const struct file_operations idefloppy_capacity_proc_fops = { + .owner = THIS_MODULE, + .open = idefloppy_capacity_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +ide_proc_entry_t ide_floppy_proc[] = { + { "capacity", S_IFREG|S_IRUGO, &idefloppy_capacity_proc_fops }, + { "geometry", S_IFREG|S_IRUGO, &ide_geometry_proc_fops }, + {} +}; + +ide_devset_rw_field(bios_cyl, bios_cyl); +ide_devset_rw_field(bios_head, bios_head); +ide_devset_rw_field(bios_sect, bios_sect); +ide_devset_rw_field(ticks, pc_delay); + +const struct ide_proc_devset ide_floppy_settings[] = { + IDE_PROC_DEVSET(bios_cyl, 0, 1023), + IDE_PROC_DEVSET(bios_head, 0, 255), + IDE_PROC_DEVSET(bios_sect, 0, 63), + IDE_PROC_DEVSET(ticks, 0, 255), + { NULL }, +}; diff --git a/drivers/ide/ide-gd.c b/drivers/ide/ide-gd.c new file mode 100644 index 00000000000..838996a0039 --- /dev/null +++ b/drivers/ide/ide-gd.c @@ -0,0 +1,449 @@ +#include <linux/module.h> +#include <linux/types.h> +#include <linux/string.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/genhd.h> +#include <linux/mutex.h> +#include <linux/ide.h> +#include <linux/hdreg.h> +#include <linux/dmi.h> +#include <linux/slab.h> + +#if !defined(CONFIG_DEBUG_BLOCK_EXT_DEVT) +#define IDE_DISK_MINORS (1 << PARTN_BITS) +#else +#define IDE_DISK_MINORS 0 +#endif + +#include "ide-disk.h" +#include "ide-floppy.h" + +#define IDE_GD_VERSION "1.18" + +/* module parameters */ +static DEFINE_MUTEX(ide_gd_mutex); +static unsigned long debug_mask; +module_param(debug_mask, ulong, 0644); + +static DEFINE_MUTEX(ide_disk_ref_mutex); + +static void ide_disk_release(struct device *); + +static struct ide_disk_obj *ide_disk_get(struct gendisk *disk) +{ + struct ide_disk_obj *idkp = NULL; + + mutex_lock(&ide_disk_ref_mutex); + idkp = ide_drv_g(disk, ide_disk_obj); + if (idkp) { + if (ide_device_get(idkp->drive)) + idkp = NULL; + else + get_device(&idkp->dev); + } + mutex_unlock(&ide_disk_ref_mutex); + return idkp; +} + +static void ide_disk_put(struct ide_disk_obj *idkp) +{ + ide_drive_t *drive = idkp->drive; + + mutex_lock(&ide_disk_ref_mutex); + put_device(&idkp->dev); + ide_device_put(drive); + mutex_unlock(&ide_disk_ref_mutex); +} + +sector_t ide_gd_capacity(ide_drive_t *drive) +{ + return drive->capacity64; +} + +static int ide_gd_probe(ide_drive_t *); + +static void ide_gd_remove(ide_drive_t *drive) +{ + struct ide_disk_obj *idkp = drive->driver_data; + struct gendisk *g = idkp->disk; + + ide_proc_unregister_driver(drive, idkp->driver); + device_del(&idkp->dev); + del_gendisk(g); + drive->disk_ops->flush(drive); + + mutex_lock(&ide_disk_ref_mutex); + put_device(&idkp->dev); + mutex_unlock(&ide_disk_ref_mutex); +} + +static void ide_disk_release(struct device *dev) +{ + struct ide_disk_obj *idkp = to_ide_drv(dev, ide_disk_obj); + ide_drive_t *drive = idkp->drive; + struct gendisk *g = idkp->disk; + + drive->disk_ops = NULL; + drive->driver_data = NULL; + g->private_data = NULL; + put_disk(g); + kfree(idkp); +} + +/* + * On HPA drives the capacity needs to be + * reinitialized on resume otherwise the disk + * can not be used and a hard reset is required + */ +static void ide_gd_resume(ide_drive_t *drive) +{ + if (ata_id_hpa_enabled(drive->id)) + (void)drive->disk_ops->get_capacity(drive); +} + +static const struct dmi_system_id ide_coldreboot_table[] = { + { + /* Acer TravelMate 66x cuts power during reboot */ + .ident = "Acer TravelMate 660", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 660"), + }, + }, + + { } /* terminate list */ +}; + +static void ide_gd_shutdown(ide_drive_t *drive) +{ +#ifdef CONFIG_ALPHA + /* On Alpha, halt(8) doesn't actually turn the machine off, + it puts you into the sort of firmware monitor. Typically, + it's used to boot another kernel image, so it's not much + different from reboot(8). Therefore, we don't need to + spin down the disk in this case, especially since Alpha + firmware doesn't handle disks in standby mode properly. + On the other hand, it's reasonably safe to turn the power + off when the shutdown process reaches the firmware prompt, + as the firmware initialization takes rather long time - + at least 10 seconds, which should be sufficient for + the disk to expire its write cache. */ + if (system_state != SYSTEM_POWER_OFF) { +#else + if (system_state == SYSTEM_RESTART && + !dmi_check_system(ide_coldreboot_table)) { +#endif + drive->disk_ops->flush(drive); + return; + } + + printk(KERN_INFO "Shutdown: %s\n", drive->name); + + drive->gendev.bus->suspend(&drive->gendev, PMSG_SUSPEND); +} + +#ifdef CONFIG_IDE_PROC_FS +static ide_proc_entry_t *ide_disk_proc_entries(ide_drive_t *drive) +{ + return (drive->media == ide_disk) ? ide_disk_proc : ide_floppy_proc; +} + +static const struct ide_proc_devset *ide_disk_proc_devsets(ide_drive_t *drive) +{ + return (drive->media == ide_disk) ? ide_disk_settings + : ide_floppy_settings; +} +#endif + +static ide_startstop_t ide_gd_do_request(ide_drive_t *drive, + struct request *rq, sector_t sector) +{ + return drive->disk_ops->do_request(drive, rq, sector); +} + +static struct ide_driver ide_gd_driver = { + .gen_driver = { + .owner = THIS_MODULE, + .name = "ide-gd", + .bus = &ide_bus_type, + }, + .probe = ide_gd_probe, + .remove = ide_gd_remove, + .resume = ide_gd_resume, + .shutdown = ide_gd_shutdown, + .version = IDE_GD_VERSION, + .do_request = ide_gd_do_request, +#ifdef CONFIG_IDE_PROC_FS + .proc_entries = ide_disk_proc_entries, + .proc_devsets = ide_disk_proc_devsets, +#endif +}; + +static int ide_gd_open(struct block_device *bdev, fmode_t mode) +{ + struct gendisk *disk = bdev->bd_disk; + struct ide_disk_obj *idkp; + ide_drive_t *drive; + int ret = 0; + + idkp = ide_disk_get(disk); + if (idkp == NULL) + return -ENXIO; + + drive = idkp->drive; + + ide_debug_log(IDE_DBG_FUNC, "enter"); + + idkp->openers++; + + if ((drive->dev_flags & IDE_DFLAG_REMOVABLE) && idkp->openers == 1) { + drive->dev_flags &= ~IDE_DFLAG_FORMAT_IN_PROGRESS; + /* Just in case */ + + ret = drive->disk_ops->init_media(drive, disk); + + /* + * Allow O_NDELAY to open a drive without a disk, or with an + * unreadable disk, so that we can get the format capacity + * of the drive or begin the format - Sam + */ + if (ret && (mode & FMODE_NDELAY) == 0) { + ret = -EIO; + goto out_put_idkp; + } + + if ((drive->dev_flags & IDE_DFLAG_WP) && (mode & FMODE_WRITE)) { + ret = -EROFS; + goto out_put_idkp; + } + + /* + * Ignore the return code from door_lock, + * since the open() has already succeeded, + * and the door_lock is irrelevant at this point. + */ + drive->disk_ops->set_doorlock(drive, disk, 1); + drive->dev_flags |= IDE_DFLAG_MEDIA_CHANGED; + check_disk_change(bdev); + } else if (drive->dev_flags & IDE_DFLAG_FORMAT_IN_PROGRESS) { + ret = -EBUSY; + goto out_put_idkp; + } + return 0; + +out_put_idkp: + idkp->openers--; + ide_disk_put(idkp); + return ret; +} + +static int ide_gd_unlocked_open(struct block_device *bdev, fmode_t mode) +{ + int ret; + + mutex_lock(&ide_gd_mutex); + ret = ide_gd_open(bdev, mode); + mutex_unlock(&ide_gd_mutex); + + return ret; +} + + +static void ide_gd_release(struct gendisk *disk, fmode_t mode) +{ + struct ide_disk_obj *idkp = ide_drv_g(disk, ide_disk_obj); + ide_drive_t *drive = idkp->drive; + + ide_debug_log(IDE_DBG_FUNC, "enter"); + + mutex_lock(&ide_gd_mutex); + if (idkp->openers == 1) + drive->disk_ops->flush(drive); + + if ((drive->dev_flags & IDE_DFLAG_REMOVABLE) && idkp->openers == 1) { + drive->disk_ops->set_doorlock(drive, disk, 0); + drive->dev_flags &= ~IDE_DFLAG_FORMAT_IN_PROGRESS; + } + + idkp->openers--; + + ide_disk_put(idkp); + mutex_unlock(&ide_gd_mutex); +} + +static int ide_gd_getgeo(struct block_device *bdev, struct hd_geometry *geo) +{ + struct ide_disk_obj *idkp = ide_drv_g(bdev->bd_disk, ide_disk_obj); + ide_drive_t *drive = idkp->drive; + + geo->heads = drive->bios_head; + geo->sectors = drive->bios_sect; + geo->cylinders = (u16)drive->bios_cyl; /* truncate */ + return 0; +} + +static unsigned int ide_gd_check_events(struct gendisk *disk, + unsigned int clearing) +{ + struct ide_disk_obj *idkp = ide_drv_g(disk, ide_disk_obj); + ide_drive_t *drive = idkp->drive; + bool ret; + + /* do not scan partitions twice if this is a removable device */ + if (drive->dev_flags & IDE_DFLAG_ATTACH) { + drive->dev_flags &= ~IDE_DFLAG_ATTACH; + return 0; + } + + /* + * The following is used to force revalidation on the first open on + * removeable devices, and never gets reported to userland as + * genhd->events is 0. This is intended as removeable ide disk + * can't really detect MEDIA_CHANGE events. + */ + ret = drive->dev_flags & IDE_DFLAG_MEDIA_CHANGED; + drive->dev_flags &= ~IDE_DFLAG_MEDIA_CHANGED; + + return ret ? DISK_EVENT_MEDIA_CHANGE : 0; +} + +static void ide_gd_unlock_native_capacity(struct gendisk *disk) +{ + struct ide_disk_obj *idkp = ide_drv_g(disk, ide_disk_obj); + ide_drive_t *drive = idkp->drive; + const struct ide_disk_ops *disk_ops = drive->disk_ops; + + if (disk_ops->unlock_native_capacity) + disk_ops->unlock_native_capacity(drive); +} + +static int ide_gd_revalidate_disk(struct gendisk *disk) +{ + struct ide_disk_obj *idkp = ide_drv_g(disk, ide_disk_obj); + ide_drive_t *drive = idkp->drive; + + if (ide_gd_check_events(disk, 0)) + drive->disk_ops->get_capacity(drive); + + set_capacity(disk, ide_gd_capacity(drive)); + return 0; +} + +static int ide_gd_ioctl(struct block_device *bdev, fmode_t mode, + unsigned int cmd, unsigned long arg) +{ + struct ide_disk_obj *idkp = ide_drv_g(bdev->bd_disk, ide_disk_obj); + ide_drive_t *drive = idkp->drive; + + return drive->disk_ops->ioctl(drive, bdev, mode, cmd, arg); +} + +static const struct block_device_operations ide_gd_ops = { + .owner = THIS_MODULE, + .open = ide_gd_unlocked_open, + .release = ide_gd_release, + .ioctl = ide_gd_ioctl, + .getgeo = ide_gd_getgeo, + .check_events = ide_gd_check_events, + .unlock_native_capacity = ide_gd_unlock_native_capacity, + .revalidate_disk = ide_gd_revalidate_disk +}; + +static int ide_gd_probe(ide_drive_t *drive) +{ + const struct ide_disk_ops *disk_ops = NULL; + struct ide_disk_obj *idkp; + struct gendisk *g; + + /* strstr("foo", "") is non-NULL */ + if (!strstr("ide-gd", drive->driver_req)) + goto failed; + +#ifdef CONFIG_IDE_GD_ATA + if (drive->media == ide_disk) + disk_ops = &ide_ata_disk_ops; +#endif +#ifdef CONFIG_IDE_GD_ATAPI + if (drive->media == ide_floppy) + disk_ops = &ide_atapi_disk_ops; +#endif + if (disk_ops == NULL) + goto failed; + + if (disk_ops->check(drive, DRV_NAME) == 0) { + printk(KERN_ERR PFX "%s: not supported by this driver\n", + drive->name); + goto failed; + } + + idkp = kzalloc(sizeof(*idkp), GFP_KERNEL); + if (!idkp) { + printk(KERN_ERR PFX "%s: can't allocate a disk structure\n", + drive->name); + goto failed; + } + + g = alloc_disk_node(IDE_DISK_MINORS, hwif_to_node(drive->hwif)); + if (!g) + goto out_free_idkp; + + ide_init_disk(g, drive); + + idkp->dev.parent = &drive->gendev; + idkp->dev.release = ide_disk_release; + dev_set_name(&idkp->dev, "%s", dev_name(&drive->gendev)); + + if (device_register(&idkp->dev)) + goto out_free_disk; + + idkp->drive = drive; + idkp->driver = &ide_gd_driver; + idkp->disk = g; + + g->private_data = &idkp->driver; + + drive->driver_data = idkp; + drive->debug_mask = debug_mask; + drive->disk_ops = disk_ops; + + disk_ops->setup(drive); + + set_capacity(g, ide_gd_capacity(drive)); + + g->minors = IDE_DISK_MINORS; + g->driverfs_dev = &drive->gendev; + g->flags |= GENHD_FL_EXT_DEVT; + if (drive->dev_flags & IDE_DFLAG_REMOVABLE) + g->flags = GENHD_FL_REMOVABLE; + g->fops = &ide_gd_ops; + add_disk(g); + return 0; + +out_free_disk: + put_disk(g); +out_free_idkp: + kfree(idkp); +failed: + return -ENODEV; +} + +static int __init ide_gd_init(void) +{ + printk(KERN_INFO DRV_NAME " driver " IDE_GD_VERSION "\n"); + return driver_register(&ide_gd_driver.gen_driver); +} + +static void __exit ide_gd_exit(void) +{ + driver_unregister(&ide_gd_driver.gen_driver); +} + +MODULE_ALIAS("ide:*m-disk*"); +MODULE_ALIAS("ide-disk"); +MODULE_ALIAS("ide:*m-floppy*"); +MODULE_ALIAS("ide-floppy"); +module_init(ide_gd_init); +module_exit(ide_gd_exit); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("generic ATA/ATAPI disk driver"); diff --git a/drivers/ide/ide-gd.h b/drivers/ide/ide-gd.h new file mode 100644 index 00000000000..55970772bd0 --- /dev/null +++ b/drivers/ide/ide-gd.h @@ -0,0 +1,42 @@ +#ifndef __IDE_GD_H +#define __IDE_GD_H + +#define DRV_NAME "ide-gd" +#define PFX DRV_NAME ": " + +/* define to see debug info */ +#define IDE_GD_DEBUG_LOG 0 + +#if IDE_GD_DEBUG_LOG +#define ide_debug_log(lvl, fmt, args...) __ide_debug_log(lvl, fmt, ## args) +#else +#define ide_debug_log(lvl, fmt, args...) do {} while (0) +#endif + +struct ide_disk_obj { + ide_drive_t *drive; + struct ide_driver *driver; + struct gendisk *disk; + struct device dev; + unsigned int openers; /* protected by BKL for now */ + + /* used for blk_{fs,pc}_request() requests */ + struct ide_atapi_pc queued_pc; + + /* Last error information */ + u8 sense_key, asc, ascq; + + int progress_indication; + + /* Device information */ + /* Current format */ + int blocks, block_size, bs_factor; + /* Last format capacity descriptor */ + u8 cap_desc[8]; + /* Copy of the flexible disk page */ + u8 flexible_disk_page[32]; +}; + +sector_t ide_gd_capacity(ide_drive_t *); + +#endif /* __IDE_GD_H */ diff --git a/drivers/ide/ide-generic.c b/drivers/ide/ide-generic.c index 99fd5615113..54d7c4685d2 100644 --- a/drivers/ide/ide-generic.c +++ b/drivers/ide/ide-generic.c @@ -1,7 +1,7 @@ /* * generic/default IDE host driver * - * Copyright (C) 2004 Bartlomiej Zolnierkiewicz + * Copyright (C) 2004, 2008-2009 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. @@ -11,20 +11,137 @@ #include <linux/init.h> #include <linux/module.h> #include <linux/ide.h> +#include <linux/pci_ids.h> + +/* FIXME: convert arm and m32r to use ide_platform host driver */ +#ifdef CONFIG_ARM +#include <asm/irq.h> +#endif +#ifdef CONFIG_M32R +#include <asm/m32r.h> +#endif + +#define DRV_NAME "ide_generic" + +static int probe_mask; +module_param(probe_mask, int, 0); +MODULE_PARM_DESC(probe_mask, "probe mask for legacy ISA IDE ports"); + +static const struct ide_port_info ide_generic_port_info = { + .host_flags = IDE_HFLAG_NO_DMA, + .chipset = ide_generic, +}; + +#ifdef CONFIG_ARM +static const u16 legacy_bases[] = { 0x1f0 }; +static const int legacy_irqs[] = { IRQ_HARDDISK }; +#elif defined(CONFIG_PLAT_M32700UT) || defined(CONFIG_PLAT_MAPPI2) || \ + defined(CONFIG_PLAT_OPSPUT) +static const u16 legacy_bases[] = { 0x1f0 }; +static const int legacy_irqs[] = { PLD_IRQ_CFIREQ }; +#elif defined(CONFIG_PLAT_MAPPI3) +static const u16 legacy_bases[] = { 0x1f0, 0x170 }; +static const int legacy_irqs[] = { PLD_IRQ_CFIREQ, PLD_IRQ_IDEIREQ }; +#elif defined(CONFIG_ALPHA) +static const u16 legacy_bases[] = { 0x1f0, 0x170, 0x1e8, 0x168 }; +static const int legacy_irqs[] = { 14, 15, 11, 10 }; +#else +static const u16 legacy_bases[] = { 0x1f0, 0x170, 0x1e8, 0x168, 0x1e0, 0x160 }; +static const int legacy_irqs[] = { 14, 15, 11, 10, 8, 12 }; +#endif + +static void ide_generic_check_pci_legacy_iobases(int *primary, int *secondary) +{ +#ifdef CONFIG_PCI + struct pci_dev *p = NULL; + u16 val; + + for_each_pci_dev(p) { + if (pci_resource_start(p, 0) == 0x1f0) + *primary = 1; + if (pci_resource_start(p, 2) == 0x170) + *secondary = 1; + + /* Cyrix CS55{1,2}0 pre SFF MWDMA ATA on the bridge */ + if (p->vendor == PCI_VENDOR_ID_CYRIX && + (p->device == PCI_DEVICE_ID_CYRIX_5510 || + p->device == PCI_DEVICE_ID_CYRIX_5520)) + *primary = *secondary = 1; + + /* Intel MPIIX - PIO ATA on non PCI side of bridge */ + if (p->vendor == PCI_VENDOR_ID_INTEL && + p->device == PCI_DEVICE_ID_INTEL_82371MX) { + pci_read_config_word(p, 0x6C, &val); + if (val & 0x8000) { + /* ATA port enabled */ + if (val & 0x4000) + *secondary = 1; + else + *primary = 1; + } + } + } +#endif +} static int __init ide_generic_init(void) { - if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET]) - ide_get_lock(NULL, NULL); /* for atari only */ + struct ide_hw hw, *hws[] = { &hw }; + unsigned long io_addr; + int i, rc = 0, primary = 0, secondary = 0; + + ide_generic_check_pci_legacy_iobases(&primary, &secondary); + + if (!probe_mask) { + printk(KERN_INFO DRV_NAME ": please use \"probe_mask=0x3f\" " + "module parameter for probing all legacy ISA IDE ports\n"); + + if (primary == 0) + probe_mask |= 0x1; + + if (secondary == 0) + probe_mask |= 0x2; + } else + printk(KERN_INFO DRV_NAME ": enforcing probing of I/O ports " + "upon user request\n"); + + for (i = 0; i < ARRAY_SIZE(legacy_bases); i++) { + io_addr = legacy_bases[i]; - (void)ideprobe_init(); + if ((probe_mask & (1 << i)) && io_addr) { + if (!request_region(io_addr, 8, DRV_NAME)) { + printk(KERN_ERR "%s: I/O resource 0x%lX-0x%lX " + "not free.\n", + DRV_NAME, io_addr, io_addr + 7); + rc = -EBUSY; + continue; + } - if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET]) - ide_release_lock(); /* for atari only */ + if (!request_region(io_addr + 0x206, 1, DRV_NAME)) { + printk(KERN_ERR "%s: I/O resource 0x%lX " + "not free.\n", + DRV_NAME, io_addr + 0x206); + release_region(io_addr, 8); + rc = -EBUSY; + continue; + } - create_proc_ide_interfaces(); + memset(&hw, 0, sizeof(hw)); + ide_std_init_ports(&hw, io_addr, io_addr + 0x206); +#ifdef CONFIG_IA64 + hw.irq = isa_irq_to_vector(legacy_irqs[i]); +#else + hw.irq = legacy_irqs[i]; +#endif + rc = ide_host_add(&ide_generic_port_info, hws, 1, NULL); + if (rc) { + release_region(io_addr + 0x206, 1); + release_region(io_addr, 8); + } + } + } - return 0; + return rc; } module_init(ide_generic_init); diff --git a/drivers/ide/ide-io-std.c b/drivers/ide/ide-io-std.c new file mode 100644 index 00000000000..19763977568 --- /dev/null +++ b/drivers/ide/ide-io-std.c @@ -0,0 +1,261 @@ + +#include <linux/kernel.h> +#include <linux/export.h> +#include <linux/ide.h> + +#if defined(CONFIG_ARM) || defined(CONFIG_M68K) || defined(CONFIG_MIPS) || \ + defined(CONFIG_PARISC) || defined(CONFIG_PPC) || defined(CONFIG_SPARC) +#include <asm/ide.h> +#else +#include <asm-generic/ide_iops.h> +#endif + +/* + * Conventional PIO operations for ATA devices + */ + +static u8 ide_inb(unsigned long port) +{ + return (u8) inb(port); +} + +static void ide_outb(u8 val, unsigned long port) +{ + outb(val, port); +} + +/* + * MMIO operations, typically used for SATA controllers + */ + +static u8 ide_mm_inb(unsigned long port) +{ + return (u8) readb((void __iomem *) port); +} + +static void ide_mm_outb(u8 value, unsigned long port) +{ + writeb(value, (void __iomem *) port); +} + +void ide_exec_command(ide_hwif_t *hwif, u8 cmd) +{ + if (hwif->host_flags & IDE_HFLAG_MMIO) + writeb(cmd, (void __iomem *)hwif->io_ports.command_addr); + else + outb(cmd, hwif->io_ports.command_addr); +} +EXPORT_SYMBOL_GPL(ide_exec_command); + +u8 ide_read_status(ide_hwif_t *hwif) +{ + if (hwif->host_flags & IDE_HFLAG_MMIO) + return readb((void __iomem *)hwif->io_ports.status_addr); + else + return inb(hwif->io_ports.status_addr); +} +EXPORT_SYMBOL_GPL(ide_read_status); + +u8 ide_read_altstatus(ide_hwif_t *hwif) +{ + if (hwif->host_flags & IDE_HFLAG_MMIO) + return readb((void __iomem *)hwif->io_ports.ctl_addr); + else + return inb(hwif->io_ports.ctl_addr); +} +EXPORT_SYMBOL_GPL(ide_read_altstatus); + +void ide_write_devctl(ide_hwif_t *hwif, u8 ctl) +{ + if (hwif->host_flags & IDE_HFLAG_MMIO) + writeb(ctl, (void __iomem *)hwif->io_ports.ctl_addr); + else + outb(ctl, hwif->io_ports.ctl_addr); +} +EXPORT_SYMBOL_GPL(ide_write_devctl); + +void ide_dev_select(ide_drive_t *drive) +{ + ide_hwif_t *hwif = drive->hwif; + u8 select = drive->select | ATA_DEVICE_OBS; + + if (hwif->host_flags & IDE_HFLAG_MMIO) + writeb(select, (void __iomem *)hwif->io_ports.device_addr); + else + outb(select, hwif->io_ports.device_addr); +} +EXPORT_SYMBOL_GPL(ide_dev_select); + +void ide_tf_load(ide_drive_t *drive, struct ide_taskfile *tf, u8 valid) +{ + ide_hwif_t *hwif = drive->hwif; + struct ide_io_ports *io_ports = &hwif->io_ports; + void (*tf_outb)(u8 addr, unsigned long port); + u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0; + + if (mmio) + tf_outb = ide_mm_outb; + else + tf_outb = ide_outb; + + if (valid & IDE_VALID_FEATURE) + tf_outb(tf->feature, io_ports->feature_addr); + if (valid & IDE_VALID_NSECT) + tf_outb(tf->nsect, io_ports->nsect_addr); + if (valid & IDE_VALID_LBAL) + tf_outb(tf->lbal, io_ports->lbal_addr); + if (valid & IDE_VALID_LBAM) + tf_outb(tf->lbam, io_ports->lbam_addr); + if (valid & IDE_VALID_LBAH) + tf_outb(tf->lbah, io_ports->lbah_addr); + if (valid & IDE_VALID_DEVICE) + tf_outb(tf->device, io_ports->device_addr); +} +EXPORT_SYMBOL_GPL(ide_tf_load); + +void ide_tf_read(ide_drive_t *drive, struct ide_taskfile *tf, u8 valid) +{ + ide_hwif_t *hwif = drive->hwif; + struct ide_io_ports *io_ports = &hwif->io_ports; + u8 (*tf_inb)(unsigned long port); + u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0; + + if (mmio) + tf_inb = ide_mm_inb; + else + tf_inb = ide_inb; + + if (valid & IDE_VALID_ERROR) + tf->error = tf_inb(io_ports->feature_addr); + if (valid & IDE_VALID_NSECT) + tf->nsect = tf_inb(io_ports->nsect_addr); + if (valid & IDE_VALID_LBAL) + tf->lbal = tf_inb(io_ports->lbal_addr); + if (valid & IDE_VALID_LBAM) + tf->lbam = tf_inb(io_ports->lbam_addr); + if (valid & IDE_VALID_LBAH) + tf->lbah = tf_inb(io_ports->lbah_addr); + if (valid & IDE_VALID_DEVICE) + tf->device = tf_inb(io_ports->device_addr); +} +EXPORT_SYMBOL_GPL(ide_tf_read); + +/* + * Some localbus EIDE interfaces require a special access sequence + * when using 32-bit I/O instructions to transfer data. We call this + * the "vlb_sync" sequence, which consists of three successive reads + * of the sector count register location, with interrupts disabled + * to ensure that the reads all happen together. + */ +static void ata_vlb_sync(unsigned long port) +{ + (void)inb(port); + (void)inb(port); + (void)inb(port); +} + +/* + * This is used for most PIO data transfers *from* the IDE interface + * + * These routines will round up any request for an odd number of bytes, + * so if an odd len is specified, be sure that there's at least one + * extra byte allocated for the buffer. + */ +void ide_input_data(ide_drive_t *drive, struct ide_cmd *cmd, void *buf, + unsigned int len) +{ + ide_hwif_t *hwif = drive->hwif; + struct ide_io_ports *io_ports = &hwif->io_ports; + unsigned long data_addr = io_ports->data_addr; + unsigned int words = (len + 1) >> 1; + u8 io_32bit = drive->io_32bit; + u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0; + + if (io_32bit) { + unsigned long uninitialized_var(flags); + + if ((io_32bit & 2) && !mmio) { + local_irq_save(flags); + ata_vlb_sync(io_ports->nsect_addr); + } + + words >>= 1; + if (mmio) + __ide_mm_insl((void __iomem *)data_addr, buf, words); + else + insl(data_addr, buf, words); + + if ((io_32bit & 2) && !mmio) + local_irq_restore(flags); + + if (((len + 1) & 3) < 2) + return; + + buf += len & ~3; + words = 1; + } + + if (mmio) + __ide_mm_insw((void __iomem *)data_addr, buf, words); + else + insw(data_addr, buf, words); +} +EXPORT_SYMBOL_GPL(ide_input_data); + +/* + * This is used for most PIO data transfers *to* the IDE interface + */ +void ide_output_data(ide_drive_t *drive, struct ide_cmd *cmd, void *buf, + unsigned int len) +{ + ide_hwif_t *hwif = drive->hwif; + struct ide_io_ports *io_ports = &hwif->io_ports; + unsigned long data_addr = io_ports->data_addr; + unsigned int words = (len + 1) >> 1; + u8 io_32bit = drive->io_32bit; + u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0; + + if (io_32bit) { + unsigned long uninitialized_var(flags); + + if ((io_32bit & 2) && !mmio) { + local_irq_save(flags); + ata_vlb_sync(io_ports->nsect_addr); + } + + words >>= 1; + if (mmio) + __ide_mm_outsl((void __iomem *)data_addr, buf, words); + else + outsl(data_addr, buf, words); + + if ((io_32bit & 2) && !mmio) + local_irq_restore(flags); + + if (((len + 1) & 3) < 2) + return; + + buf += len & ~3; + words = 1; + } + + if (mmio) + __ide_mm_outsw((void __iomem *)data_addr, buf, words); + else + outsw(data_addr, buf, words); +} +EXPORT_SYMBOL_GPL(ide_output_data); + +const struct ide_tp_ops default_tp_ops = { + .exec_command = ide_exec_command, + .read_status = ide_read_status, + .read_altstatus = ide_read_altstatus, + .write_devctl = ide_write_devctl, + + .dev_select = ide_dev_select, + .tf_load = ide_tf_load, + .tf_read = ide_tf_read, + + .input_data = ide_input_data, + .output_data = ide_output_data, +}; diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c index fb6795236e7..177db6d5b2f 100644 --- a/drivers/ide/ide-io.c +++ b/drivers/ide/ide-io.c @@ -47,785 +47,195 @@ #include <linux/device.h> #include <linux/kmod.h> #include <linux/scatterlist.h> +#include <linux/bitops.h> #include <asm/byteorder.h> #include <asm/irq.h> #include <asm/uaccess.h> #include <asm/io.h> -#include <asm/bitops.h> -static int __ide_end_request(ide_drive_t *drive, struct request *rq, - int uptodate, int nr_sectors) +int ide_end_rq(ide_drive_t *drive, struct request *rq, int error, + unsigned int nr_bytes) { - 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 ((drive->dev_flags & IDE_DFLAG_DMA_PIO_RETRY) && + drive->retry_pio <= 3) { + drive->dev_flags &= ~IDE_DFLAG_DMA_PIO_RETRY; + ide_dma_on(drive); } - if (!end_that_request_first(rq, uptodate, nr_sectors)) { - add_disk_randomness(rq->rq_disk); - blkdev_dequeue_request(rq); - HWGROUP(drive)->rq = NULL; - end_that_request_last(rq, uptodate); - ret = 0; - } - - return ret; + return blk_end_request(rq, error, nr_bytes); } +EXPORT_SYMBOL_GPL(ide_end_rq); -/** - * 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) +void ide_complete_cmd(ide_drive_t *drive, struct ide_cmd *cmd, u8 stat, u8 err) { - struct request *rq; - unsigned long flags; - int ret = 1; + const struct ide_tp_ops *tp_ops = drive->hwif->tp_ops; + struct ide_taskfile *tf = &cmd->tf; + struct request *rq = cmd->rq; + u8 tf_cmd = tf->command; - /* - * room for locking improvements here, the calls below don't - * need the queue lock held at all - */ - spin_lock_irqsave(&ide_lock, flags); - rq = HWGROUP(drive)->rq; + tf->error = err; + tf->status = stat; - if (!nr_sectors) - nr_sectors = rq->hard_cur_sectors; + if (cmd->ftf_flags & IDE_FTFLAG_IN_DATA) { + u8 data[2]; - 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... - */ + tp_ops->input_data(drive, cmd, data, 2); -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) -{ - struct request_pm_state *pm = rq->end_io_data; - - if (drive->media != ide_disk) - return; - - switch (pm->pm_step) { - case ide_pm_flush_cache: /* Suspend step 1 (flush cache) complete */ - if (pm->pm_state == PM_EVENT_FREEZE) - pm->pm_step = ide_pm_state_completed; - else - pm->pm_step = idedisk_pm_standby; - break; - case idedisk_pm_standby: /* Suspend step 2 (standby) complete */ - pm->pm_step = ide_pm_state_completed; - break; - case idedisk_pm_idle: /* Resume step 1 (idle) complete */ - pm->pm_step = ide_pm_restore_dma; - break; + cmd->tf.data = data[0]; + cmd->hob.data = data[1]; } -} - -static ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request *rq) -{ - struct request_pm_state *pm = rq->end_io_data; - ide_task_t *args = rq->special; - memset(args, 0, sizeof(*args)); + ide_tf_readback(drive, cmd); - if (drive->media != ide_disk) { - /* skip idedisk_pm_idle for ATAPI devices */ - if (pm->pm_step == idedisk_pm_idle) - pm->pm_step = ide_pm_restore_dma; + if ((cmd->tf_flags & IDE_TFLAG_CUSTOM_HANDLER) && + tf_cmd == ATA_CMD_IDLEIMMEDIATE) { + if (tf->lbal != 0xc4) { + printk(KERN_ERR "%s: head unload failed!\n", + drive->name); + ide_tf_dump(drive->name, cmd); + } else + drive->dev_flags |= IDE_DFLAG_PARKED; } - switch (pm->pm_step) { - case ide_pm_flush_cache: /* Suspend step 1 (flush cache) */ - if (drive->media != ide_disk) - break; - /* Not supported? Switch to next step now. */ - if (!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; + if (rq && rq->cmd_type == REQ_TYPE_ATA_TASKFILE) { + struct ide_cmd *orig_cmd = rq->special; + + if (cmd->tf_flags & IDE_TFLAG_DYN) + kfree(orig_cmd); 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; + memcpy(orig_cmd, cmd, sizeof(*cmd)); } - pm->pm_step = ide_pm_state_completed; - return ide_stopped; } -/** - * ide_end_dequeued_request - complete an IDE I/O - * @drive: IDE device for the I/O - * @uptodate: - * @nr_sectors: number of sectors completed - * - * Complete an I/O that is no longer on the request queue. This - * typically occurs when we pull the request and issue a REQUEST_SENSE. - * We must still finish the old request but we must not tamper with the - * queue in the meantime. - * - * NOTE: This path does not handle barrier, but barrier is not supported - * on ide-cd anyway. - */ - -int ide_end_dequeued_request(ide_drive_t *drive, struct request *rq, - int uptodate, int nr_sectors) +int ide_complete_rq(ide_drive_t *drive, int error, unsigned int nr_bytes) { - unsigned long flags; - int ret = 1; - - spin_lock_irqsave(&ide_lock, flags); - - BUG_ON(!(rq->flags & REQ_STARTED)); + ide_hwif_t *hwif = drive->hwif; + struct request *rq = hwif->rq; + int rc; /* - * if failfast is set on a request, override number of sectors and - * complete the whole request right now + * 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; + if (blk_noretry_request(rq) && error <= 0) + nr_bytes = blk_rq_sectors(rq) << 9; - /* - * 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); - } + rc = ide_end_rq(drive, rq, error, nr_bytes); + if (rc == 0) + hwif->rq = NULL; - 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); - end_that_request_last(rq, uptodate); - ret = 0; - } - spin_unlock_irqrestore(&ide_lock, flags); - return ret; + return rc; } -EXPORT_SYMBOL_GPL(ide_end_dequeued_request); +EXPORT_SYMBOL(ide_complete_rq); - -/** - * 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) +void ide_kill_rq(ide_drive_t *drive, struct request *rq) { - unsigned long flags; + u8 drv_req = (rq->cmd_type == REQ_TYPE_SPECIAL) && rq->rq_disk; + u8 media = drive->media; -#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, 1); - spin_unlock_irqrestore(&ide_lock, flags); -} + drive->failed_pc = NULL; -/* - * 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); + if ((media == ide_floppy || media == ide_tape) && drv_req) { + rq->errors = 0; } 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; - } + if (media == ide_tape) + rq->errors = IDE_DRV_ERROR_GENERAL; + else if (rq->cmd_type != REQ_TYPE_FS && rq->errors == 0) + rq->errors = -EIO; } - sector = ((u64) high << 24) | low; - return sector; + ide_complete_rq(drive, -EIO, blk_rq_bytes(rq)); } -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) +static void ide_tf_set_specify_cmd(ide_drive_t *drive, struct ide_taskfile *tf) { - 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)) { - struct request_pm_state *pm = rq->end_io_data; -#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 (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, !rq->errors); - spin_unlock_irqrestore(&ide_lock, flags); + tf->nsect = drive->sect; + tf->lbal = drive->sect; + tf->lbam = drive->cyl; + tf->lbah = drive->cyl >> 8; + tf->device = (drive->head - 1) | drive->select; + tf->command = ATA_CMD_INIT_DEV_PARAMS; } -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) +static void ide_tf_set_restore_cmd(ide_drive_t *drive, struct ide_taskfile *tf) { - 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); - } + tf->nsect = drive->sect; + tf->command = ATA_CMD_RESTORE; } -static void ide_kill_rq(ide_drive_t *drive, struct request *rq) +static void ide_tf_set_setmult_cmd(ide_drive_t *drive, struct ide_taskfile *tf) { - 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); + tf->nsect = drive->mult_req; + tf->command = ATA_CMD_SET_MULTI; } -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 && hwif->err_stops_fifo == 0) - 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 + * do_special - issue some special commands + * @drive: drive the command is for * - * 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 + * do_special() is used to issue ATA_CMD_INIT_DEV_PARAMS, + * ATA_CMD_RESTORE and ATA_CMD_SET_MULTI commands to a drive. */ - -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 operations - * @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) +static ide_startstop_t do_special(ide_drive_t *drive) { - struct request *rq; - - if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL) - return ide_stopped; + struct ide_cmd cmd; - /* 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); +#ifdef DEBUG + printk(KERN_DEBUG "%s: %s: 0x%02x\n", drive->name, __func__, + drive->special_flags); +#endif + if (drive->media != ide_disk) { + drive->special_flags = 0; + drive->mult_req = 0; return ide_stopped; } - if (rq->rq_disk) { - ide_driver_t *drv; + memset(&cmd, 0, sizeof(cmd)); + cmd.protocol = ATA_PROT_NODATA; - drv = *(ide_driver_t **)rq->rq_disk->private_data; - return drv->abort(drive, rq); + if (drive->special_flags & IDE_SFLAG_SET_GEOMETRY) { + drive->special_flags &= ~IDE_SFLAG_SET_GEOMETRY; + ide_tf_set_specify_cmd(drive, &cmd.tf); + } else if (drive->special_flags & IDE_SFLAG_RECALIBRATE) { + drive->special_flags &= ~IDE_SFLAG_RECALIBRATE; + ide_tf_set_restore_cmd(drive, &cmd.tf); + } else if (drive->special_flags & IDE_SFLAG_SET_MULTMODE) { + drive->special_flags &= ~IDE_SFLAG_SET_MULTMODE; + ide_tf_set_setmult_cmd(drive, &cmd.tf); } 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 data 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_in_hardirq(); - 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; -} + BUG(); -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; -} + cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE; + cmd.valid.in.tf = IDE_VALID_IN_TF | IDE_VALID_DEVICE; + cmd.tf_flags = IDE_TFLAG_CUSTOM_HANDLER; -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); + do_rw_taskfile(drive, &cmd); 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) +void ide_map_sg(ide_drive_t *drive, struct ide_cmd *cmd) { ide_hwif_t *hwif = drive->hwif; struct scatterlist *sg = hwif->sg_table; + struct request *rq = cmd->rq; - 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; - } + cmd->sg_nents = blk_rq_map_sg(drive->queue, rq, sg); } - EXPORT_SYMBOL_GPL(ide_map_sg); -void ide_init_sg_cmd(ide_drive_t *drive, struct request *rq) +void ide_init_sg_cmd(struct ide_cmd *cmd, unsigned int nr_bytes) { - ide_hwif_t *hwif = drive->hwif; - - hwif->nsect = hwif->nleft = rq->nr_sectors; - hwif->cursg = hwif->cursg_ofs = 0; + cmd->nbytes = cmd->nleft = nr_bytes; + cmd->cursg_ofs = 0; + cmd->cursg = NULL; } - EXPORT_SYMBOL_GPL(ide_init_sg_cmd); /** @@ -843,81 +253,17 @@ EXPORT_SYMBOL_GPL(ide_init_sg_cmd); 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; + struct ide_cmd *cmd = rq->special; + + if (cmd) { + if (cmd->protocol == ATA_PROT_PIO) { + ide_init_sg_cmd(cmd, blk_rq_sectors(rq) << 9); + ide_map_sg(drive, cmd); } - 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: + return do_rw_taskfile(drive, cmd); + } + /* * NULL is actually a valid way of waiting for * all current requests to be flushed from the queue. @@ -925,42 +271,26 @@ done: #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)); + rq->errors = 0; + ide_complete_rq(drive, 0, blk_rq_bytes(rq)); + return ide_stopped; } -static void ide_check_pm_state(ide_drive_t *drive, struct request *rq) +static ide_startstop_t ide_special_rq(ide_drive_t *drive, struct request *rq) { - struct request_pm_state *pm = rq->end_io_data; - - if (blk_pm_suspend_request(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) && - 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), 100000); - if (rc) - printk(KERN_WARNING "%s: drive not ready on wakeup\n", drive->name); + u8 cmd = rq->cmd[0]; + + switch (cmd) { + case REQ_PARK_HEADS: + case REQ_UNPARK_HEADS: + return ide_do_park_unpark(drive, rq); + case REQ_DEVSET_EXEC: + return ide_do_devset(drive, rq); + case REQ_DRIVE_RESET: + return ide_do_reset(drive); + default: + BUG(); } } @@ -968,9 +298,7 @@ static void ide_check_pm_state(ide_drive_t *drive, struct request *rq) * 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 + * accepts commands and I/O (read/write) requests. * * FIXME: this function needs a rename */ @@ -978,60 +306,67 @@ static void ide_check_pm_state(ide_drive_t *drive, struct request *rq) 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)); + BUG_ON(!(rq->cmd_flags & REQ_STARTED)); #ifdef DEBUG printk("%s: start_request: current=0x%08lx\n", - HWIF(drive)->name, (unsigned long) rq); + drive->hwif->name, (unsigned long) rq); #endif /* bail early if we've exceeded max_failures */ if (drive->max_failures && (drive->failures > drive->max_failures)) { + rq->cmd_flags |= REQ_FAILED; goto kill_rq; } - 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_request(rq)) ide_check_pm_state(drive, rq); - SELECT_DRIVE(drive); - if (ide_wait_stat(&startstop, drive, drive->ready_stat, BUSY_STAT|DRQ_STAT, WAIT_READY)) { + drive->hwif->tp_ops->dev_select(drive); + if (ide_wait_stat(&startstop, drive, drive->ready_stat, + ATA_BUSY | ATA_DRQ, WAIT_READY)) { printk(KERN_ERR "%s: drive not ready for command\n", drive->name); return startstop; } - if (!drive->special.all) { - ide_driver_t *drv; - if (rq->flags & (REQ_DRIVE_CMD | REQ_DRIVE_TASK)) - return execute_drive_cmd(drive, rq); - else if (rq->flags & REQ_DRIVE_TASKFILE) + if (drive->special_flags == 0) { + struct ide_driver *drv; + + /* + * We reset the drive so we need to issue a SETFEATURES. + * Do it _after_ do_special() restored device parameters. + */ + if (drive->current_speed == 0xff) + ide_config_drive_speed(drive, drive->desired_speed); + + if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) return execute_drive_cmd(drive, rq); else if (blk_pm_request(rq)) { - struct request_pm_state *pm = rq->end_io_data; + struct request_pm_state *pm = rq->special; #ifdef DEBUG_PM printk("%s: start_power_step(step: %d)\n", - drive->name, rq->pm->pm_step); + drive->name, pm->pm_step); #endif startstop = ide_start_power_step(drive, rq); if (startstop == ide_stopped && - pm->pm_step == ide_pm_state_completed) - ide_complete_pm_request(drive, rq); + pm->pm_step == IDE_PM_COMPLETED) + ide_complete_pm_rq(drive, rq); return startstop; - } + } else if (!rq->rq_disk && rq->cmd_type == REQ_TYPE_SPECIAL) + /* + * TODO: Once all ULDs have been modified to + * check for specific op codes rather than + * blindly accepting any special request, the + * check for ->rq_disk above may be replaced + * by a more suitable mechanism or even + * dropped entirely. + */ + return ide_special_rq(drive, rq); + + drv = *(struct ide_driver **)rq->rq_disk->private_data; - drv = *(ide_driver_t **)rq->rq_disk->private_data; - return drv->do_request(drive, rq, block); + return drv->do_request(drive, rq, blk_rq_pos(rq)); } return do_special(drive); kill_rq: @@ -1045,7 +380,7 @@ kill_rq: * @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. + * to the port by sleeping for timeout jiffies. */ void ide_stall_queue (ide_drive_t *drive, unsigned long timeout) @@ -1053,205 +388,146 @@ 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; + drive->dev_flags |= IDE_DFLAG_SLEEPING; } - EXPORT_SYMBOL(ide_stall_queue); -#define WAKEUP(drive) ((drive)->service_start + 2 * (drive)->service_time) +static inline int ide_lock_port(ide_hwif_t *hwif) +{ + if (hwif->busy) + return 1; -/** - * 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) + hwif->busy = 1; + + return 0; +} + +static inline void ide_unlock_port(ide_hwif_t *hwif) { - ide_drive_t *drive, *best; + hwif->busy = 0; +} -repeat: - best = NULL; - drive = hwgroup->drive; +static inline int ide_lock_host(struct ide_host *host, ide_hwif_t *hwif) +{ + int rc = 0; - /* - * 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; + if (host->host_flags & IDE_HFLAG_SERIALIZE) { + rc = test_and_set_bit_lock(IDE_HOST_BUSY, &host->host_busy); + if (rc == 0) { + if (host->get_lock) + host->get_lock(ide_intr, hwif); + } } + return rc; +} - 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); - } +static inline void ide_unlock_host(struct ide_host *host) +{ + if (host->host_flags & IDE_HFLAG_SERIALIZE) { + if (host->release_lock) + host->release_lock(); + clear_bit_unlock(IDE_HOST_BUSY, &host->host_busy); } - return best; +} + +static void __ide_requeue_and_plug(struct request_queue *q, struct request *rq) +{ + if (rq) + blk_requeue_request(q, rq); + if (rq || blk_peek_request(q)) { + /* Use 3ms as that was the old plug delay */ + blk_delay_queue(q, 3); + } +} + +void ide_requeue_and_plug(ide_drive_t *drive, struct request *rq) +{ + struct request_queue *q = drive->queue; + unsigned long flags; + + spin_lock_irqsave(q->queue_lock, flags); + __ide_requeue_and_plug(q, rq); + spin_unlock_irqrestore(q->queue_lock, flags); } /* - * 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. + * Issue a new request to a device. */ -static void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq) +void do_ide_request(struct request_queue *q) { - ide_drive_t *drive; - ide_hwif_t *hwif; - struct request *rq; + ide_drive_t *drive = q->queuedata; + ide_hwif_t *hwif = drive->hwif; + struct ide_host *host = hwif->host; + struct request *rq = NULL; ide_startstop_t startstop; - int loops = 0; - - /* 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; - } + unsigned long queue_run_ms = 3; /* old plug delay */ - /* no more work for this hwgroup (for now) */ - return; - } - again: - 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); + spin_unlock_irq(q->queue_lock); + + /* HLD do_request() callback might sleep, make sure it's okay */ + might_sleep(); + + if (ide_lock_host(host, hwif)) + goto plug_device_2; + + spin_lock_irq(&hwif->lock); + + if (!ide_lock_port(hwif)) { + ide_hwif_t *prev_port; + + WARN_ON_ONCE(hwif->rq); +repeat: + prev_port = hwif->host->cur_port; + if (drive->dev_flags & IDE_DFLAG_SLEEPING && + time_after(drive->sleep, jiffies)) { + unsigned long left = jiffies - drive->sleep; + + queue_run_ms = jiffies_to_msecs(left + 1); + ide_unlock_port(hwif); + goto plug_device; } - 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; + + if ((hwif->host->host_flags & IDE_HFLAG_SERIALIZE) && + hwif != prev_port) { + ide_drive_t *cur_dev = + prev_port ? prev_port->cur_dev : NULL; + + /* + * set nIEN for previous port, drives in the + * quirk list may not like intr setups/cleanups + */ + if (cur_dev && + (cur_dev->dev_flags & IDE_DFLAG_NIEN_QUIRK) == 0) + prev_port->tp_ops->write_devctl(prev_port, + ATA_NIEN | + ATA_DEVCTL_OBS); + + hwif->host->cur_port = hwif; } + hwif->cur_dev = drive; + drive->dev_flags &= ~(IDE_DFLAG_SLEEPING | IDE_DFLAG_PARKED); + spin_unlock_irq(&hwif->lock); + spin_lock_irq(q->queue_lock); /* * 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) + rq = blk_fetch_request(drive->queue); + + spin_unlock_irq(q->queue_lock); + spin_lock_irq(&hwif->lock); + if (!rq) { - hwgroup->busy = 0; - break; + ide_unlock_port(hwif); + goto out; } /* * 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() + * blk_stop_queue() doesn't prevent the blk_fetch_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... @@ -1260,110 +536,69 @@ static void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq) * though. I hope that doesn't happen too much, hopefully not * unless the subdriver triggers such a thing in its own PM * state machine. - * - * We count how many times we loop here to make sure we service - * all drives in the hwgroup without looping for ever */ - if (drive->blocked && !blk_pm_request(rq) && !(rq->flags & REQ_PREEMPT)) { - drive = drive->next ? drive->next : hwgroup->drive; - if (loops++ < 4 && !blk_queue_plugged(drive->queue)) - goto again; - /* We clear busy, there should be no pending ATA command at this point. */ - hwgroup->busy = 0; - break; + if ((drive->dev_flags & IDE_DFLAG_BLOCKED) && + blk_pm_request(rq) == 0 && + (rq->cmd_flags & REQ_PREEMPT) == 0) { + /* there should be no pending command at this point */ + ide_unlock_port(hwif); + goto plug_device; } - hwgroup->rq = rq; + hwif->rq = rq; - /* - * Some systems have trouble with IDE IRQs arriving while - * the driver is still setting things up. So, here we disable - * the IRQ used by this interface while the request is being started. - * This may look bad at first, but pretty much the same thing - * happens anyway when any interrupt comes in, IDE or otherwise - * -- the kernel masks the IRQ while it is being handled. - */ - if (masked_irq != IDE_NO_IRQ && hwif->irq != masked_irq) - disable_irq_nosync(hwif->irq); - spin_unlock(&ide_lock); - local_irq_enable_in_hardirq(); - /* allow other IRQs while we start this request */ + spin_unlock_irq(&hwif->lock); 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; - } -} + spin_lock_irq(&hwif->lock); -/* - * Passes the stuff to ide_do_request - */ -void do_ide_request(request_queue_t *q) -{ - ide_drive_t *drive = q->queuedata; + if (startstop == ide_stopped) { + rq = hwif->rq; + hwif->rq = NULL; + goto repeat; + } + } else + goto plug_device; +out: + spin_unlock_irq(&hwif->lock); + if (rq == NULL) + ide_unlock_host(host); + spin_lock_irq(q->queue_lock); + return; - ide_do_request(HWGROUP(drive), IDE_NO_IRQ); +plug_device: + spin_unlock_irq(&hwif->lock); + ide_unlock_host(host); +plug_device_2: + spin_lock_irq(q->queue_lock); + __ide_requeue_and_plug(q, rq); } -/* - * 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) +static int drive_is_ready(ide_drive_t *drive) { - 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); + ide_hwif_t *hwif = drive->hwif; + u8 stat = 0; - /* - * un-busy drive etc (hwgroup->busy is cleared on return) and - * make sure request is sane - */ - rq = HWGROUP(drive)->rq; - HWGROUP(drive)->rq = NULL; + if (drive->waiting_for_dma) + return hwif->dma_ops->dma_test_irq(drive); - rq->errors = 0; + if (hwif->io_ports.ctl_addr && + (hwif->host_flags & IDE_HFLAG_BROKEN_ALTSTATUS) == 0) + stat = hwif->tp_ops->read_altstatus(hwif); + else + /* Note: this may clear a pending IRQ!! */ + stat = hwif->tp_ops->read_status(hwif); - if (!rq->bio) - goto out; + if (stat & ATA_BUSY) + /* drive busy: definitely not interrupting */ + return 0; - 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; + /* drive ready: *might* be interrupting */ + return 1; } /** * ide_timer_expiry - handle lack of an IDE interrupt - * @data: timer callback magic (hwgroup) + * @data: timer callback magic (hwif) * * An IDE command has timed out before the expected drive return * occurred. At this point we attempt to clean up the current @@ -1377,94 +612,93 @@ out: void ide_timer_expiry (unsigned long data) { - ide_hwgroup_t *hwgroup = (ide_hwgroup_t *) data; + ide_hwif_t *hwif = (ide_hwif_t *)data; + ide_drive_t *uninitialized_var(drive); ide_handler_t *handler; - ide_expiry_t *expiry; unsigned long flags; - unsigned long wait = -1; + int wait = -1; + int plug_device = 0; + struct request *uninitialized_var(rq_in_flight); + + spin_lock_irqsave(&hwif->lock, flags); - spin_lock_irqsave(&ide_lock, flags); + handler = hwif->handler; - if ((handler = hwgroup->handler) == NULL) { + if (handler == NULL || hwif->req_gen != hwif->req_gen_timer) { /* * Either a marginal timeout occurred * (got the interrupt just as timer expired), * or we were "sleeping" to give other devices a chance. * Either way, we don't really want to complain about anything. */ - if (hwgroup->sleeping) { - hwgroup->sleeping = 0; - hwgroup->busy = 0; - } } else { - ide_drive_t *drive = hwgroup->drive; - if (!drive) { - printk(KERN_ERR "ide_timer_expiry: hwgroup->drive was NULL\n"); - hwgroup->handler = NULL; - } else { - ide_hwif_t *hwif; - ide_startstop_t startstop = ide_stopped; - if (!hwgroup->busy) { - hwgroup->busy = 1; /* paranoia */ - printk(KERN_ERR "%s: ide_timer_expiry: hwgroup->busy was 0 ??\n", drive->name); + ide_expiry_t *expiry = hwif->expiry; + ide_startstop_t startstop = ide_stopped; + + drive = hwif->cur_dev; + + if (expiry) { + wait = expiry(drive); + if (wait > 0) { /* continue */ + /* reset timer */ + hwif->timer.expires = jiffies + wait; + hwif->req_gen_timer = hwif->req_gen; + add_timer(&hwif->timer); + spin_unlock_irqrestore(&hwif->lock, flags); + return; } - 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; + } + hwif->handler = NULL; + hwif->expiry = 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(&hwif->lock); + /* disable_irq_nosync ?? */ + disable_irq(hwif->irq); + /* local CPU only, as if we were handling an interrupt */ + local_irq_disable(); + if (hwif->polling) { + startstop = handler(drive); + } else if (drive_is_ready(drive)) { + if (drive->waiting_for_dma) + hwif->dma_ops->dma_lost_irq(drive); + if (hwif->port_ops && hwif->port_ops->clear_irq) + hwif->port_ops->clear_irq(drive); + + printk(KERN_WARNING "%s: lost interrupt\n", + drive->name); + startstop = handler(drive); + } else { + if (drive->waiting_for_dma) + startstop = ide_dma_timeout_retry(drive, wait); + else + startstop = ide_error(drive, "irq timeout", + hwif->tp_ops->read_status(hwif)); + } + spin_lock_irq(&hwif->lock); + enable_irq(hwif->irq); + if (startstop == ide_stopped && hwif->polling == 0) { + rq_in_flight = hwif->rq; + hwif->rq = NULL; + ide_unlock_port(hwif); + plug_device = 1; } } - ide_do_request(hwgroup, IDE_NO_IRQ); - spin_unlock_irqrestore(&ide_lock, flags); + spin_unlock_irqrestore(&hwif->lock, flags); + + if (plug_device) { + ide_unlock_host(hwif->host); + ide_requeue_and_plug(drive, rq_in_flight); + } } /** * unexpected_intr - handle an unexpected IDE interrupt * @irq: interrupt line - * @hwgroup: hwgroup being processed + * @hwif: port 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. @@ -1488,51 +722,38 @@ void ide_timer_expiry (unsigned long data) * 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) + +static void unexpected_intr(int irq, ide_hwif_t *hwif) { - u8 stat; - ide_hwif_t *hwif = hwgroup->hwif; + u8 stat = hwif->tp_ops->read_status(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); - } - } + if (!OK_STAT(stat, ATA_DRDY, BAD_STAT)) { + /* Try to not flood the console with msgs */ + static unsigned long last_msgtime, count; + ++count; + + if (time_after(jiffies, last_msgtime + HZ)) { + last_msgtime = jiffies; + printk(KERN_ERR "%s: unexpected interrupt, " + "status=0x%02x, count=%ld\n", + hwif->name, stat, count); } - } while ((hwif = hwif->next) != hwgroup->hwif); + } } /** * ide_intr - default IDE interrupt handler * @irq: interrupt number - * @dev_id: hwif group + * @dev_id: hwif * @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 + * hwif is the interface in the group currently performing + * a command. hwif->cur_dev is the drive and hwif->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 @@ -1543,27 +764,35 @@ static void unexpected_intr (int irq, ide_hwgroup_t *hwgroup) * * 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. + * on the port and the process begins again. */ - -irqreturn_t ide_intr (int irq, void *dev_id, struct pt_regs *regs) + +irqreturn_t ide_intr (int irq, void *dev_id) { - unsigned long flags; - ide_hwgroup_t *hwgroup = (ide_hwgroup_t *)dev_id; - ide_hwif_t *hwif; - ide_drive_t *drive; + ide_hwif_t *hwif = (ide_hwif_t *)dev_id; + struct ide_host *host = hwif->host; + ide_drive_t *uninitialized_var(drive); ide_handler_t *handler; + unsigned long flags; ide_startstop_t startstop; + irqreturn_t irq_ret = IRQ_NONE; + int plug_device = 0; + struct request *uninitialized_var(rq_in_flight); - spin_lock_irqsave(&ide_lock, flags); - hwif = hwgroup->hwif; - - if (!ide_ack_intr(hwif)) { - spin_unlock_irqrestore(&ide_lock, flags); - return IRQ_NONE; + if (host->host_flags & IDE_HFLAG_SERIALIZE) { + if (hwif != host->cur_port) + goto out_early; } - if ((handler = hwgroup->handler) == NULL || hwgroup->polling) { + spin_lock_irqsave(&hwif->lock, flags); + + if (hwif->port_ops && hwif->port_ops->test_irq && + hwif->port_ops->test_irq(hwif) == 0) + goto out; + + handler = hwif->handler; + + if (handler == NULL || hwif->polling) { /* * Not expecting an interrupt from this drive. * That means this could be: @@ -1575,43 +804,26 @@ irqreturn_t ide_intr (int irq, void *dev_id, struct pt_regs *regs) * * 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 */ - { + if ((host->irq_flags & IRQF_SHARED) == 0) { /* * 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 + unexpected_intr(irq, hwif); } 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 */ + (void)hwif->tp_ops->read_status(hwif); } - 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; + goto out; } - if (!drive_is_ready(drive)) { + + drive = hwif->cur_dev; + + if (!drive_is_ready(drive)) /* * This happens regularly when we share a PCI IRQ with * another device. Unfortunately, it can also happen @@ -1619,23 +831,24 @@ irqreturn_t ide_intr (int irq, void *dev_id, struct pt_regs *regs) * 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); + goto out; + + hwif->handler = NULL; + hwif->expiry = NULL; + hwif->req_gen++; + del_timer(&hwif->timer); + spin_unlock(&hwif->lock); - if (drive->unmask) + if (hwif->port_ops && hwif->port_ops->clear_irq) + hwif->port_ops->clear_irq(drive); + + if (drive->dev_flags & IDE_DFLAG_UNMASK) local_irq_enable_in_hardirq(); + /* service this interrupt, may set handler for next interrupt */ startstop = handler(drive); - spin_lock_irq(&ide_lock); + spin_lock_irq(&hwif->lock); /* * Note that handler() may have set things up for another * interrupt to occur soon, but it cannot happen until @@ -1643,107 +856,37 @@ irqreturn_t ide_intr (int irq, void *dev_id, struct pt_regs *regs) * 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); - } + if (startstop == ide_stopped && hwif->polling == 0) { + BUG_ON(hwif->handler); + rq_in_flight = hwif->rq; + hwif->rq = NULL; + ide_unlock_port(hwif); + plug_device = 1; + } + irq_ret = IRQ_HANDLED; +out: + spin_unlock_irqrestore(&hwif->lock, flags); +out_early: + if (plug_device) { + ide_unlock_host(hwif->host); + ide_requeue_and_plug(drive, rq_in_flight); } - 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 surprise. - */ - -void ide_init_drive_cmd (struct request *rq) -{ - memset(rq, 0, sizeof(*rq)); - rq->flags = REQ_DRIVE_CMD; - rq->ref_count = 1; + return irq_ret; } +EXPORT_SYMBOL_GPL(ide_intr); -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_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) +void ide_pad_transfer(ide_drive_t *drive, int write, int len) { - unsigned long flags; - ide_hwgroup_t *hwgroup = HWGROUP(drive); - DECLARE_COMPLETION_ONSTACK(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; - } + ide_hwif_t *hwif = drive->hwif; + u8 buf[4] = { 0 }; - 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); + while (len > 0) { + if (write) + hwif->tp_ops->output_data(drive, NULL, buf, min(4, len)); + else + hwif->tp_ops->input_data(drive, NULL, buf, min(4, len)); + len -= 4; } - - return err; } - -EXPORT_SYMBOL(ide_do_drive_cmd); +EXPORT_SYMBOL_GPL(ide_pad_transfer); diff --git a/drivers/ide/ide-ioctls.c b/drivers/ide/ide-ioctls.c new file mode 100644 index 00000000000..6233fa2cb8a --- /dev/null +++ b/drivers/ide/ide-ioctls.c @@ -0,0 +1,289 @@ +/* + * IDE ioctls handling. + */ + +#include <linux/export.h> +#include <linux/hdreg.h> +#include <linux/ide.h> +#include <linux/slab.h> + +static const struct ide_ioctl_devset ide_ioctl_settings[] = { +{ HDIO_GET_32BIT, HDIO_SET_32BIT, &ide_devset_io_32bit }, +{ HDIO_GET_KEEPSETTINGS, HDIO_SET_KEEPSETTINGS, &ide_devset_keepsettings }, +{ HDIO_GET_UNMASKINTR, HDIO_SET_UNMASKINTR, &ide_devset_unmaskirq }, +{ HDIO_GET_DMA, HDIO_SET_DMA, &ide_devset_using_dma }, +{ -1, HDIO_SET_PIO_MODE, &ide_devset_pio_mode }, +{ 0 } +}; + +int ide_setting_ioctl(ide_drive_t *drive, struct block_device *bdev, + unsigned int cmd, unsigned long arg, + const struct ide_ioctl_devset *s) +{ + const struct ide_devset *ds; + int err = -EOPNOTSUPP; + + for (; (ds = s->setting); s++) { + if (ds->get && s->get_ioctl == cmd) + goto read_val; + else if (ds->set && s->set_ioctl == cmd) + goto set_val; + } + + return err; + +read_val: + mutex_lock(&ide_setting_mtx); + err = ds->get(drive); + mutex_unlock(&ide_setting_mtx); + return err >= 0 ? put_user(err, (long __user *)arg) : err; + +set_val: + if (bdev != bdev->bd_contains) + err = -EINVAL; + else { + if (!capable(CAP_SYS_ADMIN)) + err = -EACCES; + else { + mutex_lock(&ide_setting_mtx); + err = ide_devset_execute(drive, ds, arg); + mutex_unlock(&ide_setting_mtx); + } + } + return err; +} +EXPORT_SYMBOL_GPL(ide_setting_ioctl); + +static int ide_get_identity_ioctl(ide_drive_t *drive, unsigned int cmd, + unsigned long arg) +{ + u16 *id = NULL; + int size = (cmd == HDIO_GET_IDENTITY) ? (ATA_ID_WORDS * 2) : 142; + int rc = 0; + + if ((drive->dev_flags & IDE_DFLAG_ID_READ) == 0) { + rc = -ENOMSG; + goto out; + } + + /* ata_id_to_hd_driveid() relies on 'id' to be fully allocated. */ + id = kmalloc(ATA_ID_WORDS * 2, GFP_KERNEL); + if (id == NULL) { + rc = -ENOMEM; + goto out; + } + + memcpy(id, drive->id, size); + ata_id_to_hd_driveid(id); + + if (copy_to_user((void __user *)arg, id, size)) + rc = -EFAULT; + + kfree(id); +out: + return rc; +} + +static int ide_get_nice_ioctl(ide_drive_t *drive, unsigned long arg) +{ + return put_user((!!(drive->dev_flags & IDE_DFLAG_DSC_OVERLAP) + << IDE_NICE_DSC_OVERLAP) | + (!!(drive->dev_flags & IDE_DFLAG_NICE1) + << IDE_NICE_1), (long __user *)arg); +} + +static int ide_set_nice_ioctl(ide_drive_t *drive, unsigned long arg) +{ + if (arg != (arg & ((1 << IDE_NICE_DSC_OVERLAP) | (1 << IDE_NICE_1)))) + return -EPERM; + + if (((arg >> IDE_NICE_DSC_OVERLAP) & 1) && + (drive->media != ide_tape)) + return -EPERM; + + if ((arg >> IDE_NICE_DSC_OVERLAP) & 1) + drive->dev_flags |= IDE_DFLAG_DSC_OVERLAP; + else + drive->dev_flags &= ~IDE_DFLAG_DSC_OVERLAP; + + if ((arg >> IDE_NICE_1) & 1) + drive->dev_flags |= IDE_DFLAG_NICE1; + else + drive->dev_flags &= ~IDE_DFLAG_NICE1; + + return 0; +} + +static int ide_cmd_ioctl(ide_drive_t *drive, unsigned long arg) +{ + u8 *buf = NULL; + int bufsize = 0, err = 0; + u8 args[4], xfer_rate = 0; + struct ide_cmd cmd; + struct ide_taskfile *tf = &cmd.tf; + + if (NULL == (void *) arg) { + struct request *rq; + + rq = blk_get_request(drive->queue, READ, __GFP_WAIT); + rq->cmd_type = REQ_TYPE_ATA_TASKFILE; + err = blk_execute_rq(drive->queue, NULL, rq, 0); + blk_put_request(rq); + + return err; + } + + if (copy_from_user(args, (void __user *)arg, 4)) + return -EFAULT; + + memset(&cmd, 0, sizeof(cmd)); + tf->feature = args[2]; + if (args[0] == ATA_CMD_SMART) { + tf->nsect = args[3]; + tf->lbal = args[1]; + tf->lbam = ATA_SMART_LBAM_PASS; + tf->lbah = ATA_SMART_LBAH_PASS; + cmd.valid.out.tf = IDE_VALID_OUT_TF; + cmd.valid.in.tf = IDE_VALID_NSECT; + } else { + tf->nsect = args[1]; + cmd.valid.out.tf = IDE_VALID_FEATURE | IDE_VALID_NSECT; + cmd.valid.in.tf = IDE_VALID_NSECT; + } + tf->command = args[0]; + cmd.protocol = args[3] ? ATA_PROT_PIO : ATA_PROT_NODATA; + + if (args[3]) { + cmd.tf_flags |= IDE_TFLAG_IO_16BIT; + bufsize = SECTOR_SIZE * args[3]; + buf = kzalloc(bufsize, GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + } + + if (tf->command == ATA_CMD_SET_FEATURES && + tf->feature == SETFEATURES_XFER && + tf->nsect >= XFER_SW_DMA_0) { + xfer_rate = ide_find_dma_mode(drive, tf->nsect); + if (xfer_rate != tf->nsect) { + err = -EINVAL; + goto abort; + } + + cmd.tf_flags |= IDE_TFLAG_SET_XFER; + } + + err = ide_raw_taskfile(drive, &cmd, buf, args[3]); + + args[0] = tf->status; + args[1] = tf->error; + args[2] = tf->nsect; +abort: + if (copy_to_user((void __user *)arg, &args, 4)) + err = -EFAULT; + if (buf) { + if (copy_to_user((void __user *)(arg + 4), buf, bufsize)) + err = -EFAULT; + kfree(buf); + } + return err; +} + +static int ide_task_ioctl(ide_drive_t *drive, unsigned long arg) +{ + void __user *p = (void __user *)arg; + int err = 0; + u8 args[7]; + struct ide_cmd cmd; + + if (copy_from_user(args, p, 7)) + return -EFAULT; + + memset(&cmd, 0, sizeof(cmd)); + memcpy(&cmd.tf.feature, &args[1], 6); + cmd.tf.command = args[0]; + cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE; + cmd.valid.in.tf = IDE_VALID_IN_TF | IDE_VALID_DEVICE; + + err = ide_no_data_taskfile(drive, &cmd); + + args[0] = cmd.tf.command; + memcpy(&args[1], &cmd.tf.feature, 6); + + if (copy_to_user(p, args, 7)) + err = -EFAULT; + + return err; +} + +static int generic_drive_reset(ide_drive_t *drive) +{ + struct request *rq; + int ret = 0; + + rq = blk_get_request(drive->queue, READ, __GFP_WAIT); + rq->cmd_type = REQ_TYPE_SPECIAL; + rq->cmd_len = 1; + rq->cmd[0] = REQ_DRIVE_RESET; + if (blk_execute_rq(drive->queue, NULL, rq, 1)) + ret = rq->errors; + blk_put_request(rq); + return ret; +} + +int generic_ide_ioctl(ide_drive_t *drive, struct block_device *bdev, + unsigned int cmd, unsigned long arg) +{ + int err; + + err = ide_setting_ioctl(drive, bdev, cmd, arg, ide_ioctl_settings); + if (err != -EOPNOTSUPP) + return err; + + switch (cmd) { + case HDIO_OBSOLETE_IDENTITY: + case HDIO_GET_IDENTITY: + if (bdev != bdev->bd_contains) + return -EINVAL; + return ide_get_identity_ioctl(drive, cmd, arg); + case HDIO_GET_NICE: + return ide_get_nice_ioctl(drive, arg); + case HDIO_SET_NICE: + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + return ide_set_nice_ioctl(drive, arg); +#ifdef CONFIG_IDE_TASK_IOCTL + case HDIO_DRIVE_TASKFILE: + if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) + return -EACCES; + if (drive->media == ide_disk) + return ide_taskfile_ioctl(drive, arg); + return -ENOMSG; +#endif + case HDIO_DRIVE_CMD: + if (!capable(CAP_SYS_RAWIO)) + return -EACCES; + return ide_cmd_ioctl(drive, arg); + case HDIO_DRIVE_TASK: + if (!capable(CAP_SYS_RAWIO)) + return -EACCES; + return ide_task_ioctl(drive, arg); + case HDIO_DRIVE_RESET: + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + return generic_drive_reset(drive); + case HDIO_GET_BUSSTATE: + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + if (put_user(BUSSTATE_ON, (long __user *)arg)) + return -EFAULT; + return 0; + case HDIO_SET_BUSSTATE: + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + return -EOPNOTSUPP; + default: + return -EINVAL; + } +} +EXPORT_SYMBOL(generic_ide_ioctl); diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c index 77703acaec1..376f2dc410c 100644 --- a/drivers/ide/ide-iops.c +++ b/drivers/ide/ide-iops.c @@ -1,8 +1,6 @@ /* - * 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> + * Copyright (C) 2003 Red Hat * */ @@ -20,7 +18,6 @@ #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 <linux/nmi.h> @@ -30,418 +27,57 @@ #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) +void SELECT_MASK(ide_drive_t *drive, int mask) { - outsw(port, addr, count); -} + const struct ide_port_ops *port_ops = drive->hwif->port_ops; -static void ide_outl (u32 val, unsigned long port) -{ - outl(val, port); + if (port_ops && port_ops->maskproc) + port_ops->maskproc(drive, mask); } -static void ide_outsl (unsigned long port, void *addr, u32 count) +u8 ide_read_error(ide_drive_t *drive) { - outsl(port, addr, count); -} + struct ide_taskfile tf; -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; -} + drive->hwif->tp_ops->tf_read(drive, &tf, IDE_VALID_ERROR); -/* - * 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); + return tf.error; } +EXPORT_SYMBOL_GPL(ide_read_error); -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; -} - -/* - * Beginning of Taskfile OPCODE Library and feature sets. - */ -void ide_fix_driveid (struct hd_driveid *id) +void ide_fix_driveid(u16 *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); + + for (i = 0; i < 256; i++) + id[i] = __le16_to_cpu(id[i]); # 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); +/* + * ide_fixstring() cleans up and (optionally) byte-swaps a text string, + * removing leading/trailing blanks and compressing internal blanks. + * It is primarily used to tidy up the model name/number fields as + * returned by the ATA_CMD_ID_ATA[PI] commands. + */ -void ide_fixstring (u8 *s, const int bytecount, const int byteswap) +void ide_fixstring(u8 *s, const int bytecount, const int byteswap) { - u8 *p = s, *end = &s[bytecount & ~1]; /* bytecount must be even */ + u8 *p, *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); - } + for (p = s ; p != end ; p += 2) + be16_to_cpus((u16 *) p); } + /* strip leading blanks */ + p = s; while (s != end && *s == ' ') ++s; /* compress internal blanks and strip trailing blanks */ @@ -453,120 +89,49 @@ void ide_fixstring (u8 *s, const int bytecount, const int byteswap) 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; -} - -/* * 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. + * cases return error -- caller may then invoke ide_error(). * * This routine should get fixed to not hog the cpu during extra long waits.. * That could be done by busy-waiting for the first jiffy or two, and then * setting a timer to wake up at half second intervals thereafter, * until timeout is achieved, before timing out. */ -int ide_wait_stat (ide_startstop_t *startstop, ide_drive_t *drive, u8 good, u8 bad, unsigned long timeout) +int __ide_wait_stat(ide_drive_t *drive, u8 good, u8 bad, + unsigned long timeout, u8 *rstat) { - ide_hwif_t *hwif = HWIF(drive); - u8 stat; - int i; + ide_hwif_t *hwif = drive->hwif; + const struct ide_tp_ops *tp_ops = hwif->tp_ops; 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; - } + int i; + u8 stat; udelay(1); /* spec allows drive 400ns to assert "BUSY" */ - if ((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) { - local_irq_set(flags); + stat = tp_ops->read_status(hwif); + + if (stat & ATA_BUSY) { + local_save_flags(flags); + local_irq_enable_in_hardirq(); timeout += jiffies; - while ((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) { + while ((stat = tp_ops->read_status(hwif)) & ATA_BUSY) { if (time_after(jiffies, timeout)) { /* * One last read after the timeout in case * heavy interrupt load made us not make any * progress during the timeout.. */ - stat = hwif->INB(IDE_STATUS_REG); - if (!(stat & BUSY_STAT)) + stat = tp_ops->read_status(hwif); + if ((stat & ATA_BUSY) == 0) break; local_irq_restore(flags); - *startstop = ide_error(drive, "status timeout", stat); - return 1; + *rstat = stat; + return -EBUSY; } } local_irq_restore(flags); @@ -580,311 +145,293 @@ int ide_wait_stat (ide_startstop_t *startstop, ide_drive_t *drive, u8 good, u8 b */ for (i = 0; i < 10; i++) { udelay(1); - if (OK_STAT((stat = hwif->INB(IDE_STATUS_REG)), good, bad)) + stat = tp_ops->read_status(hwif); + + if (OK_STAT(stat, good, bad)) { + *rstat = stat; return 0; + } } - *startstop = ide_error(drive, "status error", stat); - return 1; + *rstat = stat; + return -EFAULT; } -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. + * In case of error returns error value after doing "*startstop = ide_error()". + * The caller should return the updated value of "startstop" in this case, + * "startstop" is unchanged when the function returns 0. */ -u8 eighty_ninty_three (ide_drive_t *drive) +int ide_wait_stat(ide_startstop_t *startstop, ide_drive_t *drive, u8 good, + u8 bad, unsigned long timeout) { - if(HWIF(drive)->udma_four == 0) - return 0; + int err; + u8 stat; - /* Check for SATA but only if we are ATA5 or higher */ - if (drive->id->hw_config == 0 && (drive->id->major_rev_num & 0x7FE0)) + /* bail early if we've exceeded max_failures */ + if (drive->max_failures && (drive->failures > drive->max_failures)) { + *startstop = ide_stopped; return 1; - if (!(drive->id->hw_config & 0x6000)) - return 0; -#ifndef CONFIG_IDEDMA_IVB - if(!(drive->id->hw_config & 0x4000)) - return 0; -#endif /* CONFIG_IDEDMA_IVB */ - return 1; + } + + err = __ide_wait_stat(drive, good, bad, timeout, &stat); + + if (err) { + char *s = (err == -EBUSY) ? "status timeout" : "status error"; + *startstop = ide_error(drive, s, stat); + } + + return err; } +EXPORT_SYMBOL(ide_wait_stat); -EXPORT_SYMBOL(eighty_ninty_three); +/** + * ide_in_drive_list - look for drive in black/white list + * @id: drive identifier + * @table: list to inspect + * + * Look for a drive in the blacklist and the whitelist tables + * Returns 1 if the drive is found in the table. + */ -int ide_ata66_check (ide_drive_t *drive, ide_task_t *args) +int ide_in_drive_list(u16 *id, const struct drive_list_entry *table) { - 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); + for ( ; table->id_model; table++) + if ((!strcmp(table->id_model, (char *)&id[ATA_ID_PROD])) && + (!table->id_firmware || + strstr((char *)&id[ATA_ID_FW_REV], table->id_firmware))) return 1; - } - if (!HWIF(drive)->udma_four) { - printk("%s: Speed warnings UDMA 3/4/5 is not " - "functional.\n", - HWIF(drive)->name); - return 1; - } - } return 0; } +EXPORT_SYMBOL_GPL(ide_in_drive_list); + +/* + * Early UDMA66 devices don't set bit14 to 1, only bit13 is valid. + * Some optical devices with the buggy firmwares have the same problem. + */ +static const struct drive_list_entry ivb_list[] = { + { "QUANTUM FIREBALLlct10 05" , "A03.0900" }, + { "QUANTUM FIREBALLlct20 30" , "APL.0900" }, + { "TSSTcorp CDDVDW SH-S202J" , "SB00" }, + { "TSSTcorp CDDVDW SH-S202J" , "SB01" }, + { "TSSTcorp CDDVDW SH-S202N" , "SB00" }, + { "TSSTcorp CDDVDW SH-S202N" , "SB01" }, + { "TSSTcorp CDDVDW SH-S202H" , "SB00" }, + { "TSSTcorp CDDVDW SH-S202H" , "SB01" }, + { "SAMSUNG SP0822N" , "WA100-10" }, + { NULL , NULL } +}; /* - * Backside of HDIO_DRIVE_CMD call of SETFEATURES_XFER. - * 1 : Safe to update drive->id DMA registers. - * 0 : OOPs not allowed. + * All hosts that use the 80c ribbon must use! + * The name is derived from upper byte of word 93 and the 80c ribbon. */ -int set_transfer (ide_drive_t *drive, ide_task_t *args) +u8 eighty_ninty_three(ide_drive_t *drive) { - 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)) + ide_hwif_t *hwif = drive->hwif; + u16 *id = drive->id; + int ivb = ide_in_drive_list(id, ivb_list); + + if (hwif->cbl == ATA_CBL_SATA || hwif->cbl == ATA_CBL_PATA40_SHORT) return 1; - return 0; -} + if (ivb) + printk(KERN_DEBUG "%s: skipping word 93 validity check\n", + drive->name); -#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; + if (ata_id_is_sata(id) && !ivb) + return 1; + + if (hwif->cbl != ATA_CBL_PATA80 && !ivb) + goto no_80w; + + /* + * FIXME: + * - change master/slave IDENTIFY order + * - force bit13 (80c cable present) check also for !ivb devices + * (unless the slave device is pre-ATA3) + */ + if (id[ATA_ID_HW_CONFIG] & 0x4000) + return 1; + + if (ivb) { + const char *model = (char *)&id[ATA_ID_PROD]; + + if (strstr(model, "TSSTcorp CDDVDW SH-S202")) { /* - * 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. + * These ATAPI devices always report 80c cable + * so we have to depend on the host in this case. */ - case XFER_UDMA_0: - default: return XFER_PIO_4; + if (hwif->cbl == ATA_CBL_PATA80) + return 1; + } else { + /* Depend on the device side cable detection. */ + if (id[ATA_ID_HW_CONFIG] & 0x2000) + return 1; + } } +no_80w: + if (drive->dev_flags & IDE_DFLAG_UDMA33_WARNED) + return 0; + + printk(KERN_WARNING "%s: %s side 80-wire cable detection failed, " + "limiting max speed to UDMA33\n", + drive->name, + hwif->cbl == ATA_CBL_PATA80 ? "drive" : "host"); + + drive->dev_flags |= IDE_DFLAG_UDMA33_WARNED; + + return 0; } -#endif /* CONFIG_BLK_DEV_IDEDMA */ -/* - * Update the - */ -int ide_driveid_update (ide_drive_t *drive) +static const char *nien_quirk_list[] = { + "QUANTUM FIREBALLlct08 08", + "QUANTUM FIREBALLP KA6.4", + "QUANTUM FIREBALLP KA9.1", + "QUANTUM FIREBALLP KX13.6", + "QUANTUM FIREBALLP KX20.5", + "QUANTUM FIREBALLP KX27.3", + "QUANTUM FIREBALLP LM20.4", + "QUANTUM FIREBALLP LM20.5", + "FUJITSU MHZ2160BH G2", + NULL +}; + +void ide_check_nien_quirk_list(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; + const char **list, *m = (char *)&drive->id[ATA_ID_PROD]; - taskfile_lib_get_identify(drive, (char *)&id); + for (list = nien_quirk_list; *list != NULL; list++) + if (strstr(m, *list) != NULL) { + drive->dev_flags |= IDE_DFLAG_NIEN_QUIRK; + return; + } +} - 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; +int ide_driveid_update(ide_drive_t *drive) +{ + u16 *id; + int rc; - 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); + id = kmalloc(SECTOR_SIZE, GFP_ATOMIC); + if (id == NULL) return 0; - } - local_irq_save(flags); + + SELECT_MASK(drive, 1); + rc = ide_dev_read_id(drive, ATA_CMD_ID_ATA, id, 1); 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); - } + + if (rc) + goto out_err; + + drive->id[ATA_ID_UDMA_MODES] = id[ATA_ID_UDMA_MODES]; + drive->id[ATA_ID_MWDMA_MODES] = id[ATA_ID_MWDMA_MODES]; + drive->id[ATA_ID_SWDMA_MODES] = id[ATA_ID_SWDMA_MODES]; + drive->id[ATA_ID_CFA_MODES] = id[ATA_ID_CFA_MODES]; + /* anything more ? */ + + kfree(id); return 1; -#endif +out_err: + if (rc == 2) + printk(KERN_ERR "%s: %s: bad status\n", drive->name, __func__); + kfree(id); + return 0; } -/* - * 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) +int ide_config_drive_speed(ide_drive_t *drive, u8 speed) { - ide_hwif_t *hwif = HWIF(drive); - int i, error = 1; + ide_hwif_t *hwif = drive->hwif; + const struct ide_tp_ops *tp_ops = hwif->tp_ops; + struct ide_taskfile tf; + u16 *id = drive->id, i; + int error = 0; 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); + if (hwif->dma_ops) /* check if host supports DMA */ + hwif->dma_ops->dma_host_set(drive, 0); #endif + /* Skip setting PIO flow-control modes on pre-EIDE drives */ + if ((speed & 0xf8) == XFER_PIO_0 && ata_id_has_iordy(drive->id) == 0) + goto skip; + /* * Don't use ide_wait_cmd here - it will * attempt to set_geometry and recalibrate, * but for some reason these don't work at * this point (lost interrupt). */ - /* - * Select the drive, and issue the SETFEATURES command - */ - disable_irq_nosync(hwif->irq); - - /* - * FIXME: we race against the running IRQ here if - * this is called from non IRQ context. If we use - * disable_irq() we hang on the error path. Work - * is needed. - */ - - udelay(1); - SELECT_DRIVE(drive); - SELECT_MASK(drive, 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); + tp_ops->dev_select(drive); + SELECT_MASK(drive, 1); 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); - } + tp_ops->write_devctl(hwif, ATA_NIEN | ATA_DEVCTL_OBS); - /* - * 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; - } - } + memset(&tf, 0, sizeof(tf)); + tf.feature = SETFEATURES_XFER; + tf.nsect = speed; - SELECT_MASK(drive, 0); + tp_ops->tf_load(drive, &tf, IDE_VALID_FEATURE | IDE_VALID_NSECT); + + tp_ops->exec_command(hwif, ATA_CMD_SET_FEATURES); + + if (drive->dev_flags & IDE_DFLAG_NIEN_QUIRK) + tp_ops->write_devctl(hwif, ATA_DEVCTL_OBS); + + error = __ide_wait_stat(drive, drive->ready_stat, + ATA_BUSY | ATA_DRQ | ATA_ERR, + WAIT_CMD, &stat); - enable_irq(hwif->irq); + SELECT_MASK(drive, 0); 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; + if (speed >= XFER_SW_DMA_0) { + id[ATA_ID_UDMA_MODES] &= ~0xFF00; + id[ATA_ID_MWDMA_MODES] &= ~0x0700; + id[ATA_ID_SWDMA_MODES] &= ~0x0700; + if (ata_id_is_cfa(id)) + id[ATA_ID_CFA_MODES] &= ~0x0E00; + } else if (ata_id_is_cfa(id)) + id[ATA_ID_CFA_MODES] &= ~0x01C0; + skip: #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); + if (speed >= XFER_SW_DMA_0 && (drive->dev_flags & IDE_DFLAG_USING_DMA)) + hwif->dma_ops->dma_host_set(drive, 1); + else if (hwif->dma_ops) /* check if host supports DMA */ + ide_dma_off_quietly(drive); #endif - 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 (speed >= XFER_UDMA_0) { + i = 1 << (speed - XFER_UDMA_0); + id[ATA_ID_UDMA_MODES] |= (i << 8 | i); + } else if (ata_id_is_cfa(id) && speed >= XFER_MW_DMA_3) { + i = speed - XFER_MW_DMA_2; + id[ATA_ID_CFA_MODES] |= i << 9; + } else if (speed >= XFER_MW_DMA_0) { + i = 1 << (speed - XFER_MW_DMA_0); + id[ATA_ID_MWDMA_MODES] |= (i << 8 | i); + } else if (speed >= XFER_SW_DMA_0) { + i = 1 << (speed - XFER_SW_DMA_0); + id[ATA_ID_SWDMA_MODES] |= (i << 8 | i); + } else if (ata_id_is_cfa(id) && speed >= XFER_PIO_5) { + i = speed - XFER_PIO_4; + id[ATA_ID_CFA_MODES] |= i << 6; } + 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 @@ -894,347 +441,81 @@ EXPORT_SYMBOL(ide_config_drive_speed); * * 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) +void __ide_set_handler(ide_drive_t *drive, ide_handler_t *handler, + unsigned int timeout) { - ide_hwgroup_t *hwgroup = HWGROUP(drive); + ide_hwif_t *hwif = drive->hwif; - 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); + BUG_ON(hwif->handler); + hwif->handler = handler; + hwif->timer.expires = jiffies + timeout; + hwif->req_gen_timer = hwif->req_gen; + add_timer(&hwif->timer); } -void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler, - unsigned int timeout, ide_expiry_t *expiry) +void ide_set_handler(ide_drive_t *drive, ide_handler_t *handler, + unsigned int timeout) { + ide_hwif_t *hwif = drive->hwif; unsigned long flags; - spin_lock_irqsave(&ide_lock, flags); - __ide_set_handler(drive, handler, timeout, expiry); - spin_unlock_irqrestore(&ide_lock, flags); -} + spin_lock_irqsave(&hwif->lock, flags); + __ide_set_handler(drive, handler, timeout); + spin_unlock_irqrestore(&hwif->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 + * @cmd: command * @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 + * 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); - - BUG_ON(hwgroup->handler); - 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)) { - BUG_ON(HWGROUP(drive)->handler != NULL); - 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)) { - BUG_ON(HWGROUP(drive)->handler != NULL); - 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) +void ide_execute_command(ide_drive_t *drive, struct ide_cmd *cmd, + ide_handler_t *handler, unsigned timeout) { - unsigned int unit; + ide_hwif_t *hwif = drive->hwif; 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 */ - BUG_ON(hwgroup->handler != NULL); - - /* For an ATAPI device, first try an ATAPI SRST. */ - if (drive->media != ide_disk && !do_not_try_atapi) { - pre_reset(drive); - SELECT_DRIVE(drive); - udelay (20); - hwif->OUTBSYNC(drive, WIN_SRST, IDE_COMMAND_REG); - ndelay(400); - hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE; - hwgroup->polling = 1; - __ide_set_handler(drive, &atapi_reset_pollfunc, HZ/20, NULL); - spin_unlock_irqrestore(&ide_lock, flags); - return ide_started; - } - - /* - * 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; - } + spin_lock_irqsave(&hwif->lock, flags); + if ((cmd->protocol != ATAPI_PROT_DMA && + cmd->protocol != ATAPI_PROT_PIO) || + (drive->atapi_flags & IDE_AFLAG_DRQ_INTERRUPT)) + __ide_set_handler(drive, handler, timeout); + hwif->tp_ops->exec_command(hwif, cmd->tf.command); /* - * 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. + * 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 */ - /* 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); + ndelay(400); + spin_unlock_irqrestore(&hwif->lock, flags); } -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(). + * to report a non-busy status, see comments in ide_probe_port(). */ int ide_wait_not_busy(ide_hwif_t *hwif, unsigned long timeout) { u8 stat = 0; - while(timeout--) { + 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) + stat = hwif->tp_ops->read_status(hwif); + if ((stat & ATA_BUSY) == 0) return 0; /* * Assume a value of 0xff means nothing is connected to @@ -1248,6 +529,3 @@ int ide_wait_not_busy(ide_hwif_t *hwif, unsigned long timeout) } return -EBUSY; } - -EXPORT_SYMBOL_GPL(ide_wait_not_busy); - diff --git a/drivers/ide/ide-legacy.c b/drivers/ide/ide-legacy.c new file mode 100644 index 00000000000..30fe3630734 --- /dev/null +++ b/drivers/ide/ide-legacy.c @@ -0,0 +1,58 @@ +#include <linux/kernel.h> +#include <linux/export.h> +#include <linux/ide.h> + +static void ide_legacy_init_one(struct ide_hw **hws, struct ide_hw *hw, + u8 port_no, const struct ide_port_info *d, + unsigned long config) +{ + unsigned long base, ctl; + int irq; + + if (port_no == 0) { + base = 0x1f0; + ctl = 0x3f6; + irq = 14; + } else { + base = 0x170; + ctl = 0x376; + irq = 15; + } + + if (!request_region(base, 8, d->name)) { + printk(KERN_ERR "%s: I/O resource 0x%lX-0x%lX not free.\n", + d->name, base, base + 7); + return; + } + + if (!request_region(ctl, 1, d->name)) { + printk(KERN_ERR "%s: I/O resource 0x%lX not free.\n", + d->name, ctl); + release_region(base, 8); + return; + } + + ide_std_init_ports(hw, base, ctl); + hw->irq = irq; + hw->config = config; + + hws[port_no] = hw; +} + +int ide_legacy_device_add(const struct ide_port_info *d, unsigned long config) +{ + struct ide_hw hw[2], *hws[] = { NULL, NULL }; + + memset(&hw, 0, sizeof(hw)); + + if ((d->host_flags & IDE_HFLAG_QD_2ND_PORT) == 0) + ide_legacy_init_one(hws, &hw[0], 0, d, config); + ide_legacy_init_one(hws, &hw[1], 1, d, config); + + if (hws[0] == NULL && hws[1] == NULL && + (d->host_flags & IDE_HFLAG_SINGLE)) + return -ENOENT; + + return ide_host_add(d, hws, 2, NULL); +} +EXPORT_SYMBOL_GPL(ide_legacy_device_add); diff --git a/drivers/ide/ide-lib.c b/drivers/ide/ide-lib.c index 1feff23487d..d9c9829c8b2 100644 --- a/drivers/ide/ide-lib.c +++ b/drivers/ide/ide-lib.c @@ -1,400 +1,11 @@ -#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/export.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 */ - BUG_ON(mode > 4); - 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 @@ -403,7 +14,7 @@ EXPORT_SYMBOL_GPL(ide_get_best_pio_mode); * 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 */ @@ -411,207 +22,150 @@ void ide_toggle_bounce(ide_drive_t *drive, int on) if (!PCI_DMA_BUS_IS_PHYS) { addr = BLK_BOUNCE_ANY; } else if (on && drive->media == ide_disk) { - if (HWIF(drive)->pci_dev) - addr = HWIF(drive)->pci_dev->dma_mask; + struct device *dev = drive->hwif->dev; + + if (dev && dev->dma_mask) + addr = *dev->dma_mask; } if (drive->queue) blk_queue_bounce_limit(drive->queue, addr); } -/** - * 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) +u64 ide_get_lba_addr(struct ide_cmd *cmd, int lba48) { -#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); + struct ide_taskfile *tf = &cmd->tf; + u32 high, low; -static void ide_dump_opcode(ide_drive_t *drive) -{ - struct request *rq; - u8 opcode = 0; - int found = 0; + low = (tf->lbah << 16) | (tf->lbam << 8) | tf->lbal; + if (lba48) { + tf = &cmd->hob; + high = (tf->lbah << 16) | (tf->lbam << 8) | tf->lbal; + } else + high = tf->device & 0xf; - 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; - } - } + return ((u64)high << 24) | low; +} +EXPORT_SYMBOL_GPL(ide_get_lba_addr); - printk("ide: failed opcode was: "); - if (!found) - printk("unknown\n"); +static void ide_dump_sector(ide_drive_t *drive) +{ + struct ide_cmd cmd; + struct ide_taskfile *tf = &cmd.tf; + u8 lba48 = !!(drive->dev_flags & IDE_DFLAG_LBA48); + + memset(&cmd, 0, sizeof(cmd)); + if (lba48) { + cmd.valid.in.tf = IDE_VALID_LBA; + cmd.valid.in.hob = IDE_VALID_LBA; + cmd.tf_flags = IDE_TFLAG_LBA48; + } else + cmd.valid.in.tf = IDE_VALID_LBA | IDE_VALID_DEVICE; + + ide_tf_readback(drive, &cmd); + + if (lba48 || (tf->device & ATA_LBA)) + printk(KERN_CONT ", LBAsect=%llu", + (unsigned long long)ide_get_lba_addr(&cmd, lba48)); else - printk("0x%02x\n", opcode); + printk(KERN_CONT ", CHS=%d/%d/%d", (tf->lbah << 8) + tf->lbam, + tf->device & 0xf, tf->lbal); } -static u8 ide_dump_ata_status(ide_drive_t *drive, const char *msg, u8 stat) +static void ide_dump_ata_error(ide_drive_t *drive, u8 err) { - ide_hwif_t *hwif = HWIF(drive); - unsigned long flags; - u8 err = 0; - - local_irq_save(flags); - printk("%s: %s: status=0x%02x { ", drive->name, msg, stat); - 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(KERN_CONT "{ "); + if (err & ATA_ABORTED) + printk(KERN_CONT "DriveStatusError "); + if (err & ATA_ICRC) + printk(KERN_CONT "%s", + (err & ATA_ABORTED) ? "BadCRC " : "BadSector "); + if (err & ATA_UNC) + printk(KERN_CONT "UncorrectableError "); + if (err & ATA_IDNF) + printk(KERN_CONT "SectorIdNotFound "); + if (err & ATA_TRK0NF) + printk(KERN_CONT "TrackZeroNotFound "); + if (err & ATA_AMNF) + printk(KERN_CONT "AddrMarkNotFound "); + printk(KERN_CONT "}"); + if ((err & (ATA_BBK | ATA_ABORTED)) == ATA_BBK || + (err & (ATA_UNC | ATA_IDNF | ATA_AMNF))) { + struct request *rq = drive->hwif->rq; + + ide_dump_sector(drive); + + if (rq) + printk(KERN_CONT ", sector=%llu", + (unsigned long long)blk_rq_pos(rq)); } - 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); - if (err & ABRT_ERR) printk("DriveStatusError "); - if (err & ICRC_ERR) - printk((err & ABRT_ERR) ? "BadCRC " : "BadSector "); - 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; + printk(KERN_CONT "\n"); +} + +static void ide_dump_atapi_error(ide_drive_t *drive, u8 err) +{ + printk(KERN_CONT "{ "); + if (err & ATAPI_ILI) + printk(KERN_CONT "IllegalLengthIndication "); + if (err & ATAPI_EOM) + printk(KERN_CONT "EndOfMedia "); + if (err & ATA_ABORTED) + printk(KERN_CONT "AbortedCommand "); + if (err & ATA_MCR) + printk(KERN_CONT "MediaChangeRequested "); + if (err & ATAPI_LFS) + printk(KERN_CONT "LastFailedSense=0x%02x ", + (err & ATAPI_LFS) >> 4); + printk(KERN_CONT "}\n"); } /** - * ide_dump_atapi_status - print human readable atapi status + * ide_dump_status - translate ATA/ATAPI error * @drive: drive that status applies to * @msg: text message to print * @stat: status byte to decode * * Error reporting, in human readable form (luxurious, but a memory hog). + * Combines the drive name, message and status byte to provide a + * user understandable explanation of the device error. */ -static u8 ide_dump_atapi_status(ide_drive_t *drive, const char *msg, u8 stat) +u8 ide_dump_status(ide_drive_t *drive, const char *msg, u8 stat) { - unsigned long flags; - - atapi_status_t status; - atapi_error_t error; + u8 err = 0; - status.all = stat; - error.all = 0; - local_irq_save(flags); - printk("%s: %s: status=0x%02x { ", drive->name, msg, stat); - if (status.b.bsy) - printk("Busy "); + printk(KERN_ERR "%s: %s: status=0x%02x { ", drive->name, msg, stat); + if (stat & ATA_BUSY) + printk(KERN_CONT "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 "); + if (stat & ATA_DRDY) + printk(KERN_CONT "DriveReady "); + if (stat & ATA_DF) + printk(KERN_CONT "DeviceFault "); + if (stat & ATA_DSC) + printk(KERN_CONT "SeekComplete "); + if (stat & ATA_DRQ) + printk(KERN_CONT "DataRequest "); + if (stat & ATA_CORR) + printk(KERN_CONT "CorrectedError "); + if (stat & ATA_IDX) + printk(KERN_CONT "Index "); + if (stat & ATA_ERR) + printk(KERN_CONT "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"); + printk(KERN_CONT "}\n"); + if ((stat & (ATA_BUSY | ATA_ERR)) == ATA_ERR) { + err = ide_read_error(drive); + printk(KERN_ERR "%s: %s: error=0x%02x ", drive->name, msg, err); + if (drive->media == ide_disk) + ide_dump_ata_error(drive, err); + else + ide_dump_atapi_error(drive, err); } - ide_dump_opcode(drive); - local_irq_restore(flags); - return 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. - */ + printk(KERN_ERR "%s: possibly failed opcode: 0x%02x\n", + drive->name, drive->hwif->cmd.tf.command); -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); + return err; } - EXPORT_SYMBOL(ide_dump_status); diff --git a/drivers/ide/ide-park.c b/drivers/ide/ide-park.c new file mode 100644 index 00000000000..f41558a0bcd --- /dev/null +++ b/drivers/ide/ide-park.c @@ -0,0 +1,151 @@ +#include <linux/kernel.h> +#include <linux/gfp.h> +#include <linux/ide.h> +#include <linux/jiffies.h> +#include <linux/blkdev.h> + +DECLARE_WAIT_QUEUE_HEAD(ide_park_wq); + +static void issue_park_cmd(ide_drive_t *drive, unsigned long timeout) +{ + ide_hwif_t *hwif = drive->hwif; + struct request_queue *q = drive->queue; + struct request *rq; + int rc; + + timeout += jiffies; + spin_lock_irq(&hwif->lock); + if (drive->dev_flags & IDE_DFLAG_PARKED) { + int reset_timer = time_before(timeout, drive->sleep); + int start_queue = 0; + + drive->sleep = timeout; + wake_up_all(&ide_park_wq); + if (reset_timer && del_timer(&hwif->timer)) + start_queue = 1; + spin_unlock_irq(&hwif->lock); + + if (start_queue) + blk_run_queue(q); + return; + } + spin_unlock_irq(&hwif->lock); + + rq = blk_get_request(q, READ, __GFP_WAIT); + rq->cmd[0] = REQ_PARK_HEADS; + rq->cmd_len = 1; + rq->cmd_type = REQ_TYPE_SPECIAL; + rq->special = &timeout; + rc = blk_execute_rq(q, NULL, rq, 1); + blk_put_request(rq); + if (rc) + goto out; + + /* + * Make sure that *some* command is sent to the drive after the + * timeout has expired, so power management will be reenabled. + */ + rq = blk_get_request(q, READ, GFP_NOWAIT); + if (unlikely(!rq)) + goto out; + + rq->cmd[0] = REQ_UNPARK_HEADS; + rq->cmd_len = 1; + rq->cmd_type = REQ_TYPE_SPECIAL; + elv_add_request(q, rq, ELEVATOR_INSERT_FRONT); + +out: + return; +} + +ide_startstop_t ide_do_park_unpark(ide_drive_t *drive, struct request *rq) +{ + struct ide_cmd cmd; + struct ide_taskfile *tf = &cmd.tf; + + memset(&cmd, 0, sizeof(cmd)); + if (rq->cmd[0] == REQ_PARK_HEADS) { + drive->sleep = *(unsigned long *)rq->special; + drive->dev_flags |= IDE_DFLAG_SLEEPING; + tf->command = ATA_CMD_IDLEIMMEDIATE; + tf->feature = 0x44; + tf->lbal = 0x4c; + tf->lbam = 0x4e; + tf->lbah = 0x55; + cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE; + cmd.valid.in.tf = IDE_VALID_IN_TF | IDE_VALID_DEVICE; + } else /* cmd == REQ_UNPARK_HEADS */ + tf->command = ATA_CMD_CHK_POWER; + + cmd.tf_flags |= IDE_TFLAG_CUSTOM_HANDLER; + cmd.protocol = ATA_PROT_NODATA; + + cmd.rq = rq; + + return do_rw_taskfile(drive, &cmd); +} + +ssize_t ide_park_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + ide_drive_t *drive = to_ide_device(dev); + ide_hwif_t *hwif = drive->hwif; + unsigned long now; + unsigned int msecs; + + if (drive->dev_flags & IDE_DFLAG_NO_UNLOAD) + return -EOPNOTSUPP; + + spin_lock_irq(&hwif->lock); + now = jiffies; + if (drive->dev_flags & IDE_DFLAG_PARKED && + time_after(drive->sleep, now)) + msecs = jiffies_to_msecs(drive->sleep - now); + else + msecs = 0; + spin_unlock_irq(&hwif->lock); + + return snprintf(buf, 20, "%u\n", msecs); +} + +ssize_t ide_park_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t len) +{ +#define MAX_PARK_TIMEOUT 30000 + ide_drive_t *drive = to_ide_device(dev); + long int input; + int rc; + + rc = kstrtol(buf, 10, &input); + if (rc) + return rc; + if (input < -2) + return -EINVAL; + if (input > MAX_PARK_TIMEOUT) { + input = MAX_PARK_TIMEOUT; + rc = -EOVERFLOW; + } + + mutex_lock(&ide_setting_mtx); + if (input >= 0) { + if (drive->dev_flags & IDE_DFLAG_NO_UNLOAD) + rc = -EOPNOTSUPP; + else if (input || drive->dev_flags & IDE_DFLAG_PARKED) + issue_park_cmd(drive, msecs_to_jiffies(input)); + } else { + if (drive->media == ide_disk) + switch (input) { + case -1: + drive->dev_flags &= ~IDE_DFLAG_NO_UNLOAD; + break; + case -2: + drive->dev_flags |= IDE_DFLAG_NO_UNLOAD; + break; + } + else + rc = -EOPNOTSUPP; + } + mutex_unlock(&ide_setting_mtx); + + return rc ? rc : len; +} diff --git a/drivers/ide/ide-pci-generic.c b/drivers/ide/ide-pci-generic.c new file mode 100644 index 00000000000..673420db953 --- /dev/null +++ b/drivers/ide/ide-pci-generic.c @@ -0,0 +1,203 @@ +/* + * Copyright (C) 2001-2002 Andre Hedrick <andre@linux-ide.org> + * Portions (C) Copyright 2002 Red Hat Inc + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * For the avoidance of doubt the "preferred form" of this code is one which + * is in an open non patent encumbered format. Where cryptographic key signing + * forms part of the process of creating an executable the information + * including keys needed to generate an equivalently functional executable + * are deemed to be part of the source code. + */ + +#include <linux/types.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/pci.h> +#include <linux/ide.h> +#include <linux/init.h> + +#define DRV_NAME "ide_pci_generic" + +static bool ide_generic_all; /* Set to claim all devices */ + +module_param_named(all_generic_ide, ide_generic_all, bool, 0444); +MODULE_PARM_DESC(all_generic_ide, "IDE generic will claim all unknown PCI IDE storage controllers."); + +static void netcell_quirkproc(ide_drive_t *drive) +{ + /* mark words 85-87 as valid */ + drive->id[ATA_ID_CSF_DEFAULT] |= 0x4000; +} + +static const struct ide_port_ops netcell_port_ops = { + .quirkproc = netcell_quirkproc, +}; + +#define DECLARE_GENERIC_PCI_DEV(extra_flags) \ + { \ + .name = DRV_NAME, \ + .host_flags = IDE_HFLAG_TRUST_BIOS_FOR_DMA | \ + extra_flags, \ + .swdma_mask = ATA_SWDMA2, \ + .mwdma_mask = ATA_MWDMA2, \ + .udma_mask = ATA_UDMA6, \ + } + +static const struct ide_port_info generic_chipsets[] = { + /* 0: Unknown */ + DECLARE_GENERIC_PCI_DEV(0), + + { /* 1: NS87410 */ + .name = DRV_NAME, + .enablebits = { {0x43, 0x08, 0x08}, {0x47, 0x08, 0x08} }, + .host_flags = IDE_HFLAG_TRUST_BIOS_FOR_DMA, + .swdma_mask = ATA_SWDMA2, + .mwdma_mask = ATA_MWDMA2, + .udma_mask = ATA_UDMA6, + }, + + /* 2: SAMURAI / HT6565 / HINT_IDE */ + DECLARE_GENERIC_PCI_DEV(0), + /* 3: UM8673F / UM8886A / UM8886BF */ + DECLARE_GENERIC_PCI_DEV(IDE_HFLAG_NO_DMA), + /* 4: VIA_IDE / OPTI621V / Piccolo010{2,3,5} */ + DECLARE_GENERIC_PCI_DEV(IDE_HFLAG_NO_AUTODMA), + + { /* 5: VIA8237SATA */ + .name = DRV_NAME, + .host_flags = IDE_HFLAG_TRUST_BIOS_FOR_DMA | + IDE_HFLAG_OFF_BOARD, + .swdma_mask = ATA_SWDMA2, + .mwdma_mask = ATA_MWDMA2, + .udma_mask = ATA_UDMA6, + }, + + { /* 6: Revolution */ + .name = DRV_NAME, + .port_ops = &netcell_port_ops, + .host_flags = IDE_HFLAG_CLEAR_SIMPLEX | + IDE_HFLAG_TRUST_BIOS_FOR_DMA | + IDE_HFLAG_OFF_BOARD, + .swdma_mask = ATA_SWDMA2, + .mwdma_mask = ATA_MWDMA2, + .udma_mask = ATA_UDMA6, + } +}; + +/** + * generic_init_one - called when a PIIX is found + * @dev: the generic device + * @id: the matching pci id + * + * Called when the PCI registration layer (or the IDE initialization) + * finds a device matching our IDE device tables. + */ + +static int generic_init_one(struct pci_dev *dev, const struct pci_device_id *id) +{ + const struct ide_port_info *d = &generic_chipsets[id->driver_data]; + int ret = -ENODEV; + + /* Don't use the generic entry unless instructed to do so */ + if (id->driver_data == 0 && ide_generic_all == 0) + goto out; + + switch (dev->vendor) { + case PCI_VENDOR_ID_UMC: + if (dev->device == PCI_DEVICE_ID_UMC_UM8886A && + !(PCI_FUNC(dev->devfn) & 1)) + goto out; /* UM8886A/BF pair */ + break; + case PCI_VENDOR_ID_OPTI: + if (dev->device == PCI_DEVICE_ID_OPTI_82C558 && + !(PCI_FUNC(dev->devfn) & 1)) + goto out; + break; + case PCI_VENDOR_ID_JMICRON: + if (dev->device != PCI_DEVICE_ID_JMICRON_JMB368 && + PCI_FUNC(dev->devfn) != 1) + goto out; + break; + case PCI_VENDOR_ID_NS: + if (dev->device == PCI_DEVICE_ID_NS_87410 && + (dev->class >> 8) != PCI_CLASS_STORAGE_IDE) + goto out; + break; + } + + if (dev->vendor != PCI_VENDOR_ID_JMICRON) { + u16 command; + pci_read_config_word(dev, PCI_COMMAND, &command); + if (!(command & PCI_COMMAND_IO)) { + printk(KERN_INFO "%s %s: skipping disabled " + "controller\n", d->name, pci_name(dev)); + goto out; + } + } + ret = ide_pci_init_one(dev, d, NULL); +out: + return ret; +} + +static const struct pci_device_id generic_pci_tbl[] = { + { PCI_VDEVICE(NS, PCI_DEVICE_ID_NS_87410), 1 }, + { PCI_VDEVICE(PCTECH, PCI_DEVICE_ID_PCTECH_SAMURAI_IDE), 2 }, + { PCI_VDEVICE(HOLTEK, PCI_DEVICE_ID_HOLTEK_6565), 2 }, + { PCI_VDEVICE(UMC, PCI_DEVICE_ID_UMC_UM8673F), 3 }, + { PCI_VDEVICE(UMC, PCI_DEVICE_ID_UMC_UM8886A), 3 }, + { PCI_VDEVICE(UMC, PCI_DEVICE_ID_UMC_UM8886BF), 3 }, + { PCI_VDEVICE(HINT, PCI_DEVICE_ID_HINT_VXPROII_IDE), 2 }, + { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_82C561), 4 }, + { PCI_VDEVICE(OPTI, PCI_DEVICE_ID_OPTI_82C558), 4 }, +#ifdef CONFIG_BLK_DEV_IDE_SATA + { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_8237_SATA), 5 }, +#endif + { PCI_VDEVICE(TOSHIBA, PCI_DEVICE_ID_TOSHIBA_PICCOLO_1), 4 }, + { PCI_VDEVICE(TOSHIBA, PCI_DEVICE_ID_TOSHIBA_PICCOLO_2), 4 }, + { PCI_VDEVICE(TOSHIBA, PCI_DEVICE_ID_TOSHIBA_PICCOLO_3), 4 }, + { PCI_VDEVICE(TOSHIBA, PCI_DEVICE_ID_TOSHIBA_PICCOLO_5), 4 }, + { PCI_VDEVICE(NETCELL, PCI_DEVICE_ID_REVOLUTION), 6 }, + /* + * Must come last. If you add entries adjust + * this table and generic_chipsets[] appropriately. + */ + { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xFFFFFF00UL, 0 }, + { 0, }, +}; +MODULE_DEVICE_TABLE(pci, generic_pci_tbl); + +static struct pci_driver generic_pci_driver = { + .name = "PCI_IDE", + .id_table = generic_pci_tbl, + .probe = generic_init_one, + .remove = ide_pci_remove, + .suspend = ide_pci_suspend, + .resume = ide_pci_resume, +}; + +static int __init generic_ide_init(void) +{ + return ide_pci_register_driver(&generic_pci_driver); +} + +static void __exit generic_ide_exit(void) +{ + pci_unregister_driver(&generic_pci_driver); +} + +module_init(generic_ide_init); +module_exit(generic_ide_exit); + +MODULE_AUTHOR("Andre Hedrick"); +MODULE_DESCRIPTION("PCI driver module for generic PCI IDE"); +MODULE_LICENSE("GPL"); diff --git a/drivers/ide/ide-pio-blacklist.c b/drivers/ide/ide-pio-blacklist.c new file mode 100644 index 00000000000..40e683a84ff --- /dev/null +++ b/drivers/ide/ide-pio-blacklist.c @@ -0,0 +1,95 @@ +/* + * PIO blacklist. Some drives incorrectly report their maximal PIO mode, + * at least in respect to CMD640. Here we keep info on some known drives. + * + * Changes to the ide_pio_blacklist[] should be made with EXTREME CAUTION + * to avoid breaking the fragile cmd640.c support. + */ + +#include <linux/string.h> +#include <linux/ide.h> + +static struct ide_pio_info { + const char *name; + int pio; +} ide_pio_blacklist [] = { + { "Conner Peripherals 540MB - CFS540A", 3 }, + + { "WDC AC2700", 3 }, + { "WDC AC2540", 3 }, + { "WDC AC2420", 3 }, + { "WDC AC2340", 3 }, + { "WDC AC2250", 0 }, + { "WDC AC2200", 0 }, + { "WDC AC21200", 4 }, + { "WDC AC2120", 0 }, + { "WDC AC2850", 3 }, + { "WDC AC1270", 3 }, + { "WDC AC1170", 1 }, + { "WDC AC1210", 1 }, + { "WDC AC280", 0 }, + { "WDC AC31000", 3 }, + { "WDC AC31200", 3 }, + + { "Maxtor 7131 AT", 1 }, + { "Maxtor 7171 AT", 1 }, + { "Maxtor 7213 AT", 1 }, + { "Maxtor 7245 AT", 1 }, + { "Maxtor 7345 AT", 1 }, + { "Maxtor 7546 AT", 3 }, + { "Maxtor 7540 AV", 3 }, + + { "SAMSUNG SHD-3121A", 1 }, + { "SAMSUNG SHD-3122A", 1 }, + { "SAMSUNG SHD-3172A", 1 }, + + { "ST5660A", 3 }, + { "ST3660A", 3 }, + { "ST3630A", 3 }, + { "ST3655A", 3 }, + { "ST3391A", 3 }, + { "ST3390A", 1 }, + { "ST3600A", 1 }, + { "ST3290A", 0 }, + { "ST3144A", 0 }, + { "ST3491A", 1 }, /* reports 3, should be 1 or 2 (depending on drive) + according to Seagate's FIND-ATA program */ + + { "QUANTUM ELS127A", 0 }, + { "QUANTUM ELS170A", 0 }, + { "QUANTUM LPS240A", 0 }, + { "QUANTUM LPS210A", 3 }, + { "QUANTUM LPS270A", 3 }, + { "QUANTUM LPS365A", 3 }, + { "QUANTUM LPS540A", 3 }, + { "QUANTUM LIGHTNING 540A", 3 }, + { "QUANTUM LIGHTNING 730A", 3 }, + + { "QUANTUM FIREBALL_540", 3 }, /* Older Quantum Fireballs don't work */ + { "QUANTUM FIREBALL_640", 3 }, + { "QUANTUM FIREBALL_1080", 3 }, + { "QUANTUM FIREBALL_1280", 3 }, + { NULL, 0 } +}; + +/** + * ide_scan_pio_blacklist - check for a blacklisted drive + * @model: Drive model string + * + * This routine searches the ide_pio_blacklist for an entry + * matching the start/whole of the supplied model name. + * + * Returns -1 if no match found. + * Otherwise returns the recommended PIO mode from ide_pio_blacklist[]. + */ + +int ide_scan_pio_blacklist(char *model) +{ + struct ide_pio_info *p; + + for (p = ide_pio_blacklist; p->name != NULL; p++) { + if (strncmp(p->name, model, strlen(p->name)) == 0) + return p->pio; + } + return -1; +} diff --git a/drivers/ide/ide-pm.c b/drivers/ide/ide-pm.c new file mode 100644 index 00000000000..8d1e32d7cd9 --- /dev/null +++ b/drivers/ide/ide-pm.c @@ -0,0 +1,248 @@ +#include <linux/kernel.h> +#include <linux/gfp.h> +#include <linux/ide.h> + +int generic_ide_suspend(struct device *dev, pm_message_t mesg) +{ + ide_drive_t *drive = to_ide_device(dev); + ide_drive_t *pair = ide_get_pair_dev(drive); + ide_hwif_t *hwif = drive->hwif; + struct request *rq; + struct request_pm_state rqpm; + int ret; + + if (ide_port_acpi(hwif)) { + /* call ACPI _GTM only once */ + if ((drive->dn & 1) == 0 || pair == NULL) + ide_acpi_get_timing(hwif); + } + + memset(&rqpm, 0, sizeof(rqpm)); + rq = blk_get_request(drive->queue, READ, __GFP_WAIT); + rq->cmd_type = REQ_TYPE_PM_SUSPEND; + rq->special = &rqpm; + rqpm.pm_step = IDE_PM_START_SUSPEND; + if (mesg.event == PM_EVENT_PRETHAW) + mesg.event = PM_EVENT_FREEZE; + rqpm.pm_state = mesg.event; + + ret = blk_execute_rq(drive->queue, NULL, rq, 0); + blk_put_request(rq); + + if (ret == 0 && ide_port_acpi(hwif)) { + /* call ACPI _PS3 only after both devices are suspended */ + if ((drive->dn & 1) || pair == NULL) + ide_acpi_set_state(hwif, 0); + } + + return ret; +} + +int generic_ide_resume(struct device *dev) +{ + ide_drive_t *drive = to_ide_device(dev); + ide_drive_t *pair = ide_get_pair_dev(drive); + ide_hwif_t *hwif = drive->hwif; + struct request *rq; + struct request_pm_state rqpm; + int err; + + if (ide_port_acpi(hwif)) { + /* call ACPI _PS0 / _STM only once */ + if ((drive->dn & 1) == 0 || pair == NULL) { + ide_acpi_set_state(hwif, 1); + ide_acpi_push_timing(hwif); + } + + ide_acpi_exec_tfs(drive); + } + + memset(&rqpm, 0, sizeof(rqpm)); + rq = blk_get_request(drive->queue, READ, __GFP_WAIT); + rq->cmd_type = REQ_TYPE_PM_RESUME; + rq->cmd_flags |= REQ_PREEMPT; + rq->special = &rqpm; + rqpm.pm_step = IDE_PM_START_RESUME; + rqpm.pm_state = PM_EVENT_ON; + + err = blk_execute_rq(drive->queue, NULL, rq, 1); + blk_put_request(rq); + + if (err == 0 && dev->driver) { + struct ide_driver *drv = to_ide_driver(dev->driver); + + if (drv->resume) + drv->resume(drive); + } + + return err; +} + +void ide_complete_power_step(ide_drive_t *drive, struct request *rq) +{ + struct request_pm_state *pm = rq->special; + +#ifdef DEBUG_PM + printk(KERN_INFO "%s: complete_power_step(step: %d)\n", + drive->name, pm->pm_step); +#endif + if (drive->media != ide_disk) + return; + + switch (pm->pm_step) { + case IDE_PM_FLUSH_CACHE: /* Suspend step 1 (flush cache) */ + if (pm->pm_state == PM_EVENT_FREEZE) + pm->pm_step = IDE_PM_COMPLETED; + else + pm->pm_step = IDE_PM_STANDBY; + break; + case IDE_PM_STANDBY: /* Suspend step 2 (standby) */ + pm->pm_step = IDE_PM_COMPLETED; + break; + case IDE_PM_RESTORE_PIO: /* Resume step 1 (restore PIO) */ + pm->pm_step = IDE_PM_IDLE; + break; + case IDE_PM_IDLE: /* Resume step 2 (idle)*/ + pm->pm_step = IDE_PM_RESTORE_DMA; + break; + } +} + +ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request *rq) +{ + struct request_pm_state *pm = rq->special; + struct ide_cmd cmd = { }; + + switch (pm->pm_step) { + case IDE_PM_FLUSH_CACHE: /* Suspend step 1 (flush cache) */ + if (drive->media != ide_disk) + break; + /* Not supported? Switch to next step now. */ + if (ata_id_flush_enabled(drive->id) == 0 || + (drive->dev_flags & IDE_DFLAG_WCACHE) == 0) { + ide_complete_power_step(drive, rq); + return ide_stopped; + } + if (ata_id_flush_ext_enabled(drive->id)) + cmd.tf.command = ATA_CMD_FLUSH_EXT; + else + cmd.tf.command = ATA_CMD_FLUSH; + goto out_do_tf; + case IDE_PM_STANDBY: /* Suspend step 2 (standby) */ + cmd.tf.command = ATA_CMD_STANDBYNOW1; + goto out_do_tf; + case IDE_PM_RESTORE_PIO: /* Resume step 1 (restore PIO) */ + ide_set_max_pio(drive); + /* + * skip IDE_PM_IDLE for ATAPI devices + */ + if (drive->media != ide_disk) + pm->pm_step = IDE_PM_RESTORE_DMA; + else + ide_complete_power_step(drive, rq); + return ide_stopped; + case IDE_PM_IDLE: /* Resume step 2 (idle) */ + cmd.tf.command = ATA_CMD_IDLEIMMEDIATE; + goto out_do_tf; + case IDE_PM_RESTORE_DMA: /* Resume step 3 (restore DMA) */ + /* + * Right now, all we do is call ide_set_dma(drive), + * we could be smarter and check for current xfer_speed + * in struct drive etc... + */ + if (drive->hwif->dma_ops == NULL) + break; + /* + * TODO: respect IDE_DFLAG_USING_DMA + */ + ide_set_dma(drive); + break; + } + + pm->pm_step = IDE_PM_COMPLETED; + + return ide_stopped; + +out_do_tf: + cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE; + cmd.valid.in.tf = IDE_VALID_IN_TF | IDE_VALID_DEVICE; + cmd.protocol = ATA_PROT_NODATA; + + return do_rw_taskfile(drive, &cmd); +} + +/** + * ide_complete_pm_rq - 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. + */ +void ide_complete_pm_rq(ide_drive_t *drive, struct request *rq) +{ + struct request_queue *q = drive->queue; + struct request_pm_state *pm = rq->special; + unsigned long flags; + + ide_complete_power_step(drive, rq); + if (pm->pm_step != IDE_PM_COMPLETED) + return; + +#ifdef DEBUG_PM + printk("%s: completing PM request, %s\n", drive->name, + (rq->cmd_type == REQ_TYPE_PM_SUSPEND) ? "suspend" : "resume"); +#endif + spin_lock_irqsave(q->queue_lock, flags); + if (rq->cmd_type == REQ_TYPE_PM_SUSPEND) + blk_stop_queue(q); + else + drive->dev_flags &= ~IDE_DFLAG_BLOCKED; + spin_unlock_irqrestore(q->queue_lock, flags); + + drive->hwif->rq = NULL; + + if (blk_end_request(rq, 0, 0)) + BUG(); +} + +void ide_check_pm_state(ide_drive_t *drive, struct request *rq) +{ + struct request_pm_state *pm = rq->special; + + if (rq->cmd_type == REQ_TYPE_PM_SUSPEND && + pm->pm_step == IDE_PM_START_SUSPEND) + /* Mark drive blocked when starting the suspend sequence. */ + drive->dev_flags |= IDE_DFLAG_BLOCKED; + else if (rq->cmd_type == REQ_TYPE_PM_RESUME && + pm->pm_step == IDE_PM_START_RESUME) { + /* + * The first thing we do on wakeup is to wait for BSY bit to + * go away (with a looong timeout) as a drive on this hwif may + * just be POSTing itself. + * We do that before even selecting as the "other" device on + * the bus may be broken enough to walk on our toes at this + * point. + */ + ide_hwif_t *hwif = drive->hwif; + const struct ide_tp_ops *tp_ops = hwif->tp_ops; + struct request_queue *q = drive->queue; + unsigned long flags; + int rc; +#ifdef DEBUG_PM + printk("%s: Wakeup request inited, waiting for !BSY...\n", drive->name); +#endif + rc = ide_wait_not_busy(hwif, 35000); + if (rc) + printk(KERN_WARNING "%s: bus not ready on wakeup\n", drive->name); + tp_ops->dev_select(drive); + tp_ops->write_devctl(hwif, ATA_DEVCTL_OBS); + rc = ide_wait_not_busy(hwif, 100000); + if (rc) + printk(KERN_WARNING "%s: drive not ready on wakeup\n", drive->name); + + spin_lock_irqsave(q->queue_lock, flags); + blk_start_queue(q); + spin_unlock_irqrestore(q->queue_lock, flags); + } +} diff --git a/drivers/ide/ide-pnp.c b/drivers/ide/ide-pnp.c index df7d1504f84..e5f3db83137 100644 --- a/drivers/ide/ide-pnp.c +++ b/drivers/ide/ide-pnp.c @@ -1,6 +1,4 @@ /* - * 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. * @@ -13,53 +11,82 @@ * * 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. + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <linux/init.h> #include <linux/pnp.h> #include <linux/ide.h> +#include <linux/module.h> + +#define DRV_NAME "ide-pnp" /* Add your devices here :)) */ static struct pnp_device_id idepnp_devices[] = { - /* Generic ESDI/IDE/ATA compatible hard disk controller */ + /* 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) +static const struct ide_port_info ide_pnp_port_info = { + .host_flags = IDE_HFLAG_NO_DMA, + .chipset = ide_generic, +}; + +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; + struct ide_host *host; + unsigned long base, ctl; + int rc; + struct ide_hw hw, *hws[] = { &hw }; + + printk(KERN_INFO DRV_NAME ": generic PnP IDE interface\n"); if (!(pnp_port_valid(dev, 0) && pnp_port_valid(dev, 1) && pnp_irq_valid(dev, 0))) return -1; + base = pnp_port_start(dev, 0); + ctl = pnp_port_start(dev, 1); + + if (!request_region(base, 8, DRV_NAME)) { + printk(KERN_ERR "%s: I/O resource 0x%lX-0x%lX not free.\n", + DRV_NAME, base, base + 7); + return -EBUSY; + } + + if (!request_region(ctl, 1, DRV_NAME)) { + printk(KERN_ERR "%s: I/O resource 0x%lX not free.\n", + DRV_NAME, ctl); + release_region(base, 8); + return -EBUSY; + } + memset(&hw, 0, sizeof(hw)); - ide_std_init_ports(&hw, pnp_port_start(dev, 0), - pnp_port_start(dev, 1)); + ide_std_init_ports(&hw, base, ctl); hw.irq = pnp_irq(dev, 0); - hw.dma = NO_DMA; - index = ide_register_hw(&hw, &hwif); + rc = ide_host_add(&ide_pnp_port_info, hws, 1, &host); + if (rc) + goto out; - if (index != -1) { - printk(KERN_INFO "ide%d: generic PnP IDE interface\n", index); - pnp_set_drvdata(dev,hwif); - return 0; - } + pnp_set_drvdata(dev, host); + + return 0; +out: + release_region(ctl, 1); + release_region(base, 8); - return -1; + return rc; } -static void idepnp_remove(struct pnp_dev * dev) +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"); + struct ide_host *host = pnp_get_drvdata(dev); + + ide_host_remove(host); + + release_region(pnp_port_start(dev, 1), 1); + release_region(pnp_port_start(dev, 0), 8); } static struct pnp_driver idepnp_driver = { @@ -69,7 +96,17 @@ static struct pnp_driver idepnp_driver = { .remove = idepnp_remove, }; -void __init pnpide_init(void) +static int __init pnpide_init(void) { - pnp_register_driver(&idepnp_driver); + return pnp_register_driver(&idepnp_driver); } + +static void __exit pnpide_exit(void) +{ + pnp_unregister_driver(&idepnp_driver); +} + +module_init(pnpide_init); +module_exit(pnpide_exit); + +MODULE_LICENSE("GPL"); diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c index 9cadf0106c6..a3d3b1733c4 100644 --- a/drivers/ide/ide-probe.c +++ b/drivers/ide/ide-probe.c @@ -1,7 +1,6 @@ /* - * linux/drivers/ide/ide-probe.c Version 1.11 Mar 05, 2003 - * - * Copyright (C) 1994-1998 Linus Torvalds & authors (see below) + * Copyright (C) 1994-1998 Linus Torvalds & authors (see below) + * Copyright (C) 2005, 2007 Bartlomiej Zolnierkiewicz */ /* @@ -13,26 +12,10 @@ * * 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 + * -- increase WAIT_PIDENTIFY to avoid CD-ROM locking at boot + * by Andrea Arcangeli */ -#undef REALLY_SLOW_IO /* most systems can safely undef this */ - #include <linux/module.h> #include <linux/types.h> #include <linux/string.h> @@ -49,6 +32,7 @@ #include <linux/spinlock.h> #include <linux/kmod.h> #include <linux/pci.h> +#include <linux/scatterlist.h> #include <asm/byteorder.h> #include <asm/irq.h> @@ -66,273 +50,276 @@ 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; + u16 *id = drive->id; + + id[ATA_ID_CUR_CYLS] = id[ATA_ID_CYLS] = drive->cyl; + id[ATA_ID_CUR_HEADS] = id[ATA_ID_HEADS] = drive->head; + id[ATA_ID_CUR_SECTORS] = id[ATA_ID_SECTORS] = drive->sect; } static void ide_disk_init_chs(ide_drive_t *drive) { - struct hd_driveid *id = drive->id; + u16 *id = drive->id; /* Extract geometry if we did not already have one for the drive */ if (!drive->cyl || !drive->head || !drive->sect) { - drive->cyl = drive->bios_cyl = id->cyls; - drive->head = drive->bios_head = id->heads; - drive->sect = drive->bios_sect = id->sectors; + drive->cyl = drive->bios_cyl = id[ATA_ID_CYLS]; + drive->head = drive->bios_head = id[ATA_ID_HEADS]; + drive->sect = drive->bios_sect = id[ATA_ID_SECTORS]; } /* Handle logical geometry translation by the drive */ - if ((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; + if (ata_id_current_chs_valid(id)) { + drive->cyl = id[ATA_ID_CUR_CYLS]; + drive->head = id[ATA_ID_CUR_HEADS]; + drive->sect = id[ATA_ID_CUR_SECTORS]; } /* Use physical geometry if what we have still makes no sense */ - if (drive->head > 16 && id->heads && id->heads <= 16) { - drive->cyl = id->cyls; - drive->head = id->heads; - drive->sect = id->sectors; + if (drive->head > 16 && id[ATA_ID_HEADS] && id[ATA_ID_HEADS] <= 16) { + drive->cyl = id[ATA_ID_CYLS]; + drive->head = id[ATA_ID_HEADS]; + drive->sect = id[ATA_ID_SECTORS]; } } static void ide_disk_init_mult_count(ide_drive_t *drive) { - 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; + u16 *id = drive->id; + u8 max_multsect = id[ATA_ID_MAX_MULTSECT] & 0xff; + + if (max_multsect) { + if ((max_multsect / 2) > 1) + id[ATA_ID_MULTSECT] = max_multsect | 0x100; + else + id[ATA_ID_MULTSECT] &= ~0x1ff; + + drive->mult_req = id[ATA_ID_MULTSECT] & 0xff; + + if (drive->mult_req) + drive->special_flags |= IDE_SFLAG_SET_MULTMODE; + } +} + +static void ide_classify_ata_dev(ide_drive_t *drive) +{ + u16 *id = drive->id; + char *m = (char *)&id[ATA_ID_PROD]; + int is_cfa = ata_id_is_cfa(id); + + /* CF devices are *not* removable in Linux definition of the term */ + if (is_cfa == 0 && (id[ATA_ID_CONFIG] & (1 << 7))) + drive->dev_flags |= IDE_DFLAG_REMOVABLE; + + drive->media = ide_disk; + + if (!ata_id_has_unload(drive->id)) + drive->dev_flags |= IDE_DFLAG_NO_UNLOAD; + + printk(KERN_INFO "%s: %s, %s DISK drive\n", drive->name, m, + is_cfa ? "CFA" : "ATA"); +} + +static void ide_classify_atapi_dev(ide_drive_t *drive) +{ + u16 *id = drive->id; + char *m = (char *)&id[ATA_ID_PROD]; + u8 type = (id[ATA_ID_CONFIG] >> 8) & 0x1f; + + printk(KERN_INFO "%s: %s, ATAPI ", drive->name, m); + switch (type) { + case ide_floppy: + if (!strstr(m, "CD-ROM")) { + if (!strstr(m, "oppy") && + !strstr(m, "poyp") && + !strstr(m, "ZIP")) + printk(KERN_CONT "cdrom or floppy?, assuming "); + if (drive->media != ide_cdrom) { + printk(KERN_CONT "FLOPPY"); + drive->dev_flags |= IDE_DFLAG_REMOVABLE; + break; + } + } + /* Early cdrom models used zero */ + type = ide_cdrom; + case ide_cdrom: + drive->dev_flags |= IDE_DFLAG_REMOVABLE; +#ifdef CONFIG_PPC + /* kludge for Apple PowerBook internal zip */ + if (!strstr(m, "CD-ROM") && strstr(m, "ZIP")) { + printk(KERN_CONT "FLOPPY"); + type = ide_floppy; + break; + } #endif + printk(KERN_CONT "CD/DVD-ROM"); + break; + case ide_tape: + printk(KERN_CONT "TAPE"); + break; + case ide_optical: + printk(KERN_CONT "OPTICAL"); + drive->dev_flags |= IDE_DFLAG_REMOVABLE; + break; + default: + printk(KERN_CONT "UNKNOWN (type %d)", type); + break; } + + printk(KERN_CONT " drive\n"); + drive->media = type; + /* an ATAPI device ignores DRDY */ + drive->ready_stat = 0; + if (ata_id_cdb_intr(id)) + drive->atapi_flags |= IDE_AFLAG_DRQ_INTERRUPT; + drive->dev_flags |= IDE_DFLAG_DOORLOCKING; + /* we don't do head unloading on ATAPI devices */ + drive->dev_flags |= IDE_DFLAG_NO_UNLOAD; } /** * do_identify - identify a drive * @drive: drive to identify * @cmd: command used + * @id: buffer for IDENTIFY data * * 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) + +static void do_identify(ide_drive_t *drive, u8 cmd, u16 *id) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; + char *m = (char *)&id[ATA_ID_PROD]; + unsigned long flags; int bswap = 1; - struct hd_driveid *id; - id = drive->id; + /* local CPU only; some systems need this */ + local_irq_save(flags); /* read 512 bytes of id info */ - hwif->ata_input_data(drive, id, SECTOR_WORDS); + hwif->tp_ops->input_data(drive, NULL, id, SECTOR_SIZE); + local_irq_restore(flags); - drive->id_read = 1; - local_irq_enable(); + drive->dev_flags |= IDE_DFLAG_ID_READ; +#ifdef DEBUG + printk(KERN_INFO "%s: dumping identify data\n", drive->name); + ide_dump_identify((u8 *)id); +#endif 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. + * ATA_CMD_ID_ATA returns little-endian info, + * ATA_CMD_ID_ATAPI *usually* returns little-endian info. */ - 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 */ + if (cmd == ATA_CMD_ID_ATAPI) { + if ((m[0] == 'N' && m[1] == 'E') || /* NEC */ + (m[0] == 'F' && m[1] == 'X') || /* Mitsumi */ + (m[0] == 'P' && m[1] == 'i')) /* Pioneer */ /* Vertos drives may still be weird */ - bswap ^= 1; + 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; + ide_fixstring(m, ATA_ID_PROD_LEN, bswap); + ide_fixstring((char *)&id[ATA_ID_FW_REV], ATA_ID_FW_REV_LEN, bswap); + ide_fixstring((char *)&id[ATA_ID_SERNO], ATA_ID_SERNO_LEN, bswap); /* we depend on this a lot! */ - 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 - */ + m[ATA_ID_PROD_LEN - 1] = '\0'; - /* - * 0x848a = CompactFlash device - * These are *not* removable in Linux definition of the term - */ - - if ((id->config != 0x848a) && (id->config & (1<<7))) - drive->removable = 1; - - drive->media = ide_disk; - printk("%s DISK drive\n", (id->config == 0x848a) ? "CFA" : "ATA" ); - QUIRK_LIST(drive); - return; - -err_misc: - kfree(id); - drive->present = 0; - return; + if (strstr(m, "E X A B Y T E N E S T")) + drive->dev_flags &= ~IDE_DFLAG_PRESENT; + else + drive->dev_flags |= IDE_DFLAG_PRESENT; } /** - * actual_try_to_identify - send ata/atapi identify + * ide_dev_read_id - send ATA/ATAPI IDENTIFY command * @drive: drive to identify * @cmd: command to use + * @id: buffer for IDENTIFY data + * @irq_ctx: flag set when called from the IRQ context * - * 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. + * Sends an ATA(PI) IDENTIFY request to a drive and waits for a response. * * 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) +int ide_dev_read_id(ide_drive_t *drive, u8 cmd, u16 *id, int irq_ctx) { - ide_hwif_t *hwif = HWIF(drive); - int rc; - unsigned long hd_status; + ide_hwif_t *hwif = drive->hwif; + struct ide_io_ports *io_ports = &hwif->io_ports; + const struct ide_tp_ops *tp_ops = hwif->tp_ops; + int use_altstatus = 0, rc; unsigned long timeout; u8 s = 0, a = 0; + /* + * Disable device IRQ. Otherwise we'll get spurious interrupts + * during the identify phase that the IRQ handler isn't expecting. + */ + if (io_ports->ctl_addr) + tp_ops->write_devctl(hwif, ATA_NIEN | ATA_DEVCTL_OBS); + /* take a deep breath */ - msleep(50); + if (irq_ctx) + mdelay(50); + else + 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); + if (io_ports->ctl_addr && + (hwif->host_flags & IDE_HFLAG_BROKEN_ALTSTATUS) == 0) { + a = tp_ops->read_altstatus(hwif); + s = tp_ops->read_status(hwif); + if ((a ^ s) & ~ATA_IDX) /* ancient Seagate drives, broken interfaces */ - hd_status = IDE_STATUS_REG; - } else { + printk(KERN_INFO "%s: probing with STATUS(0x%02x) " + "instead of ALTSTATUS(0x%02x)\n", + drive->name, s, a); + else /* use non-intrusive polling */ - hd_status = IDE_ALTSTATUS_REG; - } - } else - hd_status = IDE_STATUS_REG; + use_altstatus = 1; + } /* 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); + if (cmd == ATA_CMD_ID_ATAPI) { + struct ide_taskfile tf; + + memset(&tf, 0, sizeof(tf)); + /* disable DMA & overlap */ + tp_ops->tf_load(drive, &tf, IDE_VALID_FEATURE); + } /* ask drive for ID */ - hwif->OUTB(cmd, IDE_COMMAND_REG); + tp_ops->exec_command(hwif, cmd); - timeout = ((cmd == WIN_IDENTIFY) ? WAIT_WORSTCASE : WAIT_PIDENTIFY) / 2; - timeout += jiffies; - do { - if (time_after(jiffies, timeout)) { - /* drive timed-out */ + timeout = ((cmd == ATA_CMD_ID_ATA) ? WAIT_WORSTCASE : WAIT_PIDENTIFY) / 2; + + /* wait for IRQ and ATA_DRQ */ + if (irq_ctx) { + rc = __ide_wait_stat(drive, ATA_DRQ, BAD_R_STAT, timeout, &s); + if (rc) + return 1; + } else { + rc = ide_busy_sleep(drive, timeout, use_altstatus); + if (rc) 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; + msleep(50); + s = tp_ops->read_status(hwif); + } - /* local CPU only; some systems need this */ - local_irq_save(flags); + if (OK_STAT(s, ATA_DRQ, BAD_R_STAT)) { /* drive returned ID */ - do_identify(drive, cmd); + do_identify(drive, cmd, id); /* drive responded with ID */ rc = 0; /* clear drive IRQ */ - (void) hwif->INB(IDE_STATUS_REG); - local_irq_restore(flags); + (void)tp_ops->read_status(hwif); } else { /* drive refused ID */ rc = 2; @@ -340,65 +327,34 @@ static int actual_try_to_identify (ide_drive_t *drive, u8 cmd) 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) +int ide_busy_sleep(ide_drive_t *drive, unsigned long timeout, int altstatus) { - ide_hwif_t *hwif = HWIF(drive); - int retval; - int autoprobe = 0; - unsigned long cookie = 0; + ide_hwif_t *hwif = drive->hwif; + u8 stat; - /* - * 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); - } + timeout += jiffies; - retval = actual_try_to_identify(drive, cmd); + do { + msleep(50); /* give drive a breather */ + stat = altstatus ? hwif->tp_ops->read_altstatus(hwif) + : hwif->tp_ops->read_status(hwif); + if ((stat & ATA_BUSY) == 0) + return 0; + } while (time_before(jiffies, timeout)); - 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; + printk(KERN_ERR "%s: timeout in %s\n", drive->name, __func__); + + return 1; /* drive timed-out */ } +static u8 ide_read_device(ide_drive_t *drive) +{ + struct ide_taskfile tf; + + drive->hwif->tp_ops->tf_read(drive, &tf, IDE_VALID_DEVICE); + + return tf.device; +} /** * do_probe - probe an IDE device @@ -423,119 +379,85 @@ static int try_to_identify (ide_drive_t *drive, u8 cmd) static int do_probe (ide_drive_t *drive, u8 cmd) { + ide_hwif_t *hwif = drive->hwif; + const struct ide_tp_ops *tp_ops = hwif->tp_ops; + u16 *id = drive->id; int rc; - ide_hwif_t *hwif = HWIF(drive); + u8 present = !!(drive->dev_flags & IDE_DFLAG_PRESENT), stat; + + /* avoid waiting for inappropriate probes */ + if (present && drive->media != ide_disk && cmd == ATA_CMD_ID_ATA) + return 4; - 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"); + printk(KERN_INFO "probing for %s: present=%d, media=%d, probetype=%s\n", + drive->name, present, drive->media, + (cmd == ATA_CMD_ID_ATA) ? "ATA" : "ATAPI"); #endif /* needed for some systems * (e.g. crw9624 as drive0 with disk as slave) */ msleep(50); - SELECT_DRIVE(drive); + tp_ops->dev_select(drive); msleep(50); - if (hwif->INB(IDE_SELECT_REG) != drive->select.all && !drive->present) { - if (drive->select.b.unit != 0) { + + if (ide_read_device(drive) != drive->select && present == 0) { + if (drive->dn & 1) { /* exit with drive0 selected */ - SELECT_DRIVE(&hwif->drives[0]); - /* allow BUSY_STAT to assert & clear */ + tp_ops->dev_select(hwif->devices[0]); + /* allow ATA_BUSY 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))) { + stat = tp_ops->read_status(hwif); + + if (OK_STAT(stat, ATA_DRDY, ATA_BUSY) || + present || cmd == ATA_CMD_ID_ATAPI) { + rc = ide_dev_read_id(drive, cmd, id, 0); + if (rc) /* failed: try again */ - rc = try_to_identify(drive,cmd); - } - if (hwif->INB(IDE_STATUS_REG) == (BUSY_STAT|READY_STAT)) + rc = ide_dev_read_id(drive, cmd, id, 0); + + stat = tp_ops->read_status(hwif); + + if (stat == (ATA_BUSY | ATA_DRDY)) 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)); + if (rc == 1 && cmd == ATA_CMD_ID_ATAPI) { + printk(KERN_ERR "%s: no response (status = 0x%02x), " + "resetting drive\n", drive->name, stat); msleep(50); - hwif->OUTB(drive->select.all, IDE_SELECT_REG); + tp_ops->dev_select(drive); 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); + tp_ops->exec_command(hwif, ATA_CMD_DEV_RESET); + (void)ide_busy_sleep(drive, WAIT_WORSTCASE, 0); + rc = ide_dev_read_id(drive, cmd, id, 0); } + + /* ensure drive IRQ is clear */ + stat = tp_ops->read_status(hwif); + 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); + printk(KERN_ERR "%s: no response (status = 0x%02x)\n", + drive->name, stat); } else { /* not present or maybe ATAPI */ rc = 3; } - if (drive->select.b.unit != 0) { + if (drive->dn & 1) { /* exit with drive0 selected */ - SELECT_DRIVE(&hwif->drives[0]); + tp_ops->dev_select(hwif->devices[0]); msleep(50); /* ensure drive irq is clear */ - (void) hwif->INB(IDE_STATUS_REG); + (void)tp_ops->read_status(hwif); } 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 @@ -544,46 +466,37 @@ static void enable_nest (ide_drive_t *drive) * 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) + * 1 device was found + * (note: IDE_DFLAG_PRESENT might still be not set) */ - -static inline u8 probe_for_drive (ide_drive_t *drive) + +static 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 = kzalloc(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; - } - strcpy(drive->id->model, "UNKNOWN"); - + char *m; + int rc; + u8 cmd; + + drive->dev_flags &= ~IDE_DFLAG_ID_READ; + + m = (char *)&drive->id[ATA_ID_PROD]; + strcpy(m, "UNKNOWN"); + /* skip probing? */ - if (!drive->noprobe) - { + if ((drive->dev_flags & IDE_DFLAG_NOPROBE) == 0) { /* if !(success||timed-out) */ - if (do_probe(drive, WIN_IDENTIFY) >= 2) { + cmd = ATA_CMD_ID_ATA; + rc = do_probe(drive, cmd); + if (rc >= 2) { /* look for ATAPI device */ - (void) do_probe(drive, WIN_PIDENTIFY); + cmd = ATA_CMD_ID_ATAPI; + rc = do_probe(drive, cmd); } - 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 */ + + if ((drive->dev_flags & IDE_DFLAG_PRESENT) == 0) return 0; - + /* identification failed? */ - if (!drive->id_read) { + if ((drive->dev_flags & IDE_DFLAG_ID_READ) == 0) { if (drive->media == ide_disk) { printk(KERN_INFO "%s: non-IDE drive, CHS=%d/%d/%d\n", drive->name, drive->cyl, @@ -593,15 +506,21 @@ static inline u8 probe_for_drive (ide_drive_t *drive) } else { /* nuke it */ printk(KERN_WARNING "%s: Unknown device on bus refused identification. Ignoring.\n", drive->name); - drive->present = 0; + drive->dev_flags &= ~IDE_DFLAG_PRESENT; } + } else { + if (cmd == ATA_CMD_ID_ATAPI) + ide_classify_atapi_dev(drive); + else + ide_classify_ata_dev(drive); } - /* drive was found */ } - if(!drive->present) + + if ((drive->dev_flags & IDE_DFLAG_PRESENT) == 0) return 0; + /* The drive wasn't being helpful. Add generic info only */ - if (drive->id_read == 0) { + if ((drive->dev_flags & IDE_DFLAG_ID_READ) == 0) { generic_id(drive); return 1; } @@ -611,35 +530,75 @@ static inline u8 probe_for_drive (ide_drive_t *drive) ide_disk_init_mult_count(drive); } - return drive->present; + return 1; } -static void hwif_release_dev (struct device *dev) +static void hwif_release_dev(struct device *dev) { ide_hwif_t *hwif = container_of(dev, ide_hwif_t, gendev); complete(&hwif->gendev_rel_comp); } -static void hwif_register (ide_hwif_t *hwif) +static int ide_register_port(ide_hwif_t *hwif) { + int ret; + /* register with global device tree */ - strlcpy(hwif->gendev.bus_id,hwif->name,BUS_ID_SIZE); - hwif->gendev.driver_data = hwif; - if (hwif->gendev.parent == NULL) { - if (hwif->pci_dev) - hwif->gendev.parent = &hwif->pci_dev->dev; - else - /* Would like to do = &device_legacy */ - hwif->gendev.parent = NULL; - } + dev_set_name(&hwif->gendev, "%s", hwif->name); + dev_set_drvdata(&hwif->gendev, hwif); + if (hwif->gendev.parent == NULL) + hwif->gendev.parent = hwif->dev; hwif->gendev.release = hwif_release_dev; - device_register(&hwif->gendev); + + ret = device_register(&hwif->gendev); + if (ret < 0) { + printk(KERN_WARNING "IDE: %s: device_register error: %d\n", + __func__, ret); + goto out; + } + + hwif->portdev = device_create(ide_port_class, &hwif->gendev, + MKDEV(0, 0), hwif, "%s", hwif->name); + if (IS_ERR(hwif->portdev)) { + ret = PTR_ERR(hwif->portdev); + device_unregister(&hwif->gendev); + } +out: + return ret; } -static int wait_hwif_ready(ide_hwif_t *hwif) +/** + * ide_port_wait_ready - wait for port to become ready + * @hwif: IDE port + * + * This is needed on some PPCs and a bunch of BIOS-less embedded + * platforms. Typical cases are: + * + * - The firmware hard reset the disk before booting the kernel, + * the drive is still doing it's poweron-reset sequence, that + * can take up to 30 seconds. + * + * - The firmware does nothing (or no firmware), the device is + * still in POST state (same as above actually). + * + * - Some CD/DVD/Writer combo drives tend to drive the bus during + * their reset sequence even when they are non-selected slave + * devices, thus preventing discovery of the main HD. + * + * Doing this wait-for-non-busy should not harm any existing + * configuration and fix some issues like the above. + * + * BenH. + * + * Returns 0 on success, error code (< 0) otherwise. + */ + +static int ide_port_wait_ready(ide_hwif_t *hwif) { - int rc; + const struct ide_tp_ops *tp_ops = hwif->tp_ops; + ide_drive_t *drive; + int i, rc; printk(KERN_DEBUG "Probing IDE interface %s...\n", hwif->name); @@ -656,90 +615,77 @@ static int wait_hwif_ready(ide_hwif_t *hwif) 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, 35000); - 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, 35000); - + ide_port_for_each_dev(i, drive, hwif) { + /* Ignore disks that we will not probe for later. */ + if ((drive->dev_flags & IDE_DFLAG_NOPROBE) == 0 || + (drive->dev_flags & IDE_DFLAG_PRESENT)) { + tp_ops->dev_select(drive); + tp_ops->write_devctl(hwif, ATA_DEVCTL_OBS); + mdelay(2); + rc = ide_wait_not_busy(hwif, 35000); + if (rc) + goto out; + } else + printk(KERN_DEBUG "%s: ide_wait_not_busy() skipped\n", + drive->name); + } +out: /* Exit function with master reselected (let's be sane) */ - SELECT_DRIVE(&hwif->drives[0]); - + if (i) + tp_ops->dev_select(hwif->devices[0]); + return rc; } /** * ide_undecoded_slave - look for bad CF adapters - * @hwif: interface + * @dev1: slave device * * Analyse the drives on the interface and attempt to decide if we * have the same drive viewed twice. This occurs with crap CF adapters * and PCMCIA sometimes. */ -void ide_undecoded_slave(ide_hwif_t *hwif) +void ide_undecoded_slave(ide_drive_t *dev1) { - ide_drive_t *drive0 = &hwif->drives[0]; - ide_drive_t *drive1 = &hwif->drives[1]; + ide_drive_t *dev0 = dev1->hwif->devices[0]; - if (drive0->present == 0 || drive1->present == 0) + if ((dev1->dn & 1) == 0 || (dev0->dev_flags & IDE_DFLAG_PRESENT) == 0) return; /* If the models don't match they are not the same product */ - if (strcmp(drive0->id->model, drive1->id->model)) + if (strcmp((char *)&dev0->id[ATA_ID_PROD], + (char *)&dev1->id[ATA_ID_PROD])) return; /* Serial numbers do not match */ - if (strncmp(drive0->id->serial_no, drive1->id->serial_no, 20)) + if (strncmp((char *)&dev0->id[ATA_ID_SERNO], + (char *)&dev1->id[ATA_ID_SERNO], ATA_ID_SERNO_LEN)) return; /* No serial number, thankfully very rare for CF */ - if (drive0->id->serial_no[0] == 0) + if (*(char *)&dev0->id[ATA_ID_SERNO] == 0) return; /* Appears to be an IDE flash adapter with decode bugs */ printk(KERN_WARNING "ide-probe: ignoring undecoded slave\n"); - drive1->present = 0; + dev1->dev_flags &= ~IDE_DFLAG_PRESENT; } 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) +static int ide_probe_port(ide_hwif_t *hwif) { - unsigned int unit; - unsigned long flags; + ide_drive_t *drive; unsigned int irqd; + int i, rc = -ENODEV; - if (hwif->noprobe) - return; + BUG_ON(hwif->present); - 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; - } + if ((hwif->devices[0]->dev_flags & IDE_DFLAG_NOPROBE) && + (hwif->devices[1]->dev_flags & IDE_DFLAG_NOPROBE)) + return -EACCES; /* * We must always disable IRQ, as probe_for_drive will assert IRQ, but @@ -749,62 +695,19 @@ static void probe_hwif(ide_hwif_t *hwif) 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) + if (ide_port_wait_ready(hwif) == -EBUSY) printk(KERN_DEBUG "%s: Wait for ready failed before probe !\n", hwif->name); /* * Second drive should only exist if first drive was found, * but a lot of cdrom drives are configured as single slaves. */ - for (unit = 0; unit < MAX_DRIVES; ++unit) { - ide_drive_t *drive = &hwif->drives[unit]; - drive->dn = (hwif->channel ? 2 : 0) + unit; + ide_port_for_each_dev(i, drive, hwif) { (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 (drive->dev_flags & IDE_DFLAG_PRESENT) + rc = 0; } - 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 @@ -812,132 +715,39 @@ static void probe_hwif(ide_hwif_t *hwif) 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); - } - } - } - - for (unit = 0; unit < MAX_DRIVES; ++unit) { - ide_drive_t *drive = &hwif->drives[unit]; - - if (hwif->no_io_32bit) - drive->no_io_32bit = 1; - else - drive->no_io_32bit = drive->id->dword_io ? 1 : 0; - } + return rc; } -static int hwif_init(ide_hwif_t *hwif); - -int probe_hwif_init_with_fixup(ide_hwif_t *hwif, void (*fixup)(ide_hwif_t *hwif)) +static void ide_port_tune_devices(ide_hwif_t *hwif) { - probe_hwif(hwif); + const struct ide_port_ops *port_ops = hwif->port_ops; + ide_drive_t *drive; + int i; - if (fixup) - fixup(hwif); + ide_port_for_each_present_dev(i, drive, hwif) { + ide_check_nien_quirk_list(drive); - if (!hwif_init(hwif)) { - printk(KERN_INFO "%s: failed to initialize IDE interface\n", - hwif->name); - return -1; + if (port_ops && port_ops->quirkproc) + port_ops->quirkproc(drive); } - 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) { - device_register(&drive->gendev); - } - } - } - return 0; -} + ide_port_for_each_present_dev(i, drive, hwif) { + ide_set_max_pio(drive); -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; + drive->dev_flags |= IDE_DFLAG_NICE1; - 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 (hwif->dma_ops) + ide_set_dma(drive); } - 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); + struct request_queue *q; + ide_hwif_t *hwif = drive->hwif; int max_sectors = 256; int max_sg_entries = PRD_ENTRIES; @@ -949,22 +759,16 @@ static int ide_init_queue(ide_drive_t *drive) * do not. */ - q = blk_init_queue_node(do_ide_request, &ide_lock, hwif_to_node(hwif)); + q = blk_init_queue_node(do_ide_request, NULL, hwif_to_node(hwif)); 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); + blk_queue_max_hw_sectors(q, max_sectors); #ifdef CONFIG_PCI /* When we have an IOMMU, we may have a problem where pci_map_sg() @@ -980,8 +784,7 @@ static int ide_init_queue(ide_drive_t *drive) 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); + blk_queue_max_segments(q, max_sg_entries); /* assign drive queue */ drive->queue = q; @@ -989,190 +792,85 @@ static int ide_init_queue(ide_drive_t *drive) /* 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; } +static DEFINE_MUTEX(ide_cfg_mtx); + /* - * 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 IRQF_DISABLED 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. + * For any present drive: + * - allocate the block device queue */ -static int init_irq (ide_hwif_t *hwif) +static int ide_port_setup_devices(ide_hwif_t *hwif) { - unsigned int index; - ide_hwgroup_t *hwgroup; - ide_hwif_t *match = NULL; - - - BUG_ON(in_interrupt()); - BUG_ON(irqs_disabled()); - BUG_ON(hwif == NULL); + ide_drive_t *drive; + int i, j = 0; - 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); - } + mutex_lock(&ide_cfg_mtx); + ide_port_for_each_present_dev(i, drive, hwif) { + if (ide_init_queue(drive)) { + printk(KERN_ERR "ide: failed to init %s\n", + drive->name); + drive->dev_flags &= ~IDE_DFLAG_PRESENT; + continue; } - } -#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_node(sizeof(ide_hwgroup_t), GFP_KERNEL, - hwif_to_node(hwif->drives[0].hwif)); - 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 = IRQF_DISABLED; -#if defined(__mc68000__) || defined(CONFIG_APUS) - sa = IRQF_SHARED; -#endif /* __mc68000__ || CONFIG_APUS */ - - if (IDE_CHIPSET_IS_PCI(hwif->chipset)) { - sa = IRQF_SHARED; -#ifndef CONFIG_IDEPCI_SHARE_IRQ - sa |= IRQF_DISABLED; -#endif /* CONFIG_IDEPCI_SHARE_IRQ */ - } + j++; + } + mutex_unlock(&ide_cfg_mtx); - if (hwif->io_ports[IDE_CONTROL_OFFSET]) - /* clear nIEN */ - hwif->OUTB(0x08, hwif->io_ports[IDE_CONTROL_OFFSET]); + return j; +} - if (request_irq(hwif->irq,&ide_intr,sa,hwif->name,hwgroup)) - goto out_unlink; - } +static void ide_host_enable_irqs(struct ide_host *host) +{ + ide_hwif_t *hwif; + int i; - /* - * 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); + ide_host_for_each_port(i, hwif, host) { + if (hwif == NULL) 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); + + /* clear any pending IRQs */ + hwif->tp_ops->read_status(hwif); + + /* unmask IRQs */ + if (hwif->io_ports.ctl_addr) + hwif->tp_ops->write_devctl(hwif, ATA_DEVCTL_OBS); } +} -#if !defined(__mc68000__) && !defined(CONFIG_APUS) - 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); +/* + * This routine sets up the IRQ for an IDE interface. + */ +static int init_irq (ide_hwif_t *hwif) +{ + struct ide_io_ports *io_ports = &hwif->io_ports; + struct ide_host *host = hwif->host; + irq_handler_t irq_handler = host->irq_handler; + int sa = host->irq_flags; + + if (irq_handler == NULL) + irq_handler = ide_intr; + + if (!host->get_lock) + if (request_irq(hwif->irq, irq_handler, sa, hwif->name, hwif)) + goto out_up; + +#if !defined(__mc68000__) + printk(KERN_INFO "%s at 0x%03lx-0x%03lx,0x%03lx on irq %d", hwif->name, + io_ports->data_addr, io_ports->status_addr, + io_ports->ctl_addr, hwif->irq); #else - printk("%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); + printk(KERN_INFO "%s at 0x%08lx on irq %d", hwif->name, + io_ports->data_addr, hwif->irq); +#endif /* __mc68000__ */ + if (hwif->host->host_flags & IDE_HFLAG_SERIALIZE) + printk(KERN_CONT " (serialized)"); + printk(KERN_CONT "\n"); + 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; } @@ -1186,14 +884,13 @@ 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) + ide_drive_t *drive = hwif->devices[unit]; + + if ((drive->dev_flags & IDE_DFLAG_PRESENT) == 0) 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) @@ -1208,7 +905,7 @@ static struct kobject *exact_match(dev_t dev, int *part, void *data) { struct gendisk *p = data; *part &= (1 << PARTN_BITS) - 1; - return &p->kobj; + return &disk_to_dev(p)->kobj; } static int exact_lock(dev_t dev, void *data) @@ -1239,7 +936,7 @@ 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; + unsigned int unit = drive->dn & 1; disk->major = hwif->major; disk->first_minor = unit << PARTN_BITS; @@ -1249,97 +946,26 @@ void ide_init_disk(struct gendisk *disk, ide_drive_t *drive) EXPORT_SYMBOL_GPL(ide_init_disk); -static void ide_remove_drive_from_hwgroup(ide_drive_t *drive) -{ - ide_hwgroup_t *hwgroup = drive->hwif->hwgroup; - - if (drive == drive->next) { - /* special case: last drive from hwgroup. */ - BUG_ON(hwgroup->drive != drive); - hwgroup->drive = NULL; - } else { - ide_drive_t *walk; - - walk = hwgroup->drive; - while (walk->next != drive) - walk = walk->next; - walk->next = drive->next; - if (hwgroup->drive == drive) { - hwgroup->drive = drive->next; - hwgroup->hwif = hwgroup->drive->hwif; - } - } - BUG_ON(hwgroup->drive == drive); -} - static void drive_release_dev (struct device *dev) { ide_drive_t *drive = container_of(dev, ide_drive_t, gendev); - spin_lock_irq(&ide_lock); - ide_remove_drive_from_hwgroup(drive); - kfree(drive->id); - drive->id = NULL; - drive->present = 0; - /* Messed up locking ... */ - spin_unlock_irq(&ide_lock); + ide_proc_unregister_device(drive); + blk_cleanup_queue(drive->queue); - spin_lock_irq(&ide_lock); drive->queue = NULL; - spin_unlock_irq(&ide_lock); - complete(&drive->gendev_rel_comp); -} + drive->dev_flags &= ~IDE_DFLAG_PRESENT; -/* - * 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; - } - blk_register_region(MKDEV(hwif->major, 0), MAX_DRIVES << PARTN_BITS, - THIS_MODULE, ata_probe, ata_lock, hwif); + complete(&drive->gendev_rel_comp); } 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); + printk(KERN_ERR "%s: disabled, no IRQ\n", hwif->name); + return 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; @@ -1353,31 +979,17 @@ static int hwif_init(ide_hwif_t *hwif) 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; - } + sg_init_table(hwif->sg_table, hwif->sg_max_nents); + if (init_irq(hwif)) { - printk("%s: probed IRQ %d and default IRQ %d failed.\n", - hwif->name, old_irq, hwif->irq); + printk(KERN_ERR "%s: disabled, unable to get IRQ %d\n", + hwif->name, 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 */ + blk_register_region(MKDEV(hwif->major, 0), MAX_DRIVES << PARTN_BITS, + THIS_MODULE, ata_probe, ata_lock, hwif); return 1; out: @@ -1385,35 +997,614 @@ out: return 0; } -int ideprobe_init (void) +static void hwif_register_devices(ide_hwif_t *hwif) +{ + ide_drive_t *drive; + unsigned int i; + + ide_port_for_each_present_dev(i, drive, hwif) { + struct device *dev = &drive->gendev; + int ret; + + dev_set_name(dev, "%u.%u", hwif->index, i); + dev_set_drvdata(dev, drive); + dev->parent = &hwif->gendev; + dev->bus = &ide_bus_type; + dev->release = drive_release_dev; + + ret = device_register(dev); + if (ret < 0) + printk(KERN_WARNING "IDE: %s: device_register error: " + "%d\n", __func__, ret); + } +} + +static void ide_port_init_devices(ide_hwif_t *hwif) +{ + const struct ide_port_ops *port_ops = hwif->port_ops; + ide_drive_t *drive; + int i; + + ide_port_for_each_dev(i, drive, hwif) { + drive->dn = i + hwif->channel * 2; + + if (hwif->host_flags & IDE_HFLAG_IO_32BIT) + drive->io_32bit = 1; + if (hwif->host_flags & IDE_HFLAG_NO_IO_32BIT) + drive->dev_flags |= IDE_DFLAG_NO_IO_32BIT; + if (hwif->host_flags & IDE_HFLAG_UNMASK_IRQS) + drive->dev_flags |= IDE_DFLAG_UNMASK; + if (hwif->host_flags & IDE_HFLAG_NO_UNMASK_IRQS) + drive->dev_flags |= IDE_DFLAG_NO_UNMASK; + + drive->pio_mode = XFER_PIO_0; + + if (port_ops && port_ops->init_dev) + port_ops->init_dev(drive); + } +} + +static void ide_init_port(ide_hwif_t *hwif, unsigned int port, + const struct ide_port_info *d) +{ + hwif->channel = port; + + hwif->chipset = d->chipset ? d->chipset : ide_pci; + + if (d->init_iops) + d->init_iops(hwif); + + /* ->host_flags may be set by ->init_iops (or even earlier...) */ + hwif->host_flags |= d->host_flags; + hwif->pio_mask = d->pio_mask; + + if (d->tp_ops) + hwif->tp_ops = d->tp_ops; + + /* ->set_pio_mode for DTC2278 is currently limited to port 0 */ + if ((hwif->host_flags & IDE_HFLAG_DTC2278) == 0 || hwif->channel == 0) + hwif->port_ops = d->port_ops; + + hwif->swdma_mask = d->swdma_mask; + hwif->mwdma_mask = d->mwdma_mask; + hwif->ultra_mask = d->udma_mask; + + if ((d->host_flags & IDE_HFLAG_NO_DMA) == 0) { + int rc; + + hwif->dma_ops = d->dma_ops; + + if (d->init_dma) + rc = d->init_dma(hwif, d); + else + rc = ide_hwif_setup_dma(hwif, d); + + if (rc < 0) { + printk(KERN_INFO "%s: DMA disabled\n", hwif->name); + + hwif->dma_ops = NULL; + hwif->dma_base = 0; + hwif->swdma_mask = 0; + hwif->mwdma_mask = 0; + hwif->ultra_mask = 0; + } + } + + if ((d->host_flags & IDE_HFLAG_SERIALIZE) || + ((d->host_flags & IDE_HFLAG_SERIALIZE_DMA) && hwif->dma_base)) + hwif->host->host_flags |= IDE_HFLAG_SERIALIZE; + + if (d->max_sectors) + hwif->rqsize = d->max_sectors; + else { + if ((hwif->host_flags & IDE_HFLAG_NO_LBA48) || + (hwif->host_flags & IDE_HFLAG_NO_LBA48_DMA)) + hwif->rqsize = 256; + else + hwif->rqsize = 65536; + } + + /* call chipset specific routine for each enabled port */ + if (d->init_hwif) + d->init_hwif(hwif); +} + +static void ide_port_cable_detect(ide_hwif_t *hwif) +{ + const struct ide_port_ops *port_ops = hwif->port_ops; + + if (port_ops && port_ops->cable_detect && (hwif->ultra_mask & 0x78)) { + if (hwif->cbl != ATA_CBL_PATA40_SHORT) + hwif->cbl = port_ops->cable_detect(hwif); + } +} + +static const u8 ide_hwif_to_major[] = + { IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR, IDE4_MAJOR, + IDE5_MAJOR, IDE6_MAJOR, IDE7_MAJOR, IDE8_MAJOR, IDE9_MAJOR }; + +static void ide_port_init_devices_data(ide_hwif_t *hwif) +{ + ide_drive_t *drive; + int i; + + ide_port_for_each_dev(i, drive, hwif) { + u8 j = (hwif->index * MAX_DRIVES) + i; + u16 *saved_id = drive->id; + + memset(drive, 0, sizeof(*drive)); + memset(saved_id, 0, SECTOR_SIZE); + drive->id = saved_id; + + drive->media = ide_disk; + drive->select = (i << 4) | ATA_DEVICE_OBS; + drive->hwif = hwif; + drive->ready_stat = ATA_DRDY; + drive->bad_wstat = BAD_W_STAT; + drive->special_flags = IDE_SFLAG_RECALIBRATE | + IDE_SFLAG_SET_GEOMETRY; + drive->name[0] = 'h'; + drive->name[1] = 'd'; + drive->name[2] = 'a' + j; + drive->max_failures = IDE_DEFAULT_MAX_FAILURES; + + INIT_LIST_HEAD(&drive->list); + init_completion(&drive->gendev_rel_comp); + } +} + +static void ide_init_port_data(ide_hwif_t *hwif, unsigned int index) +{ + /* fill in any non-zero initial values */ + hwif->index = index; + hwif->major = ide_hwif_to_major[index]; + + hwif->name[0] = 'i'; + hwif->name[1] = 'd'; + hwif->name[2] = 'e'; + hwif->name[3] = '0' + index; + + spin_lock_init(&hwif->lock); + + init_timer(&hwif->timer); + hwif->timer.function = &ide_timer_expiry; + hwif->timer.data = (unsigned long)hwif; + + init_completion(&hwif->gendev_rel_comp); + + hwif->tp_ops = &default_tp_ops; + + ide_port_init_devices_data(hwif); +} + +static void ide_init_port_hw(ide_hwif_t *hwif, struct ide_hw *hw) +{ + memcpy(&hwif->io_ports, &hw->io_ports, sizeof(hwif->io_ports)); + hwif->irq = hw->irq; + hwif->dev = hw->dev; + hwif->gendev.parent = hw->parent ? hw->parent : hw->dev; + hwif->config_data = hw->config; +} + +static unsigned int ide_indexes; + +/** + * ide_find_port_slot - find free port slot + * @d: IDE port info + * + * Return the new port slot index or -ENOENT if we are out of free slots. + */ + +static int ide_find_port_slot(const struct ide_port_info *d) +{ + int idx = -ENOENT; + u8 bootable = (d && (d->host_flags & IDE_HFLAG_NON_BOOTABLE)) ? 0 : 1; + u8 i = (d && (d->host_flags & IDE_HFLAG_QD_2ND_PORT)) ? 1 : 0; + + /* + * Claim an unassigned slot. + * + * Give preference to claiming other slots before claiming ide0/ide1, + * just in case there's another interface yet-to-be-scanned + * which uses ports 0x1f0/0x170 (the ide0/ide1 defaults). + * + * Unless there is a bootable card that does not use the standard + * ports 0x1f0/0x170 (the ide0/ide1 defaults). + */ + mutex_lock(&ide_cfg_mtx); + if (bootable) { + if ((ide_indexes | i) != (1 << MAX_HWIFS) - 1) + idx = ffz(ide_indexes | i); + } else { + if ((ide_indexes | 3) != (1 << MAX_HWIFS) - 1) + idx = ffz(ide_indexes | 3); + else if ((ide_indexes & 3) != 3) + idx = ffz(ide_indexes); + } + if (idx >= 0) + ide_indexes |= (1 << idx); + mutex_unlock(&ide_cfg_mtx); + + return idx; +} + +static void ide_free_port_slot(int idx) +{ + mutex_lock(&ide_cfg_mtx); + ide_indexes &= ~(1 << idx); + mutex_unlock(&ide_cfg_mtx); +} + +static void ide_port_free_devices(ide_hwif_t *hwif) +{ + ide_drive_t *drive; + int i; + + ide_port_for_each_dev(i, drive, hwif) { + kfree(drive->id); + kfree(drive); + } +} + +static int ide_port_alloc_devices(ide_hwif_t *hwif, int node) +{ + int i; + + for (i = 0; i < MAX_DRIVES; i++) { + ide_drive_t *drive; + + drive = kzalloc_node(sizeof(*drive), GFP_KERNEL, node); + if (drive == NULL) + goto out_nomem; + + /* + * 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 = kzalloc_node(SECTOR_SIZE, GFP_KERNEL, node); + if (drive->id == NULL) + goto out_nomem; + + hwif->devices[i] = drive; + } + return 0; + +out_nomem: + ide_port_free_devices(hwif); + return -ENOMEM; +} + +struct ide_host *ide_host_alloc(const struct ide_port_info *d, + struct ide_hw **hws, unsigned int n_ports) +{ + struct ide_host *host; + struct device *dev = hws[0] ? hws[0]->dev : NULL; + int node = dev ? dev_to_node(dev) : -1; + int i; + + host = kzalloc_node(sizeof(*host), GFP_KERNEL, node); + if (host == NULL) + return NULL; + + for (i = 0; i < n_ports; i++) { + ide_hwif_t *hwif; + int idx; + + if (hws[i] == NULL) + continue; + + hwif = kzalloc_node(sizeof(*hwif), GFP_KERNEL, node); + if (hwif == NULL) + continue; + + if (ide_port_alloc_devices(hwif, node) < 0) { + kfree(hwif); + continue; + } + + idx = ide_find_port_slot(d); + if (idx < 0) { + printk(KERN_ERR "%s: no free slot for interface\n", + d ? d->name : "ide"); + ide_port_free_devices(hwif); + kfree(hwif); + continue; + } + + ide_init_port_data(hwif, idx); + + hwif->host = host; + + host->ports[i] = hwif; + host->n_ports++; + } + + if (host->n_ports == 0) { + kfree(host); + return NULL; + } + + host->dev[0] = dev; + + if (d) { + host->init_chipset = d->init_chipset; + host->get_lock = d->get_lock; + host->release_lock = d->release_lock; + host->host_flags = d->host_flags; + host->irq_flags = d->irq_flags; + } + + return host; +} +EXPORT_SYMBOL_GPL(ide_host_alloc); + +static void ide_port_free(ide_hwif_t *hwif) { - 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) + ide_port_free_devices(hwif); + ide_free_port_slot(hwif->index); + kfree(hwif); +} + +static void ide_disable_port(ide_hwif_t *hwif) +{ + struct ide_host *host = hwif->host; + int i; + + printk(KERN_INFO "%s: disabling port\n", hwif->name); + + for (i = 0; i < MAX_HOST_PORTS; i++) { + if (host->ports[i] == hwif) { + host->ports[i] = NULL; + host->n_ports--; + } + } + + ide_port_free(hwif); +} + +int ide_host_register(struct ide_host *host, const struct ide_port_info *d, + struct ide_hw **hws) +{ + ide_hwif_t *hwif, *mate = NULL; + int i, j = 0; + + ide_host_for_each_port(i, hwif, host) { + if (hwif == NULL) { + mate = NULL; + continue; + } + + ide_init_port_hw(hwif, hws[i]); + ide_port_apply_params(hwif); + + if ((i & 1) && mate) { + hwif->mate = mate; + mate->mate = hwif; + } + + mate = (i & 1) ? NULL : hwif; + + ide_init_port(hwif, i & 1, d); + ide_port_cable_detect(hwif); + + hwif->port_flags |= IDE_PFLAG_PROBING; + + ide_port_init_devices(hwif); + } + + ide_host_for_each_port(i, hwif, host) { + if (hwif == NULL) + continue; + + if (ide_probe_port(hwif) == 0) + hwif->present = 1; + + hwif->port_flags &= ~IDE_PFLAG_PROBING; + + if ((hwif->host_flags & IDE_HFLAG_4DRIVES) == 0 || + hwif->mate == NULL || hwif->mate->present == 0) { + if (ide_register_port(hwif)) { + ide_disable_port(hwif); + continue; + } + } + + if (hwif->present) + ide_port_tune_devices(hwif); + } + + ide_host_enable_irqs(host); + + ide_host_for_each_port(i, hwif, host) { + if (hwif == NULL) + continue; + + if (hwif_init(hwif) == 0) { + printk(KERN_INFO "%s: failed to initialize IDE " + "interface\n", hwif->name); + device_unregister(&hwif->gendev); + ide_disable_port(hwif); + continue; + } + + if (hwif->present) + if (ide_port_setup_devices(hwif) == 0) { + hwif->present = 0; 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) - device_register(&hwif->drives[unit].gendev); + } + + j++; + + ide_acpi_init_port(hwif); + + if (hwif->present) + ide_acpi_port_init_devices(hwif); + } + + ide_host_for_each_port(i, hwif, host) { + if (hwif == NULL) + continue; + + ide_sysfs_register_port(hwif); + ide_proc_register_port(hwif); + + if (hwif->present) { + ide_proc_port_register_devices(hwif); + hwif_register_devices(hwif); } } + + return j ? 0 : -1; +} +EXPORT_SYMBOL_GPL(ide_host_register); + +int ide_host_add(const struct ide_port_info *d, struct ide_hw **hws, + unsigned int n_ports, struct ide_host **hostp) +{ + struct ide_host *host; + int rc; + + host = ide_host_alloc(d, hws, n_ports); + if (host == NULL) + return -ENOMEM; + + rc = ide_host_register(host, d, hws); + if (rc) { + ide_host_free(host); + return rc; + } + + if (hostp) + *hostp = host; + return 0; } +EXPORT_SYMBOL_GPL(ide_host_add); + +static void __ide_port_unregister_devices(ide_hwif_t *hwif) +{ + ide_drive_t *drive; + int i; + + ide_port_for_each_present_dev(i, drive, hwif) { + device_unregister(&drive->gendev); + wait_for_completion(&drive->gendev_rel_comp); + } +} + +void ide_port_unregister_devices(ide_hwif_t *hwif) +{ + mutex_lock(&ide_cfg_mtx); + __ide_port_unregister_devices(hwif); + hwif->present = 0; + ide_port_init_devices_data(hwif); + mutex_unlock(&ide_cfg_mtx); +} +EXPORT_SYMBOL_GPL(ide_port_unregister_devices); + +/** + * ide_unregister - free an IDE interface + * @hwif: IDE interface + * + * Perform the final unregister of an IDE interface. + * + * Locking: + * The caller must not hold the IDE locks. + * + * It is up to the caller to be sure there is no pending I/O here, + * and that the interface will not be reopened (present/vanishing + * locking isn't yet done BTW). + */ + +static void ide_unregister(ide_hwif_t *hwif) +{ + BUG_ON(in_interrupt()); + BUG_ON(irqs_disabled()); + + mutex_lock(&ide_cfg_mtx); + + if (hwif->present) { + __ide_port_unregister_devices(hwif); + hwif->present = 0; + } -EXPORT_SYMBOL_GPL(ideprobe_init); + ide_proc_unregister_port(hwif); + + if (!hwif->host->get_lock) + free_irq(hwif->irq, hwif); + + device_unregister(hwif->portdev); + device_unregister(&hwif->gendev); + wait_for_completion(&hwif->gendev_rel_comp); + + /* + * Remove us from the kernel's knowledge + */ + blk_unregister_region(MKDEV(hwif->major, 0), MAX_DRIVES<<PARTN_BITS); + kfree(hwif->sg_table); + unregister_blkdev(hwif->major, hwif->name); + + ide_release_dma_engine(hwif); + + mutex_unlock(&ide_cfg_mtx); +} + +void ide_host_free(struct ide_host *host) +{ + ide_hwif_t *hwif; + int i; + + ide_host_for_each_port(i, hwif, host) { + if (hwif) + ide_port_free(hwif); + } + + kfree(host); +} +EXPORT_SYMBOL_GPL(ide_host_free); + +void ide_host_remove(struct ide_host *host) +{ + ide_hwif_t *hwif; + int i; + + ide_host_for_each_port(i, hwif, host) { + if (hwif) + ide_unregister(hwif); + } + + ide_host_free(host); +} +EXPORT_SYMBOL_GPL(ide_host_remove); + +void ide_port_scan(ide_hwif_t *hwif) +{ + int rc; + + ide_port_apply_params(hwif); + ide_port_cable_detect(hwif); + + hwif->port_flags |= IDE_PFLAG_PROBING; + + ide_port_init_devices(hwif); + + rc = ide_probe_port(hwif); + + hwif->port_flags &= ~IDE_PFLAG_PROBING; + + if (rc < 0) + return; + + hwif->present = 1; + + ide_port_tune_devices(hwif); + ide_port_setup_devices(hwif); + ide_acpi_port_init_devices(hwif); + hwif_register_devices(hwif); + ide_proc_port_register_devices(hwif); +} +EXPORT_SYMBOL_GPL(ide_port_scan); diff --git a/drivers/ide/ide-proc.c b/drivers/ide/ide-proc.c index 41b74b13a00..97c07007777 100644 --- a/drivers/ide/ide-proc.c +++ b/drivers/ide/ide-proc.c @@ -1,8 +1,8 @@ /* - * 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> + * Copyright (C) 2003 Red Hat + * + * Some code was moved here from ide.c, see it for original copyrights. */ /* @@ -12,172 +12,333 @@ * "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/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 <linux/slab.h> #include <asm/io.h> -static int proc_ide_read_imodel - (char *page, char **start, off_t off, int count, int *eof, void *data) +static struct proc_dir_entry *proc_ide_root; + +static int ide_imodel_proc_show(struct seq_file *m, void *v) { - ide_hwif_t *hwif = (ide_hwif_t *) data; - int len; + ide_hwif_t *hwif = (ide_hwif_t *) m->private; 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; - case ide_au1xxx: name = "au1xxx"; break; - default: name = "(unknown)"; break; + 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_4drives: name = "4drives"; break; + case ide_pmac: name = "mac-io"; break; + case ide_au1xxx: name = "au1xxx"; break; + case ide_palm3710: name = "palm3710"; break; + case ide_acorn: name = "acorn"; break; + default: name = "(unknown)"; break; } - len = sprintf(page, "%s\n", name); - PROC_IDE_READ_RETURN(page,start,off,count,eof,len); + seq_printf(m, "%s\n", name); + return 0; +} + +static int ide_imodel_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, ide_imodel_proc_show, PDE_DATA(inode)); } -static int proc_ide_read_mate - (char *page, char **start, off_t off, int count, int *eof, void *data) +static const struct file_operations ide_imodel_proc_fops = { + .owner = THIS_MODULE, + .open = ide_imodel_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int ide_mate_proc_show(struct seq_file *m, void *v) { - ide_hwif_t *hwif = (ide_hwif_t *) data; - int len; + ide_hwif_t *hwif = (ide_hwif_t *) m->private; - if (hwif && hwif->mate && hwif->mate->present) - len = sprintf(page, "%s\n", hwif->mate->name); + if (hwif && hwif->mate) + seq_printf(m, "%s\n", hwif->mate->name); else - len = sprintf(page, "(none)\n"); - PROC_IDE_READ_RETURN(page,start,off,count,eof,len); + seq_printf(m, "(none)\n"); + return 0; } -static int proc_ide_read_channel - (char *page, char **start, off_t off, int count, int *eof, void *data) +static int ide_mate_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, ide_mate_proc_show, PDE_DATA(inode)); +} + +static const struct file_operations ide_mate_proc_fops = { + .owner = THIS_MODULE, + .open = ide_mate_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int ide_channel_proc_show(struct seq_file *m, void *v) { - ide_hwif_t *hwif = (ide_hwif_t *) data; - int len; + ide_hwif_t *hwif = (ide_hwif_t *) m->private; - page[0] = hwif->channel ? '1' : '0'; - page[1] = '\n'; - len = 2; - PROC_IDE_READ_RETURN(page,start,off,count,eof,len); + seq_printf(m, "%c\n", hwif->channel ? '1' : '0'); + return 0; } -static int proc_ide_read_identify - (char *page, char **start, off_t off, int count, int *eof, void *data) +static int ide_channel_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, ide_channel_proc_show, PDE_DATA(inode)); +} + +static const struct file_operations ide_channel_proc_fops = { + .owner = THIS_MODULE, + .open = ide_channel_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int ide_identify_proc_show(struct seq_file *m, void *v) { - ide_drive_t *drive = (ide_drive_t *)data; - int len = 0, i = 0; - int err = 0; + ide_drive_t *drive = (ide_drive_t *)m->private; + u8 *buf; - len = sprintf(page, "\n"); + if (!drive) { + seq_putc(m, '\n'); + return 0; + } - if (drive) { - unsigned short *val = (unsigned short *) page; + buf = kmalloc(SECTOR_SIZE, GFP_KERNEL); + if (!buf) + return -ENOMEM; + if (taskfile_lib_get_identify(drive, buf) == 0) { + __le16 *val = (__le16 *)buf; + int i; - 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; + for (i = 0; i < SECTOR_SIZE / 2; i++) { + seq_printf(m, "%04x%c", le16_to_cpu(val[i]), + (i % 8) == 7 ? '\n' : ' '); } + } else + seq_putc(m, buf[0]); + kfree(buf); + return 0; +} + +static int ide_identify_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, ide_identify_proc_show, PDE_DATA(inode)); +} + +static const struct file_operations ide_identify_proc_fops = { + .owner = THIS_MODULE, + .open = ide_identify_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +/** + * ide_find_setting - find a specific setting + * @st: setting table pointer + * @name: setting name + * + * Scan's the setting table for a matching entry and returns + * this or NULL if no entry is found. The caller must hold the + * setting semaphore + */ + +static +const struct ide_proc_devset *ide_find_setting(const struct ide_proc_devset *st, + char *name) +{ + while (st->name) { + if (strcmp(st->name, name) == 0) + break; + st++; } - PROC_IDE_READ_RETURN(page,start,off,count,eof,len); + return st->name ? st : NULL; } -static void proc_ide_settings_warn(void) +/** + * ide_read_setting - read an IDE setting + * @drive: drive to read from + * @setting: drive setting + * + * Read a drive setting and return the value. The caller + * must hold the ide_setting_mtx when making this call. + * + * BUGS: the data return and error are the same return value + * so an error -EINVAL and true return of the same value cannot + * be told apart + */ + +static int ide_read_setting(ide_drive_t *drive, + const struct ide_proc_devset *setting) { - static int warned = 0; + const struct ide_devset *ds = setting->setting; + int val = -EINVAL; - if (warned) - return; + if (ds->get) + val = ds->get(drive); + + return val; +} + +/** + * ide_write_setting - read an IDE setting + * @drive: drive to read from + * @setting: drive setting + * @val: value + * + * Write a drive setting if it is possible. The caller + * must hold the ide_setting_mtx when making this call. + * + * BUGS: the data return and error are the same return value + * so an error -EINVAL and true return of the same value cannot + * be told apart + * + * FIXME: This should be changed to enqueue a special request + * to the driver to change settings, and then wait on a sema for completion. + * The current scheme of polling is kludgy, though safe enough. + */ - printk(KERN_WARNING "Warning: /proc/ide/hd?/settings interface is " +static int ide_write_setting(ide_drive_t *drive, + const struct ide_proc_devset *setting, int val) +{ + const struct ide_devset *ds = setting->setting; + + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + if (!ds->set) + return -EPERM; + if ((ds->flags & DS_SYNC) + && (val < setting->min || val > setting->max)) + return -EINVAL; + return ide_devset_execute(drive, ds, val); +} + +ide_devset_get(xfer_rate, current_speed); + +static int set_xfer_rate (ide_drive_t *drive, int arg) +{ + struct ide_cmd cmd; + + if (arg < XFER_PIO_0 || arg > XFER_UDMA_6) + return -EINVAL; + + memset(&cmd, 0, sizeof(cmd)); + cmd.tf.command = ATA_CMD_SET_FEATURES; + cmd.tf.feature = SETFEATURES_XFER; + cmd.tf.nsect = (u8)arg; + cmd.valid.out.tf = IDE_VALID_FEATURE | IDE_VALID_NSECT; + cmd.valid.in.tf = IDE_VALID_NSECT; + cmd.tf_flags = IDE_TFLAG_SET_XFER; + + return ide_no_data_taskfile(drive, &cmd); +} + +ide_devset_rw(current_speed, xfer_rate); +ide_devset_rw_field(init_speed, init_speed); +ide_devset_rw_flag(nice1, IDE_DFLAG_NICE1); +ide_devset_rw_field(number, dn); + +static const struct ide_proc_devset ide_generic_settings[] = { + IDE_PROC_DEVSET(current_speed, 0, 70), + IDE_PROC_DEVSET(init_speed, 0, 70), + IDE_PROC_DEVSET(io_32bit, 0, 1 + (SUPPORT_VLB_SYNC << 1)), + IDE_PROC_DEVSET(keepsettings, 0, 1), + IDE_PROC_DEVSET(nice1, 0, 1), + IDE_PROC_DEVSET(number, 0, 3), + IDE_PROC_DEVSET(pio_mode, 0, 255), + IDE_PROC_DEVSET(unmaskirq, 0, 1), + IDE_PROC_DEVSET(using_dma, 0, 1), + { NULL }, +}; + +static void proc_ide_settings_warn(void) +{ + printk_once(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) +static int ide_settings_proc_show(struct seq_file *m, void *v) { - 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; + const struct ide_proc_devset *setting, *g, *d; + const struct ide_devset *ds; + ide_drive_t *drive = (ide_drive_t *) m->private; + int 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); + mutex_lock(&ide_setting_mtx); + g = ide_generic_settings; + d = drive->settings; + seq_printf(m, "name\t\t\tvalue\t\tmin\t\tmax\t\tmode\n"); + seq_printf(m, "----\t\t\t-----\t\t---\t\t---\t\t----\n"); + while (g->name || (d && d->name)) { + /* read settings in the alphabetical order */ + if (g->name && d && d->name) { + if (strcmp(d->name, g->name) < 0) + setting = d++; + else + setting = g++; + } else if (d && d->name) { + setting = d++; + } else + setting = g++; + mul_factor = setting->mulf ? setting->mulf(drive) : 1; + div_factor = setting->divf ? setting->divf(drive) : 1; + seq_printf(m, "%-24s", setting->name); + rc = ide_read_setting(drive, setting); + if (rc >= 0) + seq_printf(m, "%-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; + seq_printf(m, "%-16s", "write-only"); + seq_printf(m, "%-16d%-16d", (setting->min * mul_factor + div_factor - 1) / div_factor, setting->max * mul_factor / div_factor); + ds = setting->setting; + if (ds->get) + seq_printf(m, "r"); + if (ds->set) + seq_printf(m, "w"); + seq_printf(m, "\n"); } - len = out - page; - up(&ide_setting_sem); - PROC_IDE_READ_RETURN(page,start,off,count,eof,len); + mutex_unlock(&ide_setting_mtx); + return 0; +} + +static int ide_settings_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, ide_settings_proc_show, PDE_DATA(inode)); } #define MAX_LEN 30 -static int proc_ide_write_settings(struct file *file, const char __user *buffer, - unsigned long count, void *data) +static ssize_t ide_settings_proc_write(struct file *file, const char __user *buffer, + size_t count, loff_t *pos) { - ide_drive_t *drive = (ide_drive_t *) data; + ide_drive_t *drive = PDE_DATA(file_inode(file)); char name[MAX_LEN + 1]; - int for_real = 0; + int for_real = 0, mul_factor, div_factor; unsigned long n; - ide_settings_t *setting; + + const struct ide_proc_devset *setting; char *buf, *s; if (!capable(CAP_SYS_ADMIN)) @@ -244,108 +405,160 @@ static int proc_ide_write_settings(struct file *file, const char __user *buffer, ++p; } - down(&ide_setting_sem); - setting = ide_find_setting_by_name(drive, name); - if (!setting) - { - up(&ide_setting_sem); - goto parse_error; + mutex_lock(&ide_setting_mtx); + /* generic settings first, then driver specific ones */ + setting = ide_find_setting(ide_generic_settings, name); + if (!setting) { + if (drive->settings) + setting = ide_find_setting(drive->settings, name); + if (!setting) { + mutex_unlock(&ide_setting_mtx); + goto parse_error; + } + } + if (for_real) { + mul_factor = setting->mulf ? setting->mulf(drive) : 1; + div_factor = setting->divf ? setting->divf(drive) : 1; + ide_write_setting(drive, setting, val * div_factor / mul_factor); } - if (for_real) - ide_write_setting(drive, setting, val * setting->div_factor / setting->mul_factor); - up(&ide_setting_sem); + mutex_unlock(&ide_setting_mtx); } } while (!for_real++); free_page((unsigned long)buf); return count; parse_error: free_page((unsigned long)buf); - printk("proc_ide_write_settings(): parse error\n"); + printk("%s(): parse error\n", __func__); return -EINVAL; } -int proc_ide_read_capacity - (char *page, char **start, off_t off, int count, int *eof, void *data) +static const struct file_operations ide_settings_proc_fops = { + .owner = THIS_MODULE, + .open = ide_settings_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .write = ide_settings_proc_write, +}; + +static int ide_capacity_proc_show(struct seq_file *m, void *v) +{ + seq_printf(m, "%llu\n", (long long)0x7fffffff); + return 0; +} + +static int ide_capacity_proc_open(struct inode *inode, struct file *file) { - int len = sprintf(page,"%llu\n", (long long)0x7fffffff); - PROC_IDE_READ_RETURN(page,start,off,count,eof,len); + return single_open(file, ide_capacity_proc_show, NULL); } -EXPORT_SYMBOL_GPL(proc_ide_read_capacity); +const struct file_operations ide_capacity_proc_fops = { + .owner = THIS_MODULE, + .open = ide_capacity_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; +EXPORT_SYMBOL_GPL(ide_capacity_proc_fops); -int proc_ide_read_geometry - (char *page, char **start, off_t off, int count, int *eof, void *data) +static int ide_geometry_proc_show(struct seq_file *m, void *v) { - ide_drive_t *drive = (ide_drive_t *) data; - char *out = page; - int len; + ide_drive_t *drive = (ide_drive_t *) m->private; - out += sprintf(out,"physical %d/%d/%d\n", + seq_printf(m, "physical %d/%d/%d\n", drive->cyl, drive->head, drive->sect); - out += sprintf(out,"logical %d/%d/%d\n", + seq_printf(m, "logical %d/%d/%d\n", drive->bios_cyl, drive->bios_head, drive->bios_sect); + return 0; +} - len = out - page; - PROC_IDE_READ_RETURN(page,start,off,count,eof,len); +static int ide_geometry_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, ide_geometry_proc_show, PDE_DATA(inode)); } -EXPORT_SYMBOL(proc_ide_read_geometry); +const struct file_operations ide_geometry_proc_fops = { + .owner = THIS_MODULE, + .open = ide_geometry_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; +EXPORT_SYMBOL(ide_geometry_proc_fops); -static int proc_ide_read_dmodel - (char *page, char **start, off_t off, int count, int *eof, void *data) +static int ide_dmodel_proc_show(struct seq_file *seq, void *v) { - ide_drive_t *drive = (ide_drive_t *) data; - struct hd_driveid *id = drive->id; - int len; + ide_drive_t *drive = (ide_drive_t *) seq->private; + char *m = (char *)&drive->id[ATA_ID_PROD]; - len = sprintf(page, "%.40s\n", - (id && id->model[0]) ? (char *)id->model : "(none)"); - PROC_IDE_READ_RETURN(page,start,off,count,eof,len); + seq_printf(seq, "%.40s\n", m[0] ? m : "(none)"); + return 0; } -static int proc_ide_read_driver - (char *page, char **start, off_t off, int count, int *eof, void *data) +static int ide_dmodel_proc_open(struct inode *inode, struct file *file) { - ide_drive_t *drive = (ide_drive_t *) data; - struct device *dev = &drive->gendev; - ide_driver_t *ide_drv; - int len; + return single_open(file, ide_dmodel_proc_show, PDE_DATA(inode)); +} + +static const struct file_operations ide_dmodel_proc_fops = { + .owner = THIS_MODULE, + .open = ide_dmodel_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int ide_driver_proc_show(struct seq_file *m, void *v) +{ + ide_drive_t *drive = (ide_drive_t *)m->private; + struct device *dev = &drive->gendev; + struct ide_driver *ide_drv; - down_read(&dev->bus->subsys.rwsem); if (dev->driver) { - ide_drv = container_of(dev->driver, ide_driver_t, gen_driver); - len = sprintf(page, "%s version %s\n", + ide_drv = to_ide_driver(dev->driver); + seq_printf(m, "%s version %s\n", dev->driver->name, ide_drv->version); } else - len = sprintf(page, "ide-default version 0.9.newide\n"); - up_read(&dev->bus->subsys.rwsem); - PROC_IDE_READ_RETURN(page,start,off,count,eof,len); + seq_printf(m, "ide-default version 0.9.newide\n"); + return 0; +} + +static int ide_driver_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, ide_driver_proc_show, PDE_DATA(inode)); } static int ide_replace_subdriver(ide_drive_t *drive, const char *driver) { struct device *dev = &drive->gendev; int ret = 1; + int err; - down_write(&dev->bus->subsys.rwsem); device_release_driver(dev); /* FIXME: device can still be in use by previous driver */ strlcpy(drive->driver_req, driver, sizeof(drive->driver_req)); - device_attach(dev); + err = device_attach(dev); + if (err < 0) + printk(KERN_WARNING "IDE: %s: device_attach error: %d\n", + __func__, err); drive->driver_req[0] = 0; - if (dev->driver == NULL) - device_attach(dev); + if (dev->driver == NULL) { + err = device_attach(dev); + if (err < 0) + printk(KERN_WARNING + "IDE: %s: device_attach(2) error: %d\n", + __func__, err); + } if (dev->driver && !strcmp(dev->driver->name, driver)) ret = 0; - up_write(&dev->bus->subsys.rwsem); return ret; } -static int proc_ide_write_driver - (struct file *file, const char __user *buffer, unsigned long count, void *data) +static ssize_t ide_driver_proc_write(struct file *file, const char __user *buffer, + size_t count, loff_t *pos) { - ide_drive_t *drive = (ide_drive_t *) data; + ide_drive_t *drive = PDE_DATA(file_inode(file)); char name[32]; if (!capable(CAP_SYS_ADMIN)) @@ -360,59 +573,68 @@ static int proc_ide_write_driver return count; } -static int proc_ide_read_media - (char *page, char **start, off_t off, int count, int *eof, void *data) +static const struct file_operations ide_driver_proc_fops = { + .owner = THIS_MODULE, + .open = ide_driver_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .write = ide_driver_proc_write, +}; + +static int ide_media_proc_show(struct seq_file *m, void *v) { - ide_drive_t *drive = (ide_drive_t *) data; + ide_drive_t *drive = (ide_drive_t *) m->private; const char *media; - int len; switch (drive->media) { - case ide_disk: media = "disk\n"; - break; - case ide_cdrom: media = "cdrom\n"; - break; - case ide_tape: media = "tape\n"; - break; - case ide_floppy:media = "floppy\n"; - break; - case ide_optical:media = "optical\n"; - break; - default: media = "UNKNOWN\n"; - break; + case ide_disk: media = "disk\n"; break; + case ide_cdrom: media = "cdrom\n"; break; + case ide_tape: media = "tape\n"; break; + case ide_floppy: media = "floppy\n"; break; + case ide_optical: media = "optical\n"; break; + default: media = "UNKNOWN\n"; break; } - strcpy(page,media); - len = strlen(media); - PROC_IDE_READ_RETURN(page,start,off,count,eof,len); + seq_puts(m, media); + return 0; +} + +static int ide_media_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, ide_media_proc_show, PDE_DATA(inode)); } +static const struct file_operations ide_media_proc_fops = { + .owner = THIS_MODULE, + .open = ide_media_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + 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 } + { "driver", S_IFREG|S_IRUGO, &ide_driver_proc_fops }, + { "identify", S_IFREG|S_IRUSR, &ide_identify_proc_fops}, + { "media", S_IFREG|S_IRUGO, &ide_media_proc_fops }, + { "model", S_IFREG|S_IRUGO, &ide_dmodel_proc_fops }, + { "settings", S_IFREG|S_IRUSR|S_IWUSR, &ide_settings_proc_fops}, + {} }; -void ide_add_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p, void *data) +static void ide_add_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p, void *data) { struct proc_dir_entry *ent; if (!dir || !p) return; while (p->name != NULL) { - ent = create_proc_entry(p->name, p->mode, dir); + ent = proc_create_data(p->name, p->mode, dir, p->proc_fops, data); 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) +static void ide_remove_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p) { if (!dir || !p) return; @@ -422,92 +644,95 @@ void ide_remove_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p) } } -static void create_proc_ide_drives(ide_hwif_t *hwif) +void ide_proc_register_driver(ide_drive_t *drive, struct ide_driver *driver) +{ + mutex_lock(&ide_setting_mtx); + drive->settings = driver->proc_devsets(drive); + mutex_unlock(&ide_setting_mtx); + + ide_add_proc_entries(drive->proc, driver->proc_entries(drive), drive); +} + +EXPORT_SYMBOL(ide_proc_register_driver); + +/** + * ide_proc_unregister_driver - remove driver specific data + * @drive: drive + * @driver: driver + * + * Clean up the driver specific /proc files and IDE settings + * for a given drive. + * + * Takes ide_setting_mtx. + */ + +void ide_proc_unregister_driver(ide_drive_t *drive, struct ide_driver *driver) +{ + ide_remove_proc_entries(drive->proc, driver->proc_entries(drive)); + + mutex_lock(&ide_setting_mtx); + /* + * ide_setting_mtx protects both the settings list and the use + * of settings (we cannot take a setting out that is being used). + */ + drive->settings = NULL; + mutex_unlock(&ide_setting_mtx); +} +EXPORT_SYMBOL(ide_proc_unregister_driver); + +void ide_proc_port_register_devices(ide_hwif_t *hwif) { - int d; struct proc_dir_entry *ent; struct proc_dir_entry *parent = hwif->proc; + ide_drive_t *drive; char name[64]; + int i; - for (d = 0; d < MAX_DRIVES; d++) { - ide_drive_t *drive = &hwif->drives[d]; - - if (!drive->present) - continue; - if (drive->proc) + ide_port_for_each_dev(i, drive, hwif) { + if ((drive->dev_flags & IDE_DFLAG_PRESENT) == 0) 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); + 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) +void ide_proc_unregister_device(ide_drive_t *drive) { if (drive->proc) { ide_remove_proc_entries(drive->proc, generic_drive_entries); remove_proc_entry(drive->name, proc_ide_root); - remove_proc_entry(drive->name, hwif->proc); + remove_proc_entry(drive->name, drive->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 } + { "channel", S_IFREG|S_IRUGO, &ide_channel_proc_fops }, + { "mate", S_IFREG|S_IRUGO, &ide_mate_proc_fops }, + { "model", S_IFREG|S_IRUGO, &ide_imodel_proc_fops }, + {} }; -void create_proc_ide_interfaces(void) +void ide_proc_register_port(ide_hwif_t *hwif) { - int h; + if (!hwif->proc) { + hwif->proc = proc_mkdir(hwif->name, proc_ide_root); - for (h = 0; h < MAX_HWIFS; h++) { - ide_hwif_t *hwif = &ide_hwifs[h]; + if (!hwif->proc) + return; - 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); + ide_add_proc_entries(hwif->proc, hwif_entries, 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) +void ide_proc_unregister_port(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; @@ -516,7 +741,7 @@ void destroy_proc_ide_interface(ide_hwif_t *hwif) static int proc_print_driver(struct device_driver *drv, void *data) { - ide_driver_t *ide_drv = container_of(drv, ide_driver_t, gen_driver); + struct ide_driver *ide_drv = to_ide_driver(drv); struct seq_file *s = data; seq_printf(s, "%s version %s\n", drv->name, ide_drv->version); @@ -526,7 +751,12 @@ static int proc_print_driver(struct device_driver *drv, void *data) static int ide_drivers_show(struct seq_file *s, void *p) { - bus_for_each_drv(&ide_bus_type, NULL, s, proc_print_driver); + int err; + + err = bus_for_each_drv(&ide_bus_type, NULL, s, proc_print_driver); + if (err < 0) + printk(KERN_WARNING "IDE: %s: bus_for_each_drv error: %d\n", + __func__, err); return 0; } @@ -535,7 +765,8 @@ static int ide_drivers_open(struct inode *inode, struct file *file) return single_open(file, &ide_drivers_show, NULL); } -static struct file_operations ide_drivers_operations = { +static const struct file_operations ide_drivers_operations = { + .owner = THIS_MODULE, .open = ide_drivers_open, .read = seq_read, .llseek = seq_lseek, @@ -544,16 +775,12 @@ static struct file_operations ide_drivers_operations = { void proc_ide_create(void) { - struct proc_dir_entry *entry; + proc_ide_root = proc_mkdir("ide", NULL); 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; + proc_create("drivers", 0, proc_ide_root, &ide_drivers_operations); } void proc_ide_destroy(void) diff --git a/drivers/ide/ide-scan-pci.c b/drivers/ide/ide-scan-pci.c new file mode 100644 index 00000000000..c3da53e7bb2 --- /dev/null +++ b/drivers/ide/ide-scan-pci.c @@ -0,0 +1,111 @@ +/* + * support for probing IDE PCI devices in the PCI bus order + * + * Copyright (c) 1998-2000 Andre Hedrick <andre@linux-ide.org> + * Copyright (c) 1995-1998 Mark Lord + * + * May be copied or modified under the terms of the GNU General Public License + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/ide.h> + +/* + * Module interfaces + */ + +static int pre_init = 1; /* Before first ordered IDE scan */ +static LIST_HEAD(ide_pci_drivers); + +/* + * __ide_pci_register_driver - attach IDE driver + * @driver: pci driver + * @module: owner module of the driver + * + * Registers a driver with the IDE layer. The IDE layer arranges that + * boot time setup is done in the expected device order and then + * hands the controllers off to the core PCI code to do the rest of + * the work. + * + * Returns are the same as for pci_register_driver + */ + +int __ide_pci_register_driver(struct pci_driver *driver, struct module *module, + const char *mod_name) +{ + if (!pre_init) + return __pci_register_driver(driver, module, mod_name); + driver->driver.owner = module; + list_add_tail(&driver->node, &ide_pci_drivers); + return 0; +} +EXPORT_SYMBOL_GPL(__ide_pci_register_driver); + +/** + * ide_scan_pcidev - find an IDE driver for a device + * @dev: PCI device to check + * + * Look for an IDE driver to handle the device we are considering. + * This is only used during boot up to get the ordering correct. After + * boot up the pci layer takes over the job. + */ + +static int __init ide_scan_pcidev(struct pci_dev *dev) +{ + struct list_head *l; + struct pci_driver *d; + + list_for_each(l, &ide_pci_drivers) { + d = list_entry(l, struct pci_driver, node); + if (d->id_table) { + const struct pci_device_id *id = + pci_match_id(d->id_table, dev); + + if (id != NULL && d->probe(dev, id) >= 0) { + dev->driver = d; + pci_dev_get(dev); + return 1; + } + } + } + return 0; +} + +/** + * ide_scan_pcibus - perform the initial IDE driver scan + * + * Perform the initial bus rather than driver ordered scan of the + * PCI drivers. After this all IDE pci handling becomes standard + * module ordering not traditionally ordered. + */ + +static int __init ide_scan_pcibus(void) +{ + struct pci_dev *dev = NULL; + struct pci_driver *d; + struct list_head *l, *n; + + pre_init = 0; + for_each_pci_dev(dev) + ide_scan_pcidev(dev); + + /* + * Hand the drivers over to the PCI layer now we + * are post init. + */ + + list_for_each_safe(l, n, &ide_pci_drivers) { + list_del(l); + d = list_entry(l, struct pci_driver, node); + if (__pci_register_driver(d, d->driver.owner, + d->driver.mod_name)) + printk(KERN_ERR "%s: failed to register %s driver\n", + __func__, d->driver.mod_name); + } + + return 0; +} + +module_init(ide_scan_pcibus); diff --git a/drivers/ide/ide-sysfs.c b/drivers/ide/ide-sysfs.c new file mode 100644 index 00000000000..84a6a9e08d6 --- /dev/null +++ b/drivers/ide/ide-sysfs.c @@ -0,0 +1,142 @@ +#include <linux/kernel.h> +#include <linux/ide.h> + +char *ide_media_string(ide_drive_t *drive) +{ + switch (drive->media) { + case ide_disk: + return "disk"; + case ide_cdrom: + return "cdrom"; + case ide_tape: + return "tape"; + case ide_floppy: + return "floppy"; + case ide_optical: + return "optical"; + default: + return "UNKNOWN"; + } +} + +static ssize_t media_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + ide_drive_t *drive = to_ide_device(dev); + return sprintf(buf, "%s\n", ide_media_string(drive)); +} +static DEVICE_ATTR_RO(media); + +static ssize_t drivename_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + ide_drive_t *drive = to_ide_device(dev); + return sprintf(buf, "%s\n", drive->name); +} +static DEVICE_ATTR_RO(drivename); + +static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + ide_drive_t *drive = to_ide_device(dev); + return sprintf(buf, "ide:m-%s\n", ide_media_string(drive)); +} +static DEVICE_ATTR_RO(modalias); + +static ssize_t model_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + ide_drive_t *drive = to_ide_device(dev); + return sprintf(buf, "%s\n", (char *)&drive->id[ATA_ID_PROD]); +} +static DEVICE_ATTR_RO(model); + +static ssize_t firmware_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + ide_drive_t *drive = to_ide_device(dev); + return sprintf(buf, "%s\n", (char *)&drive->id[ATA_ID_FW_REV]); +} +static DEVICE_ATTR_RO(firmware); + +static ssize_t serial_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + ide_drive_t *drive = to_ide_device(dev); + return sprintf(buf, "%s\n", (char *)&drive->id[ATA_ID_SERNO]); +} +static DEVICE_ATTR(serial, 0400, serial_show, NULL); + +static DEVICE_ATTR(unload_heads, 0644, ide_park_show, ide_park_store); + +static struct attribute *ide_attrs[] = { + &dev_attr_media.attr, + &dev_attr_drivename.attr, + &dev_attr_modalias.attr, + &dev_attr_model.attr, + &dev_attr_firmware.attr, + &dev_attr_serial.attr, + &dev_attr_unload_heads.attr, + NULL, +}; + +static const struct attribute_group ide_attr_group = { + .attrs = ide_attrs, +}; + +const struct attribute_group *ide_dev_groups[] = { + &ide_attr_group, + NULL, +}; + +static ssize_t store_delete_devices(struct device *portdev, + struct device_attribute *attr, + const char *buf, size_t n) +{ + ide_hwif_t *hwif = dev_get_drvdata(portdev); + + if (strncmp(buf, "1", n)) + return -EINVAL; + + ide_port_unregister_devices(hwif); + + return n; +}; + +static DEVICE_ATTR(delete_devices, S_IWUSR, NULL, store_delete_devices); + +static ssize_t store_scan(struct device *portdev, + struct device_attribute *attr, + const char *buf, size_t n) +{ + ide_hwif_t *hwif = dev_get_drvdata(portdev); + + if (strncmp(buf, "1", n)) + return -EINVAL; + + ide_port_unregister_devices(hwif); + ide_port_scan(hwif); + + return n; +}; + +static DEVICE_ATTR(scan, S_IWUSR, NULL, store_scan); + +static struct device_attribute *ide_port_attrs[] = { + &dev_attr_delete_devices, + &dev_attr_scan, + NULL +}; + +int ide_sysfs_register_port(ide_hwif_t *hwif) +{ + int i, uninitialized_var(rc); + + for (i = 0; ide_port_attrs[i]; i++) { + rc = device_create_file(hwif->portdev, ide_port_attrs[i]); + if (rc) + break; + } + + return rc; +} diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c index 7067ab99792..1793aea4a7d 100644 --- a/drivers/ide/ide-tape.c +++ b/drivers/ide/ide-tape.c @@ -1,9 +1,8 @@ /* - * linux/drivers/ide/ide-tape.c Version 1.19 Nov, 2003 - * - * Copyright (C) 1995 - 1999 Gadi Oxman <gadio@netvision.net.il> + * IDE ATAPI streaming tape driver. * - * $Header$ + * Copyright (C) 1995-1999 Gadi Oxman <gadio@netvision.net.il> + * Copyright (C) 2003-2005 Bartlomiej Zolnierkiewicz * * This driver was constructed as a student project in the software laboratory * of the faculty of electrical engineering in the Technion - Israel's @@ -11,418 +10,14 @@ * * 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. + * For a historical changelog see + * Documentation/ide/ChangeLog.ide-tape.1995-2002 */ -/* - * 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 DRV_NAME "ide-tape" -#define IDETAPE_VERSION "1.19" +#define IDETAPE_VERSION "1.20" #include <linux/module.h> #include <linux/types.h> @@ -436,174 +31,73 @@ #include <linux/major.h> #include <linux/errno.h> #include <linux/genhd.h> +#include <linux/seq_file.h> #include <linux/slab.h> #include <linux/pci.h> #include <linux/ide.h> -#include <linux/smp_lock.h> #include <linux/completion.h> #include <linux/bitops.h> #include <linux/mutex.h> +#include <scsi/scsi.h> #include <asm/byteorder.h> -#include <asm/irq.h> -#include <asm/uaccess.h> -#include <asm/io.h> +#include <linux/uaccess.h> +#include <linux/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 +/* define to see debug info */ +#undef IDETAPE_DEBUG_LOG -/* - * 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 +#ifdef IDETAPE_DEBUG_LOG +#define ide_debug_log(lvl, fmt, args...) __ide_debug_log(lvl, fmt, ## args) +#else +#define ide_debug_log(lvl, fmt, args...) do {} while (0) +#endif +/**************************** Tunable parameters *****************************/ /* - * After each failed packet command we issue a request sense command - * and retry the packet command IDETAPE_MAX_PC_RETRIES times. + * 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. + * 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). + * The following parameter is used to select the point in the internal tape fifo + * in which we will start to refill the buffer. Decreasing the following + * parameter will improve the system's latency and interactive response, while + * using a high value might improve system throughput. */ -#define IDETAPE_WAIT_CMD (900*HZ) +#define IDETAPE_FIFO_THRESHOLD 2 /* - * 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: + * DSC polling parameters. * - * 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. + * 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: * - * 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). + * 1. Before a read/write packet command, to ensure that we can transfer data + * from/to the tape's data buffers, without causing an actual media access. + * In case the tape is not ready yet, we take out our request from the device + * request queue, so that ide.c could service requests from the other device + * on the same interface in the meantime. * - * 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). + * 2. After the successful initialization of a "media access packet command", + * which is a command that can take a long time to complete (the interval can + * range from several seconds to even an hour). Again, we postpone our request + * in the middle to free the bus for the other device. The polling frequency + * here should be lower than the read/write frequency since those media access + * commands are slow. We start from a "fast" frequency - IDETAPE_DSC_MA_FAST + * (1 second), and if we don't receive DSC after IDETAPE_DSC_MA_THRESHOLD + * (5 min), we switch it to a lower frequency - IDETAPE_DSC_MA_SLOW (1 min). * - * We also set a timeout for the timer, in case something goes wrong. - * The timeout should be longer then the maximum execution time of a - * tape operation. - */ - -/* - * DSC timings. + * 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 */ @@ -614,1538 +108,357 @@ typedef struct os_dat_s { /*************************** 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; +/* tape directions */ +enum { + IDETAPE_DIR_NONE = (1 << 0), + IDETAPE_DIR_READ = (1 << 1), + IDETAPE_DIR_WRITE = (1 << 2), }; -/* - * 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; +/* Tape door status */ +#define DOOR_UNLOCKED 0 +#define DOOR_LOCKED 1 +#define DOOR_EXPLICITLY_LOCKED 2 -/* - * 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; +/* Some defines for the SPACE command */ +#define IDETAPE_SPACE_OVER_FILEMARK 1 +#define IDETAPE_SPACE_TO_EOD 3 -/* - * 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; +/* Some defines for the LOAD UNLOAD command */ +#define IDETAPE_LU_LOAD_MASK 1 +#define IDETAPE_LU_RETENSION_MASK 2 +#define IDETAPE_LU_EOT_MASK 4 +/* Structures related to the SELECT SENSE / MODE SENSE packet commands. */ +#define IDETAPE_BLOCK_DESCRIPTOR 0 +#define IDETAPE_CAPABILITIES_PAGE 0x2a /* - * Most of our global data which we need to save even as we leave the - * driver due to an interrupt or a timer event is stored in a variable - * of type idetape_tape_t, defined below. + * Most of our global data which we need to save even as we leave the driver due + * to an interrupt or a timer event is stored in the struct defined below. */ typedef struct ide_tape_obj { - ide_drive_t *drive; - ide_driver_t *driver; - struct gendisk *disk; - struct kref kref; + ide_drive_t *drive; + struct ide_driver *driver; + struct gendisk *disk; + struct device dev; - /* - * 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; + /* used by REQ_IDETAPE_{READ,WRITE} requests */ + struct ide_atapi_pc queued_pc; /* - * DSC polling variables. + * 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. + * While polling for DSC we use postponed_rq to postpone the current + * request so that ide.c will be able to service pending requests on the + * other device. Note that at most we will have only one DSC (usually + * data transfer) request in the device request queue. */ - struct request *postponed_rq; + bool 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 best_dsc_rw_freq; + unsigned long dsc_poll_freq; unsigned long dsc_timeout; - /* - * Read position information - */ + /* Read position information */ u8 partition; /* Current block */ - unsigned int first_frame_position; - unsigned int last_frame_position; - unsigned int blocks_in_buffer; + unsigned int first_frame; - /* - * Last error information - */ + /* Last error information */ u8 sense_key, asc, ascq; - /* - * Character device operation - */ + /* Character device operation */ unsigned int minor; /* device name */ char name[4]; /* Current character device data transfer direction */ - idetape_chrdev_direction_t chrdev_direction; + u8 chrdev_dir; - /* - * Device information - */ - /* Usually 512 or 1024 bytes */ - unsigned short tape_block_size; + /* tape block size, usually 512 or 1024 bytes */ + unsigned short blk_size; int user_bs_factor; + /* Copy of the tape's Capabilities and Mechanical Page */ - idetape_capabilities_page_t capabilities; + u8 caps[20]; /* - * Active data transfer request parameters. - * - * At most, there is only one ide-tape originated data transfer - * request in the device request queue. This allows ide.c to - * easily service requests from the other device when we - * postpone our active request. 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. + * Active data transfer request parameters. * - * To accomplish non-pipelined mode, we simply set the following - * variables to zero (or NULL, where appropriate). + * 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. */ - /* 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 - */ + /* Data buffer size chosen based on the tape's recommendation */ + int buffer_size; + /* Staging buffer of buffer_size bytes */ + void *buf; + /* The read/write cursor */ + void *cur; + /* The number of valid bytes in buf */ + size_t valid; + + /* Measures average tape speed */ unsigned long avg_time; int avg_size; int avg_speed; - /* last sense information */ - idetape_request_sense_result_t sense; - - char vendor_id[10]; - char product_id[18]; - char firmware_revision[6]; - int firmware_revision_num; - /* the door is currently locked */ int door_locked; /* the tape hardware is write protected */ char drv_write_prot; /* the tape is write protected (hardware or opened as read-only) */ char write_prot; - - /* - * Limit the number of times a request can - * be postponed, to avoid an infinite postpone - * deadlock. - */ - /* request postpone count limit */ - int postpone_cnt; - - /* - * Measures number of frames: - * - * 1. written/read to/from the driver pipeline (pipeline_head). - * 2. written/read to/from the tape buffers (idetape_bh). - * 3. written/read by the tape to/from the media (tape_head). - */ - int pipeline_head; - int buffer_head; - int tape_head; - int last_tape_head; - - /* - * Speed control at the tape buffers input/output - */ - unsigned long insert_time; - int insert_size; - int insert_speed; - int max_insert_speed; - int measure_insert_time; - - /* - * Measure tape still time, in milliseconds - */ - unsigned long tape_still_time_begin; - int tape_still_time; - - /* - * Speed regulation negative feedback loop - */ - int speed_control; - int pipeline_head_speed; - int controlled_pipeline_head_speed; - int uncontrolled_pipeline_head_speed; - int controlled_last_pipeline_head; - int uncontrolled_last_pipeline_head; - unsigned long uncontrolled_pipeline_head_time; - unsigned long controlled_pipeline_head_time; - int controlled_previous_pipeline_head; - int uncontrolled_previous_pipeline_head; - unsigned long controlled_previous_head_time; - unsigned long uncontrolled_previous_head_time; - int restart_speed_control_req; - - /* - * Debug_level determines amount of debugging output; - * can be changed using /proc/ide/hdx/settings - * 0 : almost no debugging output - * 1 : 0+output errors only - * 2 : 1+output all sensekey/asc - * 3 : 2+follow all chrdev related procedures - * 4 : 3+follow all procedures - * 5 : 4+include pc_stack rq_stack info - * 6 : 5+USE_COUNT updates - */ - int debug_level; } idetape_tape_t; +static DEFINE_MUTEX(ide_tape_mutex); static DEFINE_MUTEX(idetape_ref_mutex); +static DEFINE_MUTEX(idetape_chrdev_mutex); + static struct class *idetape_sysfs_class; -#define to_ide_tape(obj) container_of(obj, struct ide_tape_obj, kref) +static void ide_tape_release(struct device *); -#define ide_tape_g(disk) \ - container_of((disk)->private_data, struct ide_tape_obj, driver) +static struct ide_tape_obj *idetape_devs[MAX_HWIFS * MAX_DRIVES]; -static struct ide_tape_obj *ide_tape_get(struct gendisk *disk) +static struct ide_tape_obj *ide_tape_get(struct gendisk *disk, bool cdev, + unsigned int i) { struct ide_tape_obj *tape = NULL; mutex_lock(&idetape_ref_mutex); - tape = ide_tape_g(disk); - if (tape) - kref_get(&tape->kref); - mutex_unlock(&idetape_ref_mutex); - return tape; -} - -static void ide_tape_release(struct kref *); - -static void ide_tape_put(struct ide_tape_obj *tape) -{ - mutex_lock(&idetape_ref_mutex); - kref_put(&tape->kref, ide_tape_release); - mutex_unlock(&idetape_ref_mutex); -} - -/* - * Tape door status - */ -#define DOOR_UNLOCKED 0 -#define DOOR_LOCKED 1 -#define DOOR_EXPLICITLY_LOCKED 2 - -/* - * Tape flag bits values. - */ -#define IDETAPE_IGNORE_DSC 0 -#define IDETAPE_ADDRESS_VALID 1 /* 0 When the tape position is unknown */ -#define IDETAPE_BUSY 2 /* Device already opened */ -#define IDETAPE_PIPELINE_ERROR 3 /* Error detected in a pipeline stage */ -#define IDETAPE_DETECT_BS 4 /* Attempt to auto-detect the current user block size */ -#define IDETAPE_FILEMARK 5 /* Currently on a filemark */ -#define IDETAPE_DRQ_INTERRUPT 6 /* DRQ interrupt device */ -#define IDETAPE_READ_ERROR 7 -#define IDETAPE_PIPELINE_ACTIVE 8 /* pipeline active */ -/* 0 = no tape is loaded, so we don't rewind after ejecting */ -#define IDETAPE_MEDIUM_PRESENT 9 - -/* - * Supported ATAPI tape drives packet commands - */ -#define IDETAPE_TEST_UNIT_READY_CMD 0x00 -#define IDETAPE_REWIND_CMD 0x01 -#define IDETAPE_REQUEST_SENSE_CMD 0x03 -#define IDETAPE_READ_CMD 0x08 -#define IDETAPE_WRITE_CMD 0x0a -#define IDETAPE_WRITE_FILEMARK_CMD 0x10 -#define IDETAPE_SPACE_CMD 0x11 -#define IDETAPE_INQUIRY_CMD 0x12 -#define IDETAPE_ERASE_CMD 0x19 -#define IDETAPE_MODE_SENSE_CMD 0x1a -#define IDETAPE_MODE_SELECT_CMD 0x15 -#define IDETAPE_LOAD_UNLOAD_CMD 0x1b -#define IDETAPE_PREVENT_CMD 0x1e -#define IDETAPE_LOCATE_CMD 0x2b -#define IDETAPE_READ_POSITION_CMD 0x34 -#define IDETAPE_READ_BUFFER_CMD 0x3c -#define IDETAPE_SET_SPEED_CMD 0xbb - -/* - * Some defines for the READ BUFFER command - */ -#define IDETAPE_RETRIEVE_FAULTY_BLOCK 6 - -/* - * Some defines for the SPACE command - */ -#define IDETAPE_SPACE_OVER_FILEMARK 1 -#define IDETAPE_SPACE_TO_EOD 3 - -/* - * Some defines for the LOAD UNLOAD command - */ -#define IDETAPE_LU_LOAD_MASK 1 -#define IDETAPE_LU_RETENSION_MASK 2 -#define IDETAPE_LU_EOT_MASK 4 - -/* - * Special requests for our block device strategy routine. - * - * In order to service a character device command, we add special - * requests to the tail of our block device request queue and wait - * for their completion. - */ - -enum { - REQ_IDETAPE_PC1 = (1 << 0), /* packet command (first stage) */ - REQ_IDETAPE_PC2 = (1 << 1), /* packet command (second stage) */ - REQ_IDETAPE_READ = (1 << 2), - REQ_IDETAPE_WRITE = (1 << 3), - REQ_IDETAPE_READ_BUFFER = (1 << 4), -}; - -/* - * Error codes which are returned in rq->errors to the higher part - * of the driver. - */ -#define IDETAPE_ERROR_GENERAL 101 -#define IDETAPE_ERROR_FILEMARK 102 -#define IDETAPE_ERROR_EOD 103 - -/* - * The following is used to format the general configuration word of - * the ATAPI IDENTIFY DEVICE command. - */ -struct idetape_id_gcw { - unsigned packet_size :2; /* Packet Size */ - unsigned reserved234 :3; /* Reserved */ - unsigned drq_type :2; /* Command packet DRQ type */ - unsigned removable :1; /* Removable media */ - unsigned device_type :5; /* Device type */ - unsigned reserved13 :1; /* Reserved */ - unsigned protocol :2; /* Protocol type */ -}; - -/* - * INQUIRY packet command - Data Format (From Table 6-8 of QIC-157C) - */ -typedef struct { - unsigned device_type :5; /* Peripheral Device Type */ - unsigned reserved0_765 :3; /* Peripheral Qualifier - Reserved */ - unsigned reserved1_6t0 :7; /* Reserved */ - unsigned rmb :1; /* Removable Medium Bit */ - unsigned ansi_version :3; /* ANSI Version */ - unsigned ecma_version :3; /* ECMA Version */ - unsigned iso_version :2; /* ISO Version */ - unsigned response_format :4; /* Response Data Format */ - unsigned reserved3_45 :2; /* Reserved */ - unsigned reserved3_6 :1; /* TrmIOP - Reserved */ - unsigned reserved3_7 :1; /* AENC - Reserved */ - __u8 additional_length; /* Additional Length (total_length-4) */ - __u8 rsv5, rsv6, rsv7; /* Reserved */ - __u8 vendor_id[8]; /* Vendor Identification */ - __u8 product_id[16]; /* Product Identification */ - __u8 revision_level[4]; /* Revision Level */ - __u8 vendor_specific[20]; /* Vendor Specific - Optional */ - __u8 reserved56t95[40]; /* Reserved - Optional */ - /* Additional information may be returned */ -} idetape_inquiry_result_t; - -/* - * READ POSITION packet command - Data Format (From Table 6-57) - */ -typedef struct { - unsigned reserved0_10 :2; /* Reserved */ - unsigned bpu :1; /* Block Position Unknown */ - unsigned reserved0_543 :3; /* Reserved */ - unsigned eop :1; /* End Of Partition */ - unsigned bop :1; /* Beginning Of Partition */ - u8 partition; /* Partition Number */ - u8 reserved2, reserved3; /* Reserved */ - u32 first_block; /* First Block Location */ - u32 last_block; /* Last Block Location (Optional) */ - u8 reserved12; /* Reserved */ - u8 blocks_in_buffer[3]; /* Blocks In Buffer - (Optional) */ - u32 bytes_in_buffer; /* Bytes In Buffer (Optional) */ -} idetape_read_position_result_t; - -/* - * Follows structures which are related to the SELECT SENSE / MODE SENSE - * packet commands. Those packet commands are still not supported - * by ide-tape. - */ -#define IDETAPE_BLOCK_DESCRIPTOR 0 -#define IDETAPE_CAPABILITIES_PAGE 0x2a -#define IDETAPE_PARAMTR_PAGE 0x2b /* Onstream DI-x0 only */ -#define IDETAPE_BLOCK_SIZE_PAGE 0x30 -#define IDETAPE_BUFFER_FILLING_PAGE 0x33 - -/* - * Mode Parameter Header for the MODE SENSE packet command - */ -typedef struct { - __u8 mode_data_length; /* Length of the following data transfer */ - __u8 medium_type; /* Medium Type */ - __u8 dsp; /* Device Specific Parameter */ - __u8 bdl; /* Block Descriptor Length */ -#if 0 - /* data transfer page */ - __u8 page_code :6; - __u8 reserved0_6 :1; - __u8 ps :1; /* parameters saveable */ - __u8 page_length; /* page Length == 0x02 */ - __u8 reserved2; - __u8 read32k :1; /* 32k blk size (data only) */ - __u8 read32k5 :1; /* 32.5k blk size (data&AUX) */ - __u8 reserved3_23 :2; - __u8 write32k :1; /* 32k blk size (data only) */ - __u8 write32k5 :1; /* 32.5k blk size (data&AUX) */ - __u8 reserved3_6 :1; - __u8 streaming :1; /* streaming mode enable */ -#endif -} idetape_mode_parameter_header_t; -/* - * Mode Parameter Block Descriptor the MODE SENSE packet command - * - * Support for block descriptors is optional. - */ -typedef struct { - __u8 density_code; /* Medium density code */ - __u8 blocks[3]; /* Number of blocks */ - __u8 reserved4; /* Reserved */ - __u8 length[3]; /* Block Length */ -} idetape_parameter_block_descriptor_t; - -/* - * The Data Compression Page, as returned by the MODE SENSE packet command. - */ -typedef struct { - unsigned page_code :6; /* Page Code - Should be 0xf */ - unsigned reserved0 :1; /* Reserved */ - unsigned ps :1; - __u8 page_length; /* Page Length - Should be 14 */ - unsigned reserved2 :6; /* Reserved */ - unsigned dcc :1; /* Data Compression Capable */ - unsigned dce :1; /* Data Compression Enable */ - unsigned reserved3 :5; /* Reserved */ - unsigned red :2; /* Report Exception on Decompression */ - unsigned dde :1; /* Data Decompression Enable */ - __u32 ca; /* Compression Algorithm */ - __u32 da; /* Decompression Algorithm */ - __u8 reserved[4]; /* Reserved */ -} idetape_data_compression_page_t; - -/* - * The Medium Partition Page, as returned by the MODE SENSE packet command. - */ -typedef struct { - unsigned page_code :6; /* Page Code - Should be 0x11 */ - unsigned reserved1_6 :1; /* Reserved */ - unsigned ps :1; - __u8 page_length; /* Page Length - Should be 6 */ - __u8 map; /* Maximum Additional Partitions - Should be 0 */ - __u8 apd; /* Additional Partitions Defined - Should be 0 */ - unsigned reserved4_012 :3; /* Reserved */ - unsigned psum :2; /* Should be 0 */ - unsigned idp :1; /* Should be 0 */ - unsigned sdp :1; /* Should be 0 */ - unsigned fdp :1; /* Fixed Data Partitions */ - __u8 mfr; /* Medium Format Recognition */ - __u8 reserved[2]; /* Reserved */ -} idetape_medium_partition_page_t; - -/* - * Run time configurable parameters. - */ -typedef struct { - int dsc_rw_frequency; - int dsc_media_access_frequency; - int nr_stages; -} idetape_config_t; - -/* - * The variables below are used for the character device interface. - * Additional state variables are defined in our ide_drive_t structure. - */ -static struct ide_tape_obj * idetape_devs[MAX_HWIFS * MAX_DRIVES]; - -#define ide_tape_f(file) ((file)->private_data) + if (cdev) + tape = idetape_devs[i]; + else + tape = ide_drv_g(disk, ide_tape_obj); -static struct ide_tape_obj *ide_tape_chrdev_get(unsigned int i) -{ - struct ide_tape_obj *tape = NULL; + if (tape) { + if (ide_device_get(tape->drive)) + tape = NULL; + else + get_device(&tape->dev); + } - mutex_lock(&idetape_ref_mutex); - tape = idetape_devs[i]; - if (tape) - kref_get(&tape->kref); mutex_unlock(&idetape_ref_mutex); return tape; } -/* - * Function declarations - * - */ -static int idetape_chrdev_release (struct inode *inode, struct file *filp); -static void idetape_write_release (ide_drive_t *drive, unsigned int minor); - -/* - * Too bad. The drive wants to send us data which we are not ready to accept. - * Just throw it away. - */ -static void idetape_discard_data (ide_drive_t *drive, unsigned int bcount) -{ - while (bcount--) - (void) HWIF(drive)->INB(IDE_DATA_REG); -} - -static void idetape_input_buffers (ide_drive_t *drive, idetape_pc_t *pc, unsigned int bcount) -{ - struct idetape_bh *bh = pc->bh; - int count; - - while (bcount) { -#if IDETAPE_DEBUG_BUGS - if (bh == NULL) { - printk(KERN_ERR "ide-tape: bh == NULL in " - "idetape_input_buffers\n"); - idetape_discard_data(drive, bcount); - return; - } -#endif /* IDETAPE_DEBUG_BUGS */ - count = min((unsigned int)(bh->b_size - atomic_read(&bh->b_count)), bcount); - HWIF(drive)->atapi_input_bytes(drive, bh->b_data + atomic_read(&bh->b_count), count); - bcount -= count; - atomic_add(count, &bh->b_count); - if (atomic_read(&bh->b_count) == bh->b_size) { - bh = bh->b_reqnext; - if (bh) - atomic_set(&bh->b_count, 0); - } - } - pc->bh = bh; -} - -static void idetape_output_buffers (ide_drive_t *drive, idetape_pc_t *pc, unsigned int bcount) -{ - struct idetape_bh *bh = pc->bh; - int count; - - while (bcount) { -#if IDETAPE_DEBUG_BUGS - if (bh == NULL) { - printk(KERN_ERR "ide-tape: bh == NULL in " - "idetape_output_buffers\n"); - return; - } -#endif /* IDETAPE_DEBUG_BUGS */ - count = min((unsigned int)pc->b_count, (unsigned int)bcount); - HWIF(drive)->atapi_output_bytes(drive, pc->b_data, count); - bcount -= count; - pc->b_data += count; - pc->b_count -= count; - if (!pc->b_count) { - pc->bh = bh = bh->b_reqnext; - if (bh) { - pc->b_data = bh->b_data; - pc->b_count = atomic_read(&bh->b_count); - } - } - } -} - -static void idetape_update_buffers (idetape_pc_t *pc) -{ - struct idetape_bh *bh = pc->bh; - int count; - unsigned int bcount = pc->actually_transferred; - - if (test_bit(PC_WRITING, &pc->flags)) - return; - while (bcount) { -#if IDETAPE_DEBUG_BUGS - if (bh == NULL) { - printk(KERN_ERR "ide-tape: bh == NULL in " - "idetape_update_buffers\n"); - return; - } -#endif /* IDETAPE_DEBUG_BUGS */ - count = min((unsigned int)bh->b_size, (unsigned int)bcount); - atomic_set(&bh->b_count, count); - if (atomic_read(&bh->b_count) == bh->b_size) - bh = bh->b_reqnext; - bcount -= count; - } - pc->bh = bh; -} - -/* - * idetape_next_pc_storage returns a pointer to a place in which we can - * safely store a packet command, even though we intend to leave the - * driver. A storage space for a maximum of IDETAPE_PC_STACK packet - * commands is allocated at initialization time. - */ -static idetape_pc_t *idetape_next_pc_storage (ide_drive_t *drive) +static void ide_tape_put(struct ide_tape_obj *tape) { - idetape_tape_t *tape = drive->driver_data; + ide_drive_t *drive = tape->drive; -#if IDETAPE_DEBUG_LOG - if (tape->debug_level >= 5) - printk(KERN_INFO "ide-tape: pc_stack_index=%d\n", - tape->pc_stack_index); -#endif /* IDETAPE_DEBUG_LOG */ - if (tape->pc_stack_index == IDETAPE_PC_STACK) - tape->pc_stack_index=0; - return (&tape->pc_stack[tape->pc_stack_index++]); + mutex_lock(&idetape_ref_mutex); + put_device(&tape->dev); + ide_device_put(drive); + mutex_unlock(&idetape_ref_mutex); } /* - * idetape_next_rq_storage is used along with idetape_next_pc_storage. - * Since we queue packet commands in the request queue, we need to - * allocate a request, along with the allocation of a packet command. + * called on each failed packet command retry to analyze the request sense. We + * currently do not utilize this information. */ - -/************************************************************** - * * - * This should get fixed to use kmalloc(.., GFP_ATOMIC) * - * followed later on by kfree(). -ml * - * * - **************************************************************/ - -static struct request *idetape_next_rq_storage (ide_drive_t *drive) +static void idetape_analyze_error(ide_drive_t *drive) { idetape_tape_t *tape = drive->driver_data; + struct ide_atapi_pc *pc = drive->failed_pc; + struct request *rq = drive->hwif->rq; + u8 *sense = bio_data(rq->bio); -#if IDETAPE_DEBUG_LOG - if (tape->debug_level >= 5) - printk(KERN_INFO "ide-tape: rq_stack_index=%d\n", - tape->rq_stack_index); -#endif /* IDETAPE_DEBUG_LOG */ - if (tape->rq_stack_index == IDETAPE_PC_STACK) - tape->rq_stack_index=0; - return (&tape->rq_stack[tape->rq_stack_index++]); -} + tape->sense_key = sense[2] & 0xF; + tape->asc = sense[12]; + tape->ascq = sense[13]; -/* - * idetape_init_pc initializes a packet command. - */ -static void idetape_init_pc (idetape_pc_t *pc) -{ - memset(pc->c, 0, 12); - pc->retries = 0; - pc->flags = 0; - pc->request_transfer = 0; - pc->buffer = pc->pc_buffer; - pc->buffer_size = IDETAPE_PC_BUFFER_SIZE; - pc->bh = NULL; - pc->b_data = NULL; -} + ide_debug_log(IDE_DBG_FUNC, + "cmd: 0x%x, sense key = %x, asc = %x, ascq = %x", + rq->cmd[0], tape->sense_key, tape->asc, tape->ascq); -/* - * idetape_analyze_error is called on each failed packet command retry - * to analyze the request sense. We currently do not utilize this - * information. - */ -static void idetape_analyze_error (ide_drive_t *drive, idetape_request_sense_result_t *result) -{ - idetape_tape_t *tape = drive->driver_data; - idetape_pc_t *pc = tape->failed_pc; - - tape->sense = *result; - tape->sense_key = result->sense_key; - tape->asc = result->asc; - tape->ascq = result->ascq; -#if IDETAPE_DEBUG_LOG - /* - * Without debugging, we only log an error if we decided to - * give up retrying. - */ - if (tape->debug_level >= 1) - printk(KERN_INFO "ide-tape: pc = %x, sense key = %x, " - "asc = %x, ascq = %x\n", - pc->c[0], result->sense_key, - result->asc, result->ascq); -#endif /* IDETAPE_DEBUG_LOG */ - - /* - * Correct pc->actually_transferred by asking the tape. - */ - if (test_bit(PC_DMA_ERROR, &pc->flags)) { - pc->actually_transferred = pc->request_transfer - tape->tape_block_size * ntohl(get_unaligned(&result->information)); - idetape_update_buffers(pc); - } + /* correct remaining bytes to transfer */ + if (pc->flags & PC_FLAG_DMA_ERROR) + rq->resid_len = tape->blk_size * get_unaligned_be32(&sense[3]); /* * If error was the result of a zero-length read or write command, * with sense key=5, asc=0x22, ascq=0, let it slide. Some drives * (i.e. Seagate STT3401A Travan) don't support 0-length read/writes. */ - if ((pc->c[0] == IDETAPE_READ_CMD || pc->c[0] == IDETAPE_WRITE_CMD) - && pc->c[4] == 0 && pc->c[3] == 0 && pc->c[2] == 0) { /* length==0 */ - if (result->sense_key == 5) { + if ((pc->c[0] == READ_6 || pc->c[0] == WRITE_6) + /* length == 0 */ + && pc->c[4] == 0 && pc->c[3] == 0 && pc->c[2] == 0) { + if (tape->sense_key == 5) { /* don't report an error, everything's ok */ pc->error = 0; /* don't retry read/write */ - set_bit(PC_ABORT, &pc->flags); + pc->flags |= PC_FLAG_ABORT; } } - if (pc->c[0] == IDETAPE_READ_CMD && result->filemark) { - pc->error = IDETAPE_ERROR_FILEMARK; - set_bit(PC_ABORT, &pc->flags); + if (pc->c[0] == READ_6 && (sense[2] & 0x80)) { + pc->error = IDE_DRV_ERROR_FILEMARK; + pc->flags |= PC_FLAG_ABORT; } - if (pc->c[0] == IDETAPE_WRITE_CMD) { - if (result->eom || - (result->sense_key == 0xd && result->asc == 0x0 && - result->ascq == 0x2)) { - pc->error = IDETAPE_ERROR_EOD; - set_bit(PC_ABORT, &pc->flags); + if (pc->c[0] == WRITE_6) { + if ((sense[2] & 0x40) || (tape->sense_key == 0xd + && tape->asc == 0x0 && tape->ascq == 0x2)) { + pc->error = IDE_DRV_ERROR_EOD; + pc->flags |= PC_FLAG_ABORT; } } - if (pc->c[0] == IDETAPE_READ_CMD || pc->c[0] == IDETAPE_WRITE_CMD) { - if (result->sense_key == 8) { - pc->error = IDETAPE_ERROR_EOD; - set_bit(PC_ABORT, &pc->flags); + if (pc->c[0] == READ_6 || pc->c[0] == WRITE_6) { + if (tape->sense_key == 8) { + pc->error = IDE_DRV_ERROR_EOD; + pc->flags |= PC_FLAG_ABORT; } - if (!test_bit(PC_ABORT, &pc->flags) && - pc->actually_transferred) + if (!(pc->flags & PC_FLAG_ABORT) && + (blk_rq_bytes(rq) - rq->resid_len)) pc->retries = IDETAPE_MAX_PC_RETRIES + 1; } } -/* - * idetape_active_next_stage will declare the next stage as "active". - */ -static void idetape_active_next_stage (ide_drive_t *drive) -{ - idetape_tape_t *tape = drive->driver_data; - idetape_stage_t *stage = tape->next_stage; - struct request *rq = &stage->rq; - -#if IDETAPE_DEBUG_LOG - if (tape->debug_level >= 4) - printk(KERN_INFO "ide-tape: Reached idetape_active_next_stage\n"); -#endif /* IDETAPE_DEBUG_LOG */ -#if IDETAPE_DEBUG_BUGS - if (stage == NULL) { - printk(KERN_ERR "ide-tape: bug: Trying to activate a non existing stage\n"); - return; - } -#endif /* IDETAPE_DEBUG_BUGS */ - - rq->rq_disk = tape->disk; - rq->buffer = NULL; - rq->special = (void *)stage->bh; - tape->active_data_request = rq; - tape->active_stage = stage; - tape->next_stage = stage->next; -} +static void ide_tape_handle_dsc(ide_drive_t *); -/* - * idetape_increase_max_pipeline_stages is a part of the feedback - * loop which tries to find the optimum number of stages. In the - * feedback loop, we are starting from a minimum maximum number of - * stages, and if we sense that the pipeline is empty, we try to - * increase it, until we reach the user compile time memory limit. - */ -static void idetape_increase_max_pipeline_stages (ide_drive_t *drive) +static int ide_tape_callback(ide_drive_t *drive, int dsc) { idetape_tape_t *tape = drive->driver_data; - int increase = (tape->max_pipeline - tape->min_pipeline) / 10; - -#if IDETAPE_DEBUG_LOG - if (tape->debug_level >= 4) - printk (KERN_INFO "ide-tape: Reached idetape_increase_max_pipeline_stages\n"); -#endif /* IDETAPE_DEBUG_LOG */ - - tape->max_stages += max(increase, 1); - tape->max_stages = max(tape->max_stages, tape->min_pipeline); - tape->max_stages = min(tape->max_stages, tape->max_pipeline); -} - -/* - * idetape_kfree_stage calls kfree to completely free a stage, along with - * its related buffers. - */ -static void __idetape_kfree_stage (idetape_stage_t *stage) -{ - struct idetape_bh *prev_bh, *bh = stage->bh; - int size; - - while (bh != NULL) { - if (bh->b_data != NULL) { - size = (int) bh->b_size; - while (size > 0) { - free_page((unsigned long) bh->b_data); - size -= PAGE_SIZE; - bh->b_data += PAGE_SIZE; - } - } - prev_bh = bh; - bh = bh->b_reqnext; - kfree(prev_bh); - } - kfree(stage); -} - -static void idetape_kfree_stage (idetape_tape_t *tape, idetape_stage_t *stage) -{ - __idetape_kfree_stage(stage); -} + struct ide_atapi_pc *pc = drive->pc; + struct request *rq = drive->hwif->rq; + int uptodate = pc->error ? 0 : 1; + int err = uptodate ? 0 : IDE_DRV_ERROR_GENERAL; -/* - * idetape_remove_stage_head removes tape->first_stage from the pipeline. - * The caller should avoid race conditions. - */ -static void idetape_remove_stage_head (ide_drive_t *drive) -{ - idetape_tape_t *tape = drive->driver_data; - idetape_stage_t *stage; - -#if IDETAPE_DEBUG_LOG - if (tape->debug_level >= 4) - printk(KERN_INFO "ide-tape: Reached idetape_remove_stage_head\n"); -#endif /* IDETAPE_DEBUG_LOG */ -#if IDETAPE_DEBUG_BUGS - if (tape->first_stage == NULL) { - printk(KERN_ERR "ide-tape: bug: tape->first_stage is NULL\n"); - return; - } - if (tape->active_stage == tape->first_stage) { - printk(KERN_ERR "ide-tape: bug: Trying to free our active pipeline stage\n"); - return; - } -#endif /* IDETAPE_DEBUG_BUGS */ - stage = tape->first_stage; - tape->first_stage = stage->next; - idetape_kfree_stage(tape, stage); - tape->nr_stages--; - if (tape->first_stage == NULL) { - tape->last_stage = NULL; -#if IDETAPE_DEBUG_BUGS - if (tape->next_stage != NULL) - printk(KERN_ERR "ide-tape: bug: tape->next_stage != NULL\n"); - if (tape->nr_stages) - printk(KERN_ERR "ide-tape: bug: nr_stages should be 0 now\n"); -#endif /* IDETAPE_DEBUG_BUGS */ - } -} + ide_debug_log(IDE_DBG_FUNC, "cmd: 0x%x, dsc: %d, err: %d", rq->cmd[0], + dsc, err); -/* - * This will free all the pipeline stages starting from new_last_stage->next - * to the end of the list, and point tape->last_stage to new_last_stage. - */ -static void idetape_abort_pipeline(ide_drive_t *drive, - idetape_stage_t *new_last_stage) -{ - idetape_tape_t *tape = drive->driver_data; - idetape_stage_t *stage = new_last_stage->next; - idetape_stage_t *nstage; + if (dsc) + ide_tape_handle_dsc(drive); -#if IDETAPE_DEBUG_LOG - if (tape->debug_level >= 4) - printk(KERN_INFO "ide-tape: %s: idetape_abort_pipeline called\n", tape->name); -#endif - while (stage) { - nstage = stage->next; - idetape_kfree_stage(tape, stage); - --tape->nr_stages; - --tape->nr_pending_stages; - stage = nstage; - } - if (new_last_stage) - new_last_stage->next = NULL; - tape->last_stage = new_last_stage; - tape->next_stage = NULL; -} + if (drive->failed_pc == pc) + drive->failed_pc = NULL; -/* - * idetape_end_request is used to finish servicing a request, and to - * insert a pending pipeline request into the main device queue. - */ -static int idetape_end_request(ide_drive_t *drive, int uptodate, int nr_sects) -{ - struct request *rq = HWGROUP(drive)->rq; - idetape_tape_t *tape = drive->driver_data; - unsigned long flags; - int error; - int remove_stage = 0; - idetape_stage_t *active_stage; - -#if IDETAPE_DEBUG_LOG - if (tape->debug_level >= 4) - printk(KERN_INFO "ide-tape: Reached idetape_end_request\n"); -#endif /* IDETAPE_DEBUG_LOG */ - - switch (uptodate) { - case 0: error = IDETAPE_ERROR_GENERAL; break; - case 1: error = 0; break; - default: error = uptodate; - } - rq->errors = error; - if (error) - tape->failed_pc = NULL; - - spin_lock_irqsave(&tape->spinlock, flags); - - /* The request was a pipelined data transfer request */ - if (tape->active_data_request == rq) { - active_stage = tape->active_stage; - tape->active_stage = NULL; - tape->active_data_request = NULL; - tape->nr_pending_stages--; - if (rq->cmd[0] & REQ_IDETAPE_WRITE) { - remove_stage = 1; - if (error) { - set_bit(IDETAPE_PIPELINE_ERROR, &tape->flags); - if (error == IDETAPE_ERROR_EOD) - idetape_abort_pipeline(drive, active_stage); - } - } else if (rq->cmd[0] & REQ_IDETAPE_READ) { - if (error == IDETAPE_ERROR_EOD) { - set_bit(IDETAPE_PIPELINE_ERROR, &tape->flags); - idetape_abort_pipeline(drive, active_stage); - } - } - if (tape->next_stage != NULL) { - idetape_active_next_stage(drive); - - /* - * Insert the next request into the request queue. - */ - (void) ide_do_drive_cmd(drive, tape->active_data_request, ide_end); - } else if (!error) { - idetape_increase_max_pipeline_stages(drive); + if (pc->c[0] == REQUEST_SENSE) { + if (uptodate) + idetape_analyze_error(drive); + else + printk(KERN_ERR "ide-tape: Error in REQUEST SENSE " + "itself - Aborting request!\n"); + } else if (pc->c[0] == READ_6 || pc->c[0] == WRITE_6) { + unsigned int blocks = + (blk_rq_bytes(rq) - rq->resid_len) / tape->blk_size; + + tape->avg_size += blocks * tape->blk_size; + + if (time_after_eq(jiffies, tape->avg_time + HZ)) { + tape->avg_speed = tape->avg_size * HZ / + (jiffies - tape->avg_time) / 1024; + tape->avg_size = 0; + tape->avg_time = jiffies; } - } - ide_end_drive_cmd(drive, 0, 0); -// blkdev_dequeue_request(rq); -// drive->rq = NULL; -// end_that_request_last(rq); - - if (remove_stage) - idetape_remove_stage_head(drive); - if (tape->active_data_request == NULL) - clear_bit(IDETAPE_PIPELINE_ACTIVE, &tape->flags); - spin_unlock_irqrestore(&tape->spinlock, flags); - return 0; -} -static ide_startstop_t idetape_request_sense_callback (ide_drive_t *drive) -{ - idetape_tape_t *tape = drive->driver_data; + tape->first_frame += blocks; -#if IDETAPE_DEBUG_LOG - if (tape->debug_level >= 4) - printk(KERN_INFO "ide-tape: Reached idetape_request_sense_callback\n"); -#endif /* IDETAPE_DEBUG_LOG */ - if (!tape->pc->error) { - idetape_analyze_error(drive, (idetape_request_sense_result_t *) tape->pc->buffer); - idetape_end_request(drive, 1, 0); - } else { - printk(KERN_ERR "ide-tape: Error in REQUEST SENSE itself - Aborting request!\n"); - idetape_end_request(drive, 0, 0); + if (pc->error) { + uptodate = 0; + err = pc->error; + } } - return ide_stopped; -} - -static void idetape_create_request_sense_cmd (idetape_pc_t *pc) -{ - idetape_init_pc(pc); - pc->c[0] = IDETAPE_REQUEST_SENSE_CMD; - pc->c[4] = 20; - pc->request_transfer = 20; - pc->callback = &idetape_request_sense_callback; -} - -static void idetape_init_rq(struct request *rq, u8 cmd) -{ - memset(rq, 0, sizeof(*rq)); - rq->flags = REQ_SPECIAL; - rq->cmd[0] = cmd; -} - -/* - * idetape_queue_pc_head generates a new packet command request in front - * of the request queue, before the current request, so that it will be - * processed immediately, on the next pass through the driver. - * - * idetape_queue_pc_head is called from the request handling part of - * the driver (the "bottom" part). Safe storage for the request should - * be allocated with idetape_next_pc_storage and idetape_next_rq_storage - * before calling idetape_queue_pc_head. - * - * Memory for those requests is pre-allocated at initialization time, and - * is limited to IDETAPE_PC_STACK requests. We assume that we have enough - * space for the maximum possible number of inter-dependent packet commands. - * - * The higher level of the driver - The ioctl handler and the character - * device handling functions should queue request to the lower level part - * and wait for their completion using idetape_queue_pc_tail or - * idetape_queue_rw_tail. - */ -static void idetape_queue_pc_head (ide_drive_t *drive, idetape_pc_t *pc,struct request *rq) -{ - struct ide_tape_obj *tape = drive->driver_data; + rq->errors = err; - idetape_init_rq(rq, REQ_IDETAPE_PC1); - rq->buffer = (char *) pc; - rq->rq_disk = tape->disk; - (void) ide_do_drive_cmd(drive, rq, ide_preempt); + return uptodate; } /* - * idetape_retry_pc is called when an error was detected during the - * last packet command. We queue a request sense packet command in - * the head of the request list. + * Postpone the current request so that ide.c will be able to service requests + * from another device on the same port while we are polling for DSC. */ -static ide_startstop_t idetape_retry_pc (ide_drive_t *drive) +static void ide_tape_stall_queue(ide_drive_t *drive) { idetape_tape_t *tape = drive->driver_data; - idetape_pc_t *pc; - struct request *rq; - atapi_error_t error; - - error.all = HWIF(drive)->INB(IDE_ERROR_REG); - pc = idetape_next_pc_storage(drive); - rq = idetape_next_rq_storage(drive); - idetape_create_request_sense_cmd(pc); - set_bit(IDETAPE_IGNORE_DSC, &tape->flags); - idetape_queue_pc_head(drive, pc, rq); - return ide_stopped; -} -/* - * idetape_postpone_request postpones the current request so that - * ide.c will be able to service requests from another device on - * the same hwgroup while we are polling for DSC. - */ -static void idetape_postpone_request (ide_drive_t *drive) -{ - idetape_tape_t *tape = drive->driver_data; + ide_debug_log(IDE_DBG_FUNC, "cmd: 0x%x, dsc_poll_freq: %lu", + drive->hwif->rq->cmd[0], tape->dsc_poll_freq); -#if IDETAPE_DEBUG_LOG - if (tape->debug_level >= 4) - printk(KERN_INFO "ide-tape: idetape_postpone_request\n"); -#endif - tape->postponed_rq = HWGROUP(drive)->rq; - ide_stall_queue(drive, tape->dsc_polling_frequency); + tape->postponed_rq = true; + + ide_stall_queue(drive, tape->dsc_poll_freq); } -/* - * idetape_pc_intr is the usual interrupt handler which will be called - * during a packet command. We will transfer some of the data (as - * requested by the drive) and will re-point interrupt handler to us. - * When data transfer is finished, we will act according to the - * algorithm described before idetape_issue_packet_command. - * - */ -static ide_startstop_t idetape_pc_intr (ide_drive_t *drive) +static void ide_tape_handle_dsc(ide_drive_t *drive) { - ide_hwif_t *hwif = drive->hwif; idetape_tape_t *tape = drive->driver_data; - atapi_status_t status; - atapi_bcount_t bcount; - atapi_ireason_t ireason; - idetape_pc_t *pc = tape->pc; - - unsigned int temp; -#if SIMULATE_ERRORS - static int error_sim_count = 0; -#endif - -#if IDETAPE_DEBUG_LOG - if (tape->debug_level >= 4) - printk(KERN_INFO "ide-tape: Reached idetape_pc_intr " - "interrupt handler\n"); -#endif /* IDETAPE_DEBUG_LOG */ - - /* Clear the interrupt */ - status.all = HWIF(drive)->INB(IDE_STATUS_REG); - - if (test_bit(PC_DMA_IN_PROGRESS, &pc->flags)) { - if (HWIF(drive)->ide_dma_end(drive) || status.b.check) { - /* - * A DMA error is sometimes expected. For example, - * if the tape is crossing a filemark during a - * READ command, it will issue an irq and position - * itself before the filemark, so that only a partial - * data transfer will occur (which causes the DMA - * error). In that case, we will later ask the tape - * how much bytes of the original request were - * actually transferred (we can't receive that - * information from the DMA engine on most chipsets). - */ - - /* - * On the contrary, a DMA error is never expected; - * it usually indicates a hardware error or abort. - * If the tape crosses a filemark during a READ - * command, it will issue an irq and position itself - * after the filemark (not before). Only a partial - * data transfer will occur, but no DMA error. - * (AS, 19 Apr 2001) - */ - set_bit(PC_DMA_ERROR, &pc->flags); - } else { - pc->actually_transferred = pc->request_transfer; - idetape_update_buffers(pc); - } -#if IDETAPE_DEBUG_LOG - if (tape->debug_level >= 4) - printk(KERN_INFO "ide-tape: DMA finished\n"); -#endif /* IDETAPE_DEBUG_LOG */ - } - /* No more interrupts */ - if (!status.b.drq) { -#if IDETAPE_DEBUG_LOG - if (tape->debug_level >= 2) - printk(KERN_INFO "ide-tape: Packet command completed, %d bytes transferred\n", pc->actually_transferred); -#endif /* IDETAPE_DEBUG_LOG */ - clear_bit(PC_DMA_IN_PROGRESS, &pc->flags); - - local_irq_enable(); - -#if SIMULATE_ERRORS - if ((pc->c[0] == IDETAPE_WRITE_CMD || - pc->c[0] == IDETAPE_READ_CMD) && - (++error_sim_count % 100) == 0) { - printk(KERN_INFO "ide-tape: %s: simulating error\n", - tape->name); - status.b.check = 1; - } -#endif - if (status.b.check && pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) - status.b.check = 0; - if (status.b.check || test_bit(PC_DMA_ERROR, &pc->flags)) { /* Error detected */ -#if IDETAPE_DEBUG_LOG - if (tape->debug_level >= 1) - printk(KERN_INFO "ide-tape: %s: I/O error\n", - tape->name); -#endif /* IDETAPE_DEBUG_LOG */ - if (pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) { - printk(KERN_ERR "ide-tape: I/O error in request sense command\n"); - return ide_do_reset(drive); - } -#if IDETAPE_DEBUG_LOG - if (tape->debug_level >= 1) - printk(KERN_INFO "ide-tape: [cmd %x]: check condition\n", pc->c[0]); -#endif - /* Retry operation */ - return idetape_retry_pc(drive); - } - pc->error = 0; - if (test_bit(PC_WAIT_FOR_DSC, &pc->flags) && - !status.b.dsc) { - /* Media access command */ - tape->dsc_polling_start = jiffies; - tape->dsc_polling_frequency = IDETAPE_DSC_MA_FAST; - tape->dsc_timeout = jiffies + IDETAPE_DSC_MA_TIMEOUT; - /* Allow ide.c to handle other requests */ - idetape_postpone_request(drive); - return ide_stopped; - } - if (tape->failed_pc == pc) - tape->failed_pc = NULL; - /* Command finished - Call the callback function */ - return pc->callback(drive); - } - if (test_and_clear_bit(PC_DMA_IN_PROGRESS, &pc->flags)) { - printk(KERN_ERR "ide-tape: The tape wants to issue more " - "interrupts in DMA mode\n"); - printk(KERN_ERR "ide-tape: DMA disabled, reverting to PIO\n"); - (void)__ide_dma_off(drive); - return ide_do_reset(drive); - } - /* Get the number of bytes to transfer on this interrupt. */ - bcount.b.high = hwif->INB(IDE_BCOUNTH_REG); - bcount.b.low = hwif->INB(IDE_BCOUNTL_REG); - - ireason.all = hwif->INB(IDE_IREASON_REG); - - if (ireason.b.cod) { - printk(KERN_ERR "ide-tape: CoD != 0 in idetape_pc_intr\n"); - return ide_do_reset(drive); - } - if (ireason.b.io == test_bit(PC_WRITING, &pc->flags)) { - /* Hopefully, we will never get here */ - printk(KERN_ERR "ide-tape: We wanted to %s, ", - ireason.b.io ? "Write":"Read"); - printk(KERN_ERR "ide-tape: but the tape wants us to %s !\n", - ireason.b.io ? "Read":"Write"); - return ide_do_reset(drive); - } - if (!test_bit(PC_WRITING, &pc->flags)) { - /* Reading - Check that we have enough space */ - temp = pc->actually_transferred + bcount.all; - if (temp > pc->request_transfer) { - if (temp > pc->buffer_size) { - printk(KERN_ERR "ide-tape: The tape wants to send us more data than expected - discarding data\n"); - idetape_discard_data(drive, bcount.all); - ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL); - return ide_started; - } -#if IDETAPE_DEBUG_LOG - if (tape->debug_level >= 2) - printk(KERN_NOTICE "ide-tape: The tape wants to send us more data than expected - allowing transfer\n"); -#endif /* IDETAPE_DEBUG_LOG */ - } - } - if (test_bit(PC_WRITING, &pc->flags)) { - if (pc->bh != NULL) - idetape_output_buffers(drive, pc, bcount.all); - else - /* Write the current buffer */ - HWIF(drive)->atapi_output_bytes(drive, pc->current_position, bcount.all); - } else { - if (pc->bh != NULL) - idetape_input_buffers(drive, pc, bcount.all); - else - /* Read the current buffer */ - HWIF(drive)->atapi_input_bytes(drive, pc->current_position, bcount.all); - } - /* Update the current position */ - pc->actually_transferred += bcount.all; - pc->current_position += bcount.all; -#if IDETAPE_DEBUG_LOG - if (tape->debug_level >= 2) - printk(KERN_INFO "ide-tape: [cmd %x] transferred %d bytes on that interrupt\n", pc->c[0], bcount.all); -#endif - /* And set the interrupt handler again */ - ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL); - return ide_started; + /* Media access command */ + tape->dsc_polling_start = jiffies; + tape->dsc_poll_freq = IDETAPE_DSC_MA_FAST; + tape->dsc_timeout = jiffies + IDETAPE_DSC_MA_TIMEOUT; + /* Allow ide.c to handle other requests */ + ide_tape_stall_queue(drive); } /* - * Packet Command Interface - * - * The current Packet Command is available in tape->pc, and will not - * change until we finish handling it. Each packet command is associated - * with a callback function that will be called when the command is - * finished. + * Packet Command Interface * - * The handling will be done in three stages: + * The current Packet Command is available in drive->pc, and will not change + * until we finish handling it. Each packet command is associated with a + * callback function that will be called when the command is finished. * - * 1. idetape_issue_packet_command will send the packet command to the - * drive, and will set the interrupt handler to idetape_pc_intr. + * The handling will be done in three stages: * - * 2. On each interrupt, idetape_pc_intr will be called. This step - * will be repeated until the device signals us that no more - * interrupts will be issued. + * 1. ide_tape_issue_pc will send the packet command to the drive, and will set + * the interrupt handler to ide_pc_intr. * - * 3. ATAPI Tape media access commands have immediate status with a - * delayed process. In case of a successful initiation of a - * media access packet command, the DSC bit will be set when the - * actual execution of the command is finished. - * Since the tape drive will not issue an interrupt, we have to - * poll for this event. In this case, we define the request as - * "low priority request" by setting rq_status to - * IDETAPE_RQ_POSTPONED, set a timer to poll for DSC and exit - * the driver. + * 2. On each interrupt, ide_pc_intr will be called. This step will be + * repeated until the device signals us that no more interrupts will be issued. * - * ide.c will then give higher priority to requests which - * originate from the other device, until will change rq_status - * to RQ_ACTIVE. + * 3. ATAPI Tape media access commands have immediate status with a delayed + * process. In case of a successful initiation of a media access packet command, + * the DSC bit will be set when the actual execution of the command is finished. + * Since the tape drive will not issue an interrupt, we have to poll for this + * event. In this case, we define the request as "low priority request" by + * setting rq_status to IDETAPE_RQ_POSTPONED, set a timer to poll for DSC and + * exit the driver. * - * 4. When the packet command is finished, it will be checked for errors. + * ide.c will then give higher priority to requests which originate from the + * other device, until will change rq_status to RQ_ACTIVE. * - * 5. In case an error was found, we queue a request sense packet - * command in front of the request queue and retry the operation - * up to IDETAPE_MAX_PC_RETRIES times. + * 4. When the packet command is finished, it will be checked for errors. * - * 6. In case no error was found, or we decided to give up and not - * to retry again, the callback function will be called and then - * we will handle the next request. + * 5. In case an error was found, we queue a request sense packet command in + * front of the request queue and retry the operation up to + * IDETAPE_MAX_PC_RETRIES times. * + * 6. In case no error was found, or we decided to give up and not to retry + * again, the callback function will be called and then we will handle the next + * request. */ -static ide_startstop_t idetape_transfer_pc(ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - idetape_tape_t *tape = drive->driver_data; - idetape_pc_t *pc = tape->pc; - atapi_ireason_t ireason; - int retries = 100; - ide_startstop_t startstop; - - if (ide_wait_stat(&startstop,drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) { - printk(KERN_ERR "ide-tape: Strange, packet command initiated yet DRQ isn't asserted\n"); - return startstop; - } - ireason.all = hwif->INB(IDE_IREASON_REG); - while (retries-- && (!ireason.b.cod || ireason.b.io)) { - printk(KERN_ERR "ide-tape: (IO,CoD != (0,1) while issuing " - "a packet command, retrying\n"); - udelay(100); - ireason.all = hwif->INB(IDE_IREASON_REG); - if (retries == 0) { - printk(KERN_ERR "ide-tape: (IO,CoD != (0,1) while " - "issuing a packet command, ignoring\n"); - ireason.b.cod = 1; - ireason.b.io = 0; - } - } - if (!ireason.b.cod || ireason.b.io) { - printk(KERN_ERR "ide-tape: (IO,CoD) != (0,1) while issuing " - "a packet command\n"); - return ide_do_reset(drive); - } - /* Set the interrupt routine */ - ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL); -#ifdef CONFIG_BLK_DEV_IDEDMA - /* Begin DMA, if necessary */ - if (test_bit(PC_DMA_IN_PROGRESS, &pc->flags)) - hwif->dma_start(drive); -#endif - /* Send the actual packet */ - HWIF(drive)->atapi_output_bytes(drive, pc->c, 12); - return ide_started; -} -static ide_startstop_t idetape_issue_packet_command (ide_drive_t *drive, idetape_pc_t *pc) +static ide_startstop_t ide_tape_issue_pc(ide_drive_t *drive, + struct ide_cmd *cmd, + struct ide_atapi_pc *pc) { - ide_hwif_t *hwif = drive->hwif; idetape_tape_t *tape = drive->driver_data; - atapi_bcount_t bcount; - int dma_ok = 0; - -#if IDETAPE_DEBUG_BUGS - if (tape->pc->c[0] == IDETAPE_REQUEST_SENSE_CMD && - pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) { - printk(KERN_ERR "ide-tape: possible ide-tape.c bug - " - "Two request sense in serial were issued\n"); - } -#endif /* IDETAPE_DEBUG_BUGS */ + struct request *rq = drive->hwif->rq; + + if (drive->failed_pc == NULL && pc->c[0] != REQUEST_SENSE) + drive->failed_pc = pc; - if (tape->failed_pc == NULL && pc->c[0] != IDETAPE_REQUEST_SENSE_CMD) - tape->failed_pc = pc; /* Set the current packet command */ - tape->pc = pc; + drive->pc = pc; if (pc->retries > IDETAPE_MAX_PC_RETRIES || - test_bit(PC_ABORT, &pc->flags)) { + (pc->flags & PC_FLAG_ABORT)) { + /* - * We will "abort" retrying a packet command in case - * a legitimate error code was received (crossing a - * filemark, or end of the media, for example). + * We will "abort" retrying a packet command in case legitimate + * error code was received (crossing a filemark, or end of the + * media, for example). */ - if (!test_bit(PC_ABORT, &pc->flags)) { - if (!(pc->c[0] == IDETAPE_TEST_UNIT_READY_CMD && + if (!(pc->flags & PC_FLAG_ABORT)) { + if (!(pc->c[0] == TEST_UNIT_READY && tape->sense_key == 2 && tape->asc == 4 && (tape->ascq == 1 || tape->ascq == 8))) { printk(KERN_ERR "ide-tape: %s: I/O error, " @@ -2156,74 +469,30 @@ static ide_startstop_t idetape_issue_packet_command (ide_drive_t *drive, idetape tape->ascq); } /* Giving up */ - pc->error = IDETAPE_ERROR_GENERAL; + pc->error = IDE_DRV_ERROR_GENERAL; } - tape->failed_pc = NULL; - return pc->callback(drive); - } -#if IDETAPE_DEBUG_LOG - if (tape->debug_level >= 2) - printk(KERN_INFO "ide-tape: Retry number - %d, cmd = %02X\n", pc->retries, pc->c[0]); -#endif /* IDETAPE_DEBUG_LOG */ - pc->retries++; - /* We haven't transferred any data yet */ - pc->actually_transferred = 0; - pc->current_position = pc->buffer; - /* Request to transfer the entire buffer at once */ - bcount.all = pc->request_transfer; - - if (test_and_clear_bit(PC_DMA_ERROR, &pc->flags)) { - printk(KERN_WARNING "ide-tape: DMA disabled, " - "reverting to PIO\n"); - (void)__ide_dma_off(drive); - } - if (test_bit(PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma) - dma_ok = !hwif->dma_setup(drive); - - if (IDE_CONTROL_REG) - hwif->OUTB(drive->ctl, IDE_CONTROL_REG); - hwif->OUTB(dma_ok ? 1 : 0, IDE_FEATURE_REG); /* Use PIO/DMA */ - hwif->OUTB(bcount.b.high, IDE_BCOUNTH_REG); - hwif->OUTB(bcount.b.low, IDE_BCOUNTL_REG); - hwif->OUTB(drive->select.all, IDE_SELECT_REG); - if (dma_ok) /* Will begin DMA later */ - set_bit(PC_DMA_IN_PROGRESS, &pc->flags); - if (test_bit(IDETAPE_DRQ_INTERRUPT, &tape->flags)) { - ide_set_handler(drive, &idetape_transfer_pc, IDETAPE_WAIT_CMD, NULL); - hwif->OUTB(WIN_PACKETCMD, IDE_COMMAND_REG); - return ide_started; - } else { - hwif->OUTB(WIN_PACKETCMD, IDE_COMMAND_REG); - return idetape_transfer_pc(drive); + drive->failed_pc = NULL; + drive->pc_callback(drive, 0); + ide_complete_rq(drive, -EIO, blk_rq_bytes(rq)); + return ide_stopped; } -} + ide_debug_log(IDE_DBG_SENSE, "retry #%d, cmd: 0x%02x", pc->retries, + pc->c[0]); -/* - * General packet command callback function. - */ -static ide_startstop_t idetape_pc_callback (ide_drive_t *drive) -{ - idetape_tape_t *tape = drive->driver_data; - -#if IDETAPE_DEBUG_LOG - if (tape->debug_level >= 4) - printk(KERN_INFO "ide-tape: Reached idetape_pc_callback\n"); -#endif /* IDETAPE_DEBUG_LOG */ + pc->retries++; - idetape_end_request(drive, tape->pc->error ? 0 : 1, 0); - return ide_stopped; + return ide_issue_pc(drive, cmd); } -/* - * A mode sense command is used to "sense" tape parameters. - */ -static void idetape_create_mode_sense_cmd (idetape_pc_t *pc, u8 page_code) +/* A mode sense command is used to "sense" tape parameters. */ +static void idetape_create_mode_sense_cmd(struct ide_atapi_pc *pc, u8 page_code) { - idetape_init_pc(pc); - pc->c[0] = IDETAPE_MODE_SENSE_CMD; + ide_init_pc(pc); + pc->c[0] = MODE_SENSE; if (page_code != IDETAPE_BLOCK_DESCRIPTOR) - pc->c[1] = 8; /* DBD = 1 - Don't return block descriptors */ + /* DBD = 1 - Don't return block descriptors */ + pc->c[1] = 8; pc->c[2] = page_code; /* * Changed pc->c[3] to 0 (255 will at best return unused info). @@ -2233,679 +502,200 @@ static void idetape_create_mode_sense_cmd (idetape_pc_t *pc, u8 page_code) * and return an error when 255 is used. */ pc->c[3] = 0; - pc->c[4] = 255; /* (We will just discard data in that case) */ + /* We will just discard data in that case */ + pc->c[4] = 255; if (page_code == IDETAPE_BLOCK_DESCRIPTOR) - pc->request_transfer = 12; + pc->req_xfer = 12; else if (page_code == IDETAPE_CAPABILITIES_PAGE) - pc->request_transfer = 24; + pc->req_xfer = 24; else - pc->request_transfer = 50; - pc->callback = &idetape_pc_callback; + pc->req_xfer = 50; } -static void calculate_speeds(ide_drive_t *drive) +static ide_startstop_t idetape_media_access_finished(ide_drive_t *drive) { + ide_hwif_t *hwif = drive->hwif; idetape_tape_t *tape = drive->driver_data; - int full = 125, empty = 75; - - if (time_after(jiffies, tape->controlled_pipeline_head_time + 120 * HZ)) { - tape->controlled_previous_pipeline_head = tape->controlled_last_pipeline_head; - tape->controlled_previous_head_time = tape->controlled_pipeline_head_time; - tape->controlled_last_pipeline_head = tape->pipeline_head; - tape->controlled_pipeline_head_time = jiffies; - } - if (time_after(jiffies, tape->controlled_pipeline_head_time + 60 * HZ)) - tape->controlled_pipeline_head_speed = (tape->pipeline_head - tape->controlled_last_pipeline_head) * 32 * HZ / (jiffies - tape->controlled_pipeline_head_time); - else if (time_after(jiffies, tape->controlled_previous_head_time)) - tape->controlled_pipeline_head_speed = (tape->pipeline_head - tape->controlled_previous_pipeline_head) * 32 * HZ / (jiffies - tape->controlled_previous_head_time); - - if (tape->nr_pending_stages < tape->max_stages /*- 1 */) { - /* -1 for read mode error recovery */ - if (time_after(jiffies, tape->uncontrolled_previous_head_time + 10 * HZ)) { - tape->uncontrolled_pipeline_head_time = jiffies; - tape->uncontrolled_pipeline_head_speed = (tape->pipeline_head - tape->uncontrolled_previous_pipeline_head) * 32 * HZ / (jiffies - tape->uncontrolled_previous_head_time); - } - } else { - tape->uncontrolled_previous_head_time = jiffies; - tape->uncontrolled_previous_pipeline_head = tape->pipeline_head; - if (time_after(jiffies, tape->uncontrolled_pipeline_head_time + 30 * HZ)) { - tape->uncontrolled_pipeline_head_time = jiffies; - } - } - tape->pipeline_head_speed = max(tape->uncontrolled_pipeline_head_speed, tape->controlled_pipeline_head_speed); - if (tape->speed_control == 0) { - tape->max_insert_speed = 5000; - } else if (tape->speed_control == 1) { - if (tape->nr_pending_stages >= tape->max_stages / 2) - tape->max_insert_speed = tape->pipeline_head_speed + - (1100 - tape->pipeline_head_speed) * 2 * (tape->nr_pending_stages - tape->max_stages / 2) / tape->max_stages; - else - tape->max_insert_speed = 500 + - (tape->pipeline_head_speed - 500) * 2 * tape->nr_pending_stages / tape->max_stages; - if (tape->nr_pending_stages >= tape->max_stages * 99 / 100) - tape->max_insert_speed = 5000; - } else if (tape->speed_control == 2) { - tape->max_insert_speed = tape->pipeline_head_speed * empty / 100 + - (tape->pipeline_head_speed * full / 100 - tape->pipeline_head_speed * empty / 100) * tape->nr_pending_stages / tape->max_stages; - } else - tape->max_insert_speed = tape->speed_control; - tape->max_insert_speed = max(tape->max_insert_speed, 500); -} + struct ide_atapi_pc *pc = drive->pc; + u8 stat; -static ide_startstop_t idetape_media_access_finished (ide_drive_t *drive) -{ - idetape_tape_t *tape = drive->driver_data; - idetape_pc_t *pc = tape->pc; - atapi_status_t status; + stat = hwif->tp_ops->read_status(hwif); - status.all = HWIF(drive)->INB(IDE_STATUS_REG); - if (status.b.dsc) { - if (status.b.check) { + if (stat & ATA_DSC) { + if (stat & ATA_ERR) { /* Error detected */ - if (pc->c[0] != IDETAPE_TEST_UNIT_READY_CMD) + if (pc->c[0] != TEST_UNIT_READY) printk(KERN_ERR "ide-tape: %s: I/O error, ", tape->name); /* Retry operation */ - return idetape_retry_pc(drive); + ide_retry_pc(drive); + return ide_stopped; } pc->error = 0; - if (tape->failed_pc == pc) - tape->failed_pc = NULL; } else { - pc->error = IDETAPE_ERROR_GENERAL; - tape->failed_pc = NULL; - } - return pc->callback(drive); -} - -static ide_startstop_t idetape_rw_callback (ide_drive_t *drive) -{ - idetape_tape_t *tape = drive->driver_data; - struct request *rq = HWGROUP(drive)->rq; - int blocks = tape->pc->actually_transferred / tape->tape_block_size; - - tape->avg_size += blocks * tape->tape_block_size; - tape->insert_size += blocks * tape->tape_block_size; - if (tape->insert_size > 1024 * 1024) - tape->measure_insert_time = 1; - if (tape->measure_insert_time) { - tape->measure_insert_time = 0; - tape->insert_time = jiffies; - tape->insert_size = 0; - } - if (time_after(jiffies, tape->insert_time)) - tape->insert_speed = tape->insert_size / 1024 * HZ / (jiffies - tape->insert_time); - if (time_after_eq(jiffies, tape->avg_time + HZ)) { - tape->avg_speed = tape->avg_size * HZ / (jiffies - tape->avg_time) / 1024; - tape->avg_size = 0; - tape->avg_time = jiffies; + pc->error = IDE_DRV_ERROR_GENERAL; + drive->failed_pc = NULL; } - -#if IDETAPE_DEBUG_LOG - if (tape->debug_level >= 4) - printk(KERN_INFO "ide-tape: Reached idetape_rw_callback\n"); -#endif /* IDETAPE_DEBUG_LOG */ - - tape->first_frame_position += blocks; - rq->current_nr_sectors -= blocks; - - if (!tape->pc->error) - idetape_end_request(drive, 1, 0); - else - idetape_end_request(drive, tape->pc->error, 0); + drive->pc_callback(drive, 0); return ide_stopped; } -static void idetape_create_read_cmd(idetape_tape_t *tape, idetape_pc_t *pc, unsigned int length, struct idetape_bh *bh) +static void ide_tape_create_rw_cmd(idetape_tape_t *tape, + struct ide_atapi_pc *pc, struct request *rq, + u8 opcode) { - idetape_init_pc(pc); - pc->c[0] = IDETAPE_READ_CMD; - put_unaligned(htonl(length), (unsigned int *) &pc->c[1]); + unsigned int length = blk_rq_sectors(rq) / (tape->blk_size >> 9); + + ide_init_pc(pc); + put_unaligned(cpu_to_be32(length), (unsigned int *) &pc->c[1]); pc->c[1] = 1; - pc->callback = &idetape_rw_callback; - pc->bh = bh; - atomic_set(&bh->b_count, 0); - pc->buffer = NULL; - pc->request_transfer = pc->buffer_size = length * tape->tape_block_size; - if (pc->request_transfer == tape->stage_size) - set_bit(PC_DMA_RECOMMENDED, &pc->flags); -} -static void idetape_create_read_buffer_cmd(idetape_tape_t *tape, idetape_pc_t *pc, unsigned int length, struct idetape_bh *bh) -{ - int size = 32768; - struct idetape_bh *p = bh; - - idetape_init_pc(pc); - pc->c[0] = IDETAPE_READ_BUFFER_CMD; - pc->c[1] = IDETAPE_RETRIEVE_FAULTY_BLOCK; - pc->c[7] = size >> 8; - pc->c[8] = size & 0xff; - pc->callback = &idetape_pc_callback; - pc->bh = bh; - atomic_set(&bh->b_count, 0); - pc->buffer = NULL; - while (p) { - atomic_set(&p->b_count, 0); - p = p->b_reqnext; + if (blk_rq_bytes(rq) == tape->buffer_size) + pc->flags |= PC_FLAG_DMA_OK; + + if (opcode == READ_6) + pc->c[0] = READ_6; + else if (opcode == WRITE_6) { + pc->c[0] = WRITE_6; + pc->flags |= PC_FLAG_WRITING; } - pc->request_transfer = pc->buffer_size = size; -} -static void idetape_create_write_cmd(idetape_tape_t *tape, idetape_pc_t *pc, unsigned int length, struct idetape_bh *bh) -{ - idetape_init_pc(pc); - pc->c[0] = IDETAPE_WRITE_CMD; - put_unaligned(htonl(length), (unsigned int *) &pc->c[1]); - pc->c[1] = 1; - pc->callback = &idetape_rw_callback; - set_bit(PC_WRITING, &pc->flags); - pc->bh = bh; - pc->b_data = bh->b_data; - pc->b_count = atomic_read(&bh->b_count); - pc->buffer = NULL; - pc->request_transfer = pc->buffer_size = length * tape->tape_block_size; - if (pc->request_transfer == tape->stage_size) - set_bit(PC_DMA_RECOMMENDED, &pc->flags); + memcpy(rq->cmd, pc->c, 12); } -/* - * idetape_do_request is our request handling function. - */ static ide_startstop_t idetape_do_request(ide_drive_t *drive, struct request *rq, sector_t block) { + ide_hwif_t *hwif = drive->hwif; idetape_tape_t *tape = drive->driver_data; - idetape_pc_t *pc = NULL; - struct request *postponed_rq = tape->postponed_rq; - atapi_status_t status; - -#if IDETAPE_DEBUG_LOG -#if 0 - if (tape->debug_level >= 5) - printk(KERN_INFO "ide-tape: rq_status: %d, " - "dev: %s, cmd: %ld, errors: %d\n", rq->rq_status, - rq->rq_disk->disk_name, rq->cmd[0], rq->errors); -#endif - if (tape->debug_level >= 2) - printk(KERN_INFO "ide-tape: sector: %ld, " - "nr_sectors: %ld, current_nr_sectors: %d\n", - rq->sector, rq->nr_sectors, rq->current_nr_sectors); -#endif /* IDETAPE_DEBUG_LOG */ + struct ide_atapi_pc *pc = NULL; + struct ide_cmd cmd; + u8 stat; - if ((rq->flags & REQ_SPECIAL) == 0) { - /* - * We do not support buffer cache originated requests. - */ - printk(KERN_NOTICE "ide-tape: %s: Unsupported request in " - "request queue (%ld)\n", drive->name, rq->flags); - ide_end_request(drive, 0, 0); - return ide_stopped; - } + ide_debug_log(IDE_DBG_RQ, "cmd: 0x%x, sector: %llu, nr_sectors: %u", + rq->cmd[0], (unsigned long long)blk_rq_pos(rq), + blk_rq_sectors(rq)); - /* - * Retry a failed packet command - */ - if (tape->failed_pc != NULL && - tape->pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) { - return idetape_issue_packet_command(drive, tape->failed_pc); - } -#if IDETAPE_DEBUG_BUGS - if (postponed_rq != NULL) - if (rq != postponed_rq) { - printk(KERN_ERR "ide-tape: ide-tape.c bug - " - "Two DSC requests were queued\n"); - idetape_end_request(drive, 0, 0); - return ide_stopped; - } -#endif /* IDETAPE_DEBUG_BUGS */ + BUG_ON(!(rq->cmd_type == REQ_TYPE_SPECIAL || + rq->cmd_type == REQ_TYPE_SENSE)); - tape->postponed_rq = NULL; + /* Retry a failed packet command */ + if (drive->failed_pc && drive->pc->c[0] == REQUEST_SENSE) { + pc = drive->failed_pc; + goto out; + } /* * If the tape is still busy, postpone our request and service * the other device meanwhile. */ - status.all = HWIF(drive)->INB(IDE_STATUS_REG); + stat = hwif->tp_ops->read_status(hwif); - if (!drive->dsc_overlap && !(rq->cmd[0] & REQ_IDETAPE_PC2)) - set_bit(IDETAPE_IGNORE_DSC, &tape->flags); + if ((drive->dev_flags & IDE_DFLAG_DSC_OVERLAP) == 0 && + (rq->cmd[13] & REQ_IDETAPE_PC2) == 0) + drive->atapi_flags |= IDE_AFLAG_IGNORE_DSC; - if (drive->post_reset == 1) { - set_bit(IDETAPE_IGNORE_DSC, &tape->flags); - drive->post_reset = 0; + if (drive->dev_flags & IDE_DFLAG_POST_RESET) { + drive->atapi_flags |= IDE_AFLAG_IGNORE_DSC; + drive->dev_flags &= ~IDE_DFLAG_POST_RESET; } - if (tape->tape_still_time > 100 && tape->tape_still_time < 200) - tape->measure_insert_time = 1; - if (time_after(jiffies, tape->insert_time)) - tape->insert_speed = tape->insert_size / 1024 * HZ / (jiffies - tape->insert_time); - calculate_speeds(drive); - if (!test_and_clear_bit(IDETAPE_IGNORE_DSC, &tape->flags) && - !status.b.dsc) { - if (postponed_rq == NULL) { + if (!(drive->atapi_flags & IDE_AFLAG_IGNORE_DSC) && + !(stat & ATA_DSC)) { + if (!tape->postponed_rq) { tape->dsc_polling_start = jiffies; - tape->dsc_polling_frequency = tape->best_dsc_rw_frequency; + tape->dsc_poll_freq = tape->best_dsc_rw_freq; tape->dsc_timeout = jiffies + IDETAPE_DSC_RW_TIMEOUT; } else if (time_after(jiffies, tape->dsc_timeout)) { printk(KERN_ERR "ide-tape: %s: DSC timeout\n", tape->name); - if (rq->cmd[0] & REQ_IDETAPE_PC2) { + if (rq->cmd[13] & REQ_IDETAPE_PC2) { idetape_media_access_finished(drive); return ide_stopped; } else { return ide_do_reset(drive); } - } else if (time_after(jiffies, tape->dsc_polling_start + IDETAPE_DSC_MA_THRESHOLD)) - tape->dsc_polling_frequency = IDETAPE_DSC_MA_SLOW; - idetape_postpone_request(drive); + } else if (time_after(jiffies, + tape->dsc_polling_start + + IDETAPE_DSC_MA_THRESHOLD)) + tape->dsc_poll_freq = IDETAPE_DSC_MA_SLOW; + ide_tape_stall_queue(drive); return ide_stopped; + } else { + drive->atapi_flags &= ~IDE_AFLAG_IGNORE_DSC; + tape->postponed_rq = false; } - if (rq->cmd[0] & REQ_IDETAPE_READ) { - tape->buffer_head++; -#if USE_IOTRACE - IO_trace(IO_IDETAPE_FIFO, tape->pipeline_head, tape->buffer_head, tape->tape_head, tape->minor); -#endif - tape->postpone_cnt = 0; - pc = idetape_next_pc_storage(drive); - idetape_create_read_cmd(tape, pc, rq->current_nr_sectors, (struct idetape_bh *)rq->special); - goto out; - } - if (rq->cmd[0] & REQ_IDETAPE_WRITE) { - tape->buffer_head++; -#if USE_IOTRACE - IO_trace(IO_IDETAPE_FIFO, tape->pipeline_head, tape->buffer_head, tape->tape_head, tape->minor); -#endif - tape->postpone_cnt = 0; - pc = idetape_next_pc_storage(drive); - idetape_create_write_cmd(tape, pc, rq->current_nr_sectors, (struct idetape_bh *)rq->special); + + if (rq->cmd[13] & REQ_IDETAPE_READ) { + pc = &tape->queued_pc; + ide_tape_create_rw_cmd(tape, pc, rq, READ_6); goto out; } - if (rq->cmd[0] & REQ_IDETAPE_READ_BUFFER) { - tape->postpone_cnt = 0; - pc = idetape_next_pc_storage(drive); - idetape_create_read_buffer_cmd(tape, pc, rq->current_nr_sectors, (struct idetape_bh *)rq->special); + if (rq->cmd[13] & REQ_IDETAPE_WRITE) { + pc = &tape->queued_pc; + ide_tape_create_rw_cmd(tape, pc, rq, WRITE_6); goto out; } - if (rq->cmd[0] & REQ_IDETAPE_PC1) { - pc = (idetape_pc_t *) rq->buffer; - rq->cmd[0] &= ~(REQ_IDETAPE_PC1); - rq->cmd[0] |= REQ_IDETAPE_PC2; + if (rq->cmd[13] & REQ_IDETAPE_PC1) { + pc = (struct ide_atapi_pc *)rq->special; + rq->cmd[13] &= ~(REQ_IDETAPE_PC1); + rq->cmd[13] |= REQ_IDETAPE_PC2; goto out; } - if (rq->cmd[0] & REQ_IDETAPE_PC2) { + if (rq->cmd[13] & REQ_IDETAPE_PC2) { idetape_media_access_finished(drive); return ide_stopped; } BUG(); -out: - return idetape_issue_packet_command(drive, pc); -} - -/* - * Pipeline related functions - */ -static inline int idetape_pipeline_active (idetape_tape_t *tape) -{ - int rc1, rc2; - - rc1 = test_bit(IDETAPE_PIPELINE_ACTIVE, &tape->flags); - rc2 = (tape->active_data_request != NULL); - return rc1; -} - -/* - * idetape_kmalloc_stage uses __get_free_page to allocate a pipeline - * stage, along with all the necessary small buffers which together make - * a buffer of size tape->stage_size (or a bit more). We attempt to - * combine sequential pages as much as possible. - * - * Returns a pointer to the new allocated stage, or NULL if we - * can't (or don't want to) allocate a stage. - * - * Pipeline stages are optional and are used to increase performance. - * If we can't allocate them, we'll manage without them. - */ -static idetape_stage_t *__idetape_kmalloc_stage (idetape_tape_t *tape, int full, int clear) -{ - idetape_stage_t *stage; - struct idetape_bh *prev_bh, *bh; - int pages = tape->pages_per_stage; - char *b_data = NULL; - - if ((stage = (idetape_stage_t *) kmalloc (sizeof (idetape_stage_t),GFP_KERNEL)) == NULL) - return NULL; - stage->next = NULL; - - bh = stage->bh = (struct idetape_bh *)kmalloc(sizeof(struct idetape_bh), GFP_KERNEL); - if (bh == NULL) - goto abort; - bh->b_reqnext = NULL; - if ((bh->b_data = (char *) __get_free_page (GFP_KERNEL)) == NULL) - goto abort; - if (clear) - memset(bh->b_data, 0, PAGE_SIZE); - bh->b_size = PAGE_SIZE; - atomic_set(&bh->b_count, full ? bh->b_size : 0); - - while (--pages) { - if ((b_data = (char *) __get_free_page (GFP_KERNEL)) == NULL) - goto abort; - if (clear) - memset(b_data, 0, PAGE_SIZE); - if (bh->b_data == b_data + PAGE_SIZE) { - bh->b_size += PAGE_SIZE; - bh->b_data -= PAGE_SIZE; - if (full) - atomic_add(PAGE_SIZE, &bh->b_count); - continue; - } - if (b_data == bh->b_data + bh->b_size) { - bh->b_size += PAGE_SIZE; - if (full) - atomic_add(PAGE_SIZE, &bh->b_count); - continue; - } - prev_bh = bh; - if ((bh = (struct idetape_bh *)kmalloc(sizeof(struct idetape_bh), GFP_KERNEL)) == NULL) { - free_page((unsigned long) b_data); - goto abort; - } - bh->b_reqnext = NULL; - bh->b_data = b_data; - bh->b_size = PAGE_SIZE; - atomic_set(&bh->b_count, full ? bh->b_size : 0); - prev_bh->b_reqnext = bh; - } - bh->b_size -= tape->excess_bh_size; - if (full) - atomic_sub(tape->excess_bh_size, &bh->b_count); - return stage; -abort: - __idetape_kfree_stage(stage); - return NULL; -} -static idetape_stage_t *idetape_kmalloc_stage (idetape_tape_t *tape) -{ - idetape_stage_t *cache_stage = tape->cache_stage; - -#if IDETAPE_DEBUG_LOG - if (tape->debug_level >= 4) - printk(KERN_INFO "ide-tape: Reached idetape_kmalloc_stage\n"); -#endif /* IDETAPE_DEBUG_LOG */ - - if (tape->nr_stages >= tape->max_stages) - return NULL; - if (cache_stage != NULL) { - tape->cache_stage = NULL; - return cache_stage; - } - return __idetape_kmalloc_stage(tape, 0, 0); -} - -static int idetape_copy_stage_from_user (idetape_tape_t *tape, idetape_stage_t *stage, const char __user *buf, int n) -{ - struct idetape_bh *bh = tape->bh; - int count; - int ret = 0; - - while (n) { -#if IDETAPE_DEBUG_BUGS - if (bh == NULL) { - printk(KERN_ERR "ide-tape: bh == NULL in " - "idetape_copy_stage_from_user\n"); - return 1; - } -#endif /* IDETAPE_DEBUG_BUGS */ - count = min((unsigned int)(bh->b_size - atomic_read(&bh->b_count)), (unsigned int)n); - if (copy_from_user(bh->b_data + atomic_read(&bh->b_count), buf, count)) - ret = 1; - n -= count; - atomic_add(count, &bh->b_count); - buf += count; - if (atomic_read(&bh->b_count) == bh->b_size) { - bh = bh->b_reqnext; - if (bh) - atomic_set(&bh->b_count, 0); - } - } - tape->bh = bh; - return ret; -} +out: + /* prepare sense request for this command */ + ide_prep_sense(drive, rq); -static int idetape_copy_stage_to_user (idetape_tape_t *tape, char __user *buf, idetape_stage_t *stage, int n) -{ - struct idetape_bh *bh = tape->bh; - int count; - int ret = 0; - - while (n) { -#if IDETAPE_DEBUG_BUGS - if (bh == NULL) { - printk(KERN_ERR "ide-tape: bh == NULL in " - "idetape_copy_stage_to_user\n"); - return 1; - } -#endif /* IDETAPE_DEBUG_BUGS */ - count = min(tape->b_count, n); - if (copy_to_user(buf, tape->b_data, count)) - ret = 1; - n -= count; - tape->b_data += count; - tape->b_count -= count; - buf += count; - if (!tape->b_count) { - tape->bh = bh = bh->b_reqnext; - if (bh) { - tape->b_data = bh->b_data; - tape->b_count = atomic_read(&bh->b_count); - } - } - } - return ret; -} + memset(&cmd, 0, sizeof(cmd)); -static void idetape_init_merge_stage (idetape_tape_t *tape) -{ - struct idetape_bh *bh = tape->merge_stage->bh; - - tape->bh = bh; - if (tape->chrdev_direction == idetape_direction_write) - atomic_set(&bh->b_count, 0); - else { - tape->b_data = bh->b_data; - tape->b_count = atomic_read(&bh->b_count); - } -} + if (rq_data_dir(rq)) + cmd.tf_flags |= IDE_TFLAG_WRITE; -static void idetape_switch_buffers (idetape_tape_t *tape, idetape_stage_t *stage) -{ - struct idetape_bh *tmp; + cmd.rq = rq; - tmp = stage->bh; - stage->bh = tape->merge_stage->bh; - tape->merge_stage->bh = tmp; - idetape_init_merge_stage(tape); -} + ide_init_sg_cmd(&cmd, blk_rq_bytes(rq)); + ide_map_sg(drive, &cmd); -/* - * idetape_add_stage_tail adds a new stage at the end of the pipeline. - */ -static void idetape_add_stage_tail (ide_drive_t *drive,idetape_stage_t *stage) -{ - idetape_tape_t *tape = drive->driver_data; - unsigned long flags; - -#if IDETAPE_DEBUG_LOG - if (tape->debug_level >= 4) - printk (KERN_INFO "ide-tape: Reached idetape_add_stage_tail\n"); -#endif /* IDETAPE_DEBUG_LOG */ - spin_lock_irqsave(&tape->spinlock, flags); - stage->next = NULL; - if (tape->last_stage != NULL) - tape->last_stage->next=stage; - else - tape->first_stage = tape->next_stage=stage; - tape->last_stage = stage; - if (tape->next_stage == NULL) - tape->next_stage = tape->last_stage; - tape->nr_stages++; - tape->nr_pending_stages++; - spin_unlock_irqrestore(&tape->spinlock, flags); + return ide_tape_issue_pc(drive, &cmd, pc); } /* - * idetape_wait_for_request installs a completion in a pending request - * and sleeps until it is serviced. - * - * The caller should ensure that the request will not be serviced - * before we install the completion (usually by disabling interrupts). + * Write a filemark if write_filemark=1. Flush the device buffers without + * writing a filemark otherwise. */ -static void idetape_wait_for_request (ide_drive_t *drive, struct request *rq) -{ - DECLARE_COMPLETION(wait); - idetape_tape_t *tape = drive->driver_data; - -#if IDETAPE_DEBUG_BUGS - if (rq == NULL || (rq->flags & REQ_SPECIAL) == 0) { - printk (KERN_ERR "ide-tape: bug: Trying to sleep on non-valid request\n"); - return; - } -#endif /* IDETAPE_DEBUG_BUGS */ - rq->waiting = &wait; - rq->end_io = blk_end_sync_rq; - spin_unlock_irq(&tape->spinlock); - wait_for_completion(&wait); - /* The stage and its struct request have been deallocated */ - spin_lock_irq(&tape->spinlock); -} - -static ide_startstop_t idetape_read_position_callback (ide_drive_t *drive) +static void idetape_create_write_filemark_cmd(ide_drive_t *drive, + struct ide_atapi_pc *pc, int write_filemark) { - idetape_tape_t *tape = drive->driver_data; - idetape_read_position_result_t *result; - -#if IDETAPE_DEBUG_LOG - if (tape->debug_level >= 4) - printk(KERN_INFO "ide-tape: Reached idetape_read_position_callback\n"); -#endif /* IDETAPE_DEBUG_LOG */ - - if (!tape->pc->error) { - result = (idetape_read_position_result_t *) tape->pc->buffer; -#if IDETAPE_DEBUG_LOG - if (tape->debug_level >= 2) - printk(KERN_INFO "ide-tape: BOP - %s\n",result->bop ? "Yes":"No"); - if (tape->debug_level >= 2) - printk(KERN_INFO "ide-tape: EOP - %s\n",result->eop ? "Yes":"No"); -#endif /* IDETAPE_DEBUG_LOG */ - if (result->bpu) { - printk(KERN_INFO "ide-tape: Block location is unknown to the tape\n"); - clear_bit(IDETAPE_ADDRESS_VALID, &tape->flags); - idetape_end_request(drive, 0, 0); - } else { -#if IDETAPE_DEBUG_LOG - if (tape->debug_level >= 2) - printk(KERN_INFO "ide-tape: Block Location - %u\n", ntohl(result->first_block)); -#endif /* IDETAPE_DEBUG_LOG */ - tape->partition = result->partition; - tape->first_frame_position = ntohl(result->first_block); - tape->last_frame_position = ntohl(result->last_block); - tape->blocks_in_buffer = result->blocks_in_buffer[2]; - set_bit(IDETAPE_ADDRESS_VALID, &tape->flags); - idetape_end_request(drive, 1, 0); - } - } else { - idetape_end_request(drive, 0, 0); - } - return ide_stopped; -} - -/* - * idetape_create_write_filemark_cmd will: - * - * 1. Write a filemark if write_filemark=1. - * 2. Flush the device buffers without writing a filemark - * if write_filemark=0. - * - */ -static void idetape_create_write_filemark_cmd (ide_drive_t *drive, idetape_pc_t *pc,int write_filemark) -{ - idetape_init_pc(pc); - pc->c[0] = IDETAPE_WRITE_FILEMARK_CMD; + ide_init_pc(pc); + pc->c[0] = WRITE_FILEMARKS; pc->c[4] = write_filemark; - set_bit(PC_WAIT_FOR_DSC, &pc->flags); - pc->callback = &idetape_pc_callback; -} - -static void idetape_create_test_unit_ready_cmd(idetape_pc_t *pc) -{ - idetape_init_pc(pc); - pc->c[0] = IDETAPE_TEST_UNIT_READY_CMD; - pc->callback = &idetape_pc_callback; -} - -/* - * idetape_queue_pc_tail is based on the following functions: - * - * ide_do_drive_cmd from ide.c - * cdrom_queue_request and cdrom_queue_packet_command from ide-cd.c - * - * We add a special packet command request to the tail of the request - * queue, and wait for it to be serviced. - * - * This is not to be called from within the request handling part - * of the driver ! We allocate here data in the stack, and it is valid - * until the request is finished. This is not the case for the bottom - * part of the driver, where we are always leaving the functions to wait - * for an interrupt or a timer event. - * - * From the bottom part of the driver, we should allocate safe memory - * using idetape_next_pc_storage and idetape_next_rq_storage, and add - * the request to the request list without waiting for it to be serviced ! - * In that case, we usually use idetape_queue_pc_head. - */ -static int __idetape_queue_pc_tail (ide_drive_t *drive, idetape_pc_t *pc) -{ - struct ide_tape_obj *tape = drive->driver_data; - struct request rq; - - idetape_init_rq(&rq, REQ_IDETAPE_PC1); - rq.buffer = (char *) pc; - rq.rq_disk = tape->disk; - return ide_do_drive_cmd(drive, &rq, ide_wait); -} - -static void idetape_create_load_unload_cmd (ide_drive_t *drive, idetape_pc_t *pc,int cmd) -{ - idetape_init_pc(pc); - pc->c[0] = IDETAPE_LOAD_UNLOAD_CMD; - pc->c[4] = cmd; - set_bit(PC_WAIT_FOR_DSC, &pc->flags); - pc->callback = &idetape_pc_callback; + pc->flags |= PC_FLAG_WAIT_FOR_DSC; } static int idetape_wait_ready(ide_drive_t *drive, unsigned long timeout) { idetape_tape_t *tape = drive->driver_data; - idetape_pc_t pc; + struct gendisk *disk = tape->disk; int load_attempted = 0; - /* - * Wait for the tape to become ready - */ - set_bit(IDETAPE_MEDIUM_PRESENT, &tape->flags); + /* Wait for the tape to become ready */ + set_bit(ilog2(IDE_AFLAG_MEDIUM_PRESENT), &drive->atapi_flags); timeout += jiffies; while (time_before(jiffies, timeout)) { - idetape_create_test_unit_ready_cmd(&pc); - if (!__idetape_queue_pc_tail(drive, &pc)) + if (ide_do_test_unit_ready(drive, disk) == 0) return 0; if ((tape->sense_key == 2 && tape->asc == 4 && tape->ascq == 2) - || (tape->asc == 0x3A)) { /* no media */ + || (tape->asc == 0x3A)) { + /* no media */ if (load_attempted) return -ENOMEDIUM; - idetape_create_load_unload_cmd(drive, &pc, IDETAPE_LU_LOAD_MASK); - __idetape_queue_pc_tail(drive, &pc); + ide_do_start_stop(drive, disk, IDETAPE_LU_LOAD_MASK); load_attempted = 1; /* not about to be ready */ } else if (!(tape->sense_key == 2 && tape->asc == 4 && @@ -2916,975 +706,530 @@ static int idetape_wait_ready(ide_drive_t *drive, unsigned long timeout) return -EIO; } -static int idetape_queue_pc_tail (ide_drive_t *drive,idetape_pc_t *pc) +static int idetape_flush_tape_buffers(ide_drive_t *drive) { - return __idetape_queue_pc_tail(drive, pc); -} - -static int idetape_flush_tape_buffers (ide_drive_t *drive) -{ - idetape_pc_t pc; + struct ide_tape_obj *tape = drive->driver_data; + struct ide_atapi_pc pc; int rc; idetape_create_write_filemark_cmd(drive, &pc, 0); - if ((rc = idetape_queue_pc_tail(drive, &pc))) + rc = ide_queue_pc_tail(drive, tape->disk, &pc, NULL, 0); + if (rc) return rc; idetape_wait_ready(drive, 60 * 5 * HZ); return 0; } -static void idetape_create_read_position_cmd (idetape_pc_t *pc) -{ - idetape_init_pc(pc); - pc->c[0] = IDETAPE_READ_POSITION_CMD; - pc->request_transfer = 20; - pc->callback = &idetape_read_position_callback; -} - -static int idetape_read_position (ide_drive_t *drive) +static int ide_tape_read_position(ide_drive_t *drive) { idetape_tape_t *tape = drive->driver_data; - idetape_pc_t pc; - int position; + struct ide_atapi_pc pc; + u8 buf[20]; + + ide_debug_log(IDE_DBG_FUNC, "enter"); -#if IDETAPE_DEBUG_LOG - if (tape->debug_level >= 4) - printk(KERN_INFO "ide-tape: Reached idetape_read_position\n"); -#endif /* IDETAPE_DEBUG_LOG */ + /* prep cmd */ + ide_init_pc(&pc); + pc.c[0] = READ_POSITION; + pc.req_xfer = 20; - idetape_create_read_position_cmd(&pc); - if (idetape_queue_pc_tail(drive, &pc)) + if (ide_queue_pc_tail(drive, tape->disk, &pc, buf, pc.req_xfer)) return -1; - position = tape->first_frame_position; - return position; + + if (!pc.error) { + ide_debug_log(IDE_DBG_FUNC, "BOP - %s", + (buf[0] & 0x80) ? "Yes" : "No"); + ide_debug_log(IDE_DBG_FUNC, "EOP - %s", + (buf[0] & 0x40) ? "Yes" : "No"); + + if (buf[0] & 0x4) { + printk(KERN_INFO "ide-tape: Block location is unknown" + "to the tape\n"); + clear_bit(ilog2(IDE_AFLAG_ADDRESS_VALID), + &drive->atapi_flags); + return -1; + } else { + ide_debug_log(IDE_DBG_FUNC, "Block Location: %u", + be32_to_cpup((__be32 *)&buf[4])); + + tape->partition = buf[1]; + tape->first_frame = be32_to_cpup((__be32 *)&buf[4]); + set_bit(ilog2(IDE_AFLAG_ADDRESS_VALID), + &drive->atapi_flags); + } + } + + return tape->first_frame; } -static void idetape_create_locate_cmd (ide_drive_t *drive, idetape_pc_t *pc, unsigned int block, u8 partition, int skip) +static void idetape_create_locate_cmd(ide_drive_t *drive, + struct ide_atapi_pc *pc, + unsigned int block, u8 partition, int skip) { - idetape_init_pc(pc); - pc->c[0] = IDETAPE_LOCATE_CMD; + ide_init_pc(pc); + pc->c[0] = POSITION_TO_ELEMENT; pc->c[1] = 2; - put_unaligned(htonl(block), (unsigned int *) &pc->c[3]); + put_unaligned(cpu_to_be32(block), (unsigned int *) &pc->c[3]); pc->c[8] = partition; - set_bit(PC_WAIT_FOR_DSC, &pc->flags); - pc->callback = &idetape_pc_callback; -} - -static int idetape_create_prevent_cmd (ide_drive_t *drive, idetape_pc_t *pc, int prevent) -{ - idetape_tape_t *tape = drive->driver_data; - - if (!tape->capabilities.lock) - return 0; - - idetape_init_pc(pc); - pc->c[0] = IDETAPE_PREVENT_CMD; - pc->c[4] = prevent; - pc->callback = &idetape_pc_callback; - return 1; + pc->flags |= PC_FLAG_WAIT_FOR_DSC; } -static int __idetape_discard_read_pipeline (ide_drive_t *drive) +static void __ide_tape_discard_merge_buffer(ide_drive_t *drive) { idetape_tape_t *tape = drive->driver_data; - unsigned long flags; - int cnt; - if (tape->chrdev_direction != idetape_direction_read) - return 0; + if (tape->chrdev_dir != IDETAPE_DIR_READ) + return; - /* Remove merge stage. */ - cnt = tape->merge_stage_size / tape->tape_block_size; - if (test_and_clear_bit(IDETAPE_FILEMARK, &tape->flags)) - ++cnt; /* Filemarks count as 1 sector */ - tape->merge_stage_size = 0; - if (tape->merge_stage != NULL) { - __idetape_kfree_stage(tape->merge_stage); - tape->merge_stage = NULL; + clear_bit(ilog2(IDE_AFLAG_FILEMARK), &drive->atapi_flags); + tape->valid = 0; + if (tape->buf != NULL) { + kfree(tape->buf); + tape->buf = NULL; } - /* Clear pipeline flags. */ - clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags); - tape->chrdev_direction = idetape_direction_none; - - /* Remove pipeline stages. */ - if (tape->first_stage == NULL) - return 0; - - spin_lock_irqsave(&tape->spinlock, flags); - tape->next_stage = NULL; - if (idetape_pipeline_active(tape)) - idetape_wait_for_request(drive, tape->active_data_request); - spin_unlock_irqrestore(&tape->spinlock, flags); - - while (tape->first_stage != NULL) { - struct request *rq_ptr = &tape->first_stage->rq; - - cnt += rq_ptr->nr_sectors - rq_ptr->current_nr_sectors; - if (rq_ptr->errors == IDETAPE_ERROR_FILEMARK) - ++cnt; - idetape_remove_stage_head(drive); - } - tape->nr_pending_stages = 0; - tape->max_stages = tape->min_pipeline; - return cnt; + tape->chrdev_dir = IDETAPE_DIR_NONE; } /* - * idetape_position_tape positions the tape to the requested block - * using the LOCATE packet command. A READ POSITION command is then - * issued to check where we are positioned. - * - * Like all higher level operations, we queue the commands at the tail - * of the request queue and wait for their completion. - * + * Position the tape to the requested block using the LOCATE packet command. + * A READ POSITION command is then issued to check where we are positioned. Like + * all higher level operations, we queue the commands at the tail of the request + * queue and wait for their completion. */ -static int idetape_position_tape (ide_drive_t *drive, unsigned int block, u8 partition, int skip) +static int idetape_position_tape(ide_drive_t *drive, unsigned int block, + u8 partition, int skip) { idetape_tape_t *tape = drive->driver_data; - int retval; - idetape_pc_t pc; + struct gendisk *disk = tape->disk; + int ret; + struct ide_atapi_pc pc; - if (tape->chrdev_direction == idetape_direction_read) - __idetape_discard_read_pipeline(drive); + if (tape->chrdev_dir == IDETAPE_DIR_READ) + __ide_tape_discard_merge_buffer(drive); idetape_wait_ready(drive, 60 * 5 * HZ); idetape_create_locate_cmd(drive, &pc, block, partition, skip); - retval = idetape_queue_pc_tail(drive, &pc); - if (retval) - return (retval); + ret = ide_queue_pc_tail(drive, disk, &pc, NULL, 0); + if (ret) + return ret; - idetape_create_read_position_cmd(&pc); - return (idetape_queue_pc_tail(drive, &pc)); + ret = ide_tape_read_position(drive); + if (ret < 0) + return ret; + return 0; } -static void idetape_discard_read_pipeline (ide_drive_t *drive, int restore_position) +static void ide_tape_discard_merge_buffer(ide_drive_t *drive, + int restore_position) { idetape_tape_t *tape = drive->driver_data; - int cnt; int seek, position; - cnt = __idetape_discard_read_pipeline(drive); + __ide_tape_discard_merge_buffer(drive); if (restore_position) { - position = idetape_read_position(drive); - seek = position > cnt ? position - cnt : 0; + position = ide_tape_read_position(drive); + seek = position > 0 ? position : 0; if (idetape_position_tape(drive, seek, 0, 0)) { - printk(KERN_INFO "ide-tape: %s: position_tape failed in discard_pipeline()\n", tape->name); + printk(KERN_INFO "ide-tape: %s: position_tape failed in" + " %s\n", tape->name, __func__); return; } } } /* - * idetape_queue_rw_tail generates a read/write request for the block - * device interface and wait for it to be serviced. + * Generate a read/write request for the block device interface and wait for it + * to be serviced. */ -static int idetape_queue_rw_tail(ide_drive_t *drive, int cmd, int blocks, struct idetape_bh *bh) +static int idetape_queue_rw_tail(ide_drive_t *drive, int cmd, int size) { idetape_tape_t *tape = drive->driver_data; - struct request rq; - -#if IDETAPE_DEBUG_LOG - if (tape->debug_level >= 2) - printk(KERN_INFO "ide-tape: idetape_queue_rw_tail: cmd=%d\n",cmd); -#endif /* IDETAPE_DEBUG_LOG */ -#if IDETAPE_DEBUG_BUGS - if (idetape_pipeline_active(tape)) { - printk(KERN_ERR "ide-tape: bug: the pipeline is active in idetape_queue_rw_tail\n"); - return (0); - } -#endif /* IDETAPE_DEBUG_BUGS */ + struct request *rq; + int ret; - idetape_init_rq(&rq, cmd); - rq.rq_disk = tape->disk; - rq.special = (void *)bh; - rq.sector = tape->first_frame_position; - rq.nr_sectors = rq.current_nr_sectors = blocks; - (void) ide_do_drive_cmd(drive, &rq, ide_wait); + ide_debug_log(IDE_DBG_FUNC, "cmd: 0x%x, size: %d", cmd, size); - if ((cmd & (REQ_IDETAPE_READ | REQ_IDETAPE_WRITE)) == 0) - return 0; + BUG_ON(cmd != REQ_IDETAPE_READ && cmd != REQ_IDETAPE_WRITE); + BUG_ON(size < 0 || size % tape->blk_size); - if (tape->merge_stage) - idetape_init_merge_stage(tape); - if (rq.errors == IDETAPE_ERROR_GENERAL) - return -EIO; - return (tape->tape_block_size * (blocks-rq.current_nr_sectors)); -} - -/* - * idetape_insert_pipeline_into_queue is used to start servicing the - * pipeline stages, starting from tape->next_stage. - */ -static void idetape_insert_pipeline_into_queue (ide_drive_t *drive) -{ - idetape_tape_t *tape = drive->driver_data; + rq = blk_get_request(drive->queue, READ, __GFP_WAIT); + rq->cmd_type = REQ_TYPE_SPECIAL; + rq->cmd[13] = cmd; + rq->rq_disk = tape->disk; + rq->__sector = tape->first_frame; - if (tape->next_stage == NULL) - return; - if (!idetape_pipeline_active(tape)) { - set_bit(IDETAPE_PIPELINE_ACTIVE, &tape->flags); - idetape_active_next_stage(drive); - (void) ide_do_drive_cmd(drive, tape->active_data_request, ide_end); + if (size) { + ret = blk_rq_map_kern(drive->queue, rq, tape->buf, size, + __GFP_WAIT); + if (ret) + goto out_put; } -} -static void idetape_create_inquiry_cmd (idetape_pc_t *pc) -{ - idetape_init_pc(pc); - pc->c[0] = IDETAPE_INQUIRY_CMD; - pc->c[4] = pc->request_transfer = 254; - pc->callback = &idetape_pc_callback; + blk_execute_rq(drive->queue, tape->disk, rq, 0); + + /* calculate the number of transferred bytes and update buffer state */ + size -= rq->resid_len; + tape->cur = tape->buf; + if (cmd == REQ_IDETAPE_READ) + tape->valid = size; + else + tape->valid = 0; + + ret = size; + if (rq->errors == IDE_DRV_ERROR_GENERAL) + ret = -EIO; +out_put: + blk_put_request(rq); + return ret; } -static void idetape_create_rewind_cmd (ide_drive_t *drive, idetape_pc_t *pc) +static void idetape_create_inquiry_cmd(struct ide_atapi_pc *pc) { - idetape_init_pc(pc); - pc->c[0] = IDETAPE_REWIND_CMD; - set_bit(PC_WAIT_FOR_DSC, &pc->flags); - pc->callback = &idetape_pc_callback; + ide_init_pc(pc); + pc->c[0] = INQUIRY; + pc->c[4] = 254; + pc->req_xfer = 254; } -#if 0 -static void idetape_create_mode_select_cmd (idetape_pc_t *pc, int length) +static void idetape_create_rewind_cmd(ide_drive_t *drive, + struct ide_atapi_pc *pc) { - idetape_init_pc(pc); - set_bit(PC_WRITING, &pc->flags); - pc->c[0] = IDETAPE_MODE_SELECT_CMD; - pc->c[1] = 0x10; - put_unaligned(htons(length), (unsigned short *) &pc->c[3]); - pc->request_transfer = 255; - pc->callback = &idetape_pc_callback; + ide_init_pc(pc); + pc->c[0] = REZERO_UNIT; + pc->flags |= PC_FLAG_WAIT_FOR_DSC; } -#endif -static void idetape_create_erase_cmd (idetape_pc_t *pc) +static void idetape_create_erase_cmd(struct ide_atapi_pc *pc) { - idetape_init_pc(pc); - pc->c[0] = IDETAPE_ERASE_CMD; + ide_init_pc(pc); + pc->c[0] = ERASE; pc->c[1] = 1; - set_bit(PC_WAIT_FOR_DSC, &pc->flags); - pc->callback = &idetape_pc_callback; + pc->flags |= PC_FLAG_WAIT_FOR_DSC; } -static void idetape_create_space_cmd (idetape_pc_t *pc,int count, u8 cmd) +static void idetape_create_space_cmd(struct ide_atapi_pc *pc, int count, u8 cmd) { - idetape_init_pc(pc); - pc->c[0] = IDETAPE_SPACE_CMD; - put_unaligned(htonl(count), (unsigned int *) &pc->c[1]); + ide_init_pc(pc); + pc->c[0] = SPACE; + put_unaligned(cpu_to_be32(count), (unsigned int *) &pc->c[1]); pc->c[1] = cmd; - set_bit(PC_WAIT_FOR_DSC, &pc->flags); - pc->callback = &idetape_pc_callback; + pc->flags |= PC_FLAG_WAIT_FOR_DSC; } -static void idetape_wait_first_stage (ide_drive_t *drive) +static void ide_tape_flush_merge_buffer(ide_drive_t *drive) { idetape_tape_t *tape = drive->driver_data; - unsigned long flags; - if (tape->first_stage == NULL) + if (tape->chrdev_dir != IDETAPE_DIR_WRITE) { + printk(KERN_ERR "ide-tape: bug: Trying to empty merge buffer" + " but we are not writing.\n"); return; - spin_lock_irqsave(&tape->spinlock, flags); - if (tape->active_stage == tape->first_stage) - idetape_wait_for_request(drive, tape->active_data_request); - spin_unlock_irqrestore(&tape->spinlock, flags); + } + if (tape->buf) { + size_t aligned = roundup(tape->valid, tape->blk_size); + + memset(tape->cur, 0, aligned - tape->valid); + idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE, aligned); + kfree(tape->buf); + tape->buf = NULL; + } + tape->chrdev_dir = IDETAPE_DIR_NONE; } -/* - * idetape_add_chrdev_write_request tries to add a character device - * originated write request to our pipeline. In case we don't succeed, - * we revert to non-pipelined operation mode for this request. - * - * 1. Try to allocate a new pipeline stage. - * 2. If we can't, wait for more and more requests to be serviced - * and try again each time. - * 3. If we still can't allocate a stage, fallback to - * non-pipelined operation mode for this request. - */ -static int idetape_add_chrdev_write_request (ide_drive_t *drive, int blocks) +static int idetape_init_rw(ide_drive_t *drive, int dir) { idetape_tape_t *tape = drive->driver_data; - idetape_stage_t *new_stage; - unsigned long flags; - struct request *rq; + int rc; -#if IDETAPE_DEBUG_LOG - if (tape->debug_level >= 3) - printk(KERN_INFO "ide-tape: Reached idetape_add_chrdev_write_request\n"); -#endif /* IDETAPE_DEBUG_LOG */ + BUG_ON(dir != IDETAPE_DIR_READ && dir != IDETAPE_DIR_WRITE); - /* - * Attempt to allocate a new stage. - * Pay special attention to possible race conditions. - */ - while ((new_stage = idetape_kmalloc_stage(tape)) == NULL) { - spin_lock_irqsave(&tape->spinlock, flags); - if (idetape_pipeline_active(tape)) { - idetape_wait_for_request(drive, tape->active_data_request); - spin_unlock_irqrestore(&tape->spinlock, flags); - } else { - spin_unlock_irqrestore(&tape->spinlock, flags); - idetape_insert_pipeline_into_queue(drive); - if (idetape_pipeline_active(tape)) - continue; - /* - * Linux is short on memory. Fallback to - * non-pipelined operation mode for this request. - */ - return idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE, blocks, tape->merge_stage->bh); - } - } - rq = &new_stage->rq; - idetape_init_rq(rq, REQ_IDETAPE_WRITE); - /* Doesn't actually matter - We always assume sequential access */ - rq->sector = tape->first_frame_position; - rq->nr_sectors = rq->current_nr_sectors = blocks; - - idetape_switch_buffers(tape, new_stage); - idetape_add_stage_tail(drive, new_stage); - tape->pipeline_head++; -#if USE_IOTRACE - IO_trace(IO_IDETAPE_FIFO, tape->pipeline_head, tape->buffer_head, tape->tape_head, tape->minor); -#endif - calculate_speeds(drive); + if (tape->chrdev_dir == dir) + return 0; - /* - * Estimate whether the tape has stopped writing by checking - * if our write pipeline is currently empty. If we are not - * writing anymore, wait for the pipeline to be full enough - * (90%) before starting to service requests, so that we will - * be able to keep up with the higher speeds of the tape. - */ - if (!idetape_pipeline_active(tape)) { - if (tape->nr_stages >= tape->max_stages * 9 / 10 || - tape->nr_stages >= tape->max_stages - tape->uncontrolled_pipeline_head_speed * 3 * 1024 / tape->tape_block_size) { - tape->measure_insert_time = 1; - tape->insert_time = jiffies; - tape->insert_size = 0; - tape->insert_speed = 0; - idetape_insert_pipeline_into_queue(drive); - } + if (tape->chrdev_dir == IDETAPE_DIR_READ) + ide_tape_discard_merge_buffer(drive, 1); + else if (tape->chrdev_dir == IDETAPE_DIR_WRITE) { + ide_tape_flush_merge_buffer(drive); + idetape_flush_tape_buffers(drive); } - if (test_and_clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags)) - /* Return a deferred error */ - return -EIO; - return blocks; -} -/* - * idetape_wait_for_pipeline will wait until all pending pipeline - * requests are serviced. Typically called on device close. - */ -static void idetape_wait_for_pipeline (ide_drive_t *drive) -{ - idetape_tape_t *tape = drive->driver_data; - unsigned long flags; - - while (tape->next_stage || idetape_pipeline_active(tape)) { - idetape_insert_pipeline_into_queue(drive); - spin_lock_irqsave(&tape->spinlock, flags); - if (idetape_pipeline_active(tape)) - idetape_wait_for_request(drive, tape->active_data_request); - spin_unlock_irqrestore(&tape->spinlock, flags); + if (tape->buf || tape->valid) { + printk(KERN_ERR "ide-tape: valid should be 0 now\n"); + tape->valid = 0; } -} -static void idetape_empty_write_pipeline (ide_drive_t *drive) -{ - idetape_tape_t *tape = drive->driver_data; - int blocks, min; - struct idetape_bh *bh; - -#if IDETAPE_DEBUG_BUGS - if (tape->chrdev_direction != idetape_direction_write) { - printk(KERN_ERR "ide-tape: bug: Trying to empty write pipeline, but we are not writing.\n"); - return; - } - if (tape->merge_stage_size > tape->stage_size) { - printk(KERN_ERR "ide-tape: bug: merge_buffer too big\n"); - tape->merge_stage_size = tape->stage_size; - } -#endif /* IDETAPE_DEBUG_BUGS */ - if (tape->merge_stage_size) { - blocks = tape->merge_stage_size / tape->tape_block_size; - if (tape->merge_stage_size % tape->tape_block_size) { - unsigned int i; - - blocks++; - i = tape->tape_block_size - tape->merge_stage_size % tape->tape_block_size; - bh = tape->bh->b_reqnext; - while (bh) { - atomic_set(&bh->b_count, 0); - bh = bh->b_reqnext; - } - bh = tape->bh; - while (i) { - if (bh == NULL) { - - printk(KERN_INFO "ide-tape: bug, bh NULL\n"); - break; - } - min = min(i, (unsigned int)(bh->b_size - atomic_read(&bh->b_count))); - memset(bh->b_data + atomic_read(&bh->b_count), 0, min); - atomic_add(min, &bh->b_count); - i -= min; - bh = bh->b_reqnext; - } - } - (void) idetape_add_chrdev_write_request(drive, blocks); - tape->merge_stage_size = 0; - } - idetape_wait_for_pipeline(drive); - if (tape->merge_stage != NULL) { - __idetape_kfree_stage(tape->merge_stage); - tape->merge_stage = NULL; - } - clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags); - tape->chrdev_direction = idetape_direction_none; + tape->buf = kmalloc(tape->buffer_size, GFP_KERNEL); + if (!tape->buf) + return -ENOMEM; + tape->chrdev_dir = dir; + tape->cur = tape->buf; /* - * On the next backup, perform the feedback loop again. - * (I don't want to keep sense information between backups, - * as some systems are constantly on, and the system load - * can be totally different on the next backup). + * Issue a 0 rw command to ensure that DSC handshake is + * switched from completion mode to buffer available mode. No + * point in issuing this if DSC overlap isn't supported, some + * drives (Seagate STT3401A) will return an error. */ - tape->max_stages = tape->min_pipeline; -#if IDETAPE_DEBUG_BUGS - if (tape->first_stage != NULL || - tape->next_stage != NULL || - tape->last_stage != NULL || - tape->nr_stages != 0) { - printk(KERN_ERR "ide-tape: ide-tape pipeline bug, " - "first_stage %p, next_stage %p, " - "last_stage %p, nr_stages %d\n", - tape->first_stage, tape->next_stage, - tape->last_stage, tape->nr_stages); - } -#endif /* IDETAPE_DEBUG_BUGS */ -} - -static void idetape_restart_speed_control (ide_drive_t *drive) -{ - idetape_tape_t *tape = drive->driver_data; - - tape->restart_speed_control_req = 0; - tape->pipeline_head = 0; - tape->controlled_last_pipeline_head = tape->uncontrolled_last_pipeline_head = 0; - tape->controlled_previous_pipeline_head = tape->uncontrolled_previous_pipeline_head = 0; - tape->pipeline_head_speed = tape->controlled_pipeline_head_speed = 5000; - tape->uncontrolled_pipeline_head_speed = 0; - tape->controlled_pipeline_head_time = tape->uncontrolled_pipeline_head_time = jiffies; - tape->controlled_previous_head_time = tape->uncontrolled_previous_head_time = jiffies; -} - -static int idetape_initiate_read (ide_drive_t *drive, int max_stages) -{ - idetape_tape_t *tape = drive->driver_data; - idetape_stage_t *new_stage; - struct request rq; - int bytes_read; - int blocks = tape->capabilities.ctl; - - /* Initialize read operation */ - if (tape->chrdev_direction != idetape_direction_read) { - if (tape->chrdev_direction == idetape_direction_write) { - idetape_empty_write_pipeline(drive); - idetape_flush_tape_buffers(drive); - } -#if IDETAPE_DEBUG_BUGS - if (tape->merge_stage || tape->merge_stage_size) { - printk (KERN_ERR "ide-tape: merge_stage_size should be 0 now\n"); - tape->merge_stage_size = 0; - } -#endif /* IDETAPE_DEBUG_BUGS */ - if ((tape->merge_stage = __idetape_kmalloc_stage(tape, 0, 0)) == NULL) - return -ENOMEM; - tape->chrdev_direction = idetape_direction_read; - - /* - * Issue a read 0 command to ensure that DSC handshake - * is switched from completion mode to buffer available - * mode. - * No point in issuing this if DSC overlap isn't supported, - * some drives (Seagate STT3401A) will return an error. - */ - if (drive->dsc_overlap) { - bytes_read = idetape_queue_rw_tail(drive, REQ_IDETAPE_READ, 0, tape->merge_stage->bh); - if (bytes_read < 0) { - __idetape_kfree_stage(tape->merge_stage); - tape->merge_stage = NULL; - tape->chrdev_direction = idetape_direction_none; - return bytes_read; - } - } - } - if (tape->restart_speed_control_req) - idetape_restart_speed_control(drive); - idetape_init_rq(&rq, REQ_IDETAPE_READ); - rq.sector = tape->first_frame_position; - rq.nr_sectors = rq.current_nr_sectors = blocks; - if (!test_bit(IDETAPE_PIPELINE_ERROR, &tape->flags) && - tape->nr_stages < max_stages) { - new_stage = idetape_kmalloc_stage(tape); - while (new_stage != NULL) { - new_stage->rq = rq; - idetape_add_stage_tail(drive, new_stage); - if (tape->nr_stages >= max_stages) - break; - new_stage = idetape_kmalloc_stage(tape); - } - } - if (!idetape_pipeline_active(tape)) { - if (tape->nr_pending_stages >= 3 * max_stages / 4) { - tape->measure_insert_time = 1; - tape->insert_time = jiffies; - tape->insert_size = 0; - tape->insert_speed = 0; - idetape_insert_pipeline_into_queue(drive); + if (drive->dev_flags & IDE_DFLAG_DSC_OVERLAP) { + int cmd = dir == IDETAPE_DIR_READ ? REQ_IDETAPE_READ + : REQ_IDETAPE_WRITE; + + rc = idetape_queue_rw_tail(drive, cmd, 0); + if (rc < 0) { + kfree(tape->buf); + tape->buf = NULL; + tape->chrdev_dir = IDETAPE_DIR_NONE; + return rc; } } + return 0; } -/* - * idetape_add_chrdev_read_request is called from idetape_chrdev_read - * to service a character device read request and add read-ahead - * requests to our pipeline. - */ -static int idetape_add_chrdev_read_request (ide_drive_t *drive,int blocks) +static void idetape_pad_zeros(ide_drive_t *drive, int bcount) { idetape_tape_t *tape = drive->driver_data; - unsigned long flags; - struct request *rq_ptr; - int bytes_read; - -#if IDETAPE_DEBUG_LOG - if (tape->debug_level >= 4) - printk(KERN_INFO "ide-tape: Reached idetape_add_chrdev_read_request, %d blocks\n", blocks); -#endif /* IDETAPE_DEBUG_LOG */ - - /* - * If we are at a filemark, return a read length of 0 - */ - if (test_bit(IDETAPE_FILEMARK, &tape->flags)) - return 0; - - /* - * Wait for the next block to be available at the head - * of the pipeline - */ - idetape_initiate_read(drive, tape->max_stages); - if (tape->first_stage == NULL) { - if (test_bit(IDETAPE_PIPELINE_ERROR, &tape->flags)) - return 0; - return idetape_queue_rw_tail(drive, REQ_IDETAPE_READ, blocks, tape->merge_stage->bh); - } - idetape_wait_first_stage(drive); - rq_ptr = &tape->first_stage->rq; - bytes_read = tape->tape_block_size * (rq_ptr->nr_sectors - rq_ptr->current_nr_sectors); - rq_ptr->nr_sectors = rq_ptr->current_nr_sectors = 0; + memset(tape->buf, 0, tape->buffer_size); - if (rq_ptr->errors == IDETAPE_ERROR_EOD) - return 0; - else { - idetape_switch_buffers(tape, tape->first_stage); - if (rq_ptr->errors == IDETAPE_ERROR_FILEMARK) - set_bit(IDETAPE_FILEMARK, &tape->flags); - spin_lock_irqsave(&tape->spinlock, flags); - idetape_remove_stage_head(drive); - spin_unlock_irqrestore(&tape->spinlock, flags); - tape->pipeline_head++; -#if USE_IOTRACE - IO_trace(IO_IDETAPE_FIFO, tape->pipeline_head, tape->buffer_head, tape->tape_head, tape->minor); -#endif - calculate_speeds(drive); - } -#if IDETAPE_DEBUG_BUGS - if (bytes_read > blocks * tape->tape_block_size) { - printk(KERN_ERR "ide-tape: bug: trying to return more bytes than requested\n"); - bytes_read = blocks * tape->tape_block_size; - } -#endif /* IDETAPE_DEBUG_BUGS */ - return (bytes_read); -} - -static void idetape_pad_zeros (ide_drive_t *drive, int bcount) -{ - idetape_tape_t *tape = drive->driver_data; - struct idetape_bh *bh; - int blocks; - while (bcount) { - unsigned int count; + unsigned int count = min(tape->buffer_size, bcount); - bh = tape->merge_stage->bh; - count = min(tape->stage_size, bcount); + idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE, count); bcount -= count; - blocks = count / tape->tape_block_size; - while (count) { - atomic_set(&bh->b_count, min(count, (unsigned int)bh->b_size)); - memset(bh->b_data, 0, atomic_read(&bh->b_count)); - count -= atomic_read(&bh->b_count); - bh = bh->b_reqnext; - } - idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE, blocks, tape->merge_stage->bh); - } -} - -static int idetape_pipeline_size (ide_drive_t *drive) -{ - idetape_tape_t *tape = drive->driver_data; - idetape_stage_t *stage; - struct request *rq; - int size = 0; - - idetape_wait_for_pipeline(drive); - stage = tape->first_stage; - while (stage != NULL) { - rq = &stage->rq; - size += tape->tape_block_size * (rq->nr_sectors-rq->current_nr_sectors); - if (rq->errors == IDETAPE_ERROR_FILEMARK) - size += tape->tape_block_size; - stage = stage->next; } - size += tape->merge_stage_size; - return size; } /* - * Rewinds the tape to the Beginning Of the current Partition (BOP). - * - * We currently support only one partition. - */ -static int idetape_rewind_tape (ide_drive_t *drive) + * Rewinds the tape to the Beginning Of the current Partition (BOP). We + * currently support only one partition. + */ +static int idetape_rewind_tape(ide_drive_t *drive) { - int retval; - idetape_pc_t pc; -#if IDETAPE_DEBUG_LOG - idetape_tape_t *tape = drive->driver_data; - if (tape->debug_level >= 2) - printk(KERN_INFO "ide-tape: Reached idetape_rewind_tape\n"); -#endif /* IDETAPE_DEBUG_LOG */ - + struct ide_tape_obj *tape = drive->driver_data; + struct gendisk *disk = tape->disk; + struct ide_atapi_pc pc; + int ret; + + ide_debug_log(IDE_DBG_FUNC, "enter"); + idetape_create_rewind_cmd(drive, &pc); - retval = idetape_queue_pc_tail(drive, &pc); - if (retval) - return retval; + ret = ide_queue_pc_tail(drive, disk, &pc, NULL, 0); + if (ret) + return ret; - idetape_create_read_position_cmd(&pc); - retval = idetape_queue_pc_tail(drive, &pc); - if (retval) - return retval; + ret = ide_tape_read_position(drive); + if (ret < 0) + return ret; return 0; } -/* - * Our special ide-tape ioctl's. - * - * Currently there aren't any ioctl's. - * mtio.h compatible commands should be issued to the character device - * interface. - */ -static int idetape_blkdev_ioctl(ide_drive_t *drive, unsigned int cmd, unsigned long arg) +/* mtio.h compatible commands should be issued to the chrdev interface. */ +static int idetape_blkdev_ioctl(ide_drive_t *drive, unsigned int cmd, + unsigned long arg) { idetape_tape_t *tape = drive->driver_data; - idetape_config_t config; void __user *argp = (void __user *)arg; -#if IDETAPE_DEBUG_LOG - if (tape->debug_level >= 4) - printk(KERN_INFO "ide-tape: Reached idetape_blkdev_ioctl\n"); -#endif /* IDETAPE_DEBUG_LOG */ + struct idetape_config { + int dsc_rw_frequency; + int dsc_media_access_frequency; + int nr_stages; + } config; + + ide_debug_log(IDE_DBG_FUNC, "cmd: 0x%04x", cmd); + switch (cmd) { - case 0x0340: - if (copy_from_user(&config, argp, sizeof (idetape_config_t))) - return -EFAULT; - tape->best_dsc_rw_frequency = config.dsc_rw_frequency; - tape->max_stages = config.nr_stages; - break; - case 0x0350: - config.dsc_rw_frequency = (int) tape->best_dsc_rw_frequency; - config.nr_stages = tape->max_stages; - if (copy_to_user(argp, &config, sizeof (idetape_config_t))) - return -EFAULT; - break; - default: - return -EIO; + case 0x0340: + if (copy_from_user(&config, argp, sizeof(config))) + return -EFAULT; + tape->best_dsc_rw_freq = config.dsc_rw_frequency; + break; + case 0x0350: + memset(&config, 0, sizeof(config)); + config.dsc_rw_frequency = (int) tape->best_dsc_rw_freq; + config.nr_stages = 1; + if (copy_to_user(argp, &config, sizeof(config))) + return -EFAULT; + break; + default: + return -EIO; } return 0; } -/* - * idetape_space_over_filemarks is now a bit more complicated than just - * passing the command to the tape since we may have crossed some - * filemarks during our pipelined read-ahead mode. - * - * As a minor side effect, the pipeline enables us to support MTFSFM when - * the filemark is in our internal pipeline even if the tape doesn't - * support spacing over filemarks in the reverse direction. - */ -static int idetape_space_over_filemarks (ide_drive_t *drive,short mt_op,int mt_count) +static int idetape_space_over_filemarks(ide_drive_t *drive, short mt_op, + int mt_count) { idetape_tape_t *tape = drive->driver_data; - idetape_pc_t pc; - unsigned long flags; - int retval,count=0; + struct gendisk *disk = tape->disk; + struct ide_atapi_pc pc; + int retval, count = 0; + int sprev = !!(tape->caps[4] & 0x20); + + + ide_debug_log(IDE_DBG_FUNC, "mt_op: %d, mt_count: %d", mt_op, mt_count); if (mt_count == 0) return 0; if (MTBSF == mt_op || MTBSFM == mt_op) { - if (!tape->capabilities.sprev) + if (!sprev) return -EIO; - mt_count = - mt_count; + mt_count = -mt_count; } - if (tape->chrdev_direction == idetape_direction_read) { - /* - * We have a read-ahead buffer. Scan it for crossed - * filemarks. - */ - tape->merge_stage_size = 0; - if (test_and_clear_bit(IDETAPE_FILEMARK, &tape->flags)) + if (tape->chrdev_dir == IDETAPE_DIR_READ) { + tape->valid = 0; + if (test_and_clear_bit(ilog2(IDE_AFLAG_FILEMARK), + &drive->atapi_flags)) ++count; - while (tape->first_stage != NULL) { - if (count == mt_count) { - if (mt_op == MTFSFM) - set_bit(IDETAPE_FILEMARK, &tape->flags); - return 0; - } - spin_lock_irqsave(&tape->spinlock, flags); - if (tape->first_stage == tape->active_stage) { - /* - * We have reached the active stage in the read pipeline. - * There is no point in allowing the drive to continue - * reading any farther, so we stop the pipeline. - * - * This section should be moved to a separate subroutine, - * because a similar function is performed in - * __idetape_discard_read_pipeline(), for example. - */ - tape->next_stage = NULL; - spin_unlock_irqrestore(&tape->spinlock, flags); - idetape_wait_first_stage(drive); - tape->next_stage = tape->first_stage->next; - } else - spin_unlock_irqrestore(&tape->spinlock, flags); - if (tape->first_stage->rq.errors == IDETAPE_ERROR_FILEMARK) - ++count; - idetape_remove_stage_head(drive); - } - idetape_discard_read_pipeline(drive, 0); + ide_tape_discard_merge_buffer(drive, 0); } - /* - * The filemark was not found in our internal pipeline. - * Now we can issue the space command. - */ switch (mt_op) { - case MTFSF: - case MTBSF: - idetape_create_space_cmd(&pc,mt_count-count,IDETAPE_SPACE_OVER_FILEMARK); - return (idetape_queue_pc_tail(drive, &pc)); - case MTFSFM: - case MTBSFM: - if (!tape->capabilities.sprev) - return (-EIO); - retval = idetape_space_over_filemarks(drive, MTFSF, mt_count-count); - if (retval) return (retval); - count = (MTBSFM == mt_op ? 1 : -1); - return (idetape_space_over_filemarks(drive, MTFSF, count)); - default: - printk(KERN_ERR "ide-tape: MTIO operation %d not supported\n",mt_op); - return (-EIO); + case MTFSF: + case MTBSF: + idetape_create_space_cmd(&pc, mt_count - count, + IDETAPE_SPACE_OVER_FILEMARK); + return ide_queue_pc_tail(drive, disk, &pc, NULL, 0); + case MTFSFM: + case MTBSFM: + if (!sprev) + return -EIO; + retval = idetape_space_over_filemarks(drive, MTFSF, + mt_count - count); + if (retval) + return retval; + count = (MTBSFM == mt_op ? 1 : -1); + return idetape_space_over_filemarks(drive, MTFSF, count); + default: + printk(KERN_ERR "ide-tape: MTIO operation %d not supported\n", + mt_op); + return -EIO; } } - /* - * Our character device read / write functions. + * Our character device read / write functions. * - * The tape is optimized to maximize throughput when it is transferring - * an integral number of the "continuous transfer limit", which is - * a parameter of the specific tape (26 KB on my particular tape). - * (32 kB for Onstream) + * The tape is optimized to maximize throughput when it is transferring an + * integral number of the "continuous transfer limit", which is a parameter of + * the specific tape (26kB on my particular tape, 32kB for Onstream). * - * As of version 1.3 of the driver, the character device provides an - * abstract continuous view of the media - any mix of block sizes (even 1 - * byte) on the same backup/restore procedure is supported. The driver - * will internally convert the requests to the recommended transfer unit, - * so that an unmatch between the user's block size to the recommended - * size will only result in a (slightly) increased driver overhead, but - * will no longer hit performance. - * This is not applicable to Onstream. + * As of version 1.3 of the driver, the character device provides an abstract + * continuous view of the media - any mix of block sizes (even 1 byte) on the + * same backup/restore procedure is supported. The driver will internally + * convert the requests to the recommended transfer unit, so that an unmatch + * between the user's block size to the recommended size will only result in a + * (slightly) increased driver overhead, but will no longer hit performance. + * This is not applicable to Onstream. */ -static ssize_t idetape_chrdev_read (struct file *file, char __user *buf, - size_t count, loff_t *ppos) +static ssize_t idetape_chrdev_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) { - struct ide_tape_obj *tape = ide_tape_f(file); + struct ide_tape_obj *tape = file->private_data; ide_drive_t *drive = tape->drive; - ssize_t bytes_read,temp, actually_read = 0, rc; + size_t done = 0; ssize_t ret = 0; + int rc; -#if IDETAPE_DEBUG_LOG - if (tape->debug_level >= 3) - printk(KERN_INFO "ide-tape: Reached idetape_chrdev_read, count %Zd\n", count); -#endif /* IDETAPE_DEBUG_LOG */ + ide_debug_log(IDE_DBG_FUNC, "count %Zd", count); - if (tape->chrdev_direction != idetape_direction_read) { - if (test_bit(IDETAPE_DETECT_BS, &tape->flags)) - if (count > tape->tape_block_size && - (count % tape->tape_block_size) == 0) - tape->user_bs_factor = count / tape->tape_block_size; + if (tape->chrdev_dir != IDETAPE_DIR_READ) { + if (test_bit(ilog2(IDE_AFLAG_DETECT_BS), &drive->atapi_flags)) + if (count > tape->blk_size && + (count % tape->blk_size) == 0) + tape->user_bs_factor = count / tape->blk_size; } - if ((rc = idetape_initiate_read(drive, tape->max_stages)) < 0) + + rc = idetape_init_rw(drive, IDETAPE_DIR_READ); + if (rc < 0) return rc; - if (count == 0) - return (0); - if (tape->merge_stage_size) { - actually_read = min((unsigned int)(tape->merge_stage_size), (unsigned int)count); - if (idetape_copy_stage_to_user(tape, buf, tape->merge_stage, actually_read)) - ret = -EFAULT; - buf += actually_read; - tape->merge_stage_size -= actually_read; - count -= actually_read; - } - while (count >= tape->stage_size) { - bytes_read = idetape_add_chrdev_read_request(drive, tape->capabilities.ctl); - if (bytes_read <= 0) - goto finish; - if (idetape_copy_stage_to_user(tape, buf, tape->merge_stage, bytes_read)) - ret = -EFAULT; - buf += bytes_read; - count -= bytes_read; - actually_read += bytes_read; - } - if (count) { - bytes_read = idetape_add_chrdev_read_request(drive, tape->capabilities.ctl); - if (bytes_read <= 0) - goto finish; - temp = min((unsigned long)count, (unsigned long)bytes_read); - if (idetape_copy_stage_to_user(tape, buf, tape->merge_stage, temp)) + + while (done < count) { + size_t todo; + + /* refill if staging buffer is empty */ + if (!tape->valid) { + /* If we are at a filemark, nothing more to read */ + if (test_bit(ilog2(IDE_AFLAG_FILEMARK), + &drive->atapi_flags)) + break; + /* read */ + if (idetape_queue_rw_tail(drive, REQ_IDETAPE_READ, + tape->buffer_size) <= 0) + break; + } + + /* copy out */ + todo = min_t(size_t, count - done, tape->valid); + if (copy_to_user(buf + done, tape->cur, todo)) ret = -EFAULT; - actually_read += temp; - tape->merge_stage_size = bytes_read-temp; + + tape->cur += todo; + tape->valid -= todo; + done += todo; } -finish: - if (!actually_read && test_bit(IDETAPE_FILEMARK, &tape->flags)) { -#if IDETAPE_DEBUG_LOG - if (tape->debug_level >= 2) - printk(KERN_INFO "ide-tape: %s: spacing over filemark\n", tape->name); -#endif + + if (!done && test_bit(ilog2(IDE_AFLAG_FILEMARK), &drive->atapi_flags)) { idetape_space_over_filemarks(drive, MTFSF, 1); return 0; } - return (ret) ? ret : actually_read; + return ret ? ret : done; } -static ssize_t idetape_chrdev_write (struct file *file, const char __user *buf, +static ssize_t idetape_chrdev_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { - struct ide_tape_obj *tape = ide_tape_f(file); + struct ide_tape_obj *tape = file->private_data; ide_drive_t *drive = tape->drive; - ssize_t actually_written = 0; + size_t done = 0; ssize_t ret = 0; + int rc; /* The drive is write protected. */ if (tape->write_prot) return -EACCES; -#if IDETAPE_DEBUG_LOG - if (tape->debug_level >= 3) - printk(KERN_INFO "ide-tape: Reached idetape_chrdev_write, " - "count %Zd\n", count); -#endif /* IDETAPE_DEBUG_LOG */ + ide_debug_log(IDE_DBG_FUNC, "count %Zd", count); /* Initialize write operation */ - if (tape->chrdev_direction != idetape_direction_write) { - if (tape->chrdev_direction == idetape_direction_read) - idetape_discard_read_pipeline(drive, 1); -#if IDETAPE_DEBUG_BUGS - if (tape->merge_stage || tape->merge_stage_size) { - printk(KERN_ERR "ide-tape: merge_stage_size " - "should be 0 now\n"); - tape->merge_stage_size = 0; - } -#endif /* IDETAPE_DEBUG_BUGS */ - if ((tape->merge_stage = __idetape_kmalloc_stage(tape, 0, 0)) == NULL) - return -ENOMEM; - tape->chrdev_direction = idetape_direction_write; - idetape_init_merge_stage(tape); + rc = idetape_init_rw(drive, IDETAPE_DIR_WRITE); + if (rc < 0) + return rc; - /* - * Issue a write 0 command to ensure that DSC handshake - * is switched from completion mode to buffer available - * mode. - * No point in issuing this if DSC overlap isn't supported, - * some drives (Seagate STT3401A) will return an error. - */ - if (drive->dsc_overlap) { - ssize_t retval = idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE, 0, tape->merge_stage->bh); - if (retval < 0) { - __idetape_kfree_stage(tape->merge_stage); - tape->merge_stage = NULL; - tape->chrdev_direction = idetape_direction_none; - return retval; - } - } - } - if (count == 0) - return (0); - if (tape->restart_speed_control_req) - idetape_restart_speed_control(drive); - if (tape->merge_stage_size) { -#if IDETAPE_DEBUG_BUGS - if (tape->merge_stage_size >= tape->stage_size) { - printk(KERN_ERR "ide-tape: bug: merge buffer too big\n"); - tape->merge_stage_size = 0; - } -#endif /* IDETAPE_DEBUG_BUGS */ - actually_written = min((unsigned int)(tape->stage_size - tape->merge_stage_size), (unsigned int)count); - if (idetape_copy_stage_from_user(tape, tape->merge_stage, buf, actually_written)) - ret = -EFAULT; - buf += actually_written; - tape->merge_stage_size += actually_written; - count -= actually_written; - - if (tape->merge_stage_size == tape->stage_size) { - ssize_t retval; - tape->merge_stage_size = 0; - retval = idetape_add_chrdev_write_request(drive, tape->capabilities.ctl); - if (retval <= 0) - return (retval); - } - } - while (count >= tape->stage_size) { - ssize_t retval; - if (idetape_copy_stage_from_user(tape, tape->merge_stage, buf, tape->stage_size)) - ret = -EFAULT; - buf += tape->stage_size; - count -= tape->stage_size; - retval = idetape_add_chrdev_write_request(drive, tape->capabilities.ctl); - actually_written += tape->stage_size; - if (retval <= 0) - return (retval); - } - if (count) { - actually_written += count; - if (idetape_copy_stage_from_user(tape, tape->merge_stage, buf, count)) + while (done < count) { + size_t todo; + + /* flush if staging buffer is full */ + if (tape->valid == tape->buffer_size && + idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE, + tape->buffer_size) <= 0) + return rc; + + /* copy in */ + todo = min_t(size_t, count - done, + tape->buffer_size - tape->valid); + if (copy_from_user(tape->cur, buf + done, todo)) ret = -EFAULT; - tape->merge_stage_size += count; + + tape->cur += todo; + tape->valid += todo; + done += todo; } - return (ret) ? ret : actually_written; + + return ret ? ret : done; } -static int idetape_write_filemark (ide_drive_t *drive) +static int idetape_write_filemark(ide_drive_t *drive) { - idetape_pc_t pc; + struct ide_tape_obj *tape = drive->driver_data; + struct ide_atapi_pc pc; /* Write a filemark */ idetape_create_write_filemark_cmd(drive, &pc, 1); - if (idetape_queue_pc_tail(drive, &pc)) { + if (ide_queue_pc_tail(drive, tape->disk, &pc, NULL, 0)) { printk(KERN_ERR "ide-tape: Couldn't write a filemark\n"); return -EIO; } @@ -3892,314 +1237,277 @@ static int idetape_write_filemark (ide_drive_t *drive) } /* - * idetape_mtioctop is called from idetape_chrdev_ioctl when - * the general mtio MTIOCTOP ioctl is requested. - * - * We currently support the following mtio.h operations: + * Called from idetape_chrdev_ioctl when the general mtio MTIOCTOP ioctl is + * requested. * - * MTFSF - Space over mt_count filemarks in the positive direction. - * The tape is positioned after the last spaced filemark. + * Note: MTBSF and MTBSFM are not supported when the tape doesn't support + * spacing over filemarks in the reverse direction. In this case, MTFSFM is also + * usually not supported. * - * MTFSFM - Same as MTFSF, but the tape is positioned before the - * last filemark. + * The following commands are currently not supported: * - * MTBSF - Steps background over mt_count filemarks, tape is - * positioned before the last filemark. - * - * MTBSFM - Like MTBSF, only tape is positioned after the last filemark. - * - * Note: - * - * MTBSF and MTBSFM are not supported when the tape doesn't - * support spacing over filemarks in the reverse direction. - * In this case, MTFSFM is also usually not supported (it is - * supported in the rare case in which we crossed the filemark - * during our read-ahead pipelined operation mode). - * - * MTWEOF - Writes mt_count filemarks. Tape is positioned after - * the last written filemark. - * - * MTREW - Rewinds tape. - * - * MTLOAD - Loads the tape. - * - * MTOFFL - Puts the tape drive "Offline": Rewinds the tape and - * MTUNLOAD prevents further access until the media is replaced. - * - * MTNOP - Flushes tape buffers. - * - * MTRETEN - Retension media. This typically consists of one end - * to end pass on the media. - * - * MTEOM - Moves to the end of recorded data. - * - * MTERASE - Erases tape. - * - * MTSETBLK - Sets the user block size to mt_count bytes. If - * mt_count is 0, we will attempt to autodetect - * the block size. - * - * MTSEEK - Positions the tape in a specific block number, where - * each block is assumed to contain which user_block_size - * bytes. - * - * MTSETPART - Switches to another tape partition. - * - * MTLOCK - Locks the tape door. - * - * MTUNLOCK - Unlocks the tape door. - * - * The following commands are currently not supported: - * - * MTFSS, MTBSS, MTWSM, MTSETDENSITY, - * MTSETDRVBUFFER, MT_ST_BOOLEANS, MT_ST_WRITE_THRESHOLD. + * MTFSS, MTBSS, MTWSM, MTSETDENSITY, MTSETDRVBUFFER, MT_ST_BOOLEANS, + * MT_ST_WRITE_THRESHOLD. */ -static int idetape_mtioctop (ide_drive_t *drive,short mt_op,int mt_count) +static int idetape_mtioctop(ide_drive_t *drive, short mt_op, int mt_count) { idetape_tape_t *tape = drive->driver_data; - idetape_pc_t pc; - int i,retval; - -#if IDETAPE_DEBUG_LOG - if (tape->debug_level >= 1) - printk(KERN_INFO "ide-tape: Handling MTIOCTOP ioctl: " - "mt_op=%d, mt_count=%d\n", mt_op, mt_count); -#endif /* IDETAPE_DEBUG_LOG */ - /* - * Commands which need our pipelined read-ahead stages. - */ + struct gendisk *disk = tape->disk; + struct ide_atapi_pc pc; + int i, retval; + + ide_debug_log(IDE_DBG_FUNC, "MTIOCTOP ioctl: mt_op: %d, mt_count: %d", + mt_op, mt_count); + switch (mt_op) { - case MTFSF: - case MTFSFM: - case MTBSF: - case MTBSFM: - if (!mt_count) - return (0); - return (idetape_space_over_filemarks(drive,mt_op,mt_count)); - default: - break; + case MTFSF: + case MTFSFM: + case MTBSF: + case MTBSFM: + if (!mt_count) + return 0; + return idetape_space_over_filemarks(drive, mt_op, mt_count); + default: + break; } + switch (mt_op) { - case MTWEOF: - if (tape->write_prot) - return -EACCES; - idetape_discard_read_pipeline(drive, 1); - for (i = 0; i < mt_count; i++) { - retval = idetape_write_filemark(drive); - if (retval) - return retval; - } - return (0); - case MTREW: - idetape_discard_read_pipeline(drive, 0); - if (idetape_rewind_tape(drive)) + case MTWEOF: + if (tape->write_prot) + return -EACCES; + ide_tape_discard_merge_buffer(drive, 1); + for (i = 0; i < mt_count; i++) { + retval = idetape_write_filemark(drive); + if (retval) + return retval; + } + return 0; + case MTREW: + ide_tape_discard_merge_buffer(drive, 0); + if (idetape_rewind_tape(drive)) + return -EIO; + return 0; + case MTLOAD: + ide_tape_discard_merge_buffer(drive, 0); + return ide_do_start_stop(drive, disk, IDETAPE_LU_LOAD_MASK); + case MTUNLOAD: + case MTOFFL: + /* + * If door is locked, attempt to unlock before + * attempting to eject. + */ + if (tape->door_locked) { + if (!ide_set_media_lock(drive, disk, 0)) + tape->door_locked = DOOR_UNLOCKED; + } + ide_tape_discard_merge_buffer(drive, 0); + retval = ide_do_start_stop(drive, disk, !IDETAPE_LU_LOAD_MASK); + if (!retval) + clear_bit(ilog2(IDE_AFLAG_MEDIUM_PRESENT), + &drive->atapi_flags); + return retval; + case MTNOP: + ide_tape_discard_merge_buffer(drive, 0); + return idetape_flush_tape_buffers(drive); + case MTRETEN: + ide_tape_discard_merge_buffer(drive, 0); + return ide_do_start_stop(drive, disk, + IDETAPE_LU_RETENSION_MASK | IDETAPE_LU_LOAD_MASK); + case MTEOM: + idetape_create_space_cmd(&pc, 0, IDETAPE_SPACE_TO_EOD); + return ide_queue_pc_tail(drive, disk, &pc, NULL, 0); + case MTERASE: + (void)idetape_rewind_tape(drive); + idetape_create_erase_cmd(&pc); + return ide_queue_pc_tail(drive, disk, &pc, NULL, 0); + case MTSETBLK: + if (mt_count) { + if (mt_count < tape->blk_size || + mt_count % tape->blk_size) return -EIO; - return 0; - case MTLOAD: - idetape_discard_read_pipeline(drive, 0); - idetape_create_load_unload_cmd(drive, &pc, IDETAPE_LU_LOAD_MASK); - return (idetape_queue_pc_tail(drive, &pc)); - case MTUNLOAD: - case MTOFFL: - /* - * If door is locked, attempt to unlock before - * attempting to eject. - */ - if (tape->door_locked) { - if (idetape_create_prevent_cmd(drive, &pc, 0)) - if (!idetape_queue_pc_tail(drive, &pc)) - tape->door_locked = DOOR_UNLOCKED; - } - idetape_discard_read_pipeline(drive, 0); - idetape_create_load_unload_cmd(drive, &pc,!IDETAPE_LU_LOAD_MASK); - retval = idetape_queue_pc_tail(drive, &pc); - if (!retval) - clear_bit(IDETAPE_MEDIUM_PRESENT, &tape->flags); + tape->user_bs_factor = mt_count / tape->blk_size; + clear_bit(ilog2(IDE_AFLAG_DETECT_BS), + &drive->atapi_flags); + } else + set_bit(ilog2(IDE_AFLAG_DETECT_BS), + &drive->atapi_flags); + return 0; + case MTSEEK: + ide_tape_discard_merge_buffer(drive, 0); + return idetape_position_tape(drive, + mt_count * tape->user_bs_factor, tape->partition, 0); + case MTSETPART: + ide_tape_discard_merge_buffer(drive, 0); + return idetape_position_tape(drive, 0, mt_count, 0); + case MTFSR: + case MTBSR: + case MTLOCK: + retval = ide_set_media_lock(drive, disk, 1); + if (retval) return retval; - case MTNOP: - idetape_discard_read_pipeline(drive, 0); - return (idetape_flush_tape_buffers(drive)); - case MTRETEN: - idetape_discard_read_pipeline(drive, 0); - idetape_create_load_unload_cmd(drive, &pc,IDETAPE_LU_RETENSION_MASK | IDETAPE_LU_LOAD_MASK); - return (idetape_queue_pc_tail(drive, &pc)); - case MTEOM: - idetape_create_space_cmd(&pc, 0, IDETAPE_SPACE_TO_EOD); - return (idetape_queue_pc_tail(drive, &pc)); - case MTERASE: - (void) idetape_rewind_tape(drive); - idetape_create_erase_cmd(&pc); - return (idetape_queue_pc_tail(drive, &pc)); - case MTSETBLK: - if (mt_count) { - if (mt_count < tape->tape_block_size || mt_count % tape->tape_block_size) - return -EIO; - tape->user_bs_factor = mt_count / tape->tape_block_size; - clear_bit(IDETAPE_DETECT_BS, &tape->flags); - } else - set_bit(IDETAPE_DETECT_BS, &tape->flags); - return 0; - case MTSEEK: - idetape_discard_read_pipeline(drive, 0); - return idetape_position_tape(drive, mt_count * tape->user_bs_factor, tape->partition, 0); - case MTSETPART: - idetape_discard_read_pipeline(drive, 0); - return (idetape_position_tape(drive, 0, mt_count, 0)); - case MTFSR: - case MTBSR: - case MTLOCK: - if (!idetape_create_prevent_cmd(drive, &pc, 1)) - return 0; - retval = idetape_queue_pc_tail(drive, &pc); - if (retval) return retval; - tape->door_locked = DOOR_EXPLICITLY_LOCKED; - return 0; - case MTUNLOCK: - if (!idetape_create_prevent_cmd(drive, &pc, 0)) - return 0; - retval = idetape_queue_pc_tail(drive, &pc); - if (retval) return retval; - tape->door_locked = DOOR_UNLOCKED; - return 0; - default: - printk(KERN_ERR "ide-tape: MTIO operation %d not " - "supported\n", mt_op); - return (-EIO); + tape->door_locked = DOOR_EXPLICITLY_LOCKED; + return 0; + case MTUNLOCK: + retval = ide_set_media_lock(drive, disk, 0); + if (retval) + return retval; + tape->door_locked = DOOR_UNLOCKED; + return 0; + default: + printk(KERN_ERR "ide-tape: MTIO operation %d not supported\n", + mt_op); + return -EIO; } } /* - * Our character device ioctls. - * - * General mtio.h magnetic io commands are supported here, and not in - * the corresponding block interface. - * - * The following ioctls are supported: - * - * MTIOCTOP - Refer to idetape_mtioctop for detailed description. - * - * MTIOCGET - The mt_dsreg field in the returned mtget structure - * will be set to (user block size in bytes << - * MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK. - * - * The mt_blkno is set to the current user block number. - * The other mtget fields are not supported. - * - * MTIOCPOS - The current tape "block position" is returned. We - * assume that each block contains user_block_size - * bytes. - * - * Our own ide-tape ioctls are supported on both interfaces. + * Our character device ioctls. General mtio.h magnetic io commands are + * supported here, and not in the corresponding block interface. Our own + * ide-tape ioctls are supported on both interfaces. */ -static int idetape_chrdev_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +static long do_idetape_chrdev_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) { - struct ide_tape_obj *tape = ide_tape_f(file); + struct ide_tape_obj *tape = file->private_data; ide_drive_t *drive = tape->drive; struct mtop mtop; struct mtget mtget; struct mtpos mtpos; - int block_offset = 0, position = tape->first_frame_position; + int block_offset = 0, position = tape->first_frame; void __user *argp = (void __user *)arg; -#if IDETAPE_DEBUG_LOG - if (tape->debug_level >= 3) - printk(KERN_INFO "ide-tape: Reached idetape_chrdev_ioctl, " - "cmd=%u\n", cmd); -#endif /* IDETAPE_DEBUG_LOG */ + ide_debug_log(IDE_DBG_FUNC, "cmd: 0x%x", cmd); - tape->restart_speed_control_req = 1; - if (tape->chrdev_direction == idetape_direction_write) { - idetape_empty_write_pipeline(drive); + if (tape->chrdev_dir == IDETAPE_DIR_WRITE) { + ide_tape_flush_merge_buffer(drive); idetape_flush_tape_buffers(drive); } if (cmd == MTIOCGET || cmd == MTIOCPOS) { - block_offset = idetape_pipeline_size(drive) / (tape->tape_block_size * tape->user_bs_factor); - if ((position = idetape_read_position(drive)) < 0) + block_offset = tape->valid / + (tape->blk_size * tape->user_bs_factor); + position = ide_tape_read_position(drive); + if (position < 0) return -EIO; } switch (cmd) { - case MTIOCTOP: - if (copy_from_user(&mtop, argp, sizeof (struct mtop))) - return -EFAULT; - return (idetape_mtioctop(drive,mtop.mt_op,mtop.mt_count)); - case MTIOCGET: - memset(&mtget, 0, sizeof (struct mtget)); - mtget.mt_type = MT_ISSCSI2; - mtget.mt_blkno = position / tape->user_bs_factor - block_offset; - mtget.mt_dsreg = ((tape->tape_block_size * tape->user_bs_factor) << MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK; - if (tape->drv_write_prot) { - mtget.mt_gstat |= GMT_WR_PROT(0xffffffff); - } - if (copy_to_user(argp, &mtget, sizeof(struct mtget))) - return -EFAULT; - return 0; - case MTIOCPOS: - mtpos.mt_blkno = position / tape->user_bs_factor - block_offset; - if (copy_to_user(argp, &mtpos, sizeof(struct mtpos))) - return -EFAULT; - return 0; - default: - if (tape->chrdev_direction == idetape_direction_read) - idetape_discard_read_pipeline(drive, 1); - return idetape_blkdev_ioctl(drive, cmd, arg); + case MTIOCTOP: + if (copy_from_user(&mtop, argp, sizeof(struct mtop))) + return -EFAULT; + return idetape_mtioctop(drive, mtop.mt_op, mtop.mt_count); + case MTIOCGET: + memset(&mtget, 0, sizeof(struct mtget)); + mtget.mt_type = MT_ISSCSI2; + mtget.mt_blkno = position / tape->user_bs_factor - block_offset; + mtget.mt_dsreg = + ((tape->blk_size * tape->user_bs_factor) + << MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK; + + if (tape->drv_write_prot) + mtget.mt_gstat |= GMT_WR_PROT(0xffffffff); + + if (copy_to_user(argp, &mtget, sizeof(struct mtget))) + return -EFAULT; + return 0; + case MTIOCPOS: + mtpos.mt_blkno = position / tape->user_bs_factor - block_offset; + if (copy_to_user(argp, &mtpos, sizeof(struct mtpos))) + return -EFAULT; + return 0; + default: + if (tape->chrdev_dir == IDETAPE_DIR_READ) + ide_tape_discard_merge_buffer(drive, 1); + return idetape_blkdev_ioctl(drive, cmd, arg); } } -static void idetape_get_blocksize_from_block_descriptor(ide_drive_t *drive); +static long idetape_chrdev_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + long ret; + mutex_lock(&ide_tape_mutex); + ret = do_idetape_chrdev_ioctl(file, cmd, arg); + mutex_unlock(&ide_tape_mutex); + return ret; +} /* - * Our character device open function. + * Do a mode sense page 0 with block descriptor and if it succeeds set the tape + * block size with the reported value. */ -static int idetape_chrdev_open (struct inode *inode, struct file *filp) +static void ide_tape_get_bsize_from_bdesc(ide_drive_t *drive) +{ + idetape_tape_t *tape = drive->driver_data; + struct ide_atapi_pc pc; + u8 buf[12]; + + idetape_create_mode_sense_cmd(&pc, IDETAPE_BLOCK_DESCRIPTOR); + if (ide_queue_pc_tail(drive, tape->disk, &pc, buf, pc.req_xfer)) { + printk(KERN_ERR "ide-tape: Can't get block descriptor\n"); + if (tape->blk_size == 0) { + printk(KERN_WARNING "ide-tape: Cannot deal with zero " + "block size, assuming 32k\n"); + tape->blk_size = 32768; + } + return; + } + tape->blk_size = (buf[4 + 5] << 16) + + (buf[4 + 6] << 8) + + buf[4 + 7]; + tape->drv_write_prot = (buf[2] & 0x80) >> 7; + + ide_debug_log(IDE_DBG_FUNC, "blk_size: %d, write_prot: %d", + tape->blk_size, tape->drv_write_prot); +} + +static int idetape_chrdev_open(struct inode *inode, struct file *filp) { unsigned int minor = iminor(inode), i = minor & ~0xc0; ide_drive_t *drive; idetape_tape_t *tape; - idetape_pc_t pc; int retval; - /* - * We really want to do nonseekable_open(inode, filp); here, but some - * versions of tar incorrectly call lseek on tapes and bail out if that - * fails. So we disallow pread() and pwrite(), but permit lseeks. - */ - filp->f_mode &= ~(FMODE_PREAD | FMODE_PWRITE); - -#if IDETAPE_DEBUG_LOG - printk(KERN_INFO "ide-tape: Reached idetape_chrdev_open\n"); -#endif /* IDETAPE_DEBUG_LOG */ - if (i >= MAX_HWIFS * MAX_DRIVES) return -ENXIO; - if (!(tape = ide_tape_chrdev_get(i))) + mutex_lock(&idetape_chrdev_mutex); + + tape = ide_tape_get(NULL, true, i); + if (!tape) { + mutex_unlock(&idetape_chrdev_mutex); return -ENXIO; + } drive = tape->drive; - filp->private_data = tape; - if (test_and_set_bit(IDETAPE_BUSY, &tape->flags)) { + ide_debug_log(IDE_DBG_FUNC, "enter"); + + /* + * We really want to do nonseekable_open(inode, filp); here, but some + * versions of tar incorrectly call lseek on tapes and bail out if that + * fails. So we disallow pread() and pwrite(), but permit lseeks. + */ + filp->f_mode &= ~(FMODE_PREAD | FMODE_PWRITE); + + + if (test_and_set_bit(ilog2(IDE_AFLAG_BUSY), &drive->atapi_flags)) { retval = -EBUSY; goto out_put_tape; } retval = idetape_wait_ready(drive, 60 * HZ); if (retval) { - clear_bit(IDETAPE_BUSY, &tape->flags); + clear_bit(ilog2(IDE_AFLAG_BUSY), &drive->atapi_flags); printk(KERN_ERR "ide-tape: %s: drive not ready\n", tape->name); goto out_put_tape; } - idetape_read_position(drive); - if (!test_bit(IDETAPE_ADDRESS_VALID, &tape->flags)) + ide_tape_read_position(drive); + if (!test_bit(ilog2(IDE_AFLAG_ADDRESS_VALID), &drive->atapi_flags)) (void)idetape_rewind_tape(drive); - if (tape->chrdev_direction != idetape_direction_read) - clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags); - /* Read block size and write protect status from drive. */ - idetape_get_blocksize_from_block_descriptor(drive); + ide_tape_get_bsize_from_bdesc(drive); /* Set write protect flag if device is opened as read-only. */ if ((filp->f_flags & O_ACCMODE) == O_RDONLY) @@ -4211,518 +1519,315 @@ static int idetape_chrdev_open (struct inode *inode, struct file *filp) if (tape->write_prot) { if ((filp->f_flags & O_ACCMODE) == O_WRONLY || (filp->f_flags & O_ACCMODE) == O_RDWR) { - clear_bit(IDETAPE_BUSY, &tape->flags); + clear_bit(ilog2(IDE_AFLAG_BUSY), &drive->atapi_flags); retval = -EROFS; goto out_put_tape; } } - /* - * Lock the tape drive door so user can't eject. - */ - if (tape->chrdev_direction == idetape_direction_none) { - if (idetape_create_prevent_cmd(drive, &pc, 1)) { - if (!idetape_queue_pc_tail(drive, &pc)) { - if (tape->door_locked != DOOR_EXPLICITLY_LOCKED) - tape->door_locked = DOOR_LOCKED; - } + /* Lock the tape drive door so user can't eject. */ + if (tape->chrdev_dir == IDETAPE_DIR_NONE) { + if (!ide_set_media_lock(drive, tape->disk, 1)) { + if (tape->door_locked != DOOR_EXPLICITLY_LOCKED) + tape->door_locked = DOOR_LOCKED; } } - idetape_restart_speed_control(drive); - tape->restart_speed_control_req = 0; + mutex_unlock(&idetape_chrdev_mutex); + return 0; out_put_tape: ide_tape_put(tape); + + mutex_unlock(&idetape_chrdev_mutex); + return retval; } -static void idetape_write_release (ide_drive_t *drive, unsigned int minor) +static void idetape_write_release(ide_drive_t *drive, unsigned int minor) { idetape_tape_t *tape = drive->driver_data; - idetape_empty_write_pipeline(drive); - tape->merge_stage = __idetape_kmalloc_stage(tape, 1, 0); - if (tape->merge_stage != NULL) { - idetape_pad_zeros(drive, tape->tape_block_size * (tape->user_bs_factor - 1)); - __idetape_kfree_stage(tape->merge_stage); - tape->merge_stage = NULL; + ide_tape_flush_merge_buffer(drive); + tape->buf = kmalloc(tape->buffer_size, GFP_KERNEL); + if (tape->buf != NULL) { + idetape_pad_zeros(drive, tape->blk_size * + (tape->user_bs_factor - 1)); + kfree(tape->buf); + tape->buf = NULL; } idetape_write_filemark(drive); idetape_flush_tape_buffers(drive); idetape_flush_tape_buffers(drive); } -/* - * Our character device release function. - */ -static int idetape_chrdev_release (struct inode *inode, struct file *filp) +static int idetape_chrdev_release(struct inode *inode, struct file *filp) { - struct ide_tape_obj *tape = ide_tape_f(filp); + struct ide_tape_obj *tape = filp->private_data; ide_drive_t *drive = tape->drive; - idetape_pc_t pc; unsigned int minor = iminor(inode); - lock_kernel(); + mutex_lock(&idetape_chrdev_mutex); + tape = drive->driver_data; -#if IDETAPE_DEBUG_LOG - if (tape->debug_level >= 3) - printk(KERN_INFO "ide-tape: Reached idetape_chrdev_release\n"); -#endif /* IDETAPE_DEBUG_LOG */ - if (tape->chrdev_direction == idetape_direction_write) + ide_debug_log(IDE_DBG_FUNC, "enter"); + + if (tape->chrdev_dir == IDETAPE_DIR_WRITE) idetape_write_release(drive, minor); - if (tape->chrdev_direction == idetape_direction_read) { + if (tape->chrdev_dir == IDETAPE_DIR_READ) { if (minor < 128) - idetape_discard_read_pipeline(drive, 1); - else - idetape_wait_for_pipeline(drive); - } - if (tape->cache_stage != NULL) { - __idetape_kfree_stage(tape->cache_stage); - tape->cache_stage = NULL; + ide_tape_discard_merge_buffer(drive, 1); } - if (minor < 128 && test_bit(IDETAPE_MEDIUM_PRESENT, &tape->flags)) + + if (minor < 128 && test_bit(ilog2(IDE_AFLAG_MEDIUM_PRESENT), + &drive->atapi_flags)) (void) idetape_rewind_tape(drive); - if (tape->chrdev_direction == idetape_direction_none) { + + if (tape->chrdev_dir == IDETAPE_DIR_NONE) { if (tape->door_locked == DOOR_LOCKED) { - if (idetape_create_prevent_cmd(drive, &pc, 0)) { - if (!idetape_queue_pc_tail(drive, &pc)) - tape->door_locked = DOOR_UNLOCKED; - } + if (!ide_set_media_lock(drive, tape->disk, 0)) + tape->door_locked = DOOR_UNLOCKED; } } - clear_bit(IDETAPE_BUSY, &tape->flags); + clear_bit(ilog2(IDE_AFLAG_BUSY), &drive->atapi_flags); ide_tape_put(tape); - unlock_kernel(); - return 0; -} - -/* - * idetape_identify_device is called to check the contents of the - * ATAPI IDENTIFY command results. We return: - * - * 1 If the tape can be supported by us, based on the information - * we have so far. - * - * 0 If this tape driver is not currently supported by us. - */ -static int idetape_identify_device (ide_drive_t *drive) -{ - struct idetape_id_gcw gcw; - struct hd_driveid *id = drive->id; -#if IDETAPE_DEBUG_INFO - unsigned short mask,i; -#endif /* IDETAPE_DEBUG_INFO */ - - if (drive->id_read == 0) - return 1; - - *((unsigned short *) &gcw) = id->config; - -#if IDETAPE_DEBUG_INFO - printk(KERN_INFO "ide-tape: Dumping ATAPI Identify Device tape parameters\n"); - printk(KERN_INFO "ide-tape: Protocol Type: "); - switch (gcw.protocol) { - case 0: case 1: printk("ATA\n");break; - case 2: printk("ATAPI\n");break; - case 3: printk("Reserved (Unknown to ide-tape)\n");break; - } - printk(KERN_INFO "ide-tape: Device Type: %x - ",gcw.device_type); - switch (gcw.device_type) { - case 0: printk("Direct-access Device\n");break; - case 1: printk("Streaming Tape Device\n");break; - case 2: case 3: case 4: printk("Reserved\n");break; - case 5: printk("CD-ROM Device\n");break; - case 6: printk("Reserved\n"); - case 7: printk("Optical memory Device\n");break; - case 0x1f: printk("Unknown or no Device type\n");break; - default: printk("Reserved\n"); - } - printk(KERN_INFO "ide-tape: Removable: %s",gcw.removable ? "Yes\n":"No\n"); - printk(KERN_INFO "ide-tape: Command Packet DRQ Type: "); - switch (gcw.drq_type) { - case 0: printk("Microprocessor DRQ\n");break; - case 1: printk("Interrupt DRQ\n");break; - case 2: printk("Accelerated DRQ\n");break; - case 3: printk("Reserved\n");break; - } - printk(KERN_INFO "ide-tape: Command Packet Size: "); - switch (gcw.packet_size) { - case 0: printk("12 bytes\n");break; - case 1: printk("16 bytes\n");break; - default: printk("Reserved\n");break; - } - printk(KERN_INFO "ide-tape: Model: %.40s\n",id->model); - printk(KERN_INFO "ide-tape: Firmware Revision: %.8s\n",id->fw_rev); - printk(KERN_INFO "ide-tape: Serial Number: %.20s\n",id->serial_no); - printk(KERN_INFO "ide-tape: Write buffer size: %d bytes\n",id->buf_size*512); - printk(KERN_INFO "ide-tape: DMA: %s",id->capability & 0x01 ? "Yes\n":"No\n"); - printk(KERN_INFO "ide-tape: LBA: %s",id->capability & 0x02 ? "Yes\n":"No\n"); - printk(KERN_INFO "ide-tape: IORDY can be disabled: %s",id->capability & 0x04 ? "Yes\n":"No\n"); - printk(KERN_INFO "ide-tape: IORDY supported: %s",id->capability & 0x08 ? "Yes\n":"Unknown\n"); - printk(KERN_INFO "ide-tape: ATAPI overlap supported: %s",id->capability & 0x20 ? "Yes\n":"No\n"); - printk(KERN_INFO "ide-tape: PIO Cycle Timing Category: %d\n",id->tPIO); - printk(KERN_INFO "ide-tape: DMA Cycle Timing Category: %d\n",id->tDMA); - printk(KERN_INFO "ide-tape: Single Word DMA supported modes: "); - for (i=0,mask=1;i<8;i++,mask=mask << 1) { - if (id->dma_1word & mask) - printk("%d ",i); - if (id->dma_1word & (mask << 8)) - printk("(active) "); - } - printk("\n"); - printk(KERN_INFO "ide-tape: Multi Word DMA supported modes: "); - for (i=0,mask=1;i<8;i++,mask=mask << 1) { - if (id->dma_mword & mask) - printk("%d ",i); - if (id->dma_mword & (mask << 8)) - printk("(active) "); - } - printk("\n"); - if (id->field_valid & 0x0002) { - printk(KERN_INFO "ide-tape: Enhanced PIO Modes: %s\n", - id->eide_pio_modes & 1 ? "Mode 3":"None"); - printk(KERN_INFO "ide-tape: Minimum Multi-word DMA cycle per word: "); - if (id->eide_dma_min == 0) - printk("Not supported\n"); - else - printk("%d ns\n",id->eide_dma_min); - - printk(KERN_INFO "ide-tape: Manufacturer\'s Recommended Multi-word cycle: "); - if (id->eide_dma_time == 0) - printk("Not supported\n"); - else - printk("%d ns\n",id->eide_dma_time); - printk(KERN_INFO "ide-tape: Minimum PIO cycle without IORDY: "); - if (id->eide_pio == 0) - printk("Not supported\n"); - else - printk("%d ns\n",id->eide_pio); + mutex_unlock(&idetape_chrdev_mutex); - printk(KERN_INFO "ide-tape: Minimum PIO cycle with IORDY: "); - if (id->eide_pio_iordy == 0) - printk("Not supported\n"); - else - printk("%d ns\n",id->eide_pio_iordy); - - } else - printk(KERN_INFO "ide-tape: According to the device, fields 64-70 are not valid.\n"); -#endif /* IDETAPE_DEBUG_INFO */ - - /* Check that we can support this device */ - - if (gcw.protocol !=2 ) - printk(KERN_ERR "ide-tape: Protocol is not ATAPI\n"); - else if (gcw.device_type != 1) - printk(KERN_ERR "ide-tape: Device type is not set to tape\n"); - else if (!gcw.removable) - printk(KERN_ERR "ide-tape: The removable flag is not set\n"); - else if (gcw.packet_size != 0) { - printk(KERN_ERR "ide-tape: Packet size is not 12 bytes long\n"); - if (gcw.packet_size == 1) - printk(KERN_ERR "ide-tape: Sorry, padding to 16 bytes is still not supported\n"); - } else - return 1; return 0; } -/* - * Use INQUIRY to get the firmware revision - */ -static void idetape_get_inquiry_results (ide_drive_t *drive) +static void idetape_get_inquiry_results(ide_drive_t *drive) { - char *r; idetape_tape_t *tape = drive->driver_data; - idetape_pc_t pc; - idetape_inquiry_result_t *inquiry; - + struct ide_atapi_pc pc; + u8 pc_buf[256]; + char fw_rev[4], vendor_id[8], product_id[16]; + idetape_create_inquiry_cmd(&pc); - if (idetape_queue_pc_tail(drive, &pc)) { - printk(KERN_ERR "ide-tape: %s: can't get INQUIRY results\n", tape->name); + if (ide_queue_pc_tail(drive, tape->disk, &pc, pc_buf, pc.req_xfer)) { + printk(KERN_ERR "ide-tape: %s: can't get INQUIRY results\n", + tape->name); return; } - inquiry = (idetape_inquiry_result_t *) pc.buffer; - memcpy(tape->vendor_id, inquiry->vendor_id, 8); - memcpy(tape->product_id, inquiry->product_id, 16); - memcpy(tape->firmware_revision, inquiry->revision_level, 4); - ide_fixstring(tape->vendor_id, 10, 0); - ide_fixstring(tape->product_id, 18, 0); - ide_fixstring(tape->firmware_revision, 6, 0); - r = tape->firmware_revision; - if (*(r + 1) == '.') - tape->firmware_revision_num = (*r - '0') * 100 + (*(r + 2) - '0') * 10 + *(r + 3) - '0'; - printk(KERN_INFO "ide-tape: %s <-> %s: %s %s rev %s\n", drive->name, tape->name, tape->vendor_id, tape->product_id, tape->firmware_revision); + memcpy(vendor_id, &pc_buf[8], 8); + memcpy(product_id, &pc_buf[16], 16); + memcpy(fw_rev, &pc_buf[32], 4); + + ide_fixstring(vendor_id, 8, 0); + ide_fixstring(product_id, 16, 0); + ide_fixstring(fw_rev, 4, 0); + + printk(KERN_INFO "ide-tape: %s <-> %s: %.8s %.16s rev %.4s\n", + drive->name, tape->name, vendor_id, product_id, fw_rev); } /* - * idetape_get_mode_sense_results asks the tape about its various - * parameters. In particular, we will adjust our data transfer buffer - * size to the recommended value as returned by the tape. + * Ask the tape about its various parameters. In particular, we will adjust our + * data transfer buffer size to the recommended value as returned by the tape. */ -static void idetape_get_mode_sense_results (ide_drive_t *drive) +static void idetape_get_mode_sense_results(ide_drive_t *drive) { idetape_tape_t *tape = drive->driver_data; - idetape_pc_t pc; - idetape_mode_parameter_header_t *header; - idetape_capabilities_page_t *capabilities; - + struct ide_atapi_pc pc; + u8 buf[24], *caps; + u8 speed, max_speed; + idetape_create_mode_sense_cmd(&pc, IDETAPE_CAPABILITIES_PAGE); - if (idetape_queue_pc_tail(drive, &pc)) { - printk(KERN_ERR "ide-tape: Can't get tape parameters - assuming some default values\n"); - tape->tape_block_size = 512; - tape->capabilities.ctl = 52; - tape->capabilities.speed = 450; - tape->capabilities.buffer_size = 6 * 52; + if (ide_queue_pc_tail(drive, tape->disk, &pc, buf, pc.req_xfer)) { + printk(KERN_ERR "ide-tape: Can't get tape parameters - assuming" + " some default values\n"); + tape->blk_size = 512; + put_unaligned(52, (u16 *)&tape->caps[12]); + put_unaligned(540, (u16 *)&tape->caps[14]); + put_unaligned(6*52, (u16 *)&tape->caps[16]); return; } - header = (idetape_mode_parameter_header_t *) pc.buffer; - capabilities = (idetape_capabilities_page_t *) (pc.buffer + sizeof(idetape_mode_parameter_header_t) + header->bdl); + caps = buf + 4 + buf[3]; + + /* convert to host order and save for later use */ + speed = be16_to_cpup((__be16 *)&caps[14]); + max_speed = be16_to_cpup((__be16 *)&caps[8]); - capabilities->max_speed = ntohs(capabilities->max_speed); - capabilities->ctl = ntohs(capabilities->ctl); - capabilities->speed = ntohs(capabilities->speed); - capabilities->buffer_size = ntohs(capabilities->buffer_size); + *(u16 *)&caps[8] = max_speed; + *(u16 *)&caps[12] = be16_to_cpup((__be16 *)&caps[12]); + *(u16 *)&caps[14] = speed; + *(u16 *)&caps[16] = be16_to_cpup((__be16 *)&caps[16]); - if (!capabilities->speed) { - printk(KERN_INFO "ide-tape: %s: overriding capabilities->speed (assuming 650KB/sec)\n", drive->name); - capabilities->speed = 650; + if (!speed) { + printk(KERN_INFO "ide-tape: %s: invalid tape speed " + "(assuming 650KB/sec)\n", drive->name); + *(u16 *)&caps[14] = 650; } - if (!capabilities->max_speed) { - printk(KERN_INFO "ide-tape: %s: overriding capabilities->max_speed (assuming 650KB/sec)\n", drive->name); - capabilities->max_speed = 650; + if (!max_speed) { + printk(KERN_INFO "ide-tape: %s: invalid max_speed " + "(assuming 650KB/sec)\n", drive->name); + *(u16 *)&caps[8] = 650; } - tape->capabilities = *capabilities; /* Save us a copy */ - if (capabilities->blk512) - tape->tape_block_size = 512; - else if (capabilities->blk1024) - tape->tape_block_size = 1024; - -#if IDETAPE_DEBUG_INFO - printk(KERN_INFO "ide-tape: Dumping the results of the MODE SENSE packet command\n"); - printk(KERN_INFO "ide-tape: Mode Parameter Header:\n"); - printk(KERN_INFO "ide-tape: Mode Data Length - %d\n",header->mode_data_length); - printk(KERN_INFO "ide-tape: Medium Type - %d\n",header->medium_type); - printk(KERN_INFO "ide-tape: Device Specific Parameter - %d\n",header->dsp); - printk(KERN_INFO "ide-tape: Block Descriptor Length - %d\n",header->bdl); - - printk(KERN_INFO "ide-tape: Capabilities and Mechanical Status Page:\n"); - printk(KERN_INFO "ide-tape: Page code - %d\n",capabilities->page_code); - printk(KERN_INFO "ide-tape: Page length - %d\n",capabilities->page_length); - printk(KERN_INFO "ide-tape: Read only - %s\n",capabilities->ro ? "Yes":"No"); - printk(KERN_INFO "ide-tape: Supports reverse space - %s\n",capabilities->sprev ? "Yes":"No"); - printk(KERN_INFO "ide-tape: Supports erase initiated formatting - %s\n",capabilities->efmt ? "Yes":"No"); - printk(KERN_INFO "ide-tape: Supports QFA two Partition format - %s\n",capabilities->qfa ? "Yes":"No"); - printk(KERN_INFO "ide-tape: Supports locking the medium - %s\n",capabilities->lock ? "Yes":"No"); - printk(KERN_INFO "ide-tape: The volume is currently locked - %s\n",capabilities->locked ? "Yes":"No"); - printk(KERN_INFO "ide-tape: The device defaults in the prevent state - %s\n",capabilities->prevent ? "Yes":"No"); - printk(KERN_INFO "ide-tape: Supports ejecting the medium - %s\n",capabilities->eject ? "Yes":"No"); - printk(KERN_INFO "ide-tape: Supports error correction - %s\n",capabilities->ecc ? "Yes":"No"); - printk(KERN_INFO "ide-tape: Supports data compression - %s\n",capabilities->cmprs ? "Yes":"No"); - printk(KERN_INFO "ide-tape: Supports 512 bytes block size - %s\n",capabilities->blk512 ? "Yes":"No"); - printk(KERN_INFO "ide-tape: Supports 1024 bytes block size - %s\n",capabilities->blk1024 ? "Yes":"No"); - printk(KERN_INFO "ide-tape: Supports 32768 bytes block size / Restricted byte count for PIO transfers - %s\n",capabilities->blk32768 ? "Yes":"No"); - printk(KERN_INFO "ide-tape: Maximum supported speed in KBps - %d\n",capabilities->max_speed); - printk(KERN_INFO "ide-tape: Continuous transfer limits in blocks - %d\n",capabilities->ctl); - printk(KERN_INFO "ide-tape: Current speed in KBps - %d\n",capabilities->speed); - printk(KERN_INFO "ide-tape: Buffer size - %d\n",capabilities->buffer_size*512); -#endif /* IDETAPE_DEBUG_INFO */ -} + memcpy(&tape->caps, caps, 20); -/* - * ide_get_blocksize_from_block_descriptor does a mode sense page 0 with block descriptor - * and if it succeeds sets the tape block size with the reported value - */ -static void idetape_get_blocksize_from_block_descriptor(ide_drive_t *drive) -{ + /* device lacks locking support according to capabilities page */ + if ((caps[6] & 1) == 0) + drive->dev_flags &= ~IDE_DFLAG_DOORLOCKING; - idetape_tape_t *tape = drive->driver_data; - idetape_pc_t pc; - idetape_mode_parameter_header_t *header; - idetape_parameter_block_descriptor_t *block_descrp; - - idetape_create_mode_sense_cmd(&pc, IDETAPE_BLOCK_DESCRIPTOR); - if (idetape_queue_pc_tail(drive, &pc)) { - printk(KERN_ERR "ide-tape: Can't get block descriptor\n"); - if (tape->tape_block_size == 0) { - printk(KERN_WARNING "ide-tape: Cannot deal with zero block size, assume 32k\n"); - tape->tape_block_size = 32768; - } - return; - } - header = (idetape_mode_parameter_header_t *) pc.buffer; - block_descrp = (idetape_parameter_block_descriptor_t *) (pc.buffer + sizeof(idetape_mode_parameter_header_t)); - tape->tape_block_size =( block_descrp->length[0]<<16) + (block_descrp->length[1]<<8) + block_descrp->length[2]; - tape->drv_write_prot = (header->dsp & 0x80) >> 7; - -#if IDETAPE_DEBUG_INFO - printk(KERN_INFO "ide-tape: Adjusted block size - %d\n", tape->tape_block_size); -#endif /* IDETAPE_DEBUG_INFO */ + if (caps[7] & 0x02) + tape->blk_size = 512; + else if (caps[7] & 0x04) + tape->blk_size = 1024; } -static void idetape_add_settings (ide_drive_t *drive) -{ - idetape_tape_t *tape = drive->driver_data; -/* - * drive setting name read/write ioctl ioctl data type min max mul_factor div_factor data pointer set function - */ - ide_add_setting(drive, "buffer", SETTING_READ, -1, -1, TYPE_SHORT, 0, 0xffff, 1, 2, &tape->capabilities.buffer_size, NULL); - ide_add_setting(drive, "pipeline_min", SETTING_RW, -1, -1, TYPE_INT, 1, 0xffff, tape->stage_size / 1024, 1, &tape->min_pipeline, NULL); - ide_add_setting(drive, "pipeline", SETTING_RW, -1, -1, TYPE_INT, 1, 0xffff, tape->stage_size / 1024, 1, &tape->max_stages, NULL); - ide_add_setting(drive, "pipeline_max", SETTING_RW, -1, -1, TYPE_INT, 1, 0xffff, tape->stage_size / 1024, 1, &tape->max_pipeline, NULL); - ide_add_setting(drive, "pipeline_used",SETTING_READ, -1, -1, TYPE_INT, 0, 0xffff, tape->stage_size / 1024, 1, &tape->nr_stages, NULL); - ide_add_setting(drive, "pipeline_pending",SETTING_READ,-1, -1, TYPE_INT, 0, 0xffff, tape->stage_size / 1024, 1, &tape->nr_pending_stages, NULL); - ide_add_setting(drive, "speed", SETTING_READ, -1, -1, TYPE_SHORT, 0, 0xffff, 1, 1, &tape->capabilities.speed, NULL); - ide_add_setting(drive, "stage", SETTING_READ, -1, -1, TYPE_INT, 0, 0xffff, 1, 1024, &tape->stage_size, NULL); - ide_add_setting(drive, "tdsc", SETTING_RW, -1, -1, TYPE_INT, IDETAPE_DSC_RW_MIN, IDETAPE_DSC_RW_MAX, 1000, HZ, &tape->best_dsc_rw_frequency, NULL); - ide_add_setting(drive, "dsc_overlap", SETTING_RW, -1, -1, TYPE_BYTE, 0, 1, 1, 1, &drive->dsc_overlap, NULL); - ide_add_setting(drive, "pipeline_head_speed_c",SETTING_READ, -1, -1, TYPE_INT, 0, 0xffff, 1, 1, &tape->controlled_pipeline_head_speed, NULL); - ide_add_setting(drive, "pipeline_head_speed_u",SETTING_READ, -1, -1, TYPE_INT, 0, 0xffff, 1, 1, &tape->uncontrolled_pipeline_head_speed, NULL); - ide_add_setting(drive, "avg_speed", SETTING_READ, -1, -1, TYPE_INT, 0, 0xffff, 1, 1, &tape->avg_speed, NULL); - ide_add_setting(drive, "debug_level",SETTING_RW, -1, -1, TYPE_INT, 0, 0xffff, 1, 1, &tape->debug_level, NULL); +#ifdef CONFIG_IDE_PROC_FS +#define ide_tape_devset_get(name, field) \ +static int get_##name(ide_drive_t *drive) \ +{ \ + idetape_tape_t *tape = drive->driver_data; \ + return tape->field; \ } +#define ide_tape_devset_set(name, field) \ +static int set_##name(ide_drive_t *drive, int arg) \ +{ \ + idetape_tape_t *tape = drive->driver_data; \ + tape->field = arg; \ + return 0; \ +} + +#define ide_tape_devset_rw_field(_name, _field) \ +ide_tape_devset_get(_name, _field) \ +ide_tape_devset_set(_name, _field) \ +IDE_DEVSET(_name, DS_SYNC, get_##_name, set_##_name) + +#define ide_tape_devset_r_field(_name, _field) \ +ide_tape_devset_get(_name, _field) \ +IDE_DEVSET(_name, 0, get_##_name, NULL) + +static int mulf_tdsc(ide_drive_t *drive) { return 1000; } +static int divf_tdsc(ide_drive_t *drive) { return HZ; } +static int divf_buffer(ide_drive_t *drive) { return 2; } +static int divf_buffer_size(ide_drive_t *drive) { return 1024; } + +ide_devset_rw_flag(dsc_overlap, IDE_DFLAG_DSC_OVERLAP); + +ide_tape_devset_rw_field(tdsc, best_dsc_rw_freq); + +ide_tape_devset_r_field(avg_speed, avg_speed); +ide_tape_devset_r_field(speed, caps[14]); +ide_tape_devset_r_field(buffer, caps[16]); +ide_tape_devset_r_field(buffer_size, buffer_size); + +static const struct ide_proc_devset idetape_settings[] = { + __IDE_PROC_DEVSET(avg_speed, 0, 0xffff, NULL, NULL), + __IDE_PROC_DEVSET(buffer, 0, 0xffff, NULL, divf_buffer), + __IDE_PROC_DEVSET(buffer_size, 0, 0xffff, NULL, divf_buffer_size), + __IDE_PROC_DEVSET(dsc_overlap, 0, 1, NULL, NULL), + __IDE_PROC_DEVSET(speed, 0, 0xffff, NULL, NULL), + __IDE_PROC_DEVSET(tdsc, IDETAPE_DSC_RW_MIN, IDETAPE_DSC_RW_MAX, + mulf_tdsc, divf_tdsc), + { NULL }, +}; +#endif + /* - * ide_setup is called to: + * The function below is called to: * - * 1. Initialize our various state variables. - * 2. Ask the tape for its capabilities. - * 3. Allocate a buffer which will be used for data - * transfer. The buffer size is chosen based on - * the recommendation which we received in step (2). + * 1. Initialize our various state variables. + * 2. Ask the tape for its capabilities. + * 3. Allocate a buffer which will be used for data transfer. The buffer size + * is chosen based on the recommendation which we received in step 2. * - * Note that at this point ide.c already assigned us an irq, so that - * we can queue requests here and wait for their completion. + * Note that at this point ide.c already assigned us an irq, so that we can + * queue requests here and wait for their completion. */ -static void idetape_setup (ide_drive_t *drive, idetape_tape_t *tape, int minor) +static void idetape_setup(ide_drive_t *drive, idetape_tape_t *tape, int minor) { - unsigned long t1, tmid, tn, t; + unsigned long t; int speed; - struct idetape_id_gcw gcw; - int stage_size; - struct sysinfo si; - - spin_lock_init(&tape->spinlock); - drive->dsc_overlap = 1; -#ifdef CONFIG_BLK_DEV_IDEPCI - if (HWIF(drive)->pci_dev != NULL) { - /* - * These two ide-pci host adapters appear to need DSC overlap disabled. - * This probably needs further analysis. - */ - if ((HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) || - (HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_TTI_HPT343)) { - printk(KERN_INFO "ide-tape: %s: disabling DSC overlap\n", tape->name); - drive->dsc_overlap = 0; - } + int buffer_size; + u16 *ctl = (u16 *)&tape->caps[12]; + + ide_debug_log(IDE_DBG_FUNC, "minor: %d", minor); + + drive->pc_callback = ide_tape_callback; + + drive->dev_flags |= IDE_DFLAG_DSC_OVERLAP; + + if (drive->hwif->host_flags & IDE_HFLAG_NO_DSC) { + printk(KERN_INFO "ide-tape: %s: disabling DSC overlap\n", + tape->name); + drive->dev_flags &= ~IDE_DFLAG_DSC_OVERLAP; } -#endif /* CONFIG_BLK_DEV_IDEPCI */ + /* Seagate Travan drives do not support DSC overlap. */ - if (strstr(drive->id->model, "Seagate STT3401")) - drive->dsc_overlap = 0; + if (strstr((char *)&drive->id[ATA_ID_PROD], "Seagate STT3401")) + drive->dev_flags &= ~IDE_DFLAG_DSC_OVERLAP; + tape->minor = minor; tape->name[0] = 'h'; tape->name[1] = 't'; tape->name[2] = '0' + minor; - tape->chrdev_direction = idetape_direction_none; - tape->pc = tape->pc_stack; - tape->max_insert_speed = 10000; - tape->speed_control = 1; - *((unsigned short *) &gcw) = drive->id->config; - if (gcw.drq_type == 1) - set_bit(IDETAPE_DRQ_INTERRUPT, &tape->flags); - - tape->min_pipeline = tape->max_pipeline = tape->max_stages = 10; - + tape->chrdev_dir = IDETAPE_DIR_NONE; + idetape_get_inquiry_results(drive); idetape_get_mode_sense_results(drive); - idetape_get_blocksize_from_block_descriptor(drive); + ide_tape_get_bsize_from_bdesc(drive); tape->user_bs_factor = 1; - tape->stage_size = tape->capabilities.ctl * tape->tape_block_size; - while (tape->stage_size > 0xffff) { + tape->buffer_size = *ctl * tape->blk_size; + while (tape->buffer_size > 0xffff) { printk(KERN_NOTICE "ide-tape: decreasing stage size\n"); - tape->capabilities.ctl /= 2; - tape->stage_size = tape->capabilities.ctl * tape->tape_block_size; + *ctl /= 2; + tape->buffer_size = *ctl * tape->blk_size; } - stage_size = tape->stage_size; - tape->pages_per_stage = stage_size / PAGE_SIZE; - if (stage_size % PAGE_SIZE) { - tape->pages_per_stage++; - tape->excess_bh_size = PAGE_SIZE - stage_size % PAGE_SIZE; - } - - /* - * Select the "best" DSC read/write polling frequency - * and pipeline size. - */ - speed = max(tape->capabilities.speed, tape->capabilities.max_speed); + buffer_size = tape->buffer_size; - tape->max_stages = speed * 1000 * 10 / tape->stage_size; + /* select the "best" DSC read/write polling freq */ + speed = max(*(u16 *)&tape->caps[14], *(u16 *)&tape->caps[8]); - /* - * Limit memory use for pipeline to 10% of physical memory - */ - si_meminfo(&si); - if (tape->max_stages * tape->stage_size > si.totalram * si.mem_unit / 10) - tape->max_stages = si.totalram * si.mem_unit / (10 * tape->stage_size); - tape->max_stages = min(tape->max_stages, IDETAPE_MAX_PIPELINE_STAGES); - tape->min_pipeline = min(tape->max_stages, IDETAPE_MIN_PIPELINE_STAGES); - tape->max_pipeline = min(tape->max_stages * 2, IDETAPE_MAX_PIPELINE_STAGES); - if (tape->max_stages == 0) - tape->max_stages = tape->min_pipeline = tape->max_pipeline = 1; - - t1 = (tape->stage_size * HZ) / (speed * 1000); - tmid = (tape->capabilities.buffer_size * 32 * HZ) / (speed * 125); - tn = (IDETAPE_FIFO_THRESHOLD * tape->stage_size * HZ) / (speed * 1000); - - if (tape->max_stages) - t = tn; - else - t = t1; + t = (IDETAPE_FIFO_THRESHOLD * tape->buffer_size * HZ) / (speed * 1000); /* - * Ensure that the number we got makes sense; limit - * it within IDETAPE_DSC_RW_MIN and IDETAPE_DSC_RW_MAX. + * Ensure that the number we got makes sense; limit it within + * IDETAPE_DSC_RW_MIN and IDETAPE_DSC_RW_MAX. */ - tape->best_dsc_rw_frequency = max_t(unsigned long, min_t(unsigned long, t, IDETAPE_DSC_RW_MAX), IDETAPE_DSC_RW_MIN); + tape->best_dsc_rw_freq = clamp_t(unsigned long, t, IDETAPE_DSC_RW_MIN, + IDETAPE_DSC_RW_MAX); printk(KERN_INFO "ide-tape: %s <-> %s: %dKBps, %d*%dkB buffer, " - "%dkB pipeline, %lums tDSC%s\n", - drive->name, tape->name, tape->capabilities.speed, - (tape->capabilities.buffer_size * 512) / tape->stage_size, - tape->stage_size / 1024, - tape->max_stages * tape->stage_size / 1024, - tape->best_dsc_rw_frequency * 1000 / HZ, - drive->using_dma ? ", DMA":""); - - idetape_add_settings(drive); + "%lums tDSC%s\n", + drive->name, tape->name, *(u16 *)&tape->caps[14], + (*(u16 *)&tape->caps[16] * 512) / tape->buffer_size, + tape->buffer_size / 1024, + tape->best_dsc_rw_freq * 1000 / HZ, + (drive->dev_flags & IDE_DFLAG_USING_DMA) ? ", DMA" : ""); + + ide_proc_register_driver(drive, tape->driver); } static void ide_tape_remove(ide_drive_t *drive) { idetape_tape_t *tape = drive->driver_data; - ide_unregister_subdriver(drive, tape->driver); - + ide_proc_unregister_driver(drive, tape->driver); + device_del(&tape->dev); ide_unregister_region(tape->disk); - ide_tape_put(tape); + mutex_lock(&idetape_ref_mutex); + put_device(&tape->dev); + mutex_unlock(&idetape_ref_mutex); } -static void ide_tape_release(struct kref *kref) +static void ide_tape_release(struct device *dev) { - struct ide_tape_obj *tape = to_ide_tape(kref); + struct ide_tape_obj *tape = to_ide_drv(dev, ide_tape_obj); ide_drive_t *drive = tape->drive; struct gendisk *g = tape->disk; - BUG_ON(tape->first_stage != NULL || tape->merge_stage_size); + BUG_ON(tape->valid); - drive->dsc_overlap = 0; + drive->dev_flags &= ~IDE_DFLAG_DSC_OVERLAP; drive->driver_data = NULL; - class_device_destroy(idetape_sysfs_class, - MKDEV(IDETAPE_MAJOR, tape->minor)); - class_device_destroy(idetape_sysfs_class, + device_destroy(idetape_sysfs_class, MKDEV(IDETAPE_MAJOR, tape->minor)); + device_destroy(idetape_sysfs_class, MKDEV(IDETAPE_MAJOR, tape->minor + 128)); idetape_devs[tape->minor] = NULL; g->private_data = NULL; @@ -4730,35 +1835,49 @@ static void ide_tape_release(struct kref *kref) kfree(tape); } -#ifdef CONFIG_PROC_FS - -static int proc_idetape_read_name - (char *page, char **start, off_t off, int count, int *eof, void *data) +#ifdef CONFIG_IDE_PROC_FS +static int idetape_name_proc_show(struct seq_file *m, void *v) { - ide_drive_t *drive = (ide_drive_t *) data; + ide_drive_t *drive = (ide_drive_t *) m->private; idetape_tape_t *tape = drive->driver_data; - char *out = page; - int len; - len = sprintf(out, "%s\n", tape->name); - PROC_IDE_READ_RETURN(page, start, off, count, eof, len); + seq_printf(m, "%s\n", tape->name); + return 0; +} + +static int idetape_name_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, idetape_name_proc_show, PDE_DATA(inode)); } -static ide_proc_entry_t idetape_proc[] = { - { "capacity", S_IFREG|S_IRUGO, proc_ide_read_capacity, NULL }, - { "name", S_IFREG|S_IRUGO, proc_idetape_read_name, NULL }, - { NULL, 0, NULL, NULL } +static const struct file_operations idetape_name_proc_fops = { + .owner = THIS_MODULE, + .open = idetape_name_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, }; -#else +static ide_proc_entry_t idetape_proc[] = { + { "capacity", S_IFREG|S_IRUGO, &ide_capacity_proc_fops }, + { "name", S_IFREG|S_IRUGO, &idetape_name_proc_fops }, + {} +}; -#define idetape_proc NULL +static ide_proc_entry_t *ide_tape_proc_entries(ide_drive_t *drive) +{ + return idetape_proc; +} +static const struct ide_proc_devset *ide_tape_proc_devsets(ide_drive_t *drive) +{ + return idetape_settings; +} #endif static int ide_tape_probe(ide_drive_t *); -static ide_driver_t idetape_driver = { +static struct ide_driver idetape_driver = { .gen_driver = { .owner = THIS_MODULE, .name = "ide-tape", @@ -4767,69 +1886,64 @@ static ide_driver_t idetape_driver = { .probe = ide_tape_probe, .remove = ide_tape_remove, .version = IDETAPE_VERSION, - .media = ide_tape, - .supports_dsc_overlap = 1, .do_request = idetape_do_request, - .end_request = idetape_end_request, - .error = __ide_error, - .abort = __ide_abort, - .proc = idetape_proc, +#ifdef CONFIG_IDE_PROC_FS + .proc_entries = ide_tape_proc_entries, + .proc_devsets = ide_tape_proc_devsets, +#endif }; -/* - * Our character device supporting functions, passed to register_chrdev. - */ -static struct file_operations idetape_fops = { +/* Our character device supporting functions, passed to register_chrdev. */ +static const struct file_operations idetape_fops = { .owner = THIS_MODULE, .read = idetape_chrdev_read, .write = idetape_chrdev_write, - .ioctl = idetape_chrdev_ioctl, + .unlocked_ioctl = idetape_chrdev_ioctl, .open = idetape_chrdev_open, .release = idetape_chrdev_release, + .llseek = noop_llseek, }; -static int idetape_open(struct inode *inode, struct file *filp) +static int idetape_open(struct block_device *bdev, fmode_t mode) { - struct gendisk *disk = inode->i_bdev->bd_disk; struct ide_tape_obj *tape; - ide_drive_t *drive; - if (!(tape = ide_tape_get(disk))) - return -ENXIO; - - drive = tape->drive; + mutex_lock(&ide_tape_mutex); + tape = ide_tape_get(bdev->bd_disk, false, 0); + mutex_unlock(&ide_tape_mutex); - drive->usage++; + if (!tape) + return -ENXIO; return 0; } -static int idetape_release(struct inode *inode, struct file *filp) +static void idetape_release(struct gendisk *disk, fmode_t mode) { - struct gendisk *disk = inode->i_bdev->bd_disk; - struct ide_tape_obj *tape = ide_tape_g(disk); - ide_drive_t *drive = tape->drive; - - drive->usage--; + struct ide_tape_obj *tape = ide_drv_g(disk, ide_tape_obj); + mutex_lock(&ide_tape_mutex); ide_tape_put(tape); - - return 0; + mutex_unlock(&ide_tape_mutex); } -static int idetape_ioctl(struct inode *inode, struct file *file, +static int idetape_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, unsigned long arg) { - struct block_device *bdev = inode->i_bdev; - struct ide_tape_obj *tape = ide_tape_g(bdev->bd_disk); + struct ide_tape_obj *tape = ide_drv_g(bdev->bd_disk, ide_tape_obj); ide_drive_t *drive = tape->drive; - int err = generic_ide_ioctl(drive, file, bdev, cmd, arg); + int err; + + mutex_lock(&ide_tape_mutex); + err = generic_ide_ioctl(drive, bdev, cmd, arg); if (err == -EINVAL) err = idetape_blkdev_ioctl(drive, cmd, arg); + mutex_unlock(&ide_tape_mutex); + return err; } -static struct block_device_operations idetape_block_ops = { +static const struct block_device_operations idetape_block_ops = { .owner = THIS_MODULE, .open = idetape_open, .release = idetape_release, @@ -4842,27 +1956,24 @@ static int ide_tape_probe(ide_drive_t *drive) struct gendisk *g; int minor; - if (!strstr("ide-tape", drive->driver_req)) - goto failed; - if (!drive->present) + ide_debug_log(IDE_DBG_FUNC, "enter"); + + if (!strstr(DRV_NAME, drive->driver_req)) goto failed; + if (drive->media != ide_tape) goto failed; - if (!idetape_identify_device (drive)) { - printk(KERN_ERR "ide-tape: %s: not supported by this version of ide-tape\n", drive->name); - goto failed; - } - if (drive->scsi) { - printk("ide-tape: passing drive %s to ide-scsi emulation.\n", drive->name); + + if ((drive->dev_flags & IDE_DFLAG_ID_READ) && + ide_check_atapi_device(drive, DRV_NAME) == 0) { + printk(KERN_ERR "ide-tape: %s: not supported by this version of" + " the driver\n", drive->name); goto failed; } - if (strstr(drive->id->model, "OnStream DI-")) { - printk(KERN_WARNING "ide-tape: Use drive %s with ide-scsi emulation and osst.\n", drive->name); - printk(KERN_WARNING "ide-tape: OnStream support will be removed soon from ide-tape!\n"); - } - tape = (idetape_tape_t *) kzalloc (sizeof (idetape_tape_t), GFP_KERNEL); + tape = kzalloc(sizeof(idetape_tape_t), GFP_KERNEL); if (tape == NULL) { - printk(KERN_ERR "ide-tape: %s: Can't allocate a tape structure\n", drive->name); + printk(KERN_ERR "ide-tape: %s: Can't allocate a tape struct\n", + drive->name); goto failed; } @@ -4872,9 +1983,12 @@ static int ide_tape_probe(ide_drive_t *drive) ide_init_disk(g, drive); - ide_register_subdriver(drive, &idetape_driver); + tape->dev.parent = &drive->gendev; + tape->dev.release = ide_tape_release; + dev_set_name(&tape->dev, "%s", dev_name(&drive->gendev)); - kref_init(&tape->kref); + if (device_register(&tape->dev)) + goto out_free_disk; tape->drive = drive; tape->driver = &idetape_driver; @@ -4892,26 +2006,26 @@ static int ide_tape_probe(ide_drive_t *drive) idetape_setup(drive, tape, minor); - class_device_create(idetape_sysfs_class, NULL, - MKDEV(IDETAPE_MAJOR, minor), &drive->gendev, "%s", tape->name); - class_device_create(idetape_sysfs_class, NULL, - MKDEV(IDETAPE_MAJOR, minor + 128), &drive->gendev, "n%s", tape->name); + device_create(idetape_sysfs_class, &drive->gendev, + MKDEV(IDETAPE_MAJOR, minor), NULL, "%s", tape->name); + device_create(idetape_sysfs_class, &drive->gendev, + MKDEV(IDETAPE_MAJOR, minor + 128), NULL, + "n%s", tape->name); g->fops = &idetape_block_ops; ide_register_region(g); return 0; +out_free_disk: + put_disk(g); out_free_tape: kfree(tape); failed: return -ENODEV; } -MODULE_DESCRIPTION("ATAPI Streaming TAPE Driver"); -MODULE_LICENSE("GPL"); - -static void __exit idetape_exit (void) +static void __exit idetape_exit(void) { driver_unregister(&idetape_driver.gen_driver); class_destroy(idetape_sysfs_class); @@ -4930,7 +2044,8 @@ static int __init idetape_init(void) } if (register_chrdev(IDETAPE_MAJOR, "ht", &idetape_fops)) { - printk(KERN_ERR "ide-tape: Failed to register character device interface\n"); + printk(KERN_ERR "ide-tape: Failed to register chrdev" + " interface\n"); error = -EBUSY; goto out_free_class; } @@ -4953,3 +2068,5 @@ MODULE_ALIAS("ide:*m-tape*"); module_init(idetape_init); module_exit(idetape_exit); MODULE_ALIAS_CHARDEV_MAJOR(IDETAPE_MAJOR); +MODULE_DESCRIPTION("ATAPI Streaming TAPE Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c index 97a9244312f..dabb88b1cbe 100644 --- a/drivers/ide/ide-taskfile.c +++ b/drivers/ide/ide-taskfile.c @@ -1,481 +1,437 @@ /* - * linux/drivers/ide/ide-taskfile.c Version 0.38 March 05, 2003 - * - * Copyright (C) 2000-2002 Michael Cornwell <cornwell@acm.org> - * Copyright (C) 2000-2002 Andre Hedrick <andre@linux-ide.org> - * Copyright (C) 2001-2002 Klaus Smolin + * Copyright (C) 2000-2002 Michael Cornwell <cornwell@acm.org> + * Copyright (C) 2000-2002 Andre Hedrick <andre@linux-ide.org> + * Copyright (C) 2001-2002 Klaus Smolin * IBM Storage Technology Division - * Copyright (C) 2003-2004 Bartlomiej Zolnierkiewicz + * Copyright (C) 2003-2004, 2007 Bartlomiej Zolnierkiewicz * * The big the bad and the ugly. - * - * Problems to be fixed because of BH interface or the lack therefore. - * - * Fill me in stupid !!! - * - * HOST: - * General refers to the Controller and Driver "pair". - * DATA HANDLER: - * Under the context of Linux it generally refers to an interrupt handler. - * However, it correctly describes the 'HOST' - * DATA BLOCK: - * The amount of data needed to be transfered as predefined in the - * setup of the device. - * STORAGE ATOMIC: - * The 'DATA BLOCK' associated to the 'DATA HANDLER', and can be as - * small as a single sector or as large as the entire command block - * request. */ -#include <linux/module.h> #include <linux/types.h> #include <linux/string.h> #include <linux/kernel.h> -#include <linux/timer.h> -#include <linux/mm.h> +#include <linux/export.h> #include <linux/sched.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 <linux/scatterlist.h> +#include <linux/uaccess.h> -#include <asm/byteorder.h> -#include <asm/irq.h> -#include <asm/uaccess.h> #include <asm/io.h> -static void ata_bswap_data (void *buffer, int wcount) +void ide_tf_readback(ide_drive_t *drive, struct ide_cmd *cmd) { - u16 *p = buffer; + ide_hwif_t *hwif = drive->hwif; + const struct ide_tp_ops *tp_ops = hwif->tp_ops; + + /* Be sure we're looking at the low order bytes */ + tp_ops->write_devctl(hwif, ATA_DEVCTL_OBS); + + tp_ops->tf_read(drive, &cmd->tf, cmd->valid.in.tf); + + if (cmd->tf_flags & IDE_TFLAG_LBA48) { + tp_ops->write_devctl(hwif, ATA_HOB | ATA_DEVCTL_OBS); - while (wcount--) { - *p = *p << 8 | *p >> 8; p++; - *p = *p << 8 | *p >> 8; p++; + tp_ops->tf_read(drive, &cmd->hob, cmd->valid.in.hob); } } -static void taskfile_input_data(ide_drive_t *drive, void *buffer, u32 wcount) +void ide_tf_dump(const char *s, struct ide_cmd *cmd) { - HWIF(drive)->ata_input_data(drive, buffer, wcount); - if (drive->bswap) - ata_bswap_data(buffer, wcount); +#ifdef DEBUG + printk("%s: tf: feat 0x%02x nsect 0x%02x lbal 0x%02x " + "lbam 0x%02x lbah 0x%02x dev 0x%02x cmd 0x%02x\n", + s, cmd->tf.feature, cmd->tf.nsect, + cmd->tf.lbal, cmd->tf.lbam, cmd->tf.lbah, + cmd->tf.device, cmd->tf.command); + printk("%s: hob: nsect 0x%02x lbal 0x%02x lbam 0x%02x lbah 0x%02x\n", + s, cmd->hob.nsect, cmd->hob.lbal, cmd->hob.lbam, cmd->hob.lbah); +#endif } -static void taskfile_output_data(ide_drive_t *drive, void *buffer, u32 wcount) +int taskfile_lib_get_identify(ide_drive_t *drive, u8 *buf) { - if (drive->bswap) { - ata_bswap_data(buffer, wcount); - HWIF(drive)->ata_output_data(drive, buffer, wcount); - ata_bswap_data(buffer, wcount); - } else { - HWIF(drive)->ata_output_data(drive, buffer, wcount); - } -} + struct ide_cmd cmd; -int taskfile_lib_get_identify (ide_drive_t *drive, u8 *buf) -{ - ide_task_t args; - memset(&args, 0, sizeof(ide_task_t)); - args.tfRegister[IDE_NSECTOR_OFFSET] = 0x01; + memset(&cmd, 0, sizeof(cmd)); + cmd.tf.nsect = 0x01; if (drive->media == ide_disk) - args.tfRegister[IDE_COMMAND_OFFSET] = WIN_IDENTIFY; + cmd.tf.command = ATA_CMD_ID_ATA; else - args.tfRegister[IDE_COMMAND_OFFSET] = WIN_PIDENTIFY; - args.command_type = IDE_DRIVE_TASK_IN; - args.data_phase = TASKFILE_IN; - args.handler = &task_in_intr; - return ide_raw_taskfile(drive, &args, buf); + cmd.tf.command = ATA_CMD_ID_ATAPI; + cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE; + cmd.valid.in.tf = IDE_VALID_IN_TF | IDE_VALID_DEVICE; + cmd.protocol = ATA_PROT_PIO; + + return ide_raw_taskfile(drive, &cmd, buf, 1); } -ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task) +static ide_startstop_t task_no_data_intr(ide_drive_t *); +static ide_startstop_t pre_task_out_intr(ide_drive_t *, struct ide_cmd *); +static ide_startstop_t task_pio_intr(ide_drive_t *); + +ide_startstop_t do_rw_taskfile(ide_drive_t *drive, struct ide_cmd *orig_cmd) { - ide_hwif_t *hwif = HWIF(drive); - task_struct_t *taskfile = (task_struct_t *) task->tfRegister; - hob_struct_t *hobfile = (hob_struct_t *) task->hobRegister; - u8 HIHI = (drive->addressing == 1) ? 0xE0 : 0xEF; - - /* ALL Command Block Executions SHALL clear nIEN, unless otherwise */ - if (IDE_CONTROL_REG) { - /* clear nIEN */ - hwif->OUTB(drive->ctl, IDE_CONTROL_REG); - } - SELECT_MASK(drive, 0); - - if (drive->addressing == 1) { - hwif->OUTB(hobfile->feature, IDE_FEATURE_REG); - hwif->OUTB(hobfile->sector_count, IDE_NSECTOR_REG); - hwif->OUTB(hobfile->sector_number, IDE_SECTOR_REG); - hwif->OUTB(hobfile->low_cylinder, IDE_LCYL_REG); - hwif->OUTB(hobfile->high_cylinder, IDE_HCYL_REG); + ide_hwif_t *hwif = drive->hwif; + struct ide_cmd *cmd = &hwif->cmd; + struct ide_taskfile *tf = &cmd->tf; + ide_handler_t *handler = NULL; + const struct ide_tp_ops *tp_ops = hwif->tp_ops; + const struct ide_dma_ops *dma_ops = hwif->dma_ops; + + if (orig_cmd->protocol == ATA_PROT_PIO && + (orig_cmd->tf_flags & IDE_TFLAG_MULTI_PIO) && + drive->mult_count == 0) { + pr_err("%s: multimode not set!\n", drive->name); + return ide_stopped; } - hwif->OUTB(taskfile->feature, IDE_FEATURE_REG); - hwif->OUTB(taskfile->sector_count, IDE_NSECTOR_REG); - hwif->OUTB(taskfile->sector_number, IDE_SECTOR_REG); - hwif->OUTB(taskfile->low_cylinder, IDE_LCYL_REG); - hwif->OUTB(taskfile->high_cylinder, IDE_HCYL_REG); + if (orig_cmd->ftf_flags & IDE_FTFLAG_FLAGGED) + orig_cmd->ftf_flags |= IDE_FTFLAG_SET_IN_FLAGS; - hwif->OUTB((taskfile->device_head & HIHI) | drive->select.all, IDE_SELECT_REG); + memcpy(cmd, orig_cmd, sizeof(*cmd)); - if (task->handler != NULL) { - if (task->prehandler != NULL) { - hwif->OUTBSYNC(drive, taskfile->command, IDE_COMMAND_REG); - ndelay(400); /* FIXME */ - return task->prehandler(drive, task->rq); - } - ide_execute_command(drive, taskfile->command, task->handler, WAIT_WORSTCASE, NULL); - return ide_started; - } + if ((cmd->tf_flags & IDE_TFLAG_DMA_PIO_FALLBACK) == 0) { + ide_tf_dump(drive->name, cmd); + tp_ops->write_devctl(hwif, ATA_DEVCTL_OBS); - if (!drive->using_dma) - return ide_stopped; + if (cmd->ftf_flags & IDE_FTFLAG_OUT_DATA) { + u8 data[2] = { cmd->tf.data, cmd->hob.data }; - switch (taskfile->command) { - case WIN_WRITEDMA_ONCE: - case WIN_WRITEDMA: - case WIN_WRITEDMA_EXT: - case WIN_READDMA_ONCE: - case WIN_READDMA: - case WIN_READDMA_EXT: - case WIN_IDENTIFY_DMA: - if (!hwif->dma_setup(drive)) { - hwif->dma_exec_cmd(drive, taskfile->command); - hwif->dma_start(drive); - return ide_started; - } - break; - default: - if (task->handler == NULL) - return ide_stopped; - } + tp_ops->output_data(drive, cmd, data, 2); + } - return ide_stopped; -} + if (cmd->valid.out.tf & IDE_VALID_DEVICE) { + u8 HIHI = (cmd->tf_flags & IDE_TFLAG_LBA48) ? + 0xE0 : 0xEF; -/* - * set_multmode_intr() is invoked on completion of a WIN_SETMULT cmd. - */ -ide_startstop_t set_multmode_intr (ide_drive_t *drive) -{ - ide_hwif_t *hwif = HWIF(drive); - u8 stat; + if (!(cmd->ftf_flags & IDE_FTFLAG_FLAGGED)) + cmd->tf.device &= HIHI; + cmd->tf.device |= drive->select; + } - if (OK_STAT(stat = hwif->INB(IDE_STATUS_REG),READY_STAT,BAD_STAT)) { - drive->mult_count = drive->mult_req; - } else { - drive->mult_req = drive->mult_count = 0; - drive->special.b.recalibrate = 1; - (void) ide_dump_status(drive, "set_multmode", stat); + tp_ops->tf_load(drive, &cmd->hob, cmd->valid.out.hob); + tp_ops->tf_load(drive, &cmd->tf, cmd->valid.out.tf); + } + + switch (cmd->protocol) { + case ATA_PROT_PIO: + if (cmd->tf_flags & IDE_TFLAG_WRITE) { + tp_ops->exec_command(hwif, tf->command); + ndelay(400); /* FIXME */ + return pre_task_out_intr(drive, cmd); + } + handler = task_pio_intr; + /* fall-through */ + case ATA_PROT_NODATA: + if (handler == NULL) + handler = task_no_data_intr; + ide_execute_command(drive, cmd, handler, WAIT_WORSTCASE); + return ide_started; + case ATA_PROT_DMA: + if (ide_dma_prepare(drive, cmd)) + return ide_stopped; + hwif->expiry = dma_ops->dma_timer_expiry; + ide_execute_command(drive, cmd, ide_dma_intr, 2 * WAIT_CMD); + dma_ops->dma_start(drive); + default: + return ide_started; } - return ide_stopped; } +EXPORT_SYMBOL_GPL(do_rw_taskfile); -/* - * set_geometry_intr() is invoked on completion of a WIN_SPECIFY cmd. - */ -ide_startstop_t set_geometry_intr (ide_drive_t *drive) +static ide_startstop_t task_no_data_intr(ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); - int retries = 5; + ide_hwif_t *hwif = drive->hwif; + struct ide_cmd *cmd = &hwif->cmd; + struct ide_taskfile *tf = &cmd->tf; + int custom = (cmd->tf_flags & IDE_TFLAG_CUSTOM_HANDLER) ? 1 : 0; + int retries = (custom && tf->command == ATA_CMD_INIT_DEV_PARAMS) ? 5 : 1; u8 stat; - while (((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) && retries--) - udelay(10); - - if (OK_STAT(stat, READY_STAT, BAD_STAT)) - return ide_stopped; - - if (stat & (ERR_STAT|DRQ_STAT)) - return ide_error(drive, "set_geometry_intr", stat); + local_irq_enable_in_hardirq(); - BUG_ON(HWGROUP(drive)->handler != NULL); - ide_set_handler(drive, &set_geometry_intr, WAIT_WORSTCASE, NULL); - return ide_started; -} + while (1) { + stat = hwif->tp_ops->read_status(hwif); + if ((stat & ATA_BUSY) == 0 || retries-- == 0) + break; + udelay(10); + }; -/* - * recal_intr() is invoked on completion of a WIN_RESTORE (recalibrate) cmd. - */ -ide_startstop_t recal_intr (ide_drive_t *drive) -{ - ide_hwif_t *hwif = HWIF(drive); - u8 stat; + if (!OK_STAT(stat, ATA_DRDY, BAD_STAT)) { + if (custom && tf->command == ATA_CMD_SET_MULTI) { + drive->mult_req = drive->mult_count = 0; + drive->special_flags |= IDE_SFLAG_RECALIBRATE; + (void)ide_dump_status(drive, __func__, stat); + return ide_stopped; + } else if (custom && tf->command == ATA_CMD_INIT_DEV_PARAMS) { + if ((stat & (ATA_ERR | ATA_DRQ)) == 0) { + ide_set_handler(drive, &task_no_data_intr, + WAIT_WORSTCASE); + return ide_started; + } + } + return ide_error(drive, "task_no_data_intr", stat); + } - if (!OK_STAT(stat = hwif->INB(IDE_STATUS_REG), READY_STAT, BAD_STAT)) - return ide_error(drive, "recal_intr", stat); - return ide_stopped; -} + if (custom && tf->command == ATA_CMD_SET_MULTI) + drive->mult_count = drive->mult_req; -/* - * Handler for commands without a data phase - */ -ide_startstop_t task_no_data_intr (ide_drive_t *drive) -{ - ide_task_t *args = HWGROUP(drive)->rq->special; - ide_hwif_t *hwif = HWIF(drive); - u8 stat; + if (custom == 0 || tf->command == ATA_CMD_IDLEIMMEDIATE || + tf->command == ATA_CMD_CHK_POWER) { + struct request *rq = hwif->rq; - local_irq_enable_in_hardirq(); - if (!OK_STAT(stat = hwif->INB(IDE_STATUS_REG),READY_STAT,BAD_STAT)) { - return ide_error(drive, "task_no_data_intr", stat); - /* calls ide_end_drive_cmd */ + if (blk_pm_request(rq)) + ide_complete_pm_rq(drive, rq); + else + ide_finish_cmd(drive, cmd, stat); } - if (args) - ide_end_drive_cmd(drive, stat, hwif->INB(IDE_ERROR_REG)); return ide_stopped; } -EXPORT_SYMBOL(task_no_data_intr); - static u8 wait_drive_not_busy(ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); - int retries = 100; + ide_hwif_t *hwif = drive->hwif; + int retries; u8 stat; /* - * Last sector was transfered, wait until drive is ready. - * This can take up to 10 usec, but we will wait max 1 ms - * (drive_cmd_intr() waits that long). + * Last sector was transferred, wait until device is ready. This can + * take up to 6 ms on some ATAPI devices, so we will wait max 10 ms. */ - while (((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) && retries--) - udelay(10); + for (retries = 0; retries < 1000; retries++) { + stat = hwif->tp_ops->read_status(hwif); + + if (stat & ATA_BUSY) + udelay(10); + else + break; + } - if (!retries) - printk(KERN_ERR "%s: drive still BUSY!\n", drive->name); + if (stat & ATA_BUSY) + pr_err("%s: drive still BUSY!\n", drive->name); return stat; } -static void ide_pio_sector(ide_drive_t *drive, unsigned int write) +void ide_pio_bytes(ide_drive_t *drive, struct ide_cmd *cmd, + unsigned int write, unsigned int len) { ide_hwif_t *hwif = drive->hwif; struct scatterlist *sg = hwif->sg_table; + struct scatterlist *cursg = cmd->cursg; + unsigned long uninitialized_var(flags); struct page *page; -#ifdef CONFIG_HIGHMEM - unsigned long flags; -#endif unsigned int offset; u8 *buf; - page = sg[hwif->cursg].page; - offset = sg[hwif->cursg].offset + hwif->cursg_ofs * SECTOR_SIZE; + cursg = cmd->cursg; + if (cursg == NULL) + cursg = cmd->cursg = sg; - /* get the current page and offset */ - page = nth_page(page, (offset >> PAGE_SHIFT)); - offset %= PAGE_SIZE; + while (len) { + unsigned nr_bytes = min(len, cursg->length - cmd->cursg_ofs); + int page_is_high; -#ifdef CONFIG_HIGHMEM - local_irq_save(flags); -#endif - buf = kmap_atomic(page, KM_BIO_SRC_IRQ) + offset; + page = sg_page(cursg); + offset = cursg->offset + cmd->cursg_ofs; - hwif->nleft--; - hwif->cursg_ofs++; + /* get the current page and offset */ + page = nth_page(page, (offset >> PAGE_SHIFT)); + offset %= PAGE_SIZE; - if ((hwif->cursg_ofs * SECTOR_SIZE) == sg[hwif->cursg].length) { - hwif->cursg++; - hwif->cursg_ofs = 0; - } + nr_bytes = min_t(unsigned, nr_bytes, (PAGE_SIZE - offset)); - /* do the actual data transfer */ - if (write) - taskfile_output_data(drive, buf, SECTOR_WORDS); - else - taskfile_input_data(drive, buf, SECTOR_WORDS); + page_is_high = PageHighMem(page); + if (page_is_high) + local_irq_save(flags); - kunmap_atomic(buf, KM_BIO_SRC_IRQ); -#ifdef CONFIG_HIGHMEM - local_irq_restore(flags); -#endif -} + buf = kmap_atomic(page) + offset; -static void ide_pio_multi(ide_drive_t *drive, unsigned int write) -{ - unsigned int nsect; + cmd->nleft -= nr_bytes; + cmd->cursg_ofs += nr_bytes; - nsect = min_t(unsigned int, drive->hwif->nleft, drive->mult_count); - while (nsect--) - ide_pio_sector(drive, write); -} + if (cmd->cursg_ofs == cursg->length) { + cursg = cmd->cursg = sg_next(cmd->cursg); + cmd->cursg_ofs = 0; + } -static void ide_pio_datablock(ide_drive_t *drive, struct request *rq, - unsigned int write) -{ - if (rq->bio) /* fs request */ - rq->errors = 0; + /* do the actual data transfer */ + if (write) + hwif->tp_ops->output_data(drive, cmd, buf, nr_bytes); + else + hwif->tp_ops->input_data(drive, cmd, buf, nr_bytes); - touch_softlockup_watchdog(); + kunmap_atomic(buf); - switch (drive->hwif->data_phase) { - case TASKFILE_MULTI_IN: - case TASKFILE_MULTI_OUT: - ide_pio_multi(drive, write); - break; - default: - ide_pio_sector(drive, write); - break; + if (page_is_high) + local_irq_restore(flags); + + len -= nr_bytes; } } +EXPORT_SYMBOL_GPL(ide_pio_bytes); -static ide_startstop_t task_error(ide_drive_t *drive, struct request *rq, - const char *s, u8 stat) +static void ide_pio_datablock(ide_drive_t *drive, struct ide_cmd *cmd, + unsigned int write) { - if (rq->bio) { - ide_hwif_t *hwif = drive->hwif; - int sectors = hwif->nsect - hwif->nleft; - - switch (hwif->data_phase) { - case TASKFILE_IN: - if (hwif->nleft) - break; - /* fall through */ - case TASKFILE_OUT: - sectors--; - break; - case TASKFILE_MULTI_IN: - if (hwif->nleft) - break; - /* fall through */ - case TASKFILE_MULTI_OUT: - sectors -= drive->mult_count; - default: - break; - } + unsigned int nr_bytes; - if (sectors > 0) { - ide_driver_t *drv; + u8 saved_io_32bit = drive->io_32bit; - drv = *(ide_driver_t **)rq->rq_disk->private_data; - drv->end_request(drive, 1, sectors); - } - } - return ide_error(drive, s, stat); -} + if (cmd->tf_flags & IDE_TFLAG_FS) + cmd->rq->errors = 0; -static void task_end_request(ide_drive_t *drive, struct request *rq, u8 stat) -{ - if (rq->flags & REQ_DRIVE_TASKFILE) { - ide_task_t *task = rq->special; + if (cmd->tf_flags & IDE_TFLAG_IO_16BIT) + drive->io_32bit = 0; - if (task->tf_out_flags.all) { - u8 err = drive->hwif->INB(IDE_ERROR_REG); - ide_end_drive_cmd(drive, stat, err); - return; - } - } + touch_softlockup_watchdog(); + + if (cmd->tf_flags & IDE_TFLAG_MULTI_PIO) + nr_bytes = min_t(unsigned, cmd->nleft, drive->mult_count << 9); + else + nr_bytes = SECTOR_SIZE; - if (rq->rq_disk) { - ide_driver_t *drv; + ide_pio_bytes(drive, cmd, write, nr_bytes); - drv = *(ide_driver_t **)rq->rq_disk->private_data;; - drv->end_request(drive, 1, rq->hard_nr_sectors); - } else - ide_end_request(drive, 1, rq->hard_nr_sectors); + drive->io_32bit = saved_io_32bit; } -/* - * Handler for command with PIO data-in phase (Read/Read Multiple). - */ -ide_startstop_t task_in_intr (ide_drive_t *drive) +static void ide_error_cmd(ide_drive_t *drive, struct ide_cmd *cmd) { - ide_hwif_t *hwif = drive->hwif; - struct request *rq = HWGROUP(drive)->rq; - u8 stat = hwif->INB(IDE_STATUS_REG); - - /* new way for dealing with premature shared PCI interrupts */ - if (!OK_STAT(stat, DATA_READY, BAD_R_STAT)) { - if (stat & (ERR_STAT | DRQ_STAT)) - return task_error(drive, rq, __FUNCTION__, stat); - /* No data yet, so wait for another IRQ. */ - ide_set_handler(drive, &task_in_intr, WAIT_WORSTCASE, NULL); - return ide_started; + if (cmd->tf_flags & IDE_TFLAG_FS) { + int nr_bytes = cmd->nbytes - cmd->nleft; + + if (cmd->protocol == ATA_PROT_PIO && + ((cmd->tf_flags & IDE_TFLAG_WRITE) || cmd->nleft == 0)) { + if (cmd->tf_flags & IDE_TFLAG_MULTI_PIO) + nr_bytes -= drive->mult_count << 9; + else + nr_bytes -= SECTOR_SIZE; + } + + if (nr_bytes > 0) + ide_complete_rq(drive, 0, nr_bytes); } +} - ide_pio_datablock(drive, rq, 0); +void ide_finish_cmd(ide_drive_t *drive, struct ide_cmd *cmd, u8 stat) +{ + struct request *rq = drive->hwif->rq; + u8 err = ide_read_error(drive), nsect = cmd->tf.nsect; + u8 set_xfer = !!(cmd->tf_flags & IDE_TFLAG_SET_XFER); - /* If it was the last datablock check status and finish transfer. */ - if (!hwif->nleft) { - stat = wait_drive_not_busy(drive); - if (!OK_STAT(stat, 0, BAD_R_STAT)) - return task_error(drive, rq, __FUNCTION__, stat); - task_end_request(drive, rq, stat); - return ide_stopped; - } + ide_complete_cmd(drive, cmd, stat, err); + rq->errors = err; - /* Still data left to transfer. */ - ide_set_handler(drive, &task_in_intr, WAIT_WORSTCASE, NULL); + if (err == 0 && set_xfer) { + ide_set_xfer_rate(drive, nsect); + ide_driveid_update(drive); + } - return ide_started; + ide_complete_rq(drive, err ? -EIO : 0, blk_rq_bytes(rq)); } -EXPORT_SYMBOL(task_in_intr); /* - * Handler for command with PIO data-out phase (Write/Write Multiple). + * Handler for command with PIO data phase. */ -static ide_startstop_t task_out_intr (ide_drive_t *drive) +static ide_startstop_t task_pio_intr(ide_drive_t *drive) { ide_hwif_t *hwif = drive->hwif; - struct request *rq = HWGROUP(drive)->rq; - u8 stat = hwif->INB(IDE_STATUS_REG); - - if (!OK_STAT(stat, DRIVE_READY, drive->bad_wstat)) - return task_error(drive, rq, __FUNCTION__, stat); - - /* Deal with unexpected ATA data phase. */ - if (((stat & DRQ_STAT) == 0) ^ !hwif->nleft) - return task_error(drive, rq, __FUNCTION__, stat); + struct ide_cmd *cmd = &drive->hwif->cmd; + u8 stat = hwif->tp_ops->read_status(hwif); + u8 write = !!(cmd->tf_flags & IDE_TFLAG_WRITE); + + if (write == 0) { + /* Error? */ + if (stat & ATA_ERR) + goto out_err; + + /* Didn't want any data? Odd. */ + if ((stat & ATA_DRQ) == 0) { + /* Command all done? */ + if (OK_STAT(stat, ATA_DRDY, ATA_BUSY)) + goto out_end; + + /* Assume it was a spurious irq */ + goto out_wait; + } + } else { + if (!OK_STAT(stat, DRIVE_READY, drive->bad_wstat)) + goto out_err; - if (!hwif->nleft) { - task_end_request(drive, rq, stat); - return ide_stopped; + /* Deal with unexpected ATA data phase. */ + if (((stat & ATA_DRQ) == 0) ^ (cmd->nleft == 0)) + goto out_err; } + if (write && cmd->nleft == 0) + goto out_end; + /* Still data left to transfer. */ - ide_pio_datablock(drive, rq, 1); - ide_set_handler(drive, &task_out_intr, WAIT_WORSTCASE, NULL); + ide_pio_datablock(drive, cmd, write); + + /* Are we done? Check status and finish transfer. */ + if (write == 0 && cmd->nleft == 0) { + stat = wait_drive_not_busy(drive); + if (!OK_STAT(stat, 0, BAD_STAT)) + goto out_err; + goto out_end; + } +out_wait: + /* Still data left to transfer. */ + ide_set_handler(drive, &task_pio_intr, WAIT_WORSTCASE); return ide_started; +out_end: + if ((cmd->tf_flags & IDE_TFLAG_FS) == 0) + ide_finish_cmd(drive, cmd, stat); + else + ide_complete_rq(drive, 0, blk_rq_sectors(cmd->rq) << 9); + return ide_stopped; +out_err: + ide_error_cmd(drive, cmd); + return ide_error(drive, __func__, stat); } -ide_startstop_t pre_task_out_intr (ide_drive_t *drive, struct request *rq) +static ide_startstop_t pre_task_out_intr(ide_drive_t *drive, + struct ide_cmd *cmd) { ide_startstop_t startstop; - if (ide_wait_stat(&startstop, drive, DATA_READY, + if (ide_wait_stat(&startstop, drive, ATA_DRQ, drive->bad_wstat, WAIT_DRQ)) { - printk(KERN_ERR "%s: no DRQ after issuing %sWRITE%s\n", - drive->name, - drive->hwif->data_phase ? "MULT" : "", - drive->addressing ? "_EXT" : ""); + pr_err("%s: no DRQ after issuing %sWRITE%s\n", drive->name, + (cmd->tf_flags & IDE_TFLAG_MULTI_PIO) ? "MULT" : "", + (drive->dev_flags & IDE_DFLAG_LBA48) ? "_EXT" : ""); return startstop; } - if (!drive->unmask) + if ((drive->dev_flags & IDE_DFLAG_UNMASK) == 0) local_irq_disable(); - ide_set_handler(drive, &task_out_intr, WAIT_WORSTCASE, NULL); - ide_pio_datablock(drive, rq, 1); + ide_set_handler(drive, &task_pio_intr, WAIT_WORSTCASE); + + ide_pio_datablock(drive, cmd, 1); return ide_started; } -EXPORT_SYMBOL(pre_task_out_intr); -static int ide_diag_taskfile(ide_drive_t *drive, ide_task_t *args, unsigned long data_size, u8 *buf) +int ide_raw_taskfile(ide_drive_t *drive, struct ide_cmd *cmd, u8 *buf, + u16 nsect) { - struct request rq; + struct request *rq; + int error; + int rw = !(cmd->tf_flags & IDE_TFLAG_WRITE) ? READ : WRITE; - memset(&rq, 0, sizeof(rq)); - rq.flags = REQ_DRIVE_TASKFILE; - rq.buffer = buf; + rq = blk_get_request(drive->queue, rw, __GFP_WAIT); + rq->cmd_type = REQ_TYPE_ATA_TASKFILE; /* * (ks) We transfer currently only whole sectors. @@ -483,63 +439,58 @@ static int ide_diag_taskfile(ide_drive_t *drive, ide_task_t *args, unsigned long * if we would find a solution to transfer any size. * To support special commands like READ LONG. */ - if (args->command_type != IDE_DRIVE_TASK_NO_DATA) { - if (data_size == 0) - rq.nr_sectors = (args->hobRegister[IDE_NSECTOR_OFFSET] << 8) | args->tfRegister[IDE_NSECTOR_OFFSET]; - else - rq.nr_sectors = data_size / SECTOR_SIZE; - - if (!rq.nr_sectors) { - printk(KERN_ERR "%s: in/out command without data\n", - drive->name); - return -EFAULT; - } + if (nsect) { + error = blk_rq_map_kern(drive->queue, rq, buf, + nsect * SECTOR_SIZE, __GFP_WAIT); + if (error) + goto put_req; + } - rq.hard_nr_sectors = rq.nr_sectors; - rq.hard_cur_sectors = rq.current_nr_sectors = rq.nr_sectors; + rq->special = cmd; + cmd->rq = rq; - if (args->command_type == IDE_DRIVE_TASK_RAW_WRITE) - rq.flags |= REQ_RW; - } + error = blk_execute_rq(drive->queue, NULL, rq, 0); - rq.special = args; - args->rq = &rq; - return ide_do_drive_cmd(drive, &rq, ide_wait); +put_req: + blk_put_request(rq); + return error; } +EXPORT_SYMBOL(ide_raw_taskfile); -int ide_raw_taskfile (ide_drive_t *drive, ide_task_t *args, u8 *buf) +int ide_no_data_taskfile(ide_drive_t *drive, struct ide_cmd *cmd) { - return ide_diag_taskfile(drive, args, 0, buf); -} + cmd->protocol = ATA_PROT_NODATA; -EXPORT_SYMBOL(ide_raw_taskfile); + return ide_raw_taskfile(drive, cmd, NULL, 0); +} +EXPORT_SYMBOL_GPL(ide_no_data_taskfile); -int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg) +#ifdef CONFIG_IDE_TASK_IOCTL +int ide_taskfile_ioctl(ide_drive_t *drive, unsigned long arg) { ide_task_request_t *req_task; - ide_task_t args; + struct ide_cmd cmd; u8 *outbuf = NULL; u8 *inbuf = NULL; - task_ioreg_t *argsptr = args.tfRegister; - task_ioreg_t *hobsptr = args.hobRegister; + u8 *data_buf = NULL; int err = 0; int tasksize = sizeof(struct ide_task_request_s); - int taskin = 0; - int taskout = 0; - u8 io_32bit = drive->io_32bit; + unsigned int taskin = 0; + unsigned int taskout = 0; + u16 nsect = 0; char __user *buf = (char __user *)arg; -// printk("IDE Taskfile ...\n"); + req_task = memdup_user(buf, tasksize); + if (IS_ERR(req_task)) + return PTR_ERR(req_task); - req_task = kzalloc(tasksize, GFP_KERNEL); - if (req_task == NULL) return -ENOMEM; - if (copy_from_user(req_task, buf, tasksize)) { - kfree(req_task); - return -EFAULT; - } + taskout = req_task->out_size; + taskin = req_task->in_size; - taskout = (int) req_task->out_size; - taskin = (int) req_task->in_size; + if (taskin > 65536 || taskout > 65536) { + err = -EINVAL; + goto abort; + } if (taskout) { int outtotal = tasksize; @@ -567,67 +518,133 @@ int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg) } } - memset(&args, 0, sizeof(ide_task_t)); - memcpy(argsptr, req_task->io_ports, HDIO_DRIVE_TASK_HDR_SIZE); - memcpy(hobsptr, req_task->hob_ports, HDIO_DRIVE_HOB_HDR_SIZE); + memset(&cmd, 0, sizeof(cmd)); - args.tf_in_flags = req_task->in_flags; - args.tf_out_flags = req_task->out_flags; - args.data_phase = req_task->data_phase; - args.command_type = req_task->req_cmd; + memcpy(&cmd.hob, req_task->hob_ports, HDIO_DRIVE_HOB_HDR_SIZE - 2); + memcpy(&cmd.tf, req_task->io_ports, HDIO_DRIVE_TASK_HDR_SIZE); - drive->io_32bit = 0; - switch(req_task->data_phase) { - case TASKFILE_OUT_DMAQ: - case TASKFILE_OUT_DMA: - err = ide_diag_taskfile(drive, &args, taskout, outbuf); - break; - case TASKFILE_IN_DMAQ: - case TASKFILE_IN_DMA: - err = ide_diag_taskfile(drive, &args, taskin, inbuf); - break; - case TASKFILE_MULTI_OUT: - if (!drive->mult_count) { - /* (hs): give up if multcount is not set */ - printk(KERN_ERR "%s: %s Multimode Write " \ - "multcount is not set\n", - drive->name, __FUNCTION__); - err = -EPERM; - goto abort; - } - /* fall through */ - case TASKFILE_OUT: - args.prehandler = &pre_task_out_intr; - args.handler = &task_out_intr; - err = ide_diag_taskfile(drive, &args, taskout, outbuf); - break; - case TASKFILE_MULTI_IN: - if (!drive->mult_count) { - /* (hs): give up if multcount is not set */ - printk(KERN_ERR "%s: %s Multimode Read failure " \ - "multcount is not set\n", - drive->name, __FUNCTION__); - err = -EPERM; - goto abort; - } - /* fall through */ - case TASKFILE_IN: - args.handler = &task_in_intr; - err = ide_diag_taskfile(drive, &args, taskin, inbuf); - break; - case TASKFILE_NO_DATA: - args.handler = &task_no_data_intr; - err = ide_diag_taskfile(drive, &args, 0, NULL); - break; - default: + cmd.valid.out.tf = IDE_VALID_DEVICE; + cmd.valid.in.tf = IDE_VALID_DEVICE | IDE_VALID_IN_TF; + cmd.tf_flags = IDE_TFLAG_IO_16BIT; + + if (drive->dev_flags & IDE_DFLAG_LBA48) { + cmd.tf_flags |= IDE_TFLAG_LBA48; + cmd.valid.in.hob = IDE_VALID_IN_HOB; + } + + if (req_task->out_flags.all) { + cmd.ftf_flags |= IDE_FTFLAG_FLAGGED; + + if (req_task->out_flags.b.data) + cmd.ftf_flags |= IDE_FTFLAG_OUT_DATA; + + if (req_task->out_flags.b.nsector_hob) + cmd.valid.out.hob |= IDE_VALID_NSECT; + if (req_task->out_flags.b.sector_hob) + cmd.valid.out.hob |= IDE_VALID_LBAL; + if (req_task->out_flags.b.lcyl_hob) + cmd.valid.out.hob |= IDE_VALID_LBAM; + if (req_task->out_flags.b.hcyl_hob) + cmd.valid.out.hob |= IDE_VALID_LBAH; + + if (req_task->out_flags.b.error_feature) + cmd.valid.out.tf |= IDE_VALID_FEATURE; + if (req_task->out_flags.b.nsector) + cmd.valid.out.tf |= IDE_VALID_NSECT; + if (req_task->out_flags.b.sector) + cmd.valid.out.tf |= IDE_VALID_LBAL; + if (req_task->out_flags.b.lcyl) + cmd.valid.out.tf |= IDE_VALID_LBAM; + if (req_task->out_flags.b.hcyl) + cmd.valid.out.tf |= IDE_VALID_LBAH; + } else { + cmd.valid.out.tf |= IDE_VALID_OUT_TF; + if (cmd.tf_flags & IDE_TFLAG_LBA48) + cmd.valid.out.hob |= IDE_VALID_OUT_HOB; + } + + if (req_task->in_flags.b.data) + cmd.ftf_flags |= IDE_FTFLAG_IN_DATA; + + if (req_task->req_cmd == IDE_DRIVE_TASK_RAW_WRITE) { + /* fixup data phase if needed */ + if (req_task->data_phase == TASKFILE_IN_DMAQ || + req_task->data_phase == TASKFILE_IN_DMA) + cmd.tf_flags |= IDE_TFLAG_WRITE; + } + + cmd.protocol = ATA_PROT_DMA; + + switch (req_task->data_phase) { + case TASKFILE_MULTI_OUT: + if (!drive->mult_count) { + /* (hs): give up if multcount is not set */ + pr_err("%s: %s Multimode Write multcount is not set\n", + drive->name, __func__); + err = -EPERM; + goto abort; + } + cmd.tf_flags |= IDE_TFLAG_MULTI_PIO; + /* fall through */ + case TASKFILE_OUT: + cmd.protocol = ATA_PROT_PIO; + /* fall through */ + case TASKFILE_OUT_DMAQ: + case TASKFILE_OUT_DMA: + cmd.tf_flags |= IDE_TFLAG_WRITE; + nsect = taskout / SECTOR_SIZE; + data_buf = outbuf; + break; + case TASKFILE_MULTI_IN: + if (!drive->mult_count) { + /* (hs): give up if multcount is not set */ + pr_err("%s: %s Multimode Read multcount is not set\n", + drive->name, __func__); + err = -EPERM; + goto abort; + } + cmd.tf_flags |= IDE_TFLAG_MULTI_PIO; + /* fall through */ + case TASKFILE_IN: + cmd.protocol = ATA_PROT_PIO; + /* fall through */ + case TASKFILE_IN_DMAQ: + case TASKFILE_IN_DMA: + nsect = taskin / SECTOR_SIZE; + data_buf = inbuf; + break; + case TASKFILE_NO_DATA: + cmd.protocol = ATA_PROT_NODATA; + break; + default: + err = -EFAULT; + goto abort; + } + + if (req_task->req_cmd == IDE_DRIVE_TASK_NO_DATA) + nsect = 0; + else if (!nsect) { + nsect = (cmd.hob.nsect << 8) | cmd.tf.nsect; + + if (!nsect) { + pr_err("%s: in/out command without data\n", + drive->name); err = -EFAULT; goto abort; + } } - memcpy(req_task->io_ports, &(args.tfRegister), HDIO_DRIVE_TASK_HDR_SIZE); - memcpy(req_task->hob_ports, &(args.hobRegister), HDIO_DRIVE_HOB_HDR_SIZE); - req_task->in_flags = args.tf_in_flags; - req_task->out_flags = args.tf_out_flags; + err = ide_raw_taskfile(drive, &cmd, data_buf, nsect); + + memcpy(req_task->hob_ports, &cmd.hob, HDIO_DRIVE_HOB_HDR_SIZE - 2); + memcpy(req_task->io_ports, &cmd.tf, HDIO_DRIVE_TASK_HDR_SIZE); + + if ((cmd.ftf_flags & IDE_FTFLAG_SET_IN_FLAGS) && + req_task->in_flags.all == 0) { + req_task->in_flags.all = IDE_TASKFILE_STD_IN_FLAGS; + if (drive->dev_flags & IDE_DFLAG_LBA48) + req_task->in_flags.all |= (IDE_HOB_STD_IN_FLAGS << 8); + } if (copy_to_user(buf, req_task, tasksize)) { err = -EFAULT; @@ -652,212 +669,6 @@ abort: kfree(outbuf); kfree(inbuf); -// printk("IDE Taskfile ioctl ended. rc = %i\n", err); - - drive->io_32bit = io_32bit; - - return err; -} - -int ide_wait_cmd (ide_drive_t *drive, u8 cmd, u8 nsect, u8 feature, u8 sectors, u8 *buf) -{ - struct request rq; - u8 buffer[4]; - - if (!buf) - buf = buffer; - memset(buf, 0, 4 + SECTOR_WORDS * 4 * sectors); - ide_init_drive_cmd(&rq); - rq.buffer = buf; - *buf++ = cmd; - *buf++ = nsect; - *buf++ = feature; - *buf++ = sectors; - return ide_do_drive_cmd(drive, &rq, ide_wait); -} - -/* - * FIXME : this needs to map into at taskfile. <andre@linux-ide.org> - */ -int ide_cmd_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg) -{ - int err = 0; - u8 args[4], *argbuf = args; - u8 xfer_rate = 0; - int argsize = 4; - ide_task_t tfargs; - - if (NULL == (void *) arg) { - struct request rq; - ide_init_drive_cmd(&rq); - return ide_do_drive_cmd(drive, &rq, ide_wait); - } - - if (copy_from_user(args, (void __user *)arg, 4)) - return -EFAULT; - - memset(&tfargs, 0, sizeof(ide_task_t)); - tfargs.tfRegister[IDE_FEATURE_OFFSET] = args[2]; - tfargs.tfRegister[IDE_NSECTOR_OFFSET] = args[3]; - tfargs.tfRegister[IDE_SECTOR_OFFSET] = args[1]; - tfargs.tfRegister[IDE_LCYL_OFFSET] = 0x00; - tfargs.tfRegister[IDE_HCYL_OFFSET] = 0x00; - tfargs.tfRegister[IDE_SELECT_OFFSET] = 0x00; - tfargs.tfRegister[IDE_COMMAND_OFFSET] = args[0]; - - if (args[3]) { - argsize = 4 + (SECTOR_WORDS * 4 * args[3]); - argbuf = kzalloc(argsize, GFP_KERNEL); - if (argbuf == NULL) - return -ENOMEM; - } - if (set_transfer(drive, &tfargs)) { - xfer_rate = args[1]; - if (ide_ata66_check(drive, &tfargs)) - goto abort; - } - - err = ide_wait_cmd(drive, args[0], args[1], args[2], args[3], argbuf); - - if (!err && xfer_rate) { - /* active-retuning-calls future */ - ide_set_xfer_rate(drive, xfer_rate); - ide_driveid_update(drive); - } -abort: - if (copy_to_user((void __user *)arg, argbuf, argsize)) - err = -EFAULT; - if (argsize > 4) - kfree(argbuf); return err; } - -static int ide_wait_cmd_task(ide_drive_t *drive, u8 *buf) -{ - struct request rq; - - ide_init_drive_cmd(&rq); - rq.flags = REQ_DRIVE_TASK; - rq.buffer = buf; - return ide_do_drive_cmd(drive, &rq, ide_wait); -} - -/* - * FIXME : this needs to map into at taskfile. <andre@linux-ide.org> - */ -int ide_task_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg) -{ - void __user *p = (void __user *)arg; - int err = 0; - u8 args[7], *argbuf = args; - int argsize = 7; - - if (copy_from_user(args, p, 7)) - return -EFAULT; - err = ide_wait_cmd_task(drive, argbuf); - if (copy_to_user(p, argbuf, argsize)) - err = -EFAULT; - return err; -} - -/* - * NOTICE: This is additions from IBM to provide a discrete interface, - * for selective taskregister access operations. Nice JOB Klaus!!! - * Glad to be able to work and co-develop this with you and IBM. - */ -ide_startstop_t flagged_taskfile (ide_drive_t *drive, ide_task_t *task) -{ - ide_hwif_t *hwif = HWIF(drive); - task_struct_t *taskfile = (task_struct_t *) task->tfRegister; - hob_struct_t *hobfile = (hob_struct_t *) task->hobRegister; - - if (task->data_phase == TASKFILE_MULTI_IN || - task->data_phase == TASKFILE_MULTI_OUT) { - if (!drive->mult_count) { - printk(KERN_ERR "%s: multimode not set!\n", drive->name); - return ide_stopped; - } - } - - /* - * (ks) Check taskfile in flags. - * If set, then execute as it is defined. - * If not set, then define default settings. - * The default values are: - * read all taskfile registers (except data) - * read the hob registers (sector, nsector, lcyl, hcyl) - */ - if (task->tf_in_flags.all == 0) { - task->tf_in_flags.all = IDE_TASKFILE_STD_IN_FLAGS; - if (drive->addressing == 1) - task->tf_in_flags.all |= (IDE_HOB_STD_IN_FLAGS << 8); - } - - /* ALL Command Block Executions SHALL clear nIEN, unless otherwise */ - if (IDE_CONTROL_REG) - /* clear nIEN */ - hwif->OUTB(drive->ctl, IDE_CONTROL_REG); - SELECT_MASK(drive, 0); - - if (task->tf_out_flags.b.data) { - u16 data = taskfile->data + (hobfile->data << 8); - hwif->OUTW(data, IDE_DATA_REG); - } - - /* (ks) send hob registers first */ - if (task->tf_out_flags.b.nsector_hob) - hwif->OUTB(hobfile->sector_count, IDE_NSECTOR_REG); - if (task->tf_out_flags.b.sector_hob) - hwif->OUTB(hobfile->sector_number, IDE_SECTOR_REG); - if (task->tf_out_flags.b.lcyl_hob) - hwif->OUTB(hobfile->low_cylinder, IDE_LCYL_REG); - if (task->tf_out_flags.b.hcyl_hob) - hwif->OUTB(hobfile->high_cylinder, IDE_HCYL_REG); - - /* (ks) Send now the standard registers */ - if (task->tf_out_flags.b.error_feature) - hwif->OUTB(taskfile->feature, IDE_FEATURE_REG); - /* refers to number of sectors to transfer */ - if (task->tf_out_flags.b.nsector) - hwif->OUTB(taskfile->sector_count, IDE_NSECTOR_REG); - /* refers to sector offset or start sector */ - if (task->tf_out_flags.b.sector) - hwif->OUTB(taskfile->sector_number, IDE_SECTOR_REG); - if (task->tf_out_flags.b.lcyl) - hwif->OUTB(taskfile->low_cylinder, IDE_LCYL_REG); - if (task->tf_out_flags.b.hcyl) - hwif->OUTB(taskfile->high_cylinder, IDE_HCYL_REG); - - /* - * (ks) In the flagged taskfile approch, we will use all specified - * registers and the register value will not be changed, except the - * select bit (master/slave) in the drive_head register. We must make - * sure that the desired drive is selected. - */ - hwif->OUTB(taskfile->device_head | drive->select.all, IDE_SELECT_REG); - switch(task->data_phase) { - - case TASKFILE_OUT_DMAQ: - case TASKFILE_OUT_DMA: - case TASKFILE_IN_DMAQ: - case TASKFILE_IN_DMA: - hwif->dma_setup(drive); - hwif->dma_exec_cmd(drive, taskfile->command); - hwif->dma_start(drive); - break; - - default: - if (task->handler == NULL) - return ide_stopped; - - /* Issue the command */ - if (task->prehandler) { - hwif->OUTBSYNC(drive, taskfile->command, IDE_COMMAND_REG); - ndelay(400); /* FIXME */ - return task->prehandler(drive, task->rq); - } - ide_execute_command(drive, taskfile->command, task->handler, WAIT_WORSTCASE, NULL); - } - - return ide_started; -} +#endif diff --git a/drivers/ide/ide-timing.h b/drivers/ide/ide-timing.h deleted file mode 100644 index c0864b1e922..00000000000 --- a/drivers/ide/ide-timing.h +++ /dev/null @@ -1,286 +0,0 @@ -#ifndef _IDE_TIMING_H -#define _IDE_TIMING_H - -/* - * $Id: ide-timing.h,v 1.6 2001/12/23 22:47:56 vojtech Exp $ - * - * Copyright (c) 1999-2001 Vojtech Pavlik - */ - -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: - * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic - */ - -#include <linux/kernel.h> -#include <linux/hdreg.h> - -#define XFER_PIO_5 0x0d -#define XFER_UDMA_SLOW 0x4f - -struct ide_timing { - short mode; - short setup; /* t1 */ - short act8b; /* t2 for 8-bit io */ - short rec8b; /* t2i for 8-bit io */ - short cyc8b; /* t0 for 8-bit io */ - short active; /* t2 or tD */ - short recover; /* t2i or tK */ - short cycle; /* t0 */ - short udma; /* t2CYCTYP/2 */ -}; - -/* - * PIO 0-5, MWDMA 0-2 and UDMA 0-6 timings (in nanoseconds). - * These were taken from ATA/ATAPI-6 standard, rev 0a, except - * for PIO 5, which is a nonstandard extension and UDMA6, which - * is currently supported only by Maxtor drives. - */ - -static struct ide_timing ide_timing[] = { - - { XFER_UDMA_6, 0, 0, 0, 0, 0, 0, 0, 15 }, - { XFER_UDMA_5, 0, 0, 0, 0, 0, 0, 0, 20 }, - { XFER_UDMA_4, 0, 0, 0, 0, 0, 0, 0, 30 }, - { XFER_UDMA_3, 0, 0, 0, 0, 0, 0, 0, 45 }, - - { XFER_UDMA_2, 0, 0, 0, 0, 0, 0, 0, 60 }, - { XFER_UDMA_1, 0, 0, 0, 0, 0, 0, 0, 80 }, - { XFER_UDMA_0, 0, 0, 0, 0, 0, 0, 0, 120 }, - - { XFER_UDMA_SLOW, 0, 0, 0, 0, 0, 0, 0, 150 }, - - { XFER_MW_DMA_2, 25, 0, 0, 0, 70, 25, 120, 0 }, - { XFER_MW_DMA_1, 45, 0, 0, 0, 80, 50, 150, 0 }, - { XFER_MW_DMA_0, 60, 0, 0, 0, 215, 215, 480, 0 }, - - { XFER_SW_DMA_2, 60, 0, 0, 0, 120, 120, 240, 0 }, - { XFER_SW_DMA_1, 90, 0, 0, 0, 240, 240, 480, 0 }, - { XFER_SW_DMA_0, 120, 0, 0, 0, 480, 480, 960, 0 }, - - { XFER_PIO_5, 20, 50, 30, 100, 50, 30, 100, 0 }, - { XFER_PIO_4, 25, 70, 25, 120, 70, 25, 120, 0 }, - { XFER_PIO_3, 30, 80, 70, 180, 80, 70, 180, 0 }, - - { XFER_PIO_2, 30, 290, 40, 330, 100, 90, 240, 0 }, - { XFER_PIO_1, 50, 290, 93, 383, 125, 100, 383, 0 }, - { XFER_PIO_0, 70, 290, 240, 600, 165, 150, 600, 0 }, - - { XFER_PIO_SLOW, 120, 290, 240, 960, 290, 240, 960, 0 }, - - { -1 } -}; - -#define IDE_TIMING_SETUP 0x01 -#define IDE_TIMING_ACT8B 0x02 -#define IDE_TIMING_REC8B 0x04 -#define IDE_TIMING_CYC8B 0x08 -#define IDE_TIMING_8BIT 0x0e -#define IDE_TIMING_ACTIVE 0x10 -#define IDE_TIMING_RECOVER 0x20 -#define IDE_TIMING_CYCLE 0x40 -#define IDE_TIMING_UDMA 0x80 -#define IDE_TIMING_ALL 0xff - -#define FIT(v,vmin,vmax) max_t(short,min_t(short,v,vmax),vmin) -#define ENOUGH(v,unit) (((v)-1)/(unit)+1) -#define EZ(v,unit) ((v)?ENOUGH(v,unit):0) - -#define XFER_MODE 0xf0 -#define XFER_UDMA_133 0x48 -#define XFER_UDMA_100 0x44 -#define XFER_UDMA_66 0x42 -#define XFER_UDMA 0x40 -#define XFER_MWDMA 0x20 -#define XFER_SWDMA 0x10 -#define XFER_EPIO 0x01 -#define XFER_PIO 0x00 - -static short ide_find_best_mode(ide_drive_t *drive, int map) -{ - struct hd_driveid *id = drive->id; - short best = 0; - - if (!id) - return XFER_PIO_SLOW; - - if ((map & XFER_UDMA) && (id->field_valid & 4)) { /* Want UDMA and UDMA bitmap valid */ - - if ((map & XFER_UDMA_133) == XFER_UDMA_133) - if ((best = (id->dma_ultra & 0x0040) ? XFER_UDMA_6 : 0)) return best; - - if ((map & XFER_UDMA_100) == XFER_UDMA_100) - if ((best = (id->dma_ultra & 0x0020) ? XFER_UDMA_5 : 0)) return best; - - if ((map & XFER_UDMA_66) == XFER_UDMA_66) - if ((best = (id->dma_ultra & 0x0010) ? XFER_UDMA_4 : - (id->dma_ultra & 0x0008) ? XFER_UDMA_3 : 0)) return best; - - if ((best = (id->dma_ultra & 0x0004) ? XFER_UDMA_2 : - (id->dma_ultra & 0x0002) ? XFER_UDMA_1 : - (id->dma_ultra & 0x0001) ? XFER_UDMA_0 : 0)) return best; - } - - if ((map & XFER_MWDMA) && (id->field_valid & 2)) { /* Want MWDMA and drive has EIDE fields */ - - if ((best = (id->dma_mword & 0x0004) ? XFER_MW_DMA_2 : - (id->dma_mword & 0x0002) ? XFER_MW_DMA_1 : - (id->dma_mword & 0x0001) ? XFER_MW_DMA_0 : 0)) return best; - } - - if (map & XFER_SWDMA) { /* Want SWDMA */ - - if (id->field_valid & 2) { /* EIDE SWDMA */ - - if ((best = (id->dma_1word & 0x0004) ? XFER_SW_DMA_2 : - (id->dma_1word & 0x0002) ? XFER_SW_DMA_1 : - (id->dma_1word & 0x0001) ? XFER_SW_DMA_0 : 0)) return best; - } - - if (id->capability & 1) { /* Pre-EIDE style SWDMA */ - - if ((best = (id->tDMA == 2) ? XFER_SW_DMA_2 : - (id->tDMA == 1) ? XFER_SW_DMA_1 : - (id->tDMA == 0) ? XFER_SW_DMA_0 : 0)) return best; - } - } - - - if ((map & XFER_EPIO) && (id->field_valid & 2)) { /* EIDE PIO modes */ - - if ((best = (drive->id->eide_pio_modes & 4) ? XFER_PIO_5 : - (drive->id->eide_pio_modes & 2) ? XFER_PIO_4 : - (drive->id->eide_pio_modes & 1) ? XFER_PIO_3 : 0)) return best; - } - - return (drive->id->tPIO == 2) ? XFER_PIO_2 : - (drive->id->tPIO == 1) ? XFER_PIO_1 : - (drive->id->tPIO == 0) ? XFER_PIO_0 : XFER_PIO_SLOW; -} - -static void ide_timing_quantize(struct ide_timing *t, struct ide_timing *q, int T, int UT) -{ - q->setup = EZ(t->setup * 1000, T); - q->act8b = EZ(t->act8b * 1000, T); - q->rec8b = EZ(t->rec8b * 1000, T); - q->cyc8b = EZ(t->cyc8b * 1000, T); - q->active = EZ(t->active * 1000, T); - q->recover = EZ(t->recover * 1000, T); - q->cycle = EZ(t->cycle * 1000, T); - q->udma = EZ(t->udma * 1000, UT); -} - -static void ide_timing_merge(struct ide_timing *a, struct ide_timing *b, struct ide_timing *m, unsigned int what) -{ - if (what & IDE_TIMING_SETUP ) m->setup = max(a->setup, b->setup); - if (what & IDE_TIMING_ACT8B ) m->act8b = max(a->act8b, b->act8b); - if (what & IDE_TIMING_REC8B ) m->rec8b = max(a->rec8b, b->rec8b); - if (what & IDE_TIMING_CYC8B ) m->cyc8b = max(a->cyc8b, b->cyc8b); - if (what & IDE_TIMING_ACTIVE ) m->active = max(a->active, b->active); - if (what & IDE_TIMING_RECOVER) m->recover = max(a->recover, b->recover); - if (what & IDE_TIMING_CYCLE ) m->cycle = max(a->cycle, b->cycle); - if (what & IDE_TIMING_UDMA ) m->udma = max(a->udma, b->udma); -} - -static struct ide_timing* ide_timing_find_mode(short speed) -{ - struct ide_timing *t; - - for (t = ide_timing; t->mode != speed; t++) - if (t->mode < 0) - return NULL; - return t; -} - -static int ide_timing_compute(ide_drive_t *drive, short speed, struct ide_timing *t, int T, int UT) -{ - struct hd_driveid *id = drive->id; - struct ide_timing *s, p; - -/* - * Find the mode. - */ - - if (!(s = ide_timing_find_mode(speed))) - return -EINVAL; - -/* - * Copy the timing from the table. - */ - - *t = *s; - -/* - * If the drive is an EIDE drive, it can tell us it needs extended - * PIO/MWDMA cycle timing. - */ - - if (id && id->field_valid & 2) { /* EIDE drive */ - - memset(&p, 0, sizeof(p)); - - switch (speed & XFER_MODE) { - - case XFER_PIO: - if (speed <= XFER_PIO_2) p.cycle = p.cyc8b = id->eide_pio; - else p.cycle = p.cyc8b = id->eide_pio_iordy; - break; - - case XFER_MWDMA: - p.cycle = id->eide_dma_min; - break; - } - - ide_timing_merge(&p, t, t, IDE_TIMING_CYCLE | IDE_TIMING_CYC8B); - } - -/* - * Convert the timing to bus clock counts. - */ - - ide_timing_quantize(t, t, T, UT); - -/* - * Even in DMA/UDMA modes we still use PIO access for IDENTIFY, S.M.A.R.T - * and some other commands. We have to ensure that the DMA cycle timing is - * slower/equal than the fastest PIO timing. - */ - - if ((speed & XFER_MODE) != XFER_PIO) { - ide_timing_compute(drive, ide_find_best_mode(drive, XFER_PIO | XFER_EPIO), &p, T, UT); - ide_timing_merge(&p, t, t, IDE_TIMING_ALL); - } - -/* - * Lenghten active & recovery time so that cycle time is correct. - */ - - if (t->act8b + t->rec8b < t->cyc8b) { - t->act8b += (t->cyc8b - (t->act8b + t->rec8b)) / 2; - t->rec8b = t->cyc8b - t->act8b; - } - - if (t->active + t->recover < t->cycle) { - t->active += (t->cycle - (t->active + t->recover)) / 2; - t->recover = t->cycle - t->active; - } - - return 0; -} - -#endif diff --git a/drivers/ide/ide-timings.c b/drivers/ide/ide-timings.c new file mode 100644 index 00000000000..0e05f75934c --- /dev/null +++ b/drivers/ide/ide-timings.c @@ -0,0 +1,211 @@ +/* + * Copyright (c) 1999-2001 Vojtech Pavlik + * Copyright (c) 2007-2008 Bartlomiej Zolnierkiewicz + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic + */ + +#include <linux/kernel.h> +#include <linux/ide.h> +#include <linux/module.h> + +/* + * PIO 0-5, MWDMA 0-2 and UDMA 0-6 timings (in nanoseconds). + * These were taken from ATA/ATAPI-6 standard, rev 0a, except + * for PIO 5, which is a nonstandard extension and UDMA6, which + * is currently supported only by Maxtor drives. + */ + +static struct ide_timing ide_timing[] = { + + { XFER_UDMA_6, 0, 0, 0, 0, 0, 0, 0, 15 }, + { XFER_UDMA_5, 0, 0, 0, 0, 0, 0, 0, 20 }, + { XFER_UDMA_4, 0, 0, 0, 0, 0, 0, 0, 30 }, + { XFER_UDMA_3, 0, 0, 0, 0, 0, 0, 0, 45 }, + + { XFER_UDMA_2, 0, 0, 0, 0, 0, 0, 0, 60 }, + { XFER_UDMA_1, 0, 0, 0, 0, 0, 0, 0, 80 }, + { XFER_UDMA_0, 0, 0, 0, 0, 0, 0, 0, 120 }, + + { XFER_MW_DMA_4, 25, 0, 0, 0, 55, 20, 80, 0 }, + { XFER_MW_DMA_3, 25, 0, 0, 0, 65, 25, 100, 0 }, + { XFER_MW_DMA_2, 25, 0, 0, 0, 70, 25, 120, 0 }, + { XFER_MW_DMA_1, 45, 0, 0, 0, 80, 50, 150, 0 }, + { XFER_MW_DMA_0, 60, 0, 0, 0, 215, 215, 480, 0 }, + + { XFER_SW_DMA_2, 60, 0, 0, 0, 120, 120, 240, 0 }, + { XFER_SW_DMA_1, 90, 0, 0, 0, 240, 240, 480, 0 }, + { XFER_SW_DMA_0, 120, 0, 0, 0, 480, 480, 960, 0 }, + + { XFER_PIO_6, 10, 55, 20, 80, 55, 20, 80, 0 }, + { XFER_PIO_5, 15, 65, 25, 100, 65, 25, 100, 0 }, + { XFER_PIO_4, 25, 70, 25, 120, 70, 25, 120, 0 }, + { XFER_PIO_3, 30, 80, 70, 180, 80, 70, 180, 0 }, + + { XFER_PIO_2, 30, 290, 40, 330, 100, 90, 240, 0 }, + { XFER_PIO_1, 50, 290, 93, 383, 125, 100, 383, 0 }, + { XFER_PIO_0, 70, 290, 240, 600, 165, 150, 600, 0 }, + + { XFER_PIO_SLOW, 120, 290, 240, 960, 290, 240, 960, 0 }, + + { 0xff } +}; + +struct ide_timing *ide_timing_find_mode(u8 speed) +{ + struct ide_timing *t; + + for (t = ide_timing; t->mode != speed; t++) + if (t->mode == 0xff) + return NULL; + return t; +} +EXPORT_SYMBOL_GPL(ide_timing_find_mode); + +u16 ide_pio_cycle_time(ide_drive_t *drive, u8 pio) +{ + u16 *id = drive->id; + struct ide_timing *t = ide_timing_find_mode(XFER_PIO_0 + pio); + u16 cycle = 0; + + if (id[ATA_ID_FIELD_VALID] & 2) { + if (ata_id_has_iordy(drive->id)) + cycle = id[ATA_ID_EIDE_PIO_IORDY]; + else + cycle = id[ATA_ID_EIDE_PIO]; + + /* conservative "downgrade" for all pre-ATA2 drives */ + if (pio < 3 && cycle < t->cycle) + cycle = 0; /* use standard timing */ + + /* Use the standard timing for the CF specific modes too */ + if (pio > 4 && ata_id_is_cfa(id)) + cycle = 0; + } + + return cycle ? cycle : t->cycle; +} +EXPORT_SYMBOL_GPL(ide_pio_cycle_time); + +#define ENOUGH(v, unit) (((v) - 1) / (unit) + 1) +#define EZ(v, unit) ((v) ? ENOUGH(v, unit) : 0) + +static void ide_timing_quantize(struct ide_timing *t, struct ide_timing *q, + int T, int UT) +{ + q->setup = EZ(t->setup * 1000, T); + q->act8b = EZ(t->act8b * 1000, T); + q->rec8b = EZ(t->rec8b * 1000, T); + q->cyc8b = EZ(t->cyc8b * 1000, T); + q->active = EZ(t->active * 1000, T); + q->recover = EZ(t->recover * 1000, T); + q->cycle = EZ(t->cycle * 1000, T); + q->udma = EZ(t->udma * 1000, UT); +} + +void ide_timing_merge(struct ide_timing *a, struct ide_timing *b, + struct ide_timing *m, unsigned int what) +{ + if (what & IDE_TIMING_SETUP) + m->setup = max(a->setup, b->setup); + if (what & IDE_TIMING_ACT8B) + m->act8b = max(a->act8b, b->act8b); + if (what & IDE_TIMING_REC8B) + m->rec8b = max(a->rec8b, b->rec8b); + if (what & IDE_TIMING_CYC8B) + m->cyc8b = max(a->cyc8b, b->cyc8b); + if (what & IDE_TIMING_ACTIVE) + m->active = max(a->active, b->active); + if (what & IDE_TIMING_RECOVER) + m->recover = max(a->recover, b->recover); + if (what & IDE_TIMING_CYCLE) + m->cycle = max(a->cycle, b->cycle); + if (what & IDE_TIMING_UDMA) + m->udma = max(a->udma, b->udma); +} +EXPORT_SYMBOL_GPL(ide_timing_merge); + +int ide_timing_compute(ide_drive_t *drive, u8 speed, + struct ide_timing *t, int T, int UT) +{ + u16 *id = drive->id; + struct ide_timing *s, p; + + /* + * Find the mode. + */ + s = ide_timing_find_mode(speed); + if (s == NULL) + return -EINVAL; + + /* + * Copy the timing from the table. + */ + *t = *s; + + /* + * If the drive is an EIDE drive, it can tell us it needs extended + * PIO/MWDMA cycle timing. + */ + if (id[ATA_ID_FIELD_VALID] & 2) { /* EIDE drive */ + memset(&p, 0, sizeof(p)); + + if (speed >= XFER_PIO_0 && speed < XFER_SW_DMA_0) { + if (speed <= XFER_PIO_2) + p.cycle = p.cyc8b = id[ATA_ID_EIDE_PIO]; + else if ((speed <= XFER_PIO_4) || + (speed == XFER_PIO_5 && !ata_id_is_cfa(id))) + p.cycle = p.cyc8b = id[ATA_ID_EIDE_PIO_IORDY]; + } else if (speed >= XFER_MW_DMA_0 && speed <= XFER_MW_DMA_2) + p.cycle = id[ATA_ID_EIDE_DMA_MIN]; + + ide_timing_merge(&p, t, t, IDE_TIMING_CYCLE | IDE_TIMING_CYC8B); + } + + /* + * Convert the timing to bus clock counts. + */ + ide_timing_quantize(t, t, T, UT); + + /* + * Even in DMA/UDMA modes we still use PIO access for IDENTIFY, + * S.M.A.R.T and some other commands. We have to ensure that the + * DMA cycle timing is slower/equal than the current PIO timing. + */ + if (speed >= XFER_SW_DMA_0) { + ide_timing_compute(drive, drive->pio_mode, &p, T, UT); + ide_timing_merge(&p, t, t, IDE_TIMING_ALL); + } + + /* + * Lengthen active & recovery time so that cycle time is correct. + */ + if (t->act8b + t->rec8b < t->cyc8b) { + t->act8b += (t->cyc8b - (t->act8b + t->rec8b)) / 2; + t->rec8b = t->cyc8b - t->act8b; + } + + if (t->active + t->recover < t->cycle) { + t->active += (t->cycle - (t->active + t->recover)) / 2; + t->recover = t->cycle - t->active; + } + + return 0; +} +EXPORT_SYMBOL_GPL(ide_timing_compute); diff --git a/drivers/ide/ide-xfer-mode.c b/drivers/ide/ide-xfer-mode.c new file mode 100644 index 00000000000..eb421883c16 --- /dev/null +++ b/drivers/ide/ide-xfer-mode.c @@ -0,0 +1,266 @@ +#include <linux/types.h> +#include <linux/string.h> +#include <linux/kernel.h> +#include <linux/export.h> +#include <linux/interrupt.h> +#include <linux/ide.h> +#include <linux/bitops.h> + +static const char *udma_str[] = + { "UDMA/16", "UDMA/25", "UDMA/33", "UDMA/44", + "UDMA/66", "UDMA/100", "UDMA/133", "UDMA7" }; +static const char *mwdma_str[] = + { "MWDMA0", "MWDMA1", "MWDMA2", "MWDMA3", "MWDMA4" }; +static const char *swdma_str[] = + { "SWDMA0", "SWDMA1", "SWDMA2" }; +static const char *pio_str[] = + { "PIO0", "PIO1", "PIO2", "PIO3", "PIO4", "PIO5", "PIO6" }; + +/** + * ide_xfer_verbose - return IDE mode names + * @mode: transfer mode + * + * Returns a constant string giving the name of the mode + * requested. + */ + +const char *ide_xfer_verbose(u8 mode) +{ + const char *s; + u8 i = mode & 0xf; + + if (mode >= XFER_UDMA_0 && mode <= XFER_UDMA_7) + s = udma_str[i]; + else if (mode >= XFER_MW_DMA_0 && mode <= XFER_MW_DMA_4) + s = mwdma_str[i]; + else if (mode >= XFER_SW_DMA_0 && mode <= XFER_SW_DMA_2) + s = swdma_str[i]; + else if (mode >= XFER_PIO_0 && mode <= XFER_PIO_6) + s = pio_str[i & 0x7]; + else if (mode == XFER_PIO_SLOW) + s = "PIO SLOW"; + else + s = "XFER ERROR"; + + return s; +} +EXPORT_SYMBOL(ide_xfer_verbose); + +/** + * ide_get_best_pio_mode - get PIO mode from drive + * @drive: drive to consider + * @mode_wanted: preferred mode + * @max_mode: highest allowed mode + * + * This routine returns the recommended PIO settings for a given drive, + * based on the drive->id information and the ide_pio_blacklist[]. + * + * Drive PIO mode is auto-selected if 255 is passed as mode_wanted. + * This is used by most chipset support modules when "auto-tuning". + */ + +static u8 ide_get_best_pio_mode(ide_drive_t *drive, u8 mode_wanted, u8 max_mode) +{ + u16 *id = drive->id; + int pio_mode = -1, overridden = 0; + + if (mode_wanted != 255) + return min_t(u8, mode_wanted, max_mode); + + if ((drive->hwif->host_flags & IDE_HFLAG_PIO_NO_BLACKLIST) == 0) + pio_mode = ide_scan_pio_blacklist((char *)&id[ATA_ID_PROD]); + + if (pio_mode != -1) { + printk(KERN_INFO "%s: is on PIO blacklist\n", drive->name); + } else { + pio_mode = id[ATA_ID_OLD_PIO_MODES] >> 8; + if (pio_mode > 2) { /* 2 is maximum allowed tPIO value */ + pio_mode = 2; + overridden = 1; + } + + if (id[ATA_ID_FIELD_VALID] & 2) { /* ATA2? */ + if (ata_id_is_cfa(id) && (id[ATA_ID_CFA_MODES] & 7)) + pio_mode = 4 + min_t(int, 2, + id[ATA_ID_CFA_MODES] & 7); + else if (ata_id_has_iordy(id)) { + if (id[ATA_ID_PIO_MODES] & 7) { + overridden = 0; + if (id[ATA_ID_PIO_MODES] & 4) + pio_mode = 5; + else if (id[ATA_ID_PIO_MODES] & 2) + pio_mode = 4; + else + pio_mode = 3; + } + } + } + + if (overridden) + printk(KERN_INFO "%s: tPIO > 2, assuming tPIO = 2\n", + drive->name); + } + + if (pio_mode > max_mode) + pio_mode = max_mode; + + return pio_mode; +} + +int ide_pio_need_iordy(ide_drive_t *drive, const u8 pio) +{ + /* + * IORDY may lead to controller lock up on certain controllers + * if the port is not occupied. + */ + if (pio == 0 && (drive->hwif->port_flags & IDE_PFLAG_PROBING)) + return 0; + return ata_id_pio_need_iordy(drive->id, pio); +} +EXPORT_SYMBOL_GPL(ide_pio_need_iordy); + +int ide_set_pio_mode(ide_drive_t *drive, const u8 mode) +{ + ide_hwif_t *hwif = drive->hwif; + const struct ide_port_ops *port_ops = hwif->port_ops; + + if (hwif->host_flags & IDE_HFLAG_NO_SET_MODE) + return 0; + + if (port_ops == NULL || port_ops->set_pio_mode == NULL) + return -1; + + /* + * TODO: temporary hack for some legacy host drivers that didn't + * set transfer mode on the device in ->set_pio_mode method... + */ + if (port_ops->set_dma_mode == NULL) { + drive->pio_mode = mode; + port_ops->set_pio_mode(hwif, drive); + return 0; + } + + if (hwif->host_flags & IDE_HFLAG_POST_SET_MODE) { + if (ide_config_drive_speed(drive, mode)) + return -1; + drive->pio_mode = mode; + port_ops->set_pio_mode(hwif, drive); + return 0; + } else { + drive->pio_mode = mode; + port_ops->set_pio_mode(hwif, drive); + return ide_config_drive_speed(drive, mode); + } +} + +int ide_set_dma_mode(ide_drive_t *drive, const u8 mode) +{ + ide_hwif_t *hwif = drive->hwif; + const struct ide_port_ops *port_ops = hwif->port_ops; + + if (hwif->host_flags & IDE_HFLAG_NO_SET_MODE) + return 0; + + if (port_ops == NULL || port_ops->set_dma_mode == NULL) + return -1; + + if (hwif->host_flags & IDE_HFLAG_POST_SET_MODE) { + if (ide_config_drive_speed(drive, mode)) + return -1; + drive->dma_mode = mode; + port_ops->set_dma_mode(hwif, drive); + return 0; + } else { + drive->dma_mode = mode; + port_ops->set_dma_mode(hwif, drive); + return ide_config_drive_speed(drive, mode); + } +} +EXPORT_SYMBOL_GPL(ide_set_dma_mode); + +/* req_pio == "255" for auto-tune */ +void ide_set_pio(ide_drive_t *drive, u8 req_pio) +{ + ide_hwif_t *hwif = drive->hwif; + const struct ide_port_ops *port_ops = hwif->port_ops; + u8 host_pio, pio; + + if (port_ops == NULL || port_ops->set_pio_mode == NULL || + (hwif->host_flags & IDE_HFLAG_NO_SET_MODE)) + return; + + BUG_ON(hwif->pio_mask == 0x00); + + host_pio = fls(hwif->pio_mask) - 1; + + pio = ide_get_best_pio_mode(drive, req_pio, host_pio); + + /* + * TODO: + * - report device max PIO mode + * - check req_pio != 255 against device max PIO mode + */ + printk(KERN_DEBUG "%s: host max PIO%d wanted PIO%d%s selected PIO%d\n", + drive->name, host_pio, req_pio, + req_pio == 255 ? "(auto-tune)" : "", pio); + + (void)ide_set_pio_mode(drive, XFER_PIO_0 + pio); +} +EXPORT_SYMBOL_GPL(ide_set_pio); + +/** + * ide_rate_filter - filter transfer mode + * @drive: IDE device + * @speed: desired speed + * + * Given the available transfer modes this function returns + * the best available speed at or below the speed requested. + * + * TODO: check device PIO capabilities + */ + +static u8 ide_rate_filter(ide_drive_t *drive, u8 speed) +{ + ide_hwif_t *hwif = drive->hwif; + u8 mode = ide_find_dma_mode(drive, speed); + + if (mode == 0) { + if (hwif->pio_mask) + mode = fls(hwif->pio_mask) - 1 + XFER_PIO_0; + else + mode = XFER_PIO_4; + } + +/* printk("%s: mode 0x%02x, speed 0x%02x\n", __func__, mode, speed); */ + + return min(speed, mode); +} + +/** + * ide_set_xfer_rate - set transfer rate + * @drive: drive to set + * @rate: speed to attempt to set + * + * General helper for setting the speed of an IDE device. This + * function knows about user enforced limits from the configuration + * which ->set_pio_mode/->set_dma_mode does not. + */ + +int ide_set_xfer_rate(ide_drive_t *drive, u8 rate) +{ + ide_hwif_t *hwif = drive->hwif; + const struct ide_port_ops *port_ops = hwif->port_ops; + + if (port_ops == NULL || port_ops->set_dma_mode == NULL || + (hwif->host_flags & IDE_HFLAG_NO_SET_MODE)) + return -1; + + rate = ide_rate_filter(drive, rate); + + BUG_ON(rate < XFER_PIO_0); + + if (rate >= XFER_PIO_0 && rate <= XFER_PIO_6) + return ide_set_pio_mode(drive, rate); + + return ide_set_dma_mode(drive, rate); +} diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c index 9c8468de1a7..2ce6268a273 100644 --- a/drivers/ide/ide.c +++ b/drivers/ide/ide.c @@ -1,7 +1,6 @@ /* - * linux/drivers/ide/ide.c Version 7.00beta2 Mar 05 2003 - * - * Copyright (C) 1994-1998 Linus Torvalds & authors (see below) + * Copyright (C) 1994-1998 Linus Torvalds & authors (see below) + * Copyright (C) 2003-2005, 2007 Bartlomiej Zolnierkiewicz */ /* @@ -16,10 +15,6 @@ * (usually 14 & 15). * There can be up to two drives per interface, as per the ATA-2 spec. * - * Primary: ide0, port 0x1f0; major=3; hda is minor=0; hdb is minor=64 - * Secondary: ide1, port 0x170; major=22; hdc is minor=0; hdd is minor=64 - * Tertiary: ide2, port 0x???; major=33; hde is minor=0; hdf is minor=64 - * Quaternary: ide3, port 0x???; major=34; hdg is minor=0; hdh is minor=64 * ... * * From hd.c: @@ -47,2038 +42,374 @@ * This was a rewrite of just about everything from hd.c, though some original * code is still sprinkled about. Think of it as a major evolution, with * inspiration from lots of linux users, esp. hamish@zot.apana.org.au - * - * Version 1.0 ALPHA initial code, primary i/f working okay - * Version 1.3 BETA dual i/f on shared irq tested & working! - * Version 1.4 BETA added auto probing for irq(s) - * Version 1.5 BETA added ALPHA (untested) support for IDE cd-roms, - * ... - * Version 5.50 allow values as small as 20 for idebus= - * Version 5.51 force non io_32bit in drive_cmd_intr() - * change delay_10ms() to delay_50ms() to fix problems - * Version 5.52 fix incorrect invalidation of removable devices - * add "hdx=slow" command line option - * Version 5.60 start to modularize the driver; the disk and ATAPI - * drivers can be compiled as loadable modules. - * move IDE probe code to ide-probe.c - * move IDE disk code to ide-disk.c - * add support for generic IDE device subdrivers - * add m68k code from Geert Uytterhoeven - * probe all interfaces by default - * add ioctl to (re)probe an interface - * Version 6.00 use per device request queues - * attempt to optimize shared hwgroup performance - * add ioctl to manually adjust bandwidth algorithms - * add kerneld support for the probe module - * fix bug in ide_error() - * fix bug in the first ide_get_lock() call for Atari - * don't flush leftover data for ATAPI devices - * Version 6.01 clear hwgroup->active while the hwgroup sleeps - * support HDIO_GETGEO for floppies - * Version 6.02 fix ide_ack_intr() call - * check partition table on floppies - * Version 6.03 handle bad status bit sequencing in ide_wait_stat() - * Version 6.10 deleted old entries from this list of updates - * replaced triton.c with ide-dma.c generic PCI DMA - * added support for BIOS-enabled UltraDMA - * rename all "promise" things to "pdc4030" - * fix EZ-DRIVE handling on small disks - * Version 6.11 fix probe error in ide_scan_devices() - * fix ancient "jiffies" polling bugs - * mask all hwgroup interrupts on each irq entry - * Version 6.12 integrate ioctl and proc interfaces - * fix parsing of "idex=" command line parameter - * Version 6.13 add support for ide4/ide5 courtesy rjones@orchestream.com - * Version 6.14 fixed IRQ sharing among PCI devices - * Version 6.15 added SMP awareness to IDE drivers - * Version 6.16 fixed various bugs; even more SMP friendly - * Version 6.17 fix for newest EZ-Drive problem - * Version 6.18 default unpartitioned-disk translation now "BIOS LBA" - * Version 6.19 Re-design for a UNIFORM driver for all platforms, - * model based on suggestions from Russell King and - * Geert Uytterhoeven - * Promise DC4030VL now supported. - * add support for ide6/ide7 - * delay_50ms() changed to ide_delay_50ms() and exported. - * Version 6.20 Added/Fixed Generic ATA-66 support and hwif detection. - * Added hdx=flash to allow for second flash disk - * detection w/o the hang loop. - * Added support for ide8/ide9 - * Added idex=ata66 for the quirky chipsets that are - * ATA-66 compliant, but have yet to determine a method - * of verification of the 80c cable presence. - * Specifically Promise's PDC20262 chipset. - * Version 6.21 Fixing/Fixed SMP spinlock issue with insight from an old - * hat that clarified original low level driver design. - * Version 6.30 Added SMP support; fixed multmode issues. -ml - * Version 6.31 Debug Share INTR's and request queue streaming - * Native ATA-100 support - * Prep for Cascades Project - * Version 7.00alpha First named revision of ide rearrange - * - * Some additional driver compile-time options are in ./include/linux/ide.h - * - * To do, in likely order of completion: - * - modify kernel to obtain BIOS geometry for drives on 2nd/3rd/4th i/f - * */ -#define REVISION "Revision: 7.00alpha2" -#define VERSION "Id: ide.c 7.00a2 20020906" - -#undef REALLY_SLOW_IO /* most systems can safely undef this */ - -#define _IDE_C /* Tell ide.h it's really us */ - #include <linux/module.h> #include <linux/types.h> #include <linux/string.h> #include <linux/kernel.h> -#include <linux/timer.h> -#include <linux/mm.h> #include <linux/interrupt.h> #include <linux/major.h> #include <linux/errno.h> #include <linux/genhd.h> -#include <linux/blkpg.h> -#include <linux/slab.h> #include <linux/init.h> #include <linux/pci.h> -#include <linux/delay.h> #include <linux/ide.h> +#include <linux/hdreg.h> #include <linux/completion.h> -#include <linux/reboot.h> -#include <linux/cdrom.h> -#include <linux/seq_file.h> #include <linux/device.h> -#include <linux/bitops.h> - -#include <asm/byteorder.h> -#include <asm/irq.h> -#include <asm/uaccess.h> -#include <asm/io.h> - - -/* default maximum number of failures */ -#define IDE_DEFAULT_MAX_FAILURES 1 - -static const u8 ide_hwif_to_major[] = { IDE0_MAJOR, IDE1_MAJOR, - IDE2_MAJOR, IDE3_MAJOR, - IDE4_MAJOR, IDE5_MAJOR, - IDE6_MAJOR, IDE7_MAJOR, - IDE8_MAJOR, IDE9_MAJOR }; - -static int idebus_parameter; /* holds the "idebus=" parameter */ -static int system_bus_speed; /* holds what we think is VESA/PCI bus speed */ -static int initializing; /* set while initializing built-in drivers */ -DECLARE_MUTEX(ide_cfg_sem); - __cacheline_aligned_in_smp DEFINE_SPINLOCK(ide_lock); - -#ifdef CONFIG_BLK_DEV_IDEPCI -static int ide_scan_direction; /* THIS was formerly 2.2.x pci=reverse */ -#endif - -#ifdef CONFIG_IDEDMA_AUTO -int noautodma = 0; -#else -int noautodma = 1; -#endif - -EXPORT_SYMBOL(noautodma); - -/* - * This is declared extern in ide.h, for access by other IDE modules: - */ -ide_hwif_t ide_hwifs[MAX_HWIFS]; /* master data repository */ - -EXPORT_SYMBOL(ide_hwifs); - -/* - * Do not even *think* about calling this! - */ -static void init_hwif_data(ide_hwif_t *hwif, unsigned int index) -{ - unsigned int unit; - - /* bulk initialize hwif & drive info with zeros */ - memset(hwif, 0, sizeof(ide_hwif_t)); - - /* fill in any non-zero initial values */ - hwif->index = index; - hwif->major = ide_hwif_to_major[index]; - - hwif->name[0] = 'i'; - hwif->name[1] = 'd'; - hwif->name[2] = 'e'; - hwif->name[3] = '0' + index; - - hwif->bus_state = BUSSTATE_ON; - - hwif->atapi_dma = 0; /* disable all atapi dma */ - hwif->ultra_mask = 0x80; /* disable all ultra */ - hwif->mwdma_mask = 0x80; /* disable all mwdma */ - hwif->swdma_mask = 0x80; /* disable all swdma */ - - init_completion(&hwif->gendev_rel_comp); - - default_hwif_iops(hwif); - default_hwif_transport(hwif); - for (unit = 0; unit < MAX_DRIVES; ++unit) { - ide_drive_t *drive = &hwif->drives[unit]; - - drive->media = ide_disk; - drive->select.all = (unit<<4)|0xa0; - drive->hwif = hwif; - drive->ctl = 0x08; - drive->ready_stat = READY_STAT; - drive->bad_wstat = BAD_W_STAT; - drive->special.b.recalibrate = 1; - drive->special.b.set_geometry = 1; - drive->name[0] = 'h'; - drive->name[1] = 'd'; - drive->name[2] = 'a' + (index * MAX_DRIVES) + unit; - drive->max_failures = IDE_DEFAULT_MAX_FAILURES; - drive->using_dma = 0; - drive->vdma = 0; - INIT_LIST_HEAD(&drive->list); - init_completion(&drive->gendev_rel_comp); - } -} - -static void init_hwif_default(ide_hwif_t *hwif, unsigned int index) -{ - hw_regs_t hw; - - memset(&hw, 0, sizeof(hw_regs_t)); - - ide_init_hwif_ports(&hw, ide_default_io_base(index), 0, &hwif->irq); - - memcpy(&hwif->hw, &hw, sizeof(hw)); - memcpy(hwif->io_ports, hw.io_ports, sizeof(hw.io_ports)); - - hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET]; -#ifdef CONFIG_BLK_DEV_HD - if (hwif->io_ports[IDE_DATA_OFFSET] == HD_DATA) - hwif->noprobe = 1; /* may be overridden by ide_setup() */ -#endif -} - -extern void ide_arm_init(void); - -/* - * init_ide_data() sets reasonable default values into all fields - * of all instances of the hwifs and drives, but only on the first call. - * Subsequent calls have no effect (they don't wipe out anything). - * - * This routine is normally called at driver initialization time, - * but may also be called MUCH earlier during kernel "command-line" - * parameter processing. As such, we cannot depend on any other parts - * of the kernel (such as memory allocation) to be functioning yet. - * - * This is too bad, as otherwise we could dynamically allocate the - * ide_drive_t structs as needed, rather than always consuming memory - * for the max possible number (MAX_HWIFS * MAX_DRIVES) of them. - * - * FIXME: We should stuff the setup data into __init and copy the - * relevant hwifs/allocate them properly during boot. - */ -#define MAGIC_COOKIE 0x12345678 -static void __init init_ide_data (void) -{ - ide_hwif_t *hwif; - unsigned int index; - static unsigned long magic_cookie = MAGIC_COOKIE; - - if (magic_cookie != MAGIC_COOKIE) - return; /* already initialized */ - magic_cookie = 0; - - /* Initialise all interface structures */ - for (index = 0; index < MAX_HWIFS; ++index) { - hwif = &ide_hwifs[index]; - init_hwif_data(hwif, index); - init_hwif_default(hwif, index); -#if !defined(CONFIG_PPC32) || !defined(CONFIG_PCI) - hwif->irq = hwif->hw.irq = - ide_init_default_irq(hwif->io_ports[IDE_DATA_OFFSET]); -#endif - } -#ifdef CONFIG_IDE_ARM - initializing = 1; - ide_arm_init(); - initializing = 0; -#endif -} +struct class *ide_port_class; /** - * ide_system_bus_speed - guess bus speed - * - * ide_system_bus_speed() returns what we think is the system VESA/PCI - * bus speed (in MHz). This is used for calculating interface PIO timings. - * The default is 40 for known PCI systems, 50 otherwise. - * The "idebus=xx" parameter can be used to override this value. - * The actual value to be used is computed/displayed the first time - * through. Drivers should only use this as a last resort. + * ide_device_get - get an additional reference to a ide_drive_t + * @drive: device to get a reference to * - * Returns a guessed speed in MHz. + * Gets a reference to the ide_drive_t and increments the use count of the + * underlying LLDD module. */ - -static int ide_system_bus_speed(void) +int ide_device_get(ide_drive_t *drive) { -#ifdef CONFIG_PCI - static struct pci_device_id pci_default[] = { - { PCI_DEVICE(PCI_ANY_ID, PCI_ANY_ID) }, - { } - }; -#else -#define pci_default 0 -#endif /* CONFIG_PCI */ - - if (!system_bus_speed) { - if (idebus_parameter) { - /* user supplied value */ - system_bus_speed = idebus_parameter; - } else if (pci_dev_present(pci_default)) { - /* safe default value for PCI */ - system_bus_speed = 33; - } else { - /* safe default value for VESA and PCI */ - system_bus_speed = 50; - } - printk(KERN_INFO "ide: Assuming %dMHz system bus speed " - "for PIO modes%s\n", system_bus_speed, - idebus_parameter ? "" : "; override with idebus=xx"); - } - return system_bus_speed; -} + struct device *host_dev; + struct module *module; -#ifdef CONFIG_PROC_FS -struct proc_dir_entry *proc_ide_root; -#endif + if (!get_device(&drive->gendev)) + return -ENXIO; -static struct resource* hwif_request_region(ide_hwif_t *hwif, - unsigned long addr, int num) -{ - struct resource *res = request_region(addr, num, hwif->name); - - if (!res) - printk(KERN_ERR "%s: I/O resource 0x%lX-0x%lX not free.\n", - hwif->name, addr, addr+num-1); - return res; -} + host_dev = drive->hwif->host->dev[0]; + module = host_dev ? host_dev->driver->owner : NULL; -/** - * ide_hwif_request_regions - request resources for IDE - * @hwif: interface to use - * - * Requests all the needed resources for an interface. - * Right now core IDE code does this work which is deeply wrong. - * MMIO leaves it to the controller driver, - * PIO will migrate this way over time. - */ - -int ide_hwif_request_regions(ide_hwif_t *hwif) -{ - unsigned long addr; - unsigned int i; - - if (hwif->mmio == 2) - return 0; - BUG_ON(hwif->mmio == 1); - addr = hwif->io_ports[IDE_CONTROL_OFFSET]; - if (addr && !hwif_request_region(hwif, addr, 1)) - goto control_region_busy; - hwif->straight8 = 0; - addr = hwif->io_ports[IDE_DATA_OFFSET]; - if ((addr | 7) == hwif->io_ports[IDE_STATUS_OFFSET]) { - if (!hwif_request_region(hwif, addr, 8)) - goto data_region_busy; - hwif->straight8 = 1; - return 0; - } - for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) { - addr = hwif->io_ports[i]; - if (!hwif_request_region(hwif, addr, 1)) { - while (--i) - release_region(addr, 1); - goto data_region_busy; - } + if (module && !try_module_get(module)) { + put_device(&drive->gendev); + return -ENXIO; } - return 0; - -data_region_busy: - addr = hwif->io_ports[IDE_CONTROL_OFFSET]; - if (addr) - release_region(addr, 1); -control_region_busy: - /* If any errors are return, we drop the hwif interface. */ - return -EBUSY; -} - -/** - * ide_hwif_release_regions - free IDE resources - * - * Note that we only release the standard ports, - * and do not even try to handle any extra ports - * allocated for weird IDE interface chipsets. - * - * Note also that we don't yet handle mmio resources here. More - * importantly our caller should be doing this so we need to - * restructure this as a helper function for drivers. - */ -void ide_hwif_release_regions(ide_hwif_t *hwif) -{ - u32 i = 0; - - if (hwif->mmio == 2) - return; - if (hwif->io_ports[IDE_CONTROL_OFFSET]) - release_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1); - if (hwif->straight8) { - release_region(hwif->io_ports[IDE_DATA_OFFSET], 8); - return; - } - for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) - if (hwif->io_ports[i]) - release_region(hwif->io_ports[i], 1); + return 0; } +EXPORT_SYMBOL_GPL(ide_device_get); /** - * ide_hwif_restore - restore hwif to template - * @hwif: hwif to update - * @tmp_hwif: template + * ide_device_put - release a reference to a ide_drive_t + * @drive: device to release a reference on * - * Restore hwif to a previous state by copying most settngs - * from the template. + * Release a reference to the ide_drive_t and decrements the use count of + * the underlying LLDD module. */ - -static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif) +void ide_device_put(ide_drive_t *drive) { - hwif->hwgroup = tmp_hwif->hwgroup; +#ifdef CONFIG_MODULE_UNLOAD + struct device *host_dev = drive->hwif->host->dev[0]; + struct module *module = host_dev ? host_dev->driver->owner : NULL; - hwif->gendev.parent = tmp_hwif->gendev.parent; - - hwif->proc = tmp_hwif->proc; - - hwif->major = tmp_hwif->major; - hwif->straight8 = tmp_hwif->straight8; - hwif->bus_state = tmp_hwif->bus_state; - - hwif->atapi_dma = tmp_hwif->atapi_dma; - hwif->ultra_mask = tmp_hwif->ultra_mask; - hwif->mwdma_mask = tmp_hwif->mwdma_mask; - hwif->swdma_mask = tmp_hwif->swdma_mask; - - hwif->chipset = tmp_hwif->chipset; - hwif->hold = tmp_hwif->hold; - -#ifdef CONFIG_BLK_DEV_IDEPCI - hwif->pci_dev = tmp_hwif->pci_dev; - hwif->cds = tmp_hwif->cds; -#endif - - hwif->tuneproc = tmp_hwif->tuneproc; - hwif->speedproc = tmp_hwif->speedproc; - hwif->selectproc = tmp_hwif->selectproc; - hwif->reset_poll = tmp_hwif->reset_poll; - hwif->pre_reset = tmp_hwif->pre_reset; - hwif->resetproc = tmp_hwif->resetproc; - hwif->intrproc = tmp_hwif->intrproc; - hwif->maskproc = tmp_hwif->maskproc; - hwif->quirkproc = tmp_hwif->quirkproc; - hwif->busproc = tmp_hwif->busproc; - - hwif->ata_input_data = tmp_hwif->ata_input_data; - hwif->ata_output_data = tmp_hwif->ata_output_data; - hwif->atapi_input_bytes = tmp_hwif->atapi_input_bytes; - hwif->atapi_output_bytes = tmp_hwif->atapi_output_bytes; - - hwif->dma_setup = tmp_hwif->dma_setup; - hwif->dma_exec_cmd = tmp_hwif->dma_exec_cmd; - hwif->dma_start = tmp_hwif->dma_start; - hwif->ide_dma_end = tmp_hwif->ide_dma_end; - hwif->ide_dma_check = tmp_hwif->ide_dma_check; - hwif->ide_dma_on = tmp_hwif->ide_dma_on; - hwif->ide_dma_off_quietly = tmp_hwif->ide_dma_off_quietly; - hwif->ide_dma_test_irq = tmp_hwif->ide_dma_test_irq; - hwif->ide_dma_host_on = tmp_hwif->ide_dma_host_on; - hwif->ide_dma_host_off = tmp_hwif->ide_dma_host_off; - hwif->ide_dma_lostirq = tmp_hwif->ide_dma_lostirq; - hwif->ide_dma_timeout = tmp_hwif->ide_dma_timeout; - - hwif->OUTB = tmp_hwif->OUTB; - hwif->OUTBSYNC = tmp_hwif->OUTBSYNC; - hwif->OUTW = tmp_hwif->OUTW; - hwif->OUTL = tmp_hwif->OUTL; - hwif->OUTSW = tmp_hwif->OUTSW; - hwif->OUTSL = tmp_hwif->OUTSL; - - hwif->INB = tmp_hwif->INB; - hwif->INW = tmp_hwif->INW; - hwif->INL = tmp_hwif->INL; - hwif->INSW = tmp_hwif->INSW; - hwif->INSL = tmp_hwif->INSL; - - hwif->sg_max_nents = tmp_hwif->sg_max_nents; - - hwif->mmio = tmp_hwif->mmio; - hwif->rqsize = tmp_hwif->rqsize; - hwif->no_lba48 = tmp_hwif->no_lba48; - -#ifndef CONFIG_BLK_DEV_IDECS - hwif->irq = tmp_hwif->irq; + if (module) + module_put(module); #endif - - hwif->dma_base = tmp_hwif->dma_base; - hwif->dma_master = tmp_hwif->dma_master; - hwif->dma_command = tmp_hwif->dma_command; - hwif->dma_vendor1 = tmp_hwif->dma_vendor1; - hwif->dma_status = tmp_hwif->dma_status; - hwif->dma_vendor3 = tmp_hwif->dma_vendor3; - hwif->dma_prdtable = tmp_hwif->dma_prdtable; - - hwif->dma_extra = tmp_hwif->dma_extra; - hwif->config_data = tmp_hwif->config_data; - hwif->select_data = tmp_hwif->select_data; - hwif->autodma = tmp_hwif->autodma; - hwif->udma_four = tmp_hwif->udma_four; - hwif->no_dsc = tmp_hwif->no_dsc; - - hwif->hwif_data = tmp_hwif->hwif_data; + put_device(&drive->gendev); } +EXPORT_SYMBOL_GPL(ide_device_put); -/** - * ide_unregister - free an ide interface - * @index: index of interface (will change soon to a pointer) - * - * Perform the final unregister of an IDE interface. At the moment - * we don't refcount interfaces so this will also get split up. - * - * Locking: - * The caller must not hold the IDE locks - * The drive present/vanishing is not yet properly locked - * Take care with the callbacks. These have been split to avoid - * deadlocking the IDE layer. The shutdown callback is called - * before we take the lock and free resources. It is up to the - * caller to be sure there is no pending I/O here, and that - * the interfce will not be reopened (present/vanishing locking - * isnt yet done btw). After we commit to the final kill we - * call the cleanup callback with the ide locks held. - * - * Unregister restores the hwif structures to the default state. - * This is raving bonkers. - */ - -void ide_unregister(unsigned int index) +static int ide_bus_match(struct device *dev, struct device_driver *drv) { - ide_drive_t *drive; - ide_hwif_t *hwif, *g; - static ide_hwif_t tmp_hwif; /* protected by ide_cfg_sem */ - ide_hwgroup_t *hwgroup; - int irq_count = 0, unit; - - BUG_ON(index >= MAX_HWIFS); - - BUG_ON(in_interrupt()); - BUG_ON(irqs_disabled()); - down(&ide_cfg_sem); - spin_lock_irq(&ide_lock); - hwif = &ide_hwifs[index]; - if (!hwif->present) - goto abort; - for (unit = 0; unit < MAX_DRIVES; ++unit) { - drive = &hwif->drives[unit]; - if (!drive->present) - continue; - spin_unlock_irq(&ide_lock); - device_unregister(&drive->gendev); - wait_for_completion(&drive->gendev_rel_comp); - spin_lock_irq(&ide_lock); - } - hwif->present = 0; - - spin_unlock_irq(&ide_lock); - - destroy_proc_ide_interface(hwif); - - hwgroup = hwif->hwgroup; - /* - * free the irq if we were the only hwif using it - */ - g = hwgroup->hwif; - do { - if (g->irq == hwif->irq) - ++irq_count; - g = g->next; - } while (g != hwgroup->hwif); - if (irq_count == 1) - free_irq(hwif->irq, hwgroup); - - spin_lock_irq(&ide_lock); - /* - * Note that we only release the standard ports, - * and do not even try to handle any extra ports - * allocated for weird IDE interface chipsets. - */ - ide_hwif_release_regions(hwif); - - /* - * Remove us from the hwgroup, and free - * the hwgroup if we were the only member - */ - if (hwif->next == hwif) { - BUG_ON(hwgroup->hwif != hwif); - kfree(hwgroup); - } else { - /* There is another interface in hwgroup. - * Unlink us, and set hwgroup->drive and ->hwif to - * something sane. - */ - g = hwgroup->hwif; - while (g->next != hwif) - g = g->next; - g->next = hwif->next; - if (hwgroup->hwif == hwif) { - /* Chose a random hwif for hwgroup->hwif. - * It's guaranteed that there are no drives - * left in the hwgroup. - */ - BUG_ON(hwgroup->drive != NULL); - hwgroup->hwif = g; - } - BUG_ON(hwgroup->hwif == hwif); - } - - /* More messed up locking ... */ - spin_unlock_irq(&ide_lock); - device_unregister(&hwif->gendev); - wait_for_completion(&hwif->gendev_rel_comp); - - /* - * Remove us from the kernel's knowledge - */ - blk_unregister_region(MKDEV(hwif->major, 0), MAX_DRIVES<<PARTN_BITS); - kfree(hwif->sg_table); - unregister_blkdev(hwif->major, hwif->name); - spin_lock_irq(&ide_lock); - - if (hwif->dma_base) { - (void) ide_release_dma(hwif); - - hwif->dma_base = 0; - hwif->dma_master = 0; - hwif->dma_command = 0; - hwif->dma_vendor1 = 0; - hwif->dma_status = 0; - hwif->dma_vendor3 = 0; - hwif->dma_prdtable = 0; - } - - /* copy original settings */ - tmp_hwif = *hwif; - - /* restore hwif data to pristine status */ - init_hwif_data(hwif, index); - init_hwif_default(hwif, index); - - ide_hwif_restore(hwif, &tmp_hwif); - -abort: - spin_unlock_irq(&ide_lock); - up(&ide_cfg_sem); + return 1; } -EXPORT_SYMBOL(ide_unregister); - - -/** - * ide_setup_ports - set up IDE interface ports - * @hw: register descriptions - * @base: base register - * @offsets: table of register offsets - * @ctrl: control register - * @ack_irq: IRQ ack - * @irq: interrupt lie - * - * Setup hw_regs_t structure described by parameters. You - * may set up the hw structure yourself OR use this routine to - * do it for you. This is basically a helper - * - */ - -void ide_setup_ports ( hw_regs_t *hw, - unsigned long base, int *offsets, - unsigned long ctrl, unsigned long intr, - ide_ack_intr_t *ack_intr, -/* - * ide_io_ops_t *iops, - */ - int irq) +static int ide_uevent(struct device *dev, struct kobj_uevent_env *env) { - int i; + ide_drive_t *drive = to_ide_device(dev); - memset(hw, 0, sizeof(hw_regs_t)); - for (i = 0; i < IDE_NR_PORTS; i++) { - if (offsets[i] == -1) { - switch(i) { - case IDE_CONTROL_OFFSET: - hw->io_ports[i] = ctrl; - break; -#if defined(CONFIG_AMIGA) || defined(CONFIG_MAC) - case IDE_IRQ_OFFSET: - hw->io_ports[i] = intr; - break; -#endif /* (CONFIG_AMIGA) || (CONFIG_MAC) */ - default: - hw->io_ports[i] = 0; - break; - } - } else { - hw->io_ports[i] = base + offsets[i]; - } - } - hw->irq = irq; - hw->dma = NO_DMA; - hw->ack_intr = ack_intr; -/* - * hw->iops = iops; - */ + add_uevent_var(env, "MEDIA=%s", ide_media_string(drive)); + add_uevent_var(env, "DRIVENAME=%s", drive->name); + add_uevent_var(env, "MODALIAS=ide:m-%s", ide_media_string(drive)); + return 0; } -/** - * ide_register_hw_with_fixup - register IDE interface - * @hw: hardware registers - * @hwifp: pointer to returned hwif - * @fixup: fixup function - * - * Register an IDE interface, specifying exactly the registers etc. - * Set init=1 iff calling before probes have taken place. - * - * Returns -1 on error. - */ - -int ide_register_hw_with_fixup(hw_regs_t *hw, ide_hwif_t **hwifp, void(*fixup)(ide_hwif_t *hwif)) +static int generic_ide_probe(struct device *dev) { - int index, retry = 1; - ide_hwif_t *hwif; - - do { - for (index = 0; index < MAX_HWIFS; ++index) { - hwif = &ide_hwifs[index]; - if (hwif->hw.io_ports[IDE_DATA_OFFSET] == hw->io_ports[IDE_DATA_OFFSET]) - goto found; - } - for (index = 0; index < MAX_HWIFS; ++index) { - hwif = &ide_hwifs[index]; - if (hwif->hold) - continue; - if ((!hwif->present && !hwif->mate && !initializing) || - (!hwif->hw.io_ports[IDE_DATA_OFFSET] && initializing)) - goto found; - } - for (index = 0; index < MAX_HWIFS; index++) - ide_unregister(index); - } while (retry--); - return -1; -found: - if (hwif->present) - ide_unregister(index); - else if (!hwif->hold) { - init_hwif_data(hwif, index); - init_hwif_default(hwif, index); - } - if (hwif->present) - return -1; - memcpy(&hwif->hw, hw, sizeof(*hw)); - memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->hw.io_ports)); - hwif->irq = hw->irq; - hwif->noprobe = 0; - hwif->chipset = hw->chipset; - hwif->gendev.parent = hw->dev; - - if (!initializing) { - probe_hwif_init_with_fixup(hwif, fixup); - create_proc_ide_interfaces(); - } - - if (hwifp) - *hwifp = hwif; + ide_drive_t *drive = to_ide_device(dev); + struct ide_driver *drv = to_ide_driver(dev->driver); - return (initializing || hwif->present) ? index : -1; + return drv->probe ? drv->probe(drive) : -ENODEV; } -EXPORT_SYMBOL(ide_register_hw_with_fixup); - -int ide_register_hw(hw_regs_t *hw, ide_hwif_t **hwifp) +static int generic_ide_remove(struct device *dev) { - return ide_register_hw_with_fixup(hw, hwifp, NULL); -} - -EXPORT_SYMBOL(ide_register_hw); - -/* - * Locks for IDE setting functionality - */ - -DECLARE_MUTEX(ide_setting_sem); + ide_drive_t *drive = to_ide_device(dev); + struct ide_driver *drv = to_ide_driver(dev->driver); -/** - * __ide_add_setting - add an ide setting option - * @drive: drive to use - * @name: setting name - * @rw: true if the function is read write - * @read_ioctl: function to call on read - * @write_ioctl: function to call on write - * @data_type: type of data - * @min: range minimum - * @max: range maximum - * @mul_factor: multiplication scale - * @div_factor: divison scale - * @data: private data field - * @set: setting - * @auto_remove: setting auto removal flag - * - * Removes the setting named from the device if it is present. - * The function takes the settings_lock to protect against - * parallel changes. This function must not be called from IRQ - * context. Returns 0 on success or -1 on failure. - * - * BUGS: This code is seriously over-engineered. There is also - * magic about how the driver specific features are setup. If - * a driver is attached we assume the driver settings are auto - * remove. - */ + if (drv->remove) + drv->remove(drive); -static int __ide_add_setting(ide_drive_t *drive, const char *name, int rw, int read_ioctl, int write_ioctl, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set, int auto_remove) -{ - ide_settings_t **p = (ide_settings_t **) &drive->settings, *setting = NULL; - - down(&ide_setting_sem); - while ((*p) && strcmp((*p)->name, name) < 0) - p = &((*p)->next); - if ((setting = kzalloc(sizeof(*setting), GFP_KERNEL)) == NULL) - goto abort; - if ((setting->name = kmalloc(strlen(name) + 1, GFP_KERNEL)) == NULL) - goto abort; - strcpy(setting->name, name); - setting->rw = rw; - setting->read_ioctl = read_ioctl; - setting->write_ioctl = write_ioctl; - setting->data_type = data_type; - setting->min = min; - setting->max = max; - setting->mul_factor = mul_factor; - setting->div_factor = div_factor; - setting->data = data; - setting->set = set; - - setting->next = *p; - if (auto_remove) - setting->auto_remove = 1; - *p = setting; - up(&ide_setting_sem); return 0; -abort: - up(&ide_setting_sem); - kfree(setting); - return -1; -} - -int ide_add_setting(ide_drive_t *drive, const char *name, int rw, int read_ioctl, int write_ioctl, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set) -{ - return __ide_add_setting(drive, name, rw, read_ioctl, write_ioctl, data_type, min, max, mul_factor, div_factor, data, set, 1); } -EXPORT_SYMBOL(ide_add_setting); - -/** - * __ide_remove_setting - remove an ide setting option - * @drive: drive to use - * @name: setting name - * - * Removes the setting named from the device if it is present. - * The caller must hold the setting semaphore. - */ - -static void __ide_remove_setting (ide_drive_t *drive, char *name) +static void generic_ide_shutdown(struct device *dev) { - ide_settings_t **p, *setting; - - p = (ide_settings_t **) &drive->settings; - - while ((*p) && strcmp((*p)->name, name)) - p = &((*p)->next); - if ((setting = (*p)) == NULL) - return; + ide_drive_t *drive = to_ide_device(dev); + struct ide_driver *drv = to_ide_driver(dev->driver); - (*p) = setting->next; - - kfree(setting->name); - kfree(setting); + if (dev->driver && drv->shutdown) + drv->shutdown(drive); } -/** - * ide_find_setting_by_ioctl - find a drive specific ioctl - * @drive: drive to scan - * @cmd: ioctl command to handle - * - * Scan's the device setting table for a matching entry and returns - * this or NULL if no entry is found. The caller must hold the - * setting semaphore - */ - -static ide_settings_t *ide_find_setting_by_ioctl (ide_drive_t *drive, int cmd) -{ - ide_settings_t *setting = drive->settings; - - while (setting) { - if (setting->read_ioctl == cmd || setting->write_ioctl == cmd) - break; - setting = setting->next; - } - - return setting; -} +struct bus_type ide_bus_type = { + .name = "ide", + .match = ide_bus_match, + .uevent = ide_uevent, + .probe = generic_ide_probe, + .remove = generic_ide_remove, + .shutdown = generic_ide_shutdown, + .dev_groups = ide_dev_groups, + .suspend = generic_ide_suspend, + .resume = generic_ide_resume, +}; -/** - * ide_find_setting_by_name - find a drive specific setting - * @drive: drive to scan - * @name: setting name - * - * Scan's the device setting table for a matching entry and returns - * this or NULL if no entry is found. The caller must hold the - * setting semaphore - */ - -ide_settings_t *ide_find_setting_by_name (ide_drive_t *drive, char *name) -{ - ide_settings_t *setting = drive->settings; +EXPORT_SYMBOL_GPL(ide_bus_type); - while (setting) { - if (strcmp(setting->name, name) == 0) - break; - setting = setting->next; - } - return setting; -} +int ide_vlb_clk; +EXPORT_SYMBOL_GPL(ide_vlb_clk); -/** - * auto_remove_settings - remove driver specific settings - * @drive: drive - * - * Automatically remove all the driver specific settings for this - * drive. This function may sleep and must not be called from IRQ - * context. The caller must hold ide_setting_sem. - */ - -static void auto_remove_settings (ide_drive_t *drive) -{ - ide_settings_t *setting; -repeat: - setting = drive->settings; - while (setting) { - if (setting->auto_remove) { - __ide_remove_setting(drive, setting->name); - goto repeat; - } - setting = setting->next; - } -} +module_param_named(vlb_clock, ide_vlb_clk, int, 0); +MODULE_PARM_DESC(vlb_clock, "VLB clock frequency (in MHz)"); -/** - * ide_read_setting - read an IDE setting - * @drive: drive to read from - * @setting: drive setting - * - * Read a drive setting and return the value. The caller - * must hold the ide_setting_sem when making this call. - * - * BUGS: the data return and error are the same return value - * so an error -EINVAL and true return of the same value cannot - * be told apart - */ - -int ide_read_setting (ide_drive_t *drive, ide_settings_t *setting) -{ - int val = -EINVAL; - unsigned long flags; - - if ((setting->rw & SETTING_READ)) { - spin_lock_irqsave(&ide_lock, flags); - switch(setting->data_type) { - case TYPE_BYTE: - val = *((u8 *) setting->data); - break; - case TYPE_SHORT: - val = *((u16 *) setting->data); - break; - case TYPE_INT: - case TYPE_INTA: - val = *((u32 *) setting->data); - break; - } - spin_unlock_irqrestore(&ide_lock, flags); - } - return val; -} +int ide_pci_clk; +EXPORT_SYMBOL_GPL(ide_pci_clk); -/** - * ide_spin_wait_hwgroup - wait for group - * @drive: drive in the group - * - * Wait for an IDE device group to go non busy and then return - * holding the ide_lock which guards the hwgroup->busy status - * and right to use it. - */ +module_param_named(pci_clock, ide_pci_clk, int, 0); +MODULE_PARM_DESC(pci_clock, "PCI bus clock frequency (in MHz)"); -int ide_spin_wait_hwgroup (ide_drive_t *drive) +static int ide_set_dev_param_mask(const char *s, const struct kernel_param *kp) { - ide_hwgroup_t *hwgroup = HWGROUP(drive); - unsigned long timeout = jiffies + (3 * HZ); - - spin_lock_irq(&ide_lock); - - while (hwgroup->busy) { - unsigned long lflags; - spin_unlock_irq(&ide_lock); - local_irq_set(lflags); - if (time_after(jiffies, timeout)) { - local_irq_restore(lflags); - printk(KERN_ERR "%s: channel busy\n", drive->name); - return -EBUSY; - } - local_irq_restore(lflags); - spin_lock_irq(&ide_lock); - } - return 0; -} - -EXPORT_SYMBOL(ide_spin_wait_hwgroup); + int a, b, i, j = 1; + unsigned int *dev_param_mask = (unsigned int *)kp->arg; -/** - * ide_write_setting - read an IDE setting - * @drive: drive to read from - * @setting: drive setting - * @val: value - * - * Write a drive setting if it is possible. The caller - * must hold the ide_setting_sem when making this call. - * - * BUGS: the data return and error are the same return value - * so an error -EINVAL and true return of the same value cannot - * be told apart - * - * FIXME: This should be changed to enqueue a special request - * to the driver to change settings, and then wait on a sema for completion. - * The current scheme of polling is kludgy, though safe enough. - */ + /* controller . device (0 or 1) [ : 1 (set) | 0 (clear) ] */ + if (sscanf(s, "%d.%d:%d", &a, &b, &j) != 3 && + sscanf(s, "%d.%d", &a, &b) != 2) + return -EINVAL; -int ide_write_setting (ide_drive_t *drive, ide_settings_t *setting, int val) -{ - int i; - u32 *p; + i = a * MAX_DRIVES + b; - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; - if (!(setting->rw & SETTING_WRITE)) - return -EPERM; - if (val < setting->min || val > setting->max) + if (i >= MAX_HWIFS * MAX_DRIVES || j < 0 || j > 1) return -EINVAL; - if (setting->set) - return setting->set(drive, val); - if (ide_spin_wait_hwgroup(drive)) - return -EBUSY; - switch (setting->data_type) { - case TYPE_BYTE: - *((u8 *) setting->data) = val; - break; - case TYPE_SHORT: - *((u16 *) setting->data) = val; - break; - case TYPE_INT: - *((u32 *) setting->data) = val; - break; - case TYPE_INTA: - p = (u32 *) setting->data; - for (i = 0; i < 1 << PARTN_BITS; i++, p++) - *p = val; - break; - } - spin_unlock_irq(&ide_lock); - return 0; -} -static int set_io_32bit(ide_drive_t *drive, int arg) -{ - drive->io_32bit = arg; -#ifdef CONFIG_BLK_DEV_DTC2278 - if (HWIF(drive)->chipset == ide_dtc2278) - HWIF(drive)->drives[!drive->select.b.unit].io_32bit = arg; -#endif /* CONFIG_BLK_DEV_DTC2278 */ - return 0; -} + if (j) + *dev_param_mask |= (1 << i); + else + *dev_param_mask &= ~(1 << i); -static int set_using_dma (ide_drive_t *drive, int arg) -{ -#ifdef CONFIG_BLK_DEV_IDEDMA - if (!drive->id || !(drive->id->capability & 1)) - return -EPERM; - if (HWIF(drive)->ide_dma_check == NULL) - return -EPERM; - if (arg) { - if (HWIF(drive)->ide_dma_check(drive)) return -EIO; - if (HWIF(drive)->ide_dma_on(drive)) return -EIO; - } else { - if (__ide_dma_off(drive)) - return -EIO; - } return 0; -#else - return -EPERM; -#endif } -static int set_pio_mode (ide_drive_t *drive, int arg) -{ - struct request rq; - - if (!HWIF(drive)->tuneproc) - return -ENOSYS; - if (drive->special.b.set_tune) - return -EBUSY; - ide_init_drive_cmd(&rq); - drive->tune_req = (u8) arg; - drive->special.b.set_tune = 1; - (void) ide_do_drive_cmd(drive, &rq, ide_wait); - return 0; -} +static struct kernel_param_ops param_ops_ide_dev_mask = { + .set = ide_set_dev_param_mask +}; -static int set_xfer_rate (ide_drive_t *drive, int arg) -{ - int err = ide_wait_cmd(drive, - WIN_SETFEATURES, (u8) arg, - SETFEATURES_XFER, 0, NULL); +#define param_check_ide_dev_mask(name, p) param_check_uint(name, p) - if (!err && arg) { - ide_set_xfer_rate(drive, (u8) arg); - ide_driveid_update(drive); - } - return err; -} +static unsigned int ide_nodma; -/** - * ide_add_generic_settings - generic ide settings - * @drive: drive being configured - * - * Add the generic parts of the system settings to the /proc files and - * ioctls for this IDE device. The caller must not be holding the - * ide_setting_sem. - */ +module_param_named(nodma, ide_nodma, ide_dev_mask, 0); +MODULE_PARM_DESC(nodma, "disallow DMA for a device"); -void ide_add_generic_settings (ide_drive_t *drive) -{ -/* - * drive setting name read/write access read ioctl write ioctl data type min max mul_factor div_factor data pointer set function - */ - __ide_add_setting(drive, "io_32bit", drive->no_io_32bit ? SETTING_READ : SETTING_RW, HDIO_GET_32BIT, HDIO_SET_32BIT, TYPE_BYTE, 0, 1 + (SUPPORT_VLB_SYNC << 1), 1, 1, &drive->io_32bit, set_io_32bit, 0); - __ide_add_setting(drive, "keepsettings", SETTING_RW, HDIO_GET_KEEPSETTINGS, HDIO_SET_KEEPSETTINGS, TYPE_BYTE, 0, 1, 1, 1, &drive->keep_settings, NULL, 0); - __ide_add_setting(drive, "nice1", SETTING_RW, -1, -1, TYPE_BYTE, 0, 1, 1, 1, &drive->nice1, NULL, 0); - __ide_add_setting(drive, "pio_mode", SETTING_WRITE, -1, HDIO_SET_PIO_MODE, TYPE_BYTE, 0, 255, 1, 1, NULL, set_pio_mode, 0); - __ide_add_setting(drive, "unmaskirq", drive->no_unmask ? SETTING_READ : SETTING_RW, HDIO_GET_UNMASKINTR, HDIO_SET_UNMASKINTR, TYPE_BYTE, 0, 1, 1, 1, &drive->unmask, NULL, 0); - __ide_add_setting(drive, "using_dma", SETTING_RW, HDIO_GET_DMA, HDIO_SET_DMA, TYPE_BYTE, 0, 1, 1, 1, &drive->using_dma, set_using_dma, 0); - __ide_add_setting(drive, "init_speed", SETTING_RW, -1, -1, TYPE_BYTE, 0, 70, 1, 1, &drive->init_speed, NULL, 0); - __ide_add_setting(drive, "current_speed", SETTING_RW, -1, -1, TYPE_BYTE, 0, 70, 1, 1, &drive->current_speed, set_xfer_rate, 0); - __ide_add_setting(drive, "number", SETTING_RW, -1, -1, TYPE_BYTE, 0, 3, 1, 1, &drive->dn, NULL, 0); -} +static unsigned int ide_noflush; -/** - * system_bus_clock - clock guess - * - * External version of the bus clock guess used by very old IDE drivers - * for things like VLB timings. Should not be used. - */ +module_param_named(noflush, ide_noflush, ide_dev_mask, 0); +MODULE_PARM_DESC(noflush, "disable flush requests for a device"); -int system_bus_clock (void) -{ - return((int) ((!system_bus_speed) ? ide_system_bus_speed() : system_bus_speed )); -} +static unsigned int ide_nohpa; -EXPORT_SYMBOL(system_bus_clock); +module_param_named(nohpa, ide_nohpa, ide_dev_mask, 0); +MODULE_PARM_DESC(nohpa, "disable Host Protected Area for a device"); -static int generic_ide_suspend(struct device *dev, pm_message_t mesg) -{ - ide_drive_t *drive = dev->driver_data; - struct request rq; - struct request_pm_state rqpm; - ide_task_t args; - - memset(&rq, 0, sizeof(rq)); - memset(&rqpm, 0, sizeof(rqpm)); - memset(&args, 0, sizeof(args)); - rq.flags = REQ_PM_SUSPEND; - rq.special = &args; - rq.end_io_data = &rqpm; - rqpm.pm_step = ide_pm_state_start_suspend; - if (mesg.event == PM_EVENT_PRETHAW) - mesg.event = PM_EVENT_FREEZE; - rqpm.pm_state = mesg.event; - - return ide_do_drive_cmd(drive, &rq, ide_wait); -} +static unsigned int ide_noprobe; -static int generic_ide_resume(struct device *dev) -{ - ide_drive_t *drive = dev->driver_data; - struct request rq; - struct request_pm_state rqpm; - ide_task_t args; - - memset(&rq, 0, sizeof(rq)); - memset(&rqpm, 0, sizeof(rqpm)); - memset(&args, 0, sizeof(args)); - rq.flags = REQ_PM_RESUME; - rq.special = &args; - rq.end_io_data = &rqpm; - rqpm.pm_step = ide_pm_state_start_resume; - rqpm.pm_state = PM_EVENT_ON; - - return ide_do_drive_cmd(drive, &rq, ide_head_wait); -} +module_param_named(noprobe, ide_noprobe, ide_dev_mask, 0); +MODULE_PARM_DESC(noprobe, "skip probing for a device"); -int generic_ide_ioctl(ide_drive_t *drive, struct file *file, struct block_device *bdev, - unsigned int cmd, unsigned long arg) -{ - ide_settings_t *setting; - ide_driver_t *drv; - int err = 0; - void __user *p = (void __user *)arg; - - down(&ide_setting_sem); - if ((setting = ide_find_setting_by_ioctl(drive, cmd)) != NULL) { - if (cmd == setting->read_ioctl) { - err = ide_read_setting(drive, setting); - up(&ide_setting_sem); - return err >= 0 ? put_user(err, (long __user *)arg) : err; - } else { - if (bdev != bdev->bd_contains) - err = -EINVAL; - else - err = ide_write_setting(drive, setting, arg); - up(&ide_setting_sem); - return err; - } - } - up(&ide_setting_sem); - - switch (cmd) { - case HDIO_OBSOLETE_IDENTITY: - case HDIO_GET_IDENTITY: - if (bdev != bdev->bd_contains) - return -EINVAL; - if (drive->id_read == 0) - return -ENOMSG; - if (copy_to_user(p, drive->id, (cmd == HDIO_GET_IDENTITY) ? sizeof(*drive->id) : 142)) - return -EFAULT; - return 0; - - case HDIO_GET_NICE: - return put_user(drive->dsc_overlap << IDE_NICE_DSC_OVERLAP | - drive->atapi_overlap << IDE_NICE_ATAPI_OVERLAP | - drive->nice0 << IDE_NICE_0 | - drive->nice1 << IDE_NICE_1 | - drive->nice2 << IDE_NICE_2, - (long __user *) arg); - -#ifdef CONFIG_IDE_TASK_IOCTL - case HDIO_DRIVE_TASKFILE: - if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) - return -EACCES; - switch(drive->media) { - case ide_disk: - return ide_taskfile_ioctl(drive, cmd, arg); - default: - return -ENOMSG; - } -#endif /* CONFIG_IDE_TASK_IOCTL */ - - case HDIO_DRIVE_CMD: - if (!capable(CAP_SYS_RAWIO)) - return -EACCES; - return ide_cmd_ioctl(drive, cmd, arg); - - case HDIO_DRIVE_TASK: - if (!capable(CAP_SYS_RAWIO)) - return -EACCES; - return ide_task_ioctl(drive, cmd, arg); - - case HDIO_SCAN_HWIF: - { - hw_regs_t hw; - int args[3]; - if (!capable(CAP_SYS_RAWIO)) return -EACCES; - if (copy_from_user(args, p, 3 * sizeof(int))) - return -EFAULT; - memset(&hw, 0, sizeof(hw)); - ide_init_hwif_ports(&hw, (unsigned long) args[0], - (unsigned long) args[1], NULL); - hw.irq = args[2]; - if (ide_register_hw(&hw, NULL) == -1) - return -EIO; - return 0; - } - case HDIO_UNREGISTER_HWIF: - if (!capable(CAP_SYS_RAWIO)) return -EACCES; - /* (arg > MAX_HWIFS) checked in function */ - ide_unregister(arg); - return 0; - case HDIO_SET_NICE: - if (!capable(CAP_SYS_ADMIN)) return -EACCES; - if (arg != (arg & ((1 << IDE_NICE_DSC_OVERLAP) | (1 << IDE_NICE_1)))) - return -EPERM; - drive->dsc_overlap = (arg >> IDE_NICE_DSC_OVERLAP) & 1; - drv = *(ide_driver_t **)bdev->bd_disk->private_data; - if (drive->dsc_overlap && !drv->supports_dsc_overlap) { - drive->dsc_overlap = 0; - return -EPERM; - } - drive->nice1 = (arg >> IDE_NICE_1) & 1; - return 0; - case HDIO_DRIVE_RESET: - { - unsigned long flags; - if (!capable(CAP_SYS_ADMIN)) return -EACCES; - - /* - * Abort the current command on the - * group if there is one, taking - * care not to allow anything else - * to be queued and to die on the - * spot if we miss one somehow - */ - - spin_lock_irqsave(&ide_lock, flags); - - ide_abort(drive, "drive reset"); - - BUG_ON(HWGROUP(drive)->handler); - - /* Ensure nothing gets queued after we - drop the lock. Reset will clear the busy */ - - HWGROUP(drive)->busy = 1; - spin_unlock_irqrestore(&ide_lock, flags); - (void) ide_do_reset(drive); - - return 0; - } - - case CDROMEJECT: - case CDROMCLOSETRAY: - return scsi_cmd_ioctl(file, bdev->bd_disk, cmd, p); - - case HDIO_GET_BUSSTATE: - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; - if (put_user(HWIF(drive)->bus_state, (long __user *)arg)) - return -EFAULT; - return 0; - - case HDIO_SET_BUSSTATE: - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; - if (HWIF(drive)->busproc) - return HWIF(drive)->busproc(drive, (int)arg); - return -EOPNOTSUPP; - default: - return -EINVAL; - } -} +static unsigned int ide_nowerr; -EXPORT_SYMBOL(generic_ide_ioctl); +module_param_named(nowerr, ide_nowerr, ide_dev_mask, 0); +MODULE_PARM_DESC(nowerr, "ignore the ATA_DF bit for a device"); -/* - * stridx() returns the offset of c within s, - * or -1 if c is '\0' or not found within s. - */ -static int __init stridx (const char *s, char c) -{ - char *i = strchr(s, c); - return (i && c) ? i - s : -1; -} +static unsigned int ide_cdroms; -/* - * match_parm() does parsing for ide_setup(): - * - * 1. the first char of s must be '='. - * 2. if the remainder matches one of the supplied keywords, - * the index (1 based) of the keyword is negated and returned. - * 3. if the remainder is a series of no more than max_vals numbers - * separated by commas, the numbers are saved in vals[] and a - * count of how many were saved is returned. Base10 is assumed, - * and base16 is allowed when prefixed with "0x". - * 4. otherwise, zero is returned. - */ -static int __init match_parm (char *s, const char *keywords[], int vals[], int max_vals) -{ - static const char *decimal = "0123456789"; - static const char *hex = "0123456789abcdef"; - int i, n; - - if (*s++ == '=') { - /* - * Try matching against the supplied keywords, - * and return -(index+1) if we match one - */ - if (keywords != NULL) { - for (i = 0; *keywords != NULL; ++i) { - if (!strcmp(s, *keywords++)) - return -(i+1); - } - } - /* - * Look for a series of no more than "max_vals" - * numeric values separated by commas, in base10, - * or base16 when prefixed with "0x". - * Return a count of how many were found. - */ - for (n = 0; (i = stridx(decimal, *s)) >= 0;) { - vals[n] = i; - while ((i = stridx(decimal, *++s)) >= 0) - vals[n] = (vals[n] * 10) + i; - if (*s == 'x' && !vals[n]) { - while ((i = stridx(hex, *++s)) >= 0) - vals[n] = (vals[n] * 0x10) + i; - } - if (++n == max_vals) - break; - if (*s == ',' || *s == ';') - ++s; - } - if (!*s) - return n; - } - return 0; /* zero = nothing matched */ -} +module_param_named(cdrom, ide_cdroms, ide_dev_mask, 0); +MODULE_PARM_DESC(cdrom, "force device as a CD-ROM"); -#ifdef CONFIG_BLK_DEV_ALI14XX -static int __initdata probe_ali14xx; -extern int ali14xx_init(void); -#endif -#ifdef CONFIG_BLK_DEV_UMC8672 -static int __initdata probe_umc8672; -extern int umc8672_init(void); -#endif -#ifdef CONFIG_BLK_DEV_DTC2278 -static int __initdata probe_dtc2278; -extern int dtc2278_init(void); -#endif -#ifdef CONFIG_BLK_DEV_HT6560B -static int __initdata probe_ht6560b; -extern int ht6560b_init(void); -#endif -#ifdef CONFIG_BLK_DEV_QD65XX -static int __initdata probe_qd65xx; -extern int qd65xx_init(void); -#endif +struct chs_geom { + unsigned int cyl; + u8 head; + u8 sect; +}; -static int __initdata is_chipset_set[MAX_HWIFS]; +static unsigned int ide_disks; +static struct chs_geom ide_disks_chs[MAX_HWIFS * MAX_DRIVES]; -/* - * ide_setup() gets called VERY EARLY during initialization, - * to handle kernel "command line" strings beginning with "hdx=" or "ide". - * - * Remember to update Documentation/ide.txt if you change something here. - */ -static int __init ide_setup(char *s) +static int ide_set_disk_chs(const char *str, struct kernel_param *kp) { - int i, vals[3]; - ide_hwif_t *hwif; - ide_drive_t *drive; - unsigned int hw, unit; - const char max_drive = 'a' + ((MAX_HWIFS * MAX_DRIVES) - 1); - const char max_hwif = '0' + (MAX_HWIFS - 1); - - - if (strncmp(s,"hd",2) == 0 && s[2] == '=') /* hd= is for hd.c */ - return 0; /* driver and not us */ + int a, b, c = 0, h = 0, s = 0, i, j = 1; - if (strncmp(s,"ide",3) && strncmp(s,"idebus",6) && strncmp(s,"hd",2)) - return 0; + /* controller . device (0 or 1) : Cylinders , Heads , Sectors */ + /* controller . device (0 or 1) : 1 (use CHS) | 0 (ignore CHS) */ + if (sscanf(str, "%d.%d:%d,%d,%d", &a, &b, &c, &h, &s) != 5 && + sscanf(str, "%d.%d:%d", &a, &b, &j) != 3) + return -EINVAL; - printk(KERN_INFO "ide_setup: %s", s); - init_ide_data (); + i = a * MAX_DRIVES + b; -#ifdef CONFIG_BLK_DEV_IDEDOUBLER - if (!strcmp(s, "ide=doubler")) { - extern int ide_doubler; + if (i >= MAX_HWIFS * MAX_DRIVES || j < 0 || j > 1) + return -EINVAL; - printk(" : Enabled support for IDE doublers\n"); - ide_doubler = 1; - return 1; - } -#endif /* CONFIG_BLK_DEV_IDEDOUBLER */ + if (c > INT_MAX || h > 255 || s > 255) + return -EINVAL; - if (!strcmp(s, "ide=nodma")) { - printk(" : Prevented DMA\n"); - noautodma = 1; - return 1; - } + if (j) + ide_disks |= (1 << i); + else + ide_disks &= ~(1 << i); -#ifdef CONFIG_BLK_DEV_IDEPCI - if (!strcmp(s, "ide=reverse")) { - ide_scan_direction = 1; - printk(" : Enabled support for IDE inverse scan order.\n"); - return 1; - } -#endif /* CONFIG_BLK_DEV_IDEPCI */ - - /* - * Look for drive options: "hdx=" - */ - if (s[0] == 'h' && s[1] == 'd' && s[2] >= 'a' && s[2] <= max_drive) { - const char *hd_words[] = { - "none", "noprobe", "nowerr", "cdrom", "serialize", - "autotune", "noautotune", "minus8", "swapdata", "bswap", - "noflush", "remap", "remap63", "scsi", NULL }; - unit = s[2] - 'a'; - hw = unit / MAX_DRIVES; - unit = unit % MAX_DRIVES; - hwif = &ide_hwifs[hw]; - drive = &hwif->drives[unit]; - if (strncmp(s + 4, "ide-", 4) == 0) { - strlcpy(drive->driver_req, s + 4, sizeof(drive->driver_req)); - goto done; - } - switch (match_parm(&s[3], hd_words, vals, 3)) { - case -1: /* "none" */ - case -2: /* "noprobe" */ - drive->noprobe = 1; - goto done; - case -3: /* "nowerr" */ - drive->bad_wstat = BAD_R_STAT; - hwif->noprobe = 0; - goto done; - case -4: /* "cdrom" */ - drive->present = 1; - drive->media = ide_cdrom; - /* an ATAPI device ignores DRDY */ - drive->ready_stat = 0; - hwif->noprobe = 0; - goto done; - case -5: /* "serialize" */ - printk(" -- USE \"ide%d=serialize\" INSTEAD", hw); - goto do_serialize; - case -6: /* "autotune" */ - drive->autotune = IDE_TUNE_AUTO; - goto obsolete_option; - case -7: /* "noautotune" */ - drive->autotune = IDE_TUNE_NOAUTO; - goto obsolete_option; - case -9: /* "swapdata" */ - case -10: /* "bswap" */ - drive->bswap = 1; - goto done; - case -11: /* noflush */ - drive->noflush = 1; - goto done; - case -12: /* "remap" */ - drive->remap_0_to_1 = 1; - goto done; - case -13: /* "remap63" */ - drive->sect0 = 63; - goto done; - case -14: /* "scsi" */ - drive->scsi = 1; - goto done; - case 3: /* cyl,head,sect */ - drive->media = ide_disk; - drive->ready_stat = READY_STAT; - drive->cyl = drive->bios_cyl = vals[0]; - drive->head = drive->bios_head = vals[1]; - drive->sect = drive->bios_sect = vals[2]; - drive->present = 1; - drive->forced_geom = 1; - hwif->noprobe = 0; - goto done; - default: - goto bad_option; - } - } + ide_disks_chs[i].cyl = c; + ide_disks_chs[i].head = h; + ide_disks_chs[i].sect = s; - if (s[0] != 'i' || s[1] != 'd' || s[2] != 'e') - goto bad_option; - /* - * Look for bus speed option: "idebus=" - */ - if (s[3] == 'b' && s[4] == 'u' && s[5] == 's') { - if (match_parm(&s[6], NULL, vals, 1) != 1) - goto bad_option; - if (vals[0] >= 20 && vals[0] <= 66) { - idebus_parameter = vals[0]; - } else - printk(" -- BAD BUS SPEED! Expected value from 20 to 66"); - goto done; - } - /* - * Look for interface options: "idex=" - */ - if (s[3] >= '0' && s[3] <= max_hwif) { - /* - * Be VERY CAREFUL changing this: note hardcoded indexes below - * (-8, -9, -10) are reserved to ease the hardcoding. - */ - static const char *ide_words[] = { - "noprobe", "serialize", "autotune", "noautotune", - "reset", "dma", "ata66", "minus8", "minus9", - "minus10", "four", "qd65xx", "ht6560b", "cmd640_vlb", - "dtc2278", "umc8672", "ali14xx", NULL }; - hw = s[3] - '0'; - hwif = &ide_hwifs[hw]; - i = match_parm(&s[4], ide_words, vals, 3); - - /* - * Cryptic check to ensure chipset not already set for hwif. - * Note: we can't depend on hwif->chipset here. - */ - if ((i >= -18 && i <= -11) || (i > 0 && i <= 3)) { - /* chipset already specified */ - if (is_chipset_set[hw]) - goto bad_option; - if (i > -18 && i <= -11) { - /* these drivers are for "ide0=" only */ - if (hw != 0) - goto bad_hwif; - /* chipset already specified for 2nd port */ - if (is_chipset_set[hw+1]) - goto bad_option; - } - is_chipset_set[hw] = 1; - printk("\n"); - } - - switch (i) { -#ifdef CONFIG_BLK_DEV_ALI14XX - case -17: /* "ali14xx" */ - probe_ali14xx = 1; - goto done; -#endif -#ifdef CONFIG_BLK_DEV_UMC8672 - case -16: /* "umc8672" */ - probe_umc8672 = 1; - goto done; -#endif -#ifdef CONFIG_BLK_DEV_DTC2278 - case -15: /* "dtc2278" */ - probe_dtc2278 = 1; - goto done; -#endif -#ifdef CONFIG_BLK_DEV_CMD640 - case -14: /* "cmd640_vlb" */ - { - extern int cmd640_vlb; /* flag for cmd640.c */ - cmd640_vlb = 1; - goto done; - } -#endif -#ifdef CONFIG_BLK_DEV_HT6560B - case -13: /* "ht6560b" */ - probe_ht6560b = 1; - goto done; -#endif -#ifdef CONFIG_BLK_DEV_QD65XX - case -12: /* "qd65xx" */ - probe_qd65xx = 1; - goto done; -#endif -#ifdef CONFIG_BLK_DEV_4DRIVES - case -11: /* "four" drives on one set of ports */ - { - ide_hwif_t *mate = &ide_hwifs[hw^1]; - mate->drives[0].select.all ^= 0x20; - mate->drives[1].select.all ^= 0x20; - hwif->chipset = mate->chipset = ide_4drives; - mate->irq = hwif->irq; - memcpy(mate->io_ports, hwif->io_ports, sizeof(hwif->io_ports)); - goto do_serialize; - } -#endif /* CONFIG_BLK_DEV_4DRIVES */ - case -10: /* minus10 */ - case -9: /* minus9 */ - case -8: /* minus8 */ - goto bad_option; - case -7: /* ata66 */ -#ifdef CONFIG_BLK_DEV_IDEPCI - hwif->udma_four = 1; - goto obsolete_option; -#else - goto bad_hwif; -#endif - case -6: /* dma */ - hwif->autodma = 1; - goto obsolete_option; - case -5: /* "reset" */ - hwif->reset = 1; - goto obsolete_option; - case -4: /* "noautotune" */ - hwif->drives[0].autotune = IDE_TUNE_NOAUTO; - hwif->drives[1].autotune = IDE_TUNE_NOAUTO; - goto obsolete_option; - case -3: /* "autotune" */ - hwif->drives[0].autotune = IDE_TUNE_AUTO; - hwif->drives[1].autotune = IDE_TUNE_AUTO; - goto obsolete_option; - case -2: /* "serialize" */ - do_serialize: - hwif->mate = &ide_hwifs[hw^1]; - hwif->mate->mate = hwif; - hwif->serialized = hwif->mate->serialized = 1; - goto obsolete_option; - - case -1: /* "noprobe" */ - hwif->noprobe = 1; - goto done; - - case 1: /* base */ - vals[1] = vals[0] + 0x206; /* default ctl */ - case 2: /* base,ctl */ - vals[2] = 0; /* default irq = probe for it */ - case 3: /* base,ctl,irq */ - hwif->hw.irq = vals[2]; - ide_init_hwif_ports(&hwif->hw, (unsigned long) vals[0], (unsigned long) vals[1], &hwif->irq); - memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports)); - hwif->irq = vals[2]; - hwif->noprobe = 0; - hwif->chipset = ide_forced; - goto obsolete_option; - - case 0: goto bad_option; - default: - printk(" -- SUPPORT NOT CONFIGURED IN THIS KERNEL\n"); - return 1; - } - } -bad_option: - printk(" -- BAD OPTION\n"); - return 1; -obsolete_option: - printk(" -- OBSOLETE OPTION, WILL BE REMOVED SOON!\n"); - return 1; -bad_hwif: - printk("-- NOT SUPPORTED ON ide%d", hw); -done: - printk("\n"); - return 1; + return 0; } -extern void pnpide_init(void); -extern void h8300_ide_init(void); +module_param_call(chs, ide_set_disk_chs, NULL, NULL, 0); +MODULE_PARM_DESC(chs, "force device as a disk (using CHS)"); -/* - * probe_for_hwifs() finds/initializes "known" IDE interfaces - */ -static void __init probe_for_hwifs (void) +static void ide_dev_apply_params(ide_drive_t *drive, u8 unit) { -#ifdef CONFIG_BLK_DEV_IDEPCI - ide_scan_pcibus(ide_scan_direction); -#endif /* CONFIG_BLK_DEV_IDEPCI */ - -#ifdef CONFIG_ETRAX_IDE - { - extern void init_e100_ide(void); - init_e100_ide(); - } -#endif /* CONFIG_ETRAX_IDE */ -#ifdef CONFIG_BLK_DEV_CMD640 - { - extern void ide_probe_for_cmd640x(void); - ide_probe_for_cmd640x(); - } -#endif /* CONFIG_BLK_DEV_CMD640 */ -#ifdef CONFIG_BLK_DEV_IDE_PMAC - { - extern void pmac_ide_probe(void); - pmac_ide_probe(); + int i = drive->hwif->index * MAX_DRIVES + unit; + + if (ide_nodma & (1 << i)) { + printk(KERN_INFO "ide: disallowing DMA for %s\n", drive->name); + drive->dev_flags |= IDE_DFLAG_NODMA; } -#endif /* CONFIG_BLK_DEV_IDE_PMAC */ -#ifdef CONFIG_BLK_DEV_GAYLE - { - extern void gayle_init(void); - gayle_init(); + if (ide_noflush & (1 << i)) { + printk(KERN_INFO "ide: disabling flush requests for %s\n", + drive->name); + drive->dev_flags |= IDE_DFLAG_NOFLUSH; } -#endif /* CONFIG_BLK_DEV_GAYLE */ -#ifdef CONFIG_BLK_DEV_FALCON_IDE - { - extern void falconide_init(void); - falconide_init(); + if (ide_nohpa & (1 << i)) { + printk(KERN_INFO "ide: disabling Host Protected Area for %s\n", + drive->name); + drive->dev_flags |= IDE_DFLAG_NOHPA; } -#endif /* CONFIG_BLK_DEV_FALCON_IDE */ -#ifdef CONFIG_BLK_DEV_MAC_IDE - { - extern void macide_init(void); - macide_init(); + if (ide_noprobe & (1 << i)) { + printk(KERN_INFO "ide: skipping probe for %s\n", drive->name); + drive->dev_flags |= IDE_DFLAG_NOPROBE; } -#endif /* CONFIG_BLK_DEV_MAC_IDE */ -#ifdef CONFIG_BLK_DEV_Q40IDE - { - extern void q40ide_init(void); - q40ide_init(); + if (ide_nowerr & (1 << i)) { + printk(KERN_INFO "ide: ignoring the ATA_DF bit for %s\n", + drive->name); + drive->bad_wstat = BAD_R_STAT; } -#endif /* CONFIG_BLK_DEV_Q40IDE */ -#ifdef CONFIG_BLK_DEV_BUDDHA - { - extern void buddha_init(void); - buddha_init(); + if (ide_cdroms & (1 << i)) { + printk(KERN_INFO "ide: forcing %s as a CD-ROM\n", drive->name); + drive->dev_flags |= IDE_DFLAG_PRESENT; + drive->media = ide_cdrom; + /* an ATAPI device ignores DRDY */ + drive->ready_stat = 0; } -#endif /* CONFIG_BLK_DEV_BUDDHA */ -#ifdef CONFIG_BLK_DEV_IDEPNP - pnpide_init(); -#endif -#ifdef CONFIG_H8300 - h8300_ide_init(); -#endif -} - -void ide_register_subdriver(ide_drive_t *drive, ide_driver_t *driver) -{ -#ifdef CONFIG_PROC_FS - ide_add_proc_entries(drive->proc, driver->proc, drive); -#endif -} + if (ide_disks & (1 << i)) { + drive->cyl = drive->bios_cyl = ide_disks_chs[i].cyl; + drive->head = drive->bios_head = ide_disks_chs[i].head; + drive->sect = drive->bios_sect = ide_disks_chs[i].sect; -EXPORT_SYMBOL(ide_register_subdriver); - -/** - * ide_unregister_subdriver - disconnect drive from driver - * @drive: drive to unplug - * @driver: driver - * - * Disconnect a drive from the driver it was attached to and then - * clean up the various proc files and other objects attached to it. - * - * Takes ide_setting_sem and ide_lock. - * Caller must hold none of the locks. - */ + printk(KERN_INFO "ide: forcing %s as a disk (%d/%d/%d)\n", + drive->name, + drive->cyl, drive->head, drive->sect); -void ide_unregister_subdriver(ide_drive_t *drive, ide_driver_t *driver) -{ - unsigned long flags; - - down(&ide_setting_sem); - spin_lock_irqsave(&ide_lock, flags); -#ifdef CONFIG_PROC_FS - ide_remove_proc_entries(drive->proc, driver->proc); -#endif - auto_remove_settings(drive); - spin_unlock_irqrestore(&ide_lock, flags); - up(&ide_setting_sem); -} - -EXPORT_SYMBOL(ide_unregister_subdriver); - -/* - * Probe module - */ - -EXPORT_SYMBOL(ide_lock); - -static int ide_bus_match(struct device *dev, struct device_driver *drv) -{ - return 1; -} - -static char *media_string(ide_drive_t *drive) -{ - switch (drive->media) { - case ide_disk: - return "disk"; - case ide_cdrom: - return "cdrom"; - case ide_tape: - return "tape"; - case ide_floppy: - return "floppy"; - default: - return "UNKNOWN"; + drive->dev_flags |= IDE_DFLAG_FORCED_GEOM | IDE_DFLAG_PRESENT; + drive->media = ide_disk; + drive->ready_stat = ATA_DRDY; } } -static ssize_t media_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - ide_drive_t *drive = to_ide_device(dev); - return sprintf(buf, "%s\n", media_string(drive)); -} +static unsigned int ide_ignore_cable; -static ssize_t drivename_show(struct device *dev, struct device_attribute *attr, char *buf) +static int ide_set_ignore_cable(const char *s, struct kernel_param *kp) { - ide_drive_t *drive = to_ide_device(dev); - return sprintf(buf, "%s\n", drive->name); -} + int i, j = 1; -static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - ide_drive_t *drive = to_ide_device(dev); - return sprintf(buf, "ide:m-%s\n", media_string(drive)); -} + /* controller (ignore) */ + /* controller : 1 (ignore) | 0 (use) */ + if (sscanf(s, "%d:%d", &i, &j) != 2 && sscanf(s, "%d", &i) != 1) + return -EINVAL; -static struct device_attribute ide_dev_attrs[] = { - __ATTR_RO(media), - __ATTR_RO(drivename), - __ATTR_RO(modalias), - __ATTR_NULL -}; + if (i >= MAX_HWIFS || j < 0 || j > 1) + return -EINVAL; + + if (j) + ide_ignore_cable |= (1 << i); + else + ide_ignore_cable &= ~(1 << i); -static int ide_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) -{ - ide_drive_t *drive = to_ide_device(dev); - int i = 0; - int length = 0; - - add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, - "MEDIA=%s", media_string(drive)); - add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, - "DRIVENAME=%s", drive->name); - add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, - "MODALIAS=ide:m-%s", media_string(drive)); - envp[i] = NULL; return 0; } -static int generic_ide_probe(struct device *dev) -{ - ide_drive_t *drive = to_ide_device(dev); - ide_driver_t *drv = to_ide_driver(dev->driver); - - return drv->probe ? drv->probe(drive) : -ENODEV; -} +module_param_call(ignore_cable, ide_set_ignore_cable, NULL, NULL, 0); +MODULE_PARM_DESC(ignore_cable, "ignore cable detection"); -static int generic_ide_remove(struct device *dev) +void ide_port_apply_params(ide_hwif_t *hwif) { - ide_drive_t *drive = to_ide_device(dev); - ide_driver_t *drv = to_ide_driver(dev->driver); - - if (drv->remove) - drv->remove(drive); - - return 0; -} + ide_drive_t *drive; + int i; -static void generic_ide_shutdown(struct device *dev) -{ - ide_drive_t *drive = to_ide_device(dev); - ide_driver_t *drv = to_ide_driver(dev->driver); + if (ide_ignore_cable & (1 << hwif->index)) { + printk(KERN_INFO "ide: ignoring cable detection for %s\n", + hwif->name); + hwif->cbl = ATA_CBL_PATA40_SHORT; + } - if (dev->driver && drv->shutdown) - drv->shutdown(drive); + ide_port_for_each_dev(i, drive, hwif) + ide_dev_apply_params(drive, i); } -struct bus_type ide_bus_type = { - .name = "ide", - .match = ide_bus_match, - .uevent = ide_uevent, - .probe = generic_ide_probe, - .remove = generic_ide_remove, - .shutdown = generic_ide_shutdown, - .dev_attrs = ide_dev_attrs, - .suspend = generic_ide_suspend, - .resume = generic_ide_resume, -}; - -EXPORT_SYMBOL_GPL(ide_bus_type); - /* * This is gets invoked once during initialization, to set *everything* up */ static int __init ide_init(void) { - printk(KERN_INFO "Uniform Multi-Platform E-IDE driver " REVISION "\n"); - system_bus_speed = ide_system_bus_speed(); - - bus_register(&ide_bus_type); + int ret; - init_ide_data(); + printk(KERN_INFO "Uniform Multi-Platform E-IDE driver\n"); -#ifdef CONFIG_PROC_FS - proc_ide_root = proc_mkdir("ide", NULL); -#endif + ret = bus_register(&ide_bus_type); + if (ret < 0) { + printk(KERN_WARNING "IDE: bus_register error: %d\n", ret); + return ret; + } -#ifdef CONFIG_BLK_DEV_ALI14XX - if (probe_ali14xx) - (void)ali14xx_init(); -#endif -#ifdef CONFIG_BLK_DEV_UMC8672 - if (probe_umc8672) - (void)umc8672_init(); -#endif -#ifdef CONFIG_BLK_DEV_DTC2278 - if (probe_dtc2278) - (void)dtc2278_init(); -#endif -#ifdef CONFIG_BLK_DEV_HT6560B - if (probe_ht6560b) - (void)ht6560b_init(); -#endif -#ifdef CONFIG_BLK_DEV_QD65XX - if (probe_qd65xx) - (void)qd65xx_init(); -#endif + ide_port_class = class_create(THIS_MODULE, "ide_port"); + if (IS_ERR(ide_port_class)) { + ret = PTR_ERR(ide_port_class); + goto out_port_class; + } - initializing = 1; - /* Probe for special PCI and other "known" interface chipsets. */ - probe_for_hwifs(); - initializing = 0; + ide_acpi_init(); -#ifdef CONFIG_PROC_FS proc_ide_create(); -#endif - return 0; -} -#ifdef MODULE -static char *options = NULL; -module_param(options, charp, 0); -MODULE_LICENSE("GPL"); + return 0; -static void __init parse_options (char *line) -{ - char *next = line; - - if (line == NULL || !*line) - return; - while ((line = next) != NULL) { - if ((next = strchr(line,' ')) != NULL) - *next++ = 0; - if (!ide_setup(line)) - printk (KERN_INFO "Unknown option '%s'\n", line); - } -} +out_port_class: + bus_unregister(&ide_bus_type); -int __init init_module (void) -{ - parse_options(options); - return ide_init(); + return ret; } -void cleanup_module (void) +static void __exit ide_exit(void) { - int index; - - for (index = 0; index < MAX_HWIFS; ++index) - ide_unregister(index); - -#ifdef CONFIG_PROC_FS proc_ide_destroy(); -#endif + + class_destroy(ide_port_class); bus_unregister(&ide_bus_type); } -#else /* !MODULE */ - -__setup("", ide_setup); - module_init(ide_init); +module_exit(ide_exit); -#endif /* MODULE */ +MODULE_LICENSE("GPL"); diff --git a/drivers/ide/ide_platform.c b/drivers/ide/ide_platform.c new file mode 100644 index 00000000000..a8b4b6af80e --- /dev/null +++ b/drivers/ide/ide_platform.c @@ -0,0 +1,149 @@ +/* + * Platform IDE driver + * + * Copyright (C) 2007 MontaVista Software + * + * Maintainer: Kumar Gala <galak@kernel.crashing.org> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include <linux/types.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/ide.h> +#include <linux/ioport.h> +#include <linux/module.h> +#include <linux/ata_platform.h> +#include <linux/platform_device.h> +#include <linux/interrupt.h> +#include <linux/io.h> + +static void plat_ide_setup_ports(struct ide_hw *hw, void __iomem *base, + void __iomem *ctrl, + struct pata_platform_info *pdata, int irq) +{ + unsigned long port = (unsigned long)base; + int i; + + hw->io_ports.data_addr = port; + + port += (1 << pdata->ioport_shift); + for (i = 1; i <= 7; + i++, port += (1 << pdata->ioport_shift)) + hw->io_ports_array[i] = port; + + hw->io_ports.ctl_addr = (unsigned long)ctrl; + + hw->irq = irq; +} + +static const struct ide_port_info platform_ide_port_info = { + .host_flags = IDE_HFLAG_NO_DMA, + .chipset = ide_generic, +}; + +static int plat_ide_probe(struct platform_device *pdev) +{ + struct resource *res_base, *res_alt, *res_irq; + void __iomem *base, *alt_base; + struct pata_platform_info *pdata; + struct ide_host *host; + int ret = 0, mmio = 0; + struct ide_hw hw, *hws[] = { &hw }; + struct ide_port_info d = platform_ide_port_info; + + pdata = dev_get_platdata(&pdev->dev); + + /* get a pointer to the register memory */ + res_base = platform_get_resource(pdev, IORESOURCE_IO, 0); + res_alt = platform_get_resource(pdev, IORESOURCE_IO, 1); + + if (!res_base || !res_alt) { + res_base = platform_get_resource(pdev, IORESOURCE_MEM, 0); + res_alt = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (!res_base || !res_alt) { + ret = -ENOMEM; + goto out; + } + mmio = 1; + } + + res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!res_irq) { + ret = -EINVAL; + goto out; + } + + if (mmio) { + base = devm_ioremap(&pdev->dev, + res_base->start, resource_size(res_base)); + alt_base = devm_ioremap(&pdev->dev, + res_alt->start, resource_size(res_alt)); + } else { + base = devm_ioport_map(&pdev->dev, + res_base->start, resource_size(res_base)); + alt_base = devm_ioport_map(&pdev->dev, + res_alt->start, resource_size(res_alt)); + } + + memset(&hw, 0, sizeof(hw)); + plat_ide_setup_ports(&hw, base, alt_base, pdata, res_irq->start); + hw.dev = &pdev->dev; + + d.irq_flags = res_irq->flags & IRQF_TRIGGER_MASK; + if (res_irq->flags & IORESOURCE_IRQ_SHAREABLE) + d.irq_flags |= IRQF_SHARED; + + if (mmio) + d.host_flags |= IDE_HFLAG_MMIO; + + ret = ide_host_add(&d, hws, 1, &host); + if (ret) + goto out; + + platform_set_drvdata(pdev, host); + + return 0; + +out: + return ret; +} + +static int plat_ide_remove(struct platform_device *pdev) +{ + struct ide_host *host = dev_get_drvdata(&pdev->dev); + + ide_host_remove(host); + + return 0; +} + +static struct platform_driver platform_ide_driver = { + .driver = { + .name = "pata_platform", + .owner = THIS_MODULE, + }, + .probe = plat_ide_probe, + .remove = plat_ide_remove, +}; + +static int __init platform_ide_init(void) +{ + return platform_driver_register(&platform_ide_driver); +} + +static void __exit platform_ide_exit(void) +{ + platform_driver_unregister(&platform_ide_driver); +} + +MODULE_DESCRIPTION("Platform IDE driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:pata_platform"); + +module_init(platform_ide_init); +module_exit(platform_ide_exit); diff --git a/drivers/ide/it8172.c b/drivers/ide/it8172.c new file mode 100644 index 00000000000..b6f674ab4fb --- /dev/null +++ b/drivers/ide/it8172.c @@ -0,0 +1,165 @@ +/* + * + * BRIEF MODULE DESCRIPTION + * IT8172 IDE controller support + * + * Copyright (C) 2000 MontaVista Software Inc. + * Copyright (C) 2008 Shane McDonald + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <linux/module.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/ioport.h> +#include <linux/pci.h> +#include <linux/ide.h> +#include <linux/init.h> + +#define DRV_NAME "IT8172" + +static void it8172_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) +{ + struct pci_dev *dev = to_pci_dev(hwif->dev); + u16 drive_enables; + u32 drive_timing; + const u8 pio = drive->pio_mode - XFER_PIO_0; + + /* + * The highest value of DIOR/DIOW pulse width and recovery time + * that can be set in the IT8172 is 8 PCI clock cycles. As a result, + * it cannot be configured for PIO mode 0. This table sets these + * parameters to the maximum supported by the IT8172. + */ + static const u8 timings[] = { 0x3f, 0x3c, 0x1b, 0x12, 0x0a }; + + pci_read_config_word(dev, 0x40, &drive_enables); + pci_read_config_dword(dev, 0x44, &drive_timing); + + /* + * Enable port 0x44. The IT8172 spec is confused; it calls + * this register the "Slave IDE Timing Register", but in fact, + * it controls timing for both master and slave drives. + */ + drive_enables |= 0x4000; + + drive_enables &= drive->dn ? 0xc006 : 0xc060; + if (drive->media == ide_disk) + /* enable prefetch */ + drive_enables |= 0x0004 << (drive->dn * 4); + if (ide_pio_need_iordy(drive, pio)) + /* enable IORDY sample-point */ + drive_enables |= 0x0002 << (drive->dn * 4); + + drive_timing &= drive->dn ? 0x00003f00 : 0x000fc000; + drive_timing |= timings[pio] << (drive->dn * 6 + 8); + + pci_write_config_word(dev, 0x40, drive_enables); + pci_write_config_dword(dev, 0x44, drive_timing); +} + +static void it8172_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive) +{ + struct pci_dev *dev = to_pci_dev(hwif->dev); + int a_speed = 3 << (drive->dn * 4); + int u_flag = 1 << drive->dn; + int u_speed = 0; + u8 reg48, reg4a; + const u8 speed = drive->dma_mode; + + pci_read_config_byte(dev, 0x48, ®48); + pci_read_config_byte(dev, 0x4a, ®4a); + + if (speed >= XFER_UDMA_0) { + u8 udma = speed - XFER_UDMA_0; + u_speed = udma << (drive->dn * 4); + + pci_write_config_byte(dev, 0x48, reg48 | u_flag); + reg4a &= ~a_speed; + pci_write_config_byte(dev, 0x4a, reg4a | u_speed); + } else { + const u8 mwdma_to_pio[] = { 0, 3, 4 }; + + pci_write_config_byte(dev, 0x48, reg48 & ~u_flag); + pci_write_config_byte(dev, 0x4a, reg4a & ~a_speed); + + drive->pio_mode = + mwdma_to_pio[speed - XFER_MW_DMA_0] + XFER_PIO_0; + + it8172_set_pio_mode(hwif, drive); + } +} + + +static const struct ide_port_ops it8172_port_ops = { + .set_pio_mode = it8172_set_pio_mode, + .set_dma_mode = it8172_set_dma_mode, +}; + +static const struct ide_port_info it8172_port_info = { + .name = DRV_NAME, + .port_ops = &it8172_port_ops, + .enablebits = { {0x41, 0x80, 0x80}, {0x00, 0x00, 0x00} }, + .host_flags = IDE_HFLAG_SINGLE, + .pio_mask = ATA_PIO4 & ~ATA_PIO0, + .mwdma_mask = ATA_MWDMA2, + .udma_mask = ATA_UDMA2, +}; + +static int it8172_init_one(struct pci_dev *dev, const struct pci_device_id *id) +{ + if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE) + return -ENODEV; /* IT8172 is more than an IDE controller */ + return ide_pci_init_one(dev, &it8172_port_info, NULL); +} + +static struct pci_device_id it8172_pci_tbl[] = { + { PCI_VDEVICE(ITE, PCI_DEVICE_ID_ITE_8172), 0 }, + { 0, }, +}; +MODULE_DEVICE_TABLE(pci, it8172_pci_tbl); + +static struct pci_driver it8172_pci_driver = { + .name = "IT8172_IDE", + .id_table = it8172_pci_tbl, + .probe = it8172_init_one, + .remove = ide_pci_remove, + .suspend = ide_pci_suspend, + .resume = ide_pci_resume, +}; + +static int __init it8172_ide_init(void) +{ + return ide_pci_register_driver(&it8172_pci_driver); +} + +static void __exit it8172_ide_exit(void) +{ + pci_unregister_driver(&it8172_pci_driver); +} + +module_init(it8172_ide_init); +module_exit(it8172_ide_exit); + +MODULE_AUTHOR("Steve Longerbeam"); +MODULE_DESCRIPTION("PCI driver module for ITE 8172 IDE"); +MODULE_LICENSE("GPL"); diff --git a/drivers/ide/it8213.c b/drivers/ide/it8213.c new file mode 100644 index 00000000000..6b92846682f --- /dev/null +++ b/drivers/ide/it8213.c @@ -0,0 +1,216 @@ +/* + * ITE 8213 IDE driver + * + * Copyright (C) 2006 Jack Lee + * Copyright (C) 2006 Alan Cox + * Copyright (C) 2007 Bartlomiej Zolnierkiewicz + */ + +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/ide.h> +#include <linux/init.h> + +#define DRV_NAME "it8213" + +/** + * it8213_set_pio_mode - set host controller for PIO mode + * @hwif: port + * @drive: drive + * + * Set the interface PIO mode. + */ + +static void it8213_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) +{ + struct pci_dev *dev = to_pci_dev(hwif->dev); + int is_slave = drive->dn & 1; + int master_port = 0x40; + int slave_port = 0x44; + unsigned long flags; + u16 master_data; + u8 slave_data; + static DEFINE_SPINLOCK(tune_lock); + int control = 0; + const u8 pio = drive->pio_mode - XFER_PIO_0; + + static const u8 timings[][2] = { + { 0, 0 }, + { 0, 0 }, + { 1, 0 }, + { 2, 1 }, + { 2, 3 }, }; + + spin_lock_irqsave(&tune_lock, flags); + pci_read_config_word(dev, master_port, &master_data); + + if (pio > 1) + control |= 1; /* Programmable timing on */ + if (drive->media != ide_disk) + control |= 4; /* ATAPI */ + if (ide_pio_need_iordy(drive, pio)) + control |= 2; /* IORDY */ + if (is_slave) { + master_data |= 0x4000; + master_data &= ~0x0070; + if (pio > 1) + master_data = master_data | (control << 4); + pci_read_config_byte(dev, slave_port, &slave_data); + slave_data = slave_data & 0xf0; + slave_data = slave_data | (timings[pio][0] << 2) | timings[pio][1]; + } else { + master_data &= ~0x3307; + if (pio > 1) + master_data = master_data | control; + master_data = master_data | (timings[pio][0] << 12) | (timings[pio][1] << 8); + } + pci_write_config_word(dev, master_port, master_data); + if (is_slave) + pci_write_config_byte(dev, slave_port, slave_data); + spin_unlock_irqrestore(&tune_lock, flags); +} + +/** + * it8213_set_dma_mode - set host controller for DMA mode + * @hwif: port + * @drive: drive + * + * Tune the ITE chipset for the DMA mode. + */ + +static void it8213_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive) +{ + struct pci_dev *dev = to_pci_dev(hwif->dev); + u8 maslave = 0x40; + int a_speed = 3 << (drive->dn * 4); + int u_flag = 1 << drive->dn; + int v_flag = 0x01 << drive->dn; + int w_flag = 0x10 << drive->dn; + int u_speed = 0; + u16 reg4042, reg4a; + u8 reg48, reg54, reg55; + const u8 speed = drive->dma_mode; + + pci_read_config_word(dev, maslave, ®4042); + pci_read_config_byte(dev, 0x48, ®48); + pci_read_config_word(dev, 0x4a, ®4a); + pci_read_config_byte(dev, 0x54, ®54); + pci_read_config_byte(dev, 0x55, ®55); + + if (speed >= XFER_UDMA_0) { + u8 udma = speed - XFER_UDMA_0; + + u_speed = min_t(u8, 2 - (udma & 1), udma) << (drive->dn * 4); + + if (!(reg48 & u_flag)) + pci_write_config_byte(dev, 0x48, reg48 | u_flag); + if (speed >= XFER_UDMA_5) + pci_write_config_byte(dev, 0x55, (u8) reg55|w_flag); + else + pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag); + + if ((reg4a & a_speed) != u_speed) + pci_write_config_word(dev, 0x4a, (reg4a & ~a_speed) | u_speed); + if (speed > XFER_UDMA_2) { + if (!(reg54 & v_flag)) + pci_write_config_byte(dev, 0x54, reg54 | v_flag); + } else + pci_write_config_byte(dev, 0x54, reg54 & ~v_flag); + } else { + const u8 mwdma_to_pio[] = { 0, 3, 4 }; + + if (reg48 & u_flag) + pci_write_config_byte(dev, 0x48, reg48 & ~u_flag); + if (reg4a & a_speed) + pci_write_config_word(dev, 0x4a, reg4a & ~a_speed); + if (reg54 & v_flag) + pci_write_config_byte(dev, 0x54, reg54 & ~v_flag); + if (reg55 & w_flag) + pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag); + + if (speed >= XFER_MW_DMA_0) + drive->pio_mode = + mwdma_to_pio[speed - XFER_MW_DMA_0] + XFER_PIO_0; + else + drive->pio_mode = XFER_PIO_2; /* for SWDMA2 */ + + it8213_set_pio_mode(hwif, drive); + } +} + +static u8 it8213_cable_detect(ide_hwif_t *hwif) +{ + struct pci_dev *dev = to_pci_dev(hwif->dev); + u8 reg42h = 0; + + pci_read_config_byte(dev, 0x42, ®42h); + + return (reg42h & 0x02) ? ATA_CBL_PATA40 : ATA_CBL_PATA80; +} + +static const struct ide_port_ops it8213_port_ops = { + .set_pio_mode = it8213_set_pio_mode, + .set_dma_mode = it8213_set_dma_mode, + .cable_detect = it8213_cable_detect, +}; + +static const struct ide_port_info it8213_chipset = { + .name = DRV_NAME, + .enablebits = { {0x41, 0x80, 0x80} }, + .port_ops = &it8213_port_ops, + .host_flags = IDE_HFLAG_SINGLE, + .pio_mask = ATA_PIO4, + .swdma_mask = ATA_SWDMA2_ONLY, + .mwdma_mask = ATA_MWDMA12_ONLY, + .udma_mask = ATA_UDMA6, +}; + +/** + * it8213_init_one - pci layer discovery entry + * @dev: PCI device + * @id: ident table entry + * + * Called by the PCI code when it finds an ITE8213 controller. As + * this device follows the standard interfaces we can use the + * standard helper functions to do almost all the work for us. + */ + +static int it8213_init_one(struct pci_dev *dev, const struct pci_device_id *id) +{ + return ide_pci_init_one(dev, &it8213_chipset, NULL); +} + +static const struct pci_device_id it8213_pci_tbl[] = { + { PCI_VDEVICE(ITE, PCI_DEVICE_ID_ITE_8213), 0 }, + { 0, }, +}; + +MODULE_DEVICE_TABLE(pci, it8213_pci_tbl); + +static struct pci_driver it8213_pci_driver = { + .name = "ITE8213_IDE", + .id_table = it8213_pci_tbl, + .probe = it8213_init_one, + .remove = ide_pci_remove, + .suspend = ide_pci_suspend, + .resume = ide_pci_resume, +}; + +static int __init it8213_ide_init(void) +{ + return ide_pci_register_driver(&it8213_pci_driver); +} + +static void __exit it8213_ide_exit(void) +{ + pci_unregister_driver(&it8213_pci_driver); +} + +module_init(it8213_ide_init); +module_exit(it8213_ide_exit); + +MODULE_AUTHOR("Jack Lee, Alan Cox"); +MODULE_DESCRIPTION("PCI driver module for the ITE 8213"); +MODULE_LICENSE("GPL"); diff --git a/drivers/ide/pci/it821x.c b/drivers/ide/it821x.c index e9bad185968..f01ba4606be 100644 --- a/drivers/ide/pci/it821x.c +++ b/drivers/ide/it821x.c @@ -1,15 +1,12 @@ - /* - * linux/drivers/ide/pci/it821x.c Version 0.09 December 2004 - * - * Copyright (C) 2004 Red Hat <alan@redhat.com> + * Copyright (C) 2004 Red Hat + * Copyright (C) 2007 Bartlomiej Zolnierkiewicz * * May be copied or modified under the terms of the GNU General Public License * Based in part on the ITE vendor provided SCSI driver. * - * Documentation available from - * http://www.ite.com.tw/pc/IT8212F_V04.pdf - * Some other documents are NDA. + * Documentation: + * Datasheet is freely available, some other documents under NDA. * * The ITE8212 isn't exactly a standard IDE controller. It has two * modes. In pass through mode then it is an IDE controller. In its smart @@ -64,13 +61,14 @@ #include <linux/types.h> #include <linux/module.h> +#include <linux/slab.h> #include <linux/pci.h> -#include <linux/delay.h> -#include <linux/hdreg.h> #include <linux/ide.h> #include <linux/init.h> -#include <asm/io.h> +#define DRV_NAME "it821x" + +#define QUIRK_VORTEX86 1 struct it821x_dev { @@ -83,6 +81,7 @@ struct it821x_dev u16 pio[2]; /* Cached PIO values */ u16 mwdma[2]; /* Cached MWDMA values */ u16 udma[2]; /* Cached UDMA values (per drive) */ + u16 quirks; }; #define ATA_66 0 @@ -94,7 +93,7 @@ struct it821x_dev /* * We allow users to force the card into non raid mode without - * flashing the alternative BIOS. This is also neccessary right now + * flashing the alternative BIOS. This is also necessary right now * for embedded platforms that cannot run a PC BIOS but are using this * device. */ @@ -104,6 +103,7 @@ static int it8212_noraid; /** * it821x_program - program the PIO/MWDMA registers * @drive: drive to tune + * @timing: timing info * * Program the PIO/MWDMA timing for this channel according to the * current clock. @@ -111,7 +111,8 @@ static int it8212_noraid; static void it821x_program(ide_drive_t *drive, u16 timing) { - ide_hwif_t *hwif = drive->hwif; + ide_hwif_t *hwif = drive->hwif; + struct pci_dev *dev = to_pci_dev(hwif->dev); struct it821x_dev *itdev = ide_get_hwifdata(hwif); int channel = hwif->channel; u8 conf; @@ -121,12 +122,14 @@ static void it821x_program(ide_drive_t *drive, u16 timing) conf = timing >> 8; else conf = timing & 0xFF; - pci_write_config_byte(hwif->pci_dev, 0x54 + 4 * channel, conf); + + pci_write_config_byte(dev, 0x54 + 4 * channel, conf); } /** * it821x_program_udma - program the UDMA registers * @drive: drive to tune + * @timing: timing info * * Program the UDMA timing for this drive according to the * current clock. @@ -134,29 +137,29 @@ static void it821x_program(ide_drive_t *drive, u16 timing) static void it821x_program_udma(ide_drive_t *drive, u16 timing) { - ide_hwif_t *hwif = drive->hwif; + ide_hwif_t *hwif = drive->hwif; + struct pci_dev *dev = to_pci_dev(hwif->dev); struct it821x_dev *itdev = ide_get_hwifdata(hwif); int channel = hwif->channel; - int unit = drive->select.b.unit; - u8 conf; + u8 unit = drive->dn & 1, conf; /* Program UDMA timing bits */ if(itdev->clock_mode == ATA_66) conf = timing >> 8; else conf = timing & 0xFF; - if(itdev->timing10 == 0) - pci_write_config_byte(hwif->pci_dev, 0x56 + 4 * channel + unit, conf); + + if (itdev->timing10 == 0) + pci_write_config_byte(dev, 0x56 + 4 * channel + unit, conf); else { - pci_write_config_byte(hwif->pci_dev, 0x56 + 4 * channel, conf); - pci_write_config_byte(hwif->pci_dev, 0x56 + 4 * channel + 1, conf); + pci_write_config_byte(dev, 0x56 + 4 * channel, conf); + pci_write_config_byte(dev, 0x56 + 4 * channel + 1, conf); } } - /** * it821x_clock_strategy - * @hwif: hardware interface + * @drive: drive to set up * * Select between the 50 and 66Mhz base clocks to get the best * results for this interface. @@ -165,14 +168,11 @@ static void it821x_program_udma(ide_drive_t *drive, u16 timing) static void it821x_clock_strategy(ide_drive_t *drive) { ide_hwif_t *hwif = drive->hwif; + struct pci_dev *dev = to_pci_dev(hwif->dev); struct it821x_dev *itdev = ide_get_hwifdata(hwif); - - u8 unit = drive->select.b.unit; - ide_drive_t *pair = &hwif->drives[1-unit]; - - int clock, altclock; - u8 v; - int sel = 0; + ide_drive_t *pair = ide_get_pair_dev(drive); + int clock, altclock, sel = 0; + u8 unit = drive->dn & 1, v; if(itdev->want[0][0] > itdev->want[1][0]) { clock = itdev->want[0][1]; @@ -182,8 +182,11 @@ static void it821x_clock_strategy(ide_drive_t *drive) altclock = itdev->want[0][1]; } - /* Master doesn't care does the slave ? */ - if(clock == ATA_ANY) + /* + * if both clocks can be used for the mode with the higher priority + * use the clock needed by the mode with the lower priority + */ + if (clock == ATA_ANY) clock = altclock; /* Nobody cares - keep the same clock */ @@ -200,10 +203,11 @@ static void it821x_clock_strategy(ide_drive_t *drive) itdev->clock_mode = ATA_50; sel = 1; } - pci_read_config_byte(hwif->pci_dev, 0x50, &v); + + pci_read_config_byte(dev, 0x50, &v); v &= ~(1 << (1 + hwif->channel)); v |= sel << (1 + hwif->channel); - pci_write_config_byte(hwif->pci_dev, 0x50, v); + pci_write_config_byte(dev, 0x50, v); /* * Reprogram the UDMA/PIO of the pair drive for the switch @@ -224,51 +228,41 @@ static void it821x_clock_strategy(ide_drive_t *drive) } /** - * it821x_ratemask - Compute available modes - * @drive: IDE drive + * it821x_set_pio_mode - set host controller for PIO mode + * @hwif: port + * @drive: drive * - * Compute the available speeds for the devices on the interface. This - * is all modes to ATA133 clipped by drive cable setup. + * Tune the host to the desired PIO mode taking into the consideration + * the maximum PIO mode supported by the other device on the cable. */ -static u8 it821x_ratemask (ide_drive_t *drive) +static void it821x_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) { - u8 mode = 4; - if (!eighty_ninty_three(drive)) - mode = min(mode, (u8)1); - return mode; -} - -/** - * it821x_tuneproc - tune a drive - * @drive: drive to tune - * @mode_wanted: the target operating mode - * - * Load the timing settings for this device mode into the - * controller. By the time we are called the mode has been - * modified as neccessary to handle the absence of seperate - * master/slave timers for MWDMA/PIO. - * - * This code is only used in pass through mode. - */ - -static void it821x_tuneproc (ide_drive_t *drive, byte mode_wanted) -{ - ide_hwif_t *hwif = drive->hwif; struct it821x_dev *itdev = ide_get_hwifdata(hwif); - int unit = drive->select.b.unit; + ide_drive_t *pair = ide_get_pair_dev(drive); + const u8 pio = drive->pio_mode - XFER_PIO_0; + u8 unit = drive->dn & 1, set_pio = pio; /* Spec says 89 ref driver uses 88 */ - static u16 pio[] = { 0xAA88, 0xA382, 0xA181, 0x3332, 0x3121 }; + static u16 pio_timings[]= { 0xAA88, 0xA382, 0xA181, 0x3332, 0x3121 }; static u8 pio_want[] = { ATA_66, ATA_66, ATA_66, ATA_66, ATA_ANY }; - if(itdev->smart) - return; + /* + * Compute the best PIO mode we can for a given device. We must + * pick a speed that does not cause problems with the other device + * on the cable. + */ + if (pair) { + u8 pair_pio = pair->pio_mode - XFER_PIO_0; + /* trim PIO to the slowest of the master/slave */ + if (pair_pio < set_pio) + set_pio = pair_pio; + } /* We prefer 66Mhz clock for PIO 0-3, don't care for PIO4 */ - itdev->want[unit][1] = pio_want[mode_wanted]; + itdev->want[unit][1] = pio_want[set_pio]; itdev->want[unit][0] = 1; /* PIO is lowest priority */ - itdev->pio[unit] = pio[mode_wanted]; + itdev->pio[unit] = pio_timings[set_pio]; it821x_clock_strategy(drive); it821x_program(drive, itdev->pio[unit]); } @@ -284,13 +278,12 @@ static void it821x_tuneproc (ide_drive_t *drive, byte mode_wanted) * the shared MWDMA/PIO timing register. */ -static void it821x_tune_mwdma (ide_drive_t *drive, byte mode_wanted) +static void it821x_tune_mwdma(ide_drive_t *drive, u8 mode_wanted) { - ide_hwif_t *hwif = drive->hwif; + ide_hwif_t *hwif = drive->hwif; + struct pci_dev *dev = to_pci_dev(hwif->dev); struct it821x_dev *itdev = (void *)ide_get_hwifdata(hwif); - int unit = drive->select.b.unit; - int channel = hwif->channel; - u8 conf; + u8 unit = drive->dn & 1, channel = hwif->channel, conf; static u16 dma[] = { 0x8866, 0x3222, 0x3121 }; static u8 mwdma_want[] = { ATA_ANY, ATA_66, ATA_ANY }; @@ -301,12 +294,12 @@ static void it821x_tune_mwdma (ide_drive_t *drive, byte mode_wanted) itdev->udma[unit] = UDMA_OFF; /* UDMA bits off - Revision 0x10 do them in pairs */ - pci_read_config_byte(hwif->pci_dev, 0x50, &conf); - if(itdev->timing10) + pci_read_config_byte(dev, 0x50, &conf); + if (itdev->timing10) conf |= channel ? 0x60: 0x18; else conf |= 1 << (3 + 2 * channel + unit); - pci_write_config_byte(hwif->pci_dev, 0x50, conf); + pci_write_config_byte(dev, 0x50, conf); it821x_clock_strategy(drive); /* FIXME: do we need to program this ? */ @@ -322,13 +315,12 @@ static void it821x_tune_mwdma (ide_drive_t *drive, byte mode_wanted) * controller when doing UDMA modes in pass through. */ -static void it821x_tune_udma (ide_drive_t *drive, byte mode_wanted) +static void it821x_tune_udma(ide_drive_t *drive, u8 mode_wanted) { - ide_hwif_t *hwif = drive->hwif; + ide_hwif_t *hwif = drive->hwif; + struct pci_dev *dev = to_pci_dev(hwif->dev); struct it821x_dev *itdev = ide_get_hwifdata(hwif); - int unit = drive->select.b.unit; - int channel = hwif->channel; - u8 conf; + u8 unit = drive->dn & 1, channel = hwif->channel, conf; static u16 udma[] = { 0x4433, 0x4231, 0x3121, 0x2121, 0x1111, 0x2211, 0x1111 }; static u8 udma_want[] = { ATA_ANY, ATA_50, ATA_ANY, ATA_66, ATA_66, ATA_50, ATA_66 }; @@ -341,12 +333,12 @@ static void it821x_tune_udma (ide_drive_t *drive, byte mode_wanted) itdev->udma[unit] |= 0x8080; /* UDMA 5/6 select on */ /* UDMA on. Again revision 0x10 must do the pair */ - pci_read_config_byte(hwif->pci_dev, 0x50, &conf); - if(itdev->timing10) + pci_read_config_byte(dev, 0x50, &conf); + if (itdev->timing10) conf &= channel ? 0x9F: 0xE7; else conf &= ~ (1 << (3 + 2 * channel + unit)); - pci_write_config_byte(hwif->pci_dev, 0x50, conf); + pci_write_config_byte(dev, 0x50, conf); it821x_clock_strategy(drive); it821x_program_udma(drive, itdev->udma[unit]); @@ -354,40 +346,6 @@ static void it821x_tune_udma (ide_drive_t *drive, byte mode_wanted) } /** - * config_it821x_chipset_for_pio - set drive timings - * @drive: drive to tune - * @speed we want - * - * Compute the best pio mode we can for a given device. We must - * pick a speed that does not cause problems with the other device - * on the cable. - */ - -static void config_it821x_chipset_for_pio (ide_drive_t *drive, byte set_speed) -{ - u8 unit = drive->select.b.unit; - ide_hwif_t *hwif = drive->hwif; - ide_drive_t *pair = &hwif->drives[1-unit]; - u8 speed = 0, set_pio = ide_get_best_pio_mode(drive, 255, 5, NULL); - u8 pair_pio; - - /* We have to deal with this mess in pairs */ - if(pair != NULL) { - pair_pio = ide_get_best_pio_mode(pair, 255, 5, NULL); - /* Trim PIO to the slowest of the master/slave */ - if(pair_pio < set_pio) - set_pio = pair_pio; - } - it821x_tuneproc(drive, set_pio); - speed = XFER_PIO_0 + set_pio; - /* XXX - We trim to the lowest of the pair so the other drive - will always be fine at this point until we do hotplug passthru */ - - if (set_speed) - (void) ide_config_drive_speed(drive, speed); -} - -/** * it821x_dma_read - DMA hook * @drive: drive for DMA * @@ -404,7 +362,8 @@ static void it821x_dma_start(ide_drive_t *drive) { ide_hwif_t *hwif = drive->hwif; struct it821x_dev *itdev = ide_get_hwifdata(hwif); - int unit = drive->select.b.unit; + u8 unit = drive->dn & 1; + if(itdev->mwdma[unit] != MWDMA_OFF) it821x_program(drive, itdev->mwdma[unit]); else if(itdev->udma[unit] != UDMA_OFF && itdev->timing10) @@ -424,114 +383,40 @@ static void it821x_dma_start(ide_drive_t *drive) static int it821x_dma_end(ide_drive_t *drive) { ide_hwif_t *hwif = drive->hwif; - int unit = drive->select.b.unit; struct it821x_dev *itdev = ide_get_hwifdata(hwif); - int ret = __ide_dma_end(drive); + int ret = ide_dma_end(drive); + u8 unit = drive->dn & 1; + if(itdev->mwdma[unit] != MWDMA_OFF) it821x_program(drive, itdev->pio[unit]); return ret; } - /** - * it821x_tune_chipset - set controller timings - * @drive: Drive to set up - * @xferspeed: speed we want to achieve + * it821x_set_dma_mode - set host controller for DMA mode + * @hwif: port + * @drive: drive * - * Tune the ITE chipset for the desired mode. If we can't achieve - * the desired mode then tune for a lower one, but ultimately - * make the thing work. + * Tune the ITE chipset for the desired DMA mode. */ -static int it821x_tune_chipset (ide_drive_t *drive, byte xferspeed) +static void it821x_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive) { + const u8 speed = drive->dma_mode; - ide_hwif_t *hwif = drive->hwif; - struct it821x_dev *itdev = ide_get_hwifdata(hwif); - u8 speed = ide_rate_filter(it821x_ratemask(drive), xferspeed); - - if(!itdev->smart) { - switch(speed) { - case XFER_PIO_4: - case XFER_PIO_3: - case XFER_PIO_2: - case XFER_PIO_1: - case XFER_PIO_0: - it821x_tuneproc(drive, (speed - XFER_PIO_0)); - break; - /* MWDMA tuning is really hard because our MWDMA and PIO - timings are kept in the same place. We can switch in the - host dma on/off callbacks */ - case XFER_MW_DMA_2: - case XFER_MW_DMA_1: - case XFER_MW_DMA_0: - it821x_tune_mwdma(drive, (speed - XFER_MW_DMA_0)); - break; - case XFER_UDMA_6: - case XFER_UDMA_5: - case XFER_UDMA_4: - case XFER_UDMA_3: - case XFER_UDMA_2: - case XFER_UDMA_1: - case XFER_UDMA_0: - it821x_tune_udma(drive, (speed - XFER_UDMA_0)); - break; - default: - return 1; - } - } /* - * In smart mode the clocking is done by the host controller - * snooping the mode we picked. The rest of it is not our problem + * MWDMA tuning is really hard because our MWDMA and PIO + * timings are kept in the same place. We can switch in the + * host dma on/off callbacks. */ - return ide_config_drive_speed(drive, speed); -} - -/** - * config_chipset_for_dma - configure for DMA - * @drive: drive to configure - * - * Called by the IDE layer when it wants the timings set up. - */ - -static int config_chipset_for_dma (ide_drive_t *drive) -{ - u8 speed = ide_dma_speed(drive, it821x_ratemask(drive)); - - if (speed) { - config_it821x_chipset_for_pio(drive, 0); - it821x_tune_chipset(drive, speed); - - return ide_dma_enable(drive); - } - - return 0; -} - -/** - * it821x_configure_drive_for_dma - set up for DMA transfers - * @drive: drive we are going to set up - * - * Set up the drive for DMA, tune the controller and drive as - * required. If the drive isn't suitable for DMA or we hit - * other problems then we will drop down to PIO and set up - * PIO appropriately - */ - -static int it821x_config_drive_for_dma (ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - - if (ide_use_dma(drive)) { - if (config_chipset_for_dma(drive)) - return hwif->ide_dma_on(drive); - } - config_it821x_chipset_for_pio(drive, 1); - return hwif->ide_dma_off_quietly(drive); + if (speed >= XFER_UDMA_0 && speed <= XFER_UDMA_6) + it821x_tune_udma(drive, speed - XFER_UDMA_0); + else if (speed >= XFER_MW_DMA_0 && speed <= XFER_MW_DMA_2) + it821x_tune_mwdma(drive, speed - XFER_MW_DMA_0); } /** - * ata66_it821x - check for 80 pin cable + * it821x_cable_detect - cable detection * @hwif: interface to check * * Check for the presence of an ATA66 capable cable on the @@ -539,40 +424,35 @@ static int it821x_config_drive_for_dma (ide_drive_t *drive) * the needed logic onboard. */ -static unsigned int __devinit ata66_it821x(ide_hwif_t *hwif) +static u8 it821x_cable_detect(ide_hwif_t *hwif) { /* The reference driver also only does disk side */ - return 1; + return ATA_CBL_PATA80; } /** - * it821x_fixup - post init callback - * @hwif: interface + * it821x_quirkproc - post init callback + * @drive: drive * - * This callback is run after the drives have been probed but + * This callback is run after the drive has been probed but * before anything gets attached. It allows drivers to do any * final tuning that is needed, or fixups to work around bugs. */ -static void __devinit it821x_fixups(ide_hwif_t *hwif) +static void it821x_quirkproc(ide_drive_t *drive) { - struct it821x_dev *itdev = ide_get_hwifdata(hwif); - int i; + struct it821x_dev *itdev = ide_get_hwifdata(drive->hwif); + u16 *id = drive->id; - if(!itdev->smart) { + if (!itdev->smart) { /* * If we are in pass through mode then not much * needs to be done, but we do bother to clear the * IRQ mask as we may well be in PIO (eg rev 0x10) * for now and we know unmasking is safe on this chipset. */ - for (i = 0; i < 2; i++) { - ide_drive_t *drive = &hwif->drives[i]; - if(drive->present) - drive->unmask = 1; - } - return; - } + drive->dev_flags |= IDE_DFLAG_UNMASK; + } else { /* * Perform fixups on smart mode. We need to "lose" some * capabilities the firmware lacks but does not filter, and @@ -580,61 +460,65 @@ static void __devinit it821x_fixups(ide_hwif_t *hwif) * in RAID mode. */ - for(i = 0; i < 2; i++) { - ide_drive_t *drive = &hwif->drives[i]; - struct hd_driveid *id; - u16 *idbits; - - if(!drive->present) - continue; - id = drive->id; - idbits = (u16 *)drive->id; - /* Check for RAID v native */ - if(strstr(id->model, "Integrated Technology Express")) { + if (strstr((char *)&id[ATA_ID_PROD], + "Integrated Technology Express")) { /* In raid mode the ident block is slightly buggy We need to set the bits so that the IDE layer knows LBA28. LBA48 and DMA ar valid */ - id->capability |= 3; /* LBA28, DMA */ - id->command_set_2 |= 0x0400; /* LBA48 valid */ - id->cfs_enable_2 |= 0x0400; /* LBA48 on */ + id[ATA_ID_CAPABILITY] |= (3 << 8); /* LBA28, DMA */ + id[ATA_ID_COMMAND_SET_2] |= 0x0400; /* LBA48 valid */ + id[ATA_ID_CFS_ENABLE_2] |= 0x0400; /* LBA48 on */ /* Reporting logic */ printk(KERN_INFO "%s: IT8212 %sRAID %d volume", - drive->name, - idbits[147] ? "Bootable ":"", - idbits[129]); - if(idbits[129] != 1) - printk("(%dK stripe)", idbits[146]); - printk(".\n"); - /* Now the core code will have wrongly decided no DMA - so we need to fix this */ - hwif->ide_dma_off_quietly(drive); -#ifdef CONFIG_IDEDMA_ONLYDISK - if (drive->media == ide_disk) -#endif - hwif->ide_dma_check(drive); + drive->name, id[147] ? "Bootable " : "", + id[ATA_ID_CSFO]); + if (id[ATA_ID_CSFO] != 1) + printk(KERN_CONT "(%dK stripe)", id[146]); + printk(KERN_CONT ".\n"); } else { /* Non RAID volume. Fixups to stop the core code doing unsupported things */ - id->field_valid &= 1; - id->queue_depth = 0; - id->command_set_1 = 0; - id->command_set_2 &= 0xC400; - id->cfsse &= 0xC000; - id->cfs_enable_1 = 0; - id->cfs_enable_2 &= 0xC400; - id->csf_default &= 0xC000; - id->word127 = 0; - id->dlf = 0; - id->csfo = 0; - id->cfa_power = 0; + id[ATA_ID_FIELD_VALID] &= 3; + id[ATA_ID_QUEUE_DEPTH] = 0; + id[ATA_ID_COMMAND_SET_1] = 0; + id[ATA_ID_COMMAND_SET_2] &= 0xC400; + id[ATA_ID_CFSSE] &= 0xC000; + id[ATA_ID_CFS_ENABLE_1] = 0; + id[ATA_ID_CFS_ENABLE_2] &= 0xC400; + id[ATA_ID_CSF_DEFAULT] &= 0xC000; + id[127] = 0; + id[ATA_ID_DLF] = 0; + id[ATA_ID_CSFO] = 0; + id[ATA_ID_CFA_POWER] = 0; printk(KERN_INFO "%s: Performing identify fixups.\n", drive->name); } + + /* + * Set MWDMA0 mode as enabled/support - just to tell + * IDE core that DMA is supported (it821x hardware + * takes care of DMA mode programming). + */ + if (ata_id_has_dma(id)) { + id[ATA_ID_MWDMA_MODES] |= 0x0101; + drive->current_speed = XFER_MW_DMA_0; + } } } +static struct ide_dma_ops it821x_pass_through_dma_ops = { + .dma_host_set = ide_dma_host_set, + .dma_setup = ide_dma_setup, + .dma_start = it821x_dma_start, + .dma_end = it821x_dma_end, + .dma_test_irq = ide_dma_test_irq, + .dma_lost_irq = ide_dma_lost_irq, + .dma_timer_expiry = ide_dma_sff_timer_expiry, + .dma_sff_read_status = ide_dma_sff_read_status, +}; + /** * init_hwif_it821x - set up hwif structs * @hwif: interface to set up @@ -644,23 +528,20 @@ static void __devinit it821x_fixups(ide_hwif_t *hwif) * ide DMA handlers appropriately */ -static void __devinit init_hwif_it821x(ide_hwif_t *hwif) +static void init_hwif_it821x(ide_hwif_t *hwif) { - struct it821x_dev *idev = kzalloc(sizeof(struct it821x_dev), GFP_KERNEL); + struct pci_dev *dev = to_pci_dev(hwif->dev); + struct ide_host *host = pci_get_drvdata(dev); + struct it821x_dev *itdevs = host->host_priv; + struct it821x_dev *idev = itdevs + hwif->channel; u8 conf; - if(idev == NULL) { - printk(KERN_ERR "it821x: out of memory, falling back to legacy behaviour.\n"); - goto fallback; - } ide_set_hwifdata(hwif, idev); - hwif->atapi_dma = 1; - - pci_read_config_byte(hwif->pci_dev, 0x50, &conf); - if(conf & 1) { + pci_read_config_byte(dev, 0x50, &conf); + if (conf & 1) { idev->smart = 1; - hwif->atapi_dma = 0; + hwif->host_flags |= IDE_HFLAG_NO_ATAPI_DMA; /* Long I/O's although allowed in LBA48 space cause the onboard firmware to enter the twighlight zone */ hwif->rqsize = 256; @@ -677,55 +558,37 @@ static void __devinit init_hwif_it821x(ide_hwif_t *hwif) /* * Not in the docs but according to the reference driver - * this is neccessary. + * this is necessary. */ - pci_read_config_byte(hwif->pci_dev, 0x08, &conf); - if(conf == 0x10) { + if (dev->revision == 0x10) { idev->timing10 = 1; - hwif->atapi_dma = 0; - if(!idev->smart) - printk(KERN_WARNING "it821x: Revision 0x10, workarounds activated.\n"); - } - - hwif->speedproc = &it821x_tune_chipset; - hwif->tuneproc = &it821x_tuneproc; - - /* MWDMA/PIO clock switching for pass through mode */ - if(!idev->smart) { - hwif->dma_start = &it821x_dma_start; - hwif->ide_dma_end = &it821x_dma_end; + hwif->host_flags |= IDE_HFLAG_NO_ATAPI_DMA; + if (idev->smart == 0) + printk(KERN_WARNING DRV_NAME " %s: revision 0x10, " + "workarounds activated\n", pci_name(dev)); } - hwif->drives[0].autotune = 1; - hwif->drives[1].autotune = 1; + if (idev->smart == 0) { + /* MWDMA/PIO clock switching for pass through mode */ + hwif->dma_ops = &it821x_pass_through_dma_ops; + } else + hwif->host_flags |= IDE_HFLAG_NO_SET_MODE; - if (!hwif->dma_base) - goto fallback; - - hwif->ultra_mask = 0x7f; - hwif->mwdma_mask = 0x07; - hwif->swdma_mask = 0x07; + if (hwif->dma_base == 0) + return; - hwif->ide_dma_check = &it821x_config_drive_for_dma; - if (!(hwif->udma_four)) - hwif->udma_four = ata66_it821x(hwif); + hwif->ultra_mask = ATA_UDMA6; + hwif->mwdma_mask = ATA_MWDMA2; - /* - * The BIOS often doesn't set up DMA on this controller - * so we always do it. - */ - - hwif->autodma = 1; - hwif->drives[0].autodma = hwif->autodma; - hwif->drives[1].autodma = hwif->autodma; - return; -fallback: - hwif->autodma = 0; - return; + /* Vortex86SX quirk: prevent Ultra-DMA mode to fix BadCRC issue */ + if (idev->quirks & QUIRK_VORTEX86) { + if (dev->revision == 0x11) + hwif->ultra_mask = 0; + } } -static void __devinit it8212_disable_raid(struct pci_dev *dev) +static void it8212_disable_raid(struct pci_dev *dev) { /* Reset local CPU, and set BIOS not ready */ pci_write_config_byte(dev, 0x5E, 0x01); @@ -742,35 +605,37 @@ static void __devinit it8212_disable_raid(struct pci_dev *dev) pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x20); } -static unsigned int __devinit init_chipset_it821x(struct pci_dev *dev, const char *name) +static int init_chipset_it821x(struct pci_dev *dev) { u8 conf; static char *mode[2] = { "pass through", "smart" }; /* Force the card into bypass mode if so requested */ if (it8212_noraid) { - printk(KERN_INFO "it8212: forcing bypass mode.\n"); + printk(KERN_INFO DRV_NAME " %s: forcing bypass mode\n", + pci_name(dev)); it8212_disable_raid(dev); } pci_read_config_byte(dev, 0x50, &conf); - printk(KERN_INFO "it821x: controller in %s mode.\n", mode[conf & 1]); + printk(KERN_INFO DRV_NAME " %s: controller in %s mode\n", + pci_name(dev), mode[conf & 1]); return 0; } +static const struct ide_port_ops it821x_port_ops = { + /* it821x_set_{pio,dma}_mode() are only used in pass-through mode */ + .set_pio_mode = it821x_set_pio_mode, + .set_dma_mode = it821x_set_dma_mode, + .quirkproc = it821x_quirkproc, + .cable_detect = it821x_cable_detect, +}; -#define DECLARE_ITE_DEV(name_str) \ - { \ - .name = name_str, \ - .init_chipset = init_chipset_it821x, \ - .init_hwif = init_hwif_it821x, \ - .channels = 2, \ - .autodma = AUTODMA, \ - .bootable = ON_BOARD, \ - .fixup = it821x_fixups \ - } - -static ide_pci_device_t it821x_chipsets[] __devinitdata = { - /* 0 */ DECLARE_ITE_DEV("IT8212"), +static const struct ide_port_info it821x_chipset = { + .name = DRV_NAME, + .init_chipset = init_chipset_it821x, + .init_hwif = init_hwif_it821x, + .port_ops = &it821x_port_ops, + .pio_mask = ATA_PIO4, }; /** @@ -782,35 +647,68 @@ static ide_pci_device_t it821x_chipsets[] __devinitdata = { * We then use the IDE PCI generic helper to do most of the work. */ -static int __devinit it821x_init_one(struct pci_dev *dev, const struct pci_device_id *id) +static int it821x_init_one(struct pci_dev *dev, const struct pci_device_id *id) { - ide_setup_pci_device(dev, &it821x_chipsets[id->driver_data]); - return 0; + struct it821x_dev *itdevs; + int rc; + + itdevs = kzalloc(2 * sizeof(*itdevs), GFP_KERNEL); + if (itdevs == NULL) { + printk(KERN_ERR DRV_NAME " %s: out of memory\n", pci_name(dev)); + return -ENOMEM; + } + + itdevs->quirks = id->driver_data; + + rc = ide_pci_init_one(dev, &it821x_chipset, itdevs); + if (rc) + kfree(itdevs); + + return rc; } -static struct pci_device_id it821x_pci_tbl[] = { - { PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_8211, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - { PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_8212, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, +static void it821x_remove(struct pci_dev *dev) +{ + struct ide_host *host = pci_get_drvdata(dev); + struct it821x_dev *itdevs = host->host_priv; + + ide_pci_remove(dev); + kfree(itdevs); +} + +static const struct pci_device_id it821x_pci_tbl[] = { + { PCI_VDEVICE(ITE, PCI_DEVICE_ID_ITE_8211), 0 }, + { PCI_VDEVICE(ITE, PCI_DEVICE_ID_ITE_8212), 0 }, + { PCI_VDEVICE(RDC, PCI_DEVICE_ID_RDC_D1010), QUIRK_VORTEX86 }, { 0, }, }; MODULE_DEVICE_TABLE(pci, it821x_pci_tbl); -static struct pci_driver driver = { +static struct pci_driver it821x_pci_driver = { .name = "ITE821x IDE", .id_table = it821x_pci_tbl, .probe = it821x_init_one, + .remove = it821x_remove, + .suspend = ide_pci_suspend, + .resume = ide_pci_resume, }; static int __init it821x_ide_init(void) { - return ide_pci_register_driver(&driver); + return ide_pci_register_driver(&it821x_pci_driver); +} + +static void __exit it821x_ide_exit(void) +{ + pci_unregister_driver(&it821x_pci_driver); } module_init(it821x_ide_init); +module_exit(it821x_ide_exit); module_param_named(noraid, it8212_noraid, int, S_IRUGO); -MODULE_PARM_DESC(it8212_noraid, "Force card into bypass mode"); +MODULE_PARM_DESC(noraid, "Force card into bypass mode"); MODULE_AUTHOR("Alan Cox"); MODULE_DESCRIPTION("PCI driver module for the ITE 821x"); diff --git a/drivers/ide/jmicron.c b/drivers/ide/jmicron.c new file mode 100644 index 00000000000..ae6480dcbad --- /dev/null +++ b/drivers/ide/jmicron.c @@ -0,0 +1,176 @@ + +/* + * Copyright (C) 2006 Red Hat + * + * May be copied or modified under the terms of the GNU General Public License + */ + +#include <linux/types.h> +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/ide.h> +#include <linux/init.h> + +#define DRV_NAME "jmicron" + +typedef enum { + PORT_PATA0 = 0, + PORT_PATA1 = 1, + PORT_SATA = 2, +} port_type; + +/** + * jmicron_cable_detect - cable detection + * @hwif: IDE port + * + * Returns the cable type. + */ + +static u8 jmicron_cable_detect(ide_hwif_t *hwif) +{ + struct pci_dev *pdev = to_pci_dev(hwif->dev); + + u32 control; + u32 control5; + + int port = hwif->channel; + port_type port_map[2]; + + pci_read_config_dword(pdev, 0x40, &control); + + /* There are two basic mappings. One has the two SATA ports merged + as master/slave and the secondary as PATA, the other has only the + SATA port mapped */ + if (control & (1 << 23)) { + port_map[0] = PORT_SATA; + port_map[1] = PORT_PATA0; + } else { + port_map[0] = PORT_SATA; + port_map[1] = PORT_SATA; + } + + /* The 365/366 may have this bit set to map the second PATA port + as the internal primary channel */ + pci_read_config_dword(pdev, 0x80, &control5); + if (control5 & (1<<24)) + port_map[0] = PORT_PATA1; + + /* The two ports may then be logically swapped by the firmware */ + if (control & (1 << 22)) + port = port ^ 1; + + /* + * Now we know which physical port we are talking about we can + * actually do our cable checking etc. Thankfully we don't need + * to do the plumbing for other cases. + */ + switch (port_map[port]) { + case PORT_PATA0: + if (control & (1 << 3)) /* 40/80 pin primary */ + return ATA_CBL_PATA40; + return ATA_CBL_PATA80; + case PORT_PATA1: + if (control5 & (1 << 19)) /* 40/80 pin secondary */ + return ATA_CBL_PATA40; + return ATA_CBL_PATA80; + case PORT_SATA: + break; + } + /* Avoid bogus "control reaches end of non-void function" */ + return ATA_CBL_PATA80; +} + +static void jmicron_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) +{ +} + +/** + * jmicron_set_dma_mode - set host controller for DMA mode + * @hwif: port + * @drive: drive + * + * As the JMicron snoops for timings we don't need to do anything here. + */ + +static void jmicron_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive) +{ +} + +static const struct ide_port_ops jmicron_port_ops = { + .set_pio_mode = jmicron_set_pio_mode, + .set_dma_mode = jmicron_set_dma_mode, + .cable_detect = jmicron_cable_detect, +}; + +static const struct ide_port_info jmicron_chipset = { + .name = DRV_NAME, + .enablebits = { { 0x40, 0x01, 0x01 }, { 0x40, 0x10, 0x10 } }, + .port_ops = &jmicron_port_ops, + .pio_mask = ATA_PIO5, + .mwdma_mask = ATA_MWDMA2, + .udma_mask = ATA_UDMA6, +}; + +/** + * jmicron_init_one - pci layer discovery entry + * @dev: PCI device + * @id: ident table entry + * + * Called by the PCI code when it finds a Jmicron controller. + * We then use the IDE PCI generic helper to do most of the work. + */ + +static int jmicron_init_one(struct pci_dev *dev, const struct pci_device_id *id) +{ + return ide_pci_init_one(dev, &jmicron_chipset, NULL); +} + +/* All JMB PATA controllers have and will continue to have the same + * interface. Matching vendor and device class is enough for all + * current and future controllers if the controller is programmed + * properly. + * + * If libata is configured, jmicron PCI quirk programs the controller + * into the correct mode. If libata isn't configured, match known + * device IDs too to maintain backward compatibility. + */ +static struct pci_device_id jmicron_pci_tbl[] = { +#if !defined(CONFIG_ATA) && !defined(CONFIG_ATA_MODULE) + { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB361) }, + { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB363) }, + { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB365) }, + { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB366) }, + { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB368) }, +#endif + { PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, + PCI_CLASS_STORAGE_IDE << 8, 0xffff00, 0 }, + { 0, }, +}; + +MODULE_DEVICE_TABLE(pci, jmicron_pci_tbl); + +static struct pci_driver jmicron_pci_driver = { + .name = "JMicron IDE", + .id_table = jmicron_pci_tbl, + .probe = jmicron_init_one, + .remove = ide_pci_remove, + .suspend = ide_pci_suspend, + .resume = ide_pci_resume, +}; + +static int __init jmicron_ide_init(void) +{ + return ide_pci_register_driver(&jmicron_pci_driver); +} + +static void __exit jmicron_ide_exit(void) +{ + pci_unregister_driver(&jmicron_pci_driver); +} + +module_init(jmicron_ide_init); +module_exit(jmicron_ide_exit); + +MODULE_AUTHOR("Alan Cox"); +MODULE_DESCRIPTION("PCI driver module for the JMicron in legacy modes"); +MODULE_LICENSE("GPL"); diff --git a/drivers/ide/legacy/Makefile b/drivers/ide/legacy/Makefile deleted file mode 100644 index c7971061767..00000000000 --- a/drivers/ide/legacy/Makefile +++ /dev/null @@ -1,13 +0,0 @@ - -obj-$(CONFIG_BLK_DEV_ALI14XX) += ali14xx.o -obj-$(CONFIG_BLK_DEV_DTC2278) += dtc2278.o -obj-$(CONFIG_BLK_DEV_HT6560B) += ht6560b.o -obj-$(CONFIG_BLK_DEV_QD65XX) += qd65xx.o -obj-$(CONFIG_BLK_DEV_UMC8672) += umc8672.o - -obj-$(CONFIG_BLK_DEV_IDECS) += ide-cs.o - -# Last of all -obj-$(CONFIG_BLK_DEV_HD) += hd.o - -EXTRA_CFLAGS := -Idrivers/ide diff --git a/drivers/ide/legacy/falconide.c b/drivers/ide/legacy/falconide.c deleted file mode 100644 index a9f2cd5bb81..00000000000 --- a/drivers/ide/legacy/falconide.c +++ /dev/null @@ -1,78 +0,0 @@ -/* - * linux/drivers/ide/legacy/falconide.c -- Atari Falcon IDE Driver - * - * Created 12 Jul 1997 by Geert Uytterhoeven - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive for - * more details. - */ - -#include <linux/types.h> -#include <linux/mm.h> -#include <linux/interrupt.h> -#include <linux/blkdev.h> -#include <linux/hdreg.h> -#include <linux/ide.h> -#include <linux/init.h> - -#include <asm/setup.h> -#include <asm/atarihw.h> -#include <asm/atariints.h> -#include <asm/atari_stdma.h> - - - /* - * Base of the IDE interface - */ - -#define ATA_HD_BASE 0xfff00000 - - /* - * Offsets from the above base - */ - -#define ATA_HD_DATA 0x00 -#define ATA_HD_ERROR 0x05 /* see err-bits */ -#define ATA_HD_NSECTOR 0x09 /* nr of sectors to read/write */ -#define ATA_HD_SECTOR 0x0d /* starting sector */ -#define ATA_HD_LCYL 0x11 /* starting cylinder */ -#define ATA_HD_HCYL 0x15 /* high byte of starting cyl */ -#define ATA_HD_SELECT 0x19 /* 101dhhhh , d=drive, hhhh=head */ -#define ATA_HD_STATUS 0x1d /* see status-bits */ -#define ATA_HD_CONTROL 0x39 - -static int falconide_offsets[IDE_NR_PORTS] __initdata = { - ATA_HD_DATA, ATA_HD_ERROR, ATA_HD_NSECTOR, ATA_HD_SECTOR, ATA_HD_LCYL, - ATA_HD_HCYL, ATA_HD_SELECT, ATA_HD_STATUS, ATA_HD_CONTROL, -1 -}; - - - /* - * falconide_intr_lock is used to obtain access to the IDE interrupt, - * which is shared between several drivers. - */ - -int falconide_intr_lock; - - - /* - * Probe for a Falcon IDE interface - */ - -void __init falconide_init(void) -{ - if (MACH_IS_ATARI && ATARIHW_PRESENT(IDE)) { - hw_regs_t hw; - int index; - - ide_setup_ports(&hw, ATA_HD_BASE, falconide_offsets, - 0, 0, NULL, -// falconide_iops, - IRQ_MFP_IDE); - index = ide_register_hw(&hw, NULL); - - if (index != -1) - printk("ide%d: Falcon IDE interface\n", index); - } -} diff --git a/drivers/ide/legacy/gayle.c b/drivers/ide/legacy/gayle.c deleted file mode 100644 index 64d42619ab0..00000000000 --- a/drivers/ide/legacy/gayle.c +++ /dev/null @@ -1,185 +0,0 @@ -/* - * linux/drivers/ide/legacy/gayle.c -- Amiga Gayle IDE Driver - * - * Created 9 Jul 1997 by Geert Uytterhoeven - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive for - * more details. - */ - -#include <linux/types.h> -#include <linux/mm.h> -#include <linux/interrupt.h> -#include <linux/blkdev.h> -#include <linux/hdreg.h> -#include <linux/ide.h> -#include <linux/init.h> -#include <linux/zorro.h> - -#include <asm/setup.h> -#include <asm/amigahw.h> -#include <asm/amigaints.h> -#include <asm/amigayle.h> - - - /* - * Bases of the IDE interfaces - */ - -#define GAYLE_BASE_4000 0xdd2020 /* A4000/A4000T */ -#define GAYLE_BASE_1200 0xda0000 /* A1200/A600 and E-Matrix 530 */ - - /* - * Offsets from one of the above bases - */ - -#define GAYLE_DATA 0x00 -#define GAYLE_ERROR 0x06 /* see err-bits */ -#define GAYLE_NSECTOR 0x0a /* nr of sectors to read/write */ -#define GAYLE_SECTOR 0x0e /* starting sector */ -#define GAYLE_LCYL 0x12 /* starting cylinder */ -#define GAYLE_HCYL 0x16 /* high byte of starting cyl */ -#define GAYLE_SELECT 0x1a /* 101dhhhh , d=drive, hhhh=head */ -#define GAYLE_STATUS 0x1e /* see status-bits */ -#define GAYLE_CONTROL 0x101a - -static int gayle_offsets[IDE_NR_PORTS] __initdata = { - GAYLE_DATA, GAYLE_ERROR, GAYLE_NSECTOR, GAYLE_SECTOR, GAYLE_LCYL, - GAYLE_HCYL, GAYLE_SELECT, GAYLE_STATUS, -1, -1 -}; - - - /* - * These are at different offsets from the base - */ - -#define GAYLE_IRQ_4000 0xdd3020 /* MSB = 1, Harddisk is source of */ -#define GAYLE_IRQ_1200 0xda9000 /* interrupt */ - - - /* - * Offset of the secondary port for IDE doublers - * Note that GAYLE_CONTROL is NOT available then! - */ - -#define GAYLE_NEXT_PORT 0x1000 - -#ifndef CONFIG_BLK_DEV_IDEDOUBLER -#define GAYLE_NUM_HWIFS 1 -#define GAYLE_NUM_PROBE_HWIFS GAYLE_NUM_HWIFS -#define GAYLE_HAS_CONTROL_REG 1 -#define GAYLE_IDEREG_SIZE 0x2000 -#else /* CONFIG_BLK_DEV_IDEDOUBLER */ -#define GAYLE_NUM_HWIFS 2 -#define GAYLE_NUM_PROBE_HWIFS (ide_doubler ? GAYLE_NUM_HWIFS : \ - GAYLE_NUM_HWIFS-1) -#define GAYLE_HAS_CONTROL_REG (!ide_doubler) -#define GAYLE_IDEREG_SIZE (ide_doubler ? 0x1000 : 0x2000) -int ide_doubler = 0; /* support IDE doublers? */ -#endif /* CONFIG_BLK_DEV_IDEDOUBLER */ - - - /* - * Check and acknowledge the interrupt status - */ - -static int gayle_ack_intr_a4000(ide_hwif_t *hwif) -{ - unsigned char ch; - - ch = z_readb(hwif->io_ports[IDE_IRQ_OFFSET]); - if (!(ch & GAYLE_IRQ_IDE)) - return 0; - return 1; -} - -static int gayle_ack_intr_a1200(ide_hwif_t *hwif) -{ - unsigned char ch; - - ch = z_readb(hwif->io_ports[IDE_IRQ_OFFSET]); - if (!(ch & GAYLE_IRQ_IDE)) - return 0; - (void)z_readb(hwif->io_ports[IDE_STATUS_OFFSET]); - z_writeb(0x7c, hwif->io_ports[IDE_IRQ_OFFSET]); - return 1; -} - - /* - * Probe for a Gayle IDE interface (and optionally for an IDE doubler) - */ - -void __init gayle_init(void) -{ - int a4000, i; - - if (!MACH_IS_AMIGA) - return; - - if ((a4000 = AMIGAHW_PRESENT(A4000_IDE)) || AMIGAHW_PRESENT(A1200_IDE)) - goto found; - -#ifdef CONFIG_ZORRO - if (zorro_find_device(ZORRO_PROD_MTEC_VIPER_MK_V_E_MATRIX_530_SCSI_IDE, - NULL)) - goto found; -#endif - return; - -found: - for (i = 0; i < GAYLE_NUM_PROBE_HWIFS; i++) { - unsigned long base, ctrlport, irqport; - ide_ack_intr_t *ack_intr; - hw_regs_t hw; - ide_hwif_t *hwif; - int index; - unsigned long phys_base, res_start, res_n; - - if (a4000) { - phys_base = GAYLE_BASE_4000; - irqport = (unsigned long)ZTWO_VADDR(GAYLE_IRQ_4000); - ack_intr = gayle_ack_intr_a4000; - } else { - phys_base = GAYLE_BASE_1200; - irqport = (unsigned long)ZTWO_VADDR(GAYLE_IRQ_1200); - ack_intr = gayle_ack_intr_a1200; - } -/* - * FIXME: we now have selectable modes between mmio v/s iomio - */ - - phys_base += i*GAYLE_NEXT_PORT; - - res_start = ((unsigned long)phys_base) & ~(GAYLE_NEXT_PORT-1); - res_n = GAYLE_IDEREG_SIZE; - - if (!request_mem_region(res_start, res_n, "IDE")) - continue; - - base = (unsigned long)ZTWO_VADDR(phys_base); - ctrlport = GAYLE_HAS_CONTROL_REG ? (base + GAYLE_CONTROL) : 0; - - ide_setup_ports(&hw, base, gayle_offsets, - ctrlport, irqport, ack_intr, -// &gayle_iops, - IRQ_AMIGA_PORTS); - - index = ide_register_hw(&hw, &hwif); - if (index != -1) { - hwif->mmio = 2; - switch (i) { - case 0: - printk("ide%d: Gayle IDE interface (A%d style)\n", index, - a4000 ? 4000 : 1200); - break; -#ifdef CONFIG_BLK_DEV_IDEDOUBLER - case 1: - printk("ide%d: IDE doubler\n", index); - break; -#endif /* CONFIG_BLK_DEV_IDEDOUBLER */ - } - } else - release_mem_region(res_start, res_n); - } -} diff --git a/drivers/ide/legacy/hd.c b/drivers/ide/legacy/hd.c deleted file mode 100644 index aebecd8f51c..00000000000 --- a/drivers/ide/legacy/hd.c +++ /dev/null @@ -1,858 +0,0 @@ -/* - * Copyright (C) 1991, 1992 Linus Torvalds - * - * This is the low-level hd interrupt support. It traverses the - * request-list, using interrupts to jump between functions. As - * all the functions are called within interrupts, we may not - * sleep. Special care is recommended. - * - * modified by Drew Eckhardt to check nr of hd's from the CMOS. - * - * Thanks to Branko Lankester, lankeste@fwi.uva.nl, who found a bug - * in the early extended-partition checks and added DM partitions - * - * IRQ-unmask, drive-id, multiple-mode, support for ">16 heads", - * and general streamlining by Mark Lord. - * - * Removed 99% of above. Use Mark's ide driver for those options. - * This is now a lightweight ST-506 driver. (Paul Gortmaker) - * - * Modified 1995 Russell King for ARM processor. - * - * Bugfix: max_sectors must be <= 255 or the wheels tend to come - * off in a hurry once you queue things up - Paul G. 02/2001 - */ - -/* Uncomment the following if you want verbose error reports. */ -/* #define VERBOSE_ERRORS */ - -#include <linux/blkdev.h> -#include <linux/errno.h> -#include <linux/signal.h> -#include <linux/interrupt.h> -#include <linux/timer.h> -#include <linux/fs.h> -#include <linux/kernel.h> -#include <linux/genhd.h> -#include <linux/slab.h> -#include <linux/string.h> -#include <linux/ioport.h> -#include <linux/mc146818rtc.h> /* CMOS defines */ -#include <linux/init.h> -#include <linux/blkpg.h> -#include <linux/hdreg.h> - -#define REALLY_SLOW_IO -#include <asm/system.h> -#include <asm/io.h> -#include <asm/uaccess.h> - -#ifdef __arm__ -#undef HD_IRQ -#endif -#include <asm/irq.h> -#ifdef __arm__ -#define HD_IRQ IRQ_HARDDISK -#endif - -/* Hd controller regster ports */ - -#define HD_DATA 0x1f0 /* _CTL when writing */ -#define HD_ERROR 0x1f1 /* see err-bits */ -#define HD_NSECTOR 0x1f2 /* nr of sectors to read/write */ -#define HD_SECTOR 0x1f3 /* starting sector */ -#define HD_LCYL 0x1f4 /* starting cylinder */ -#define HD_HCYL 0x1f5 /* high byte of starting cyl */ -#define HD_CURRENT 0x1f6 /* 101dhhhh , d=drive, hhhh=head */ -#define HD_STATUS 0x1f7 /* see status-bits */ -#define HD_FEATURE HD_ERROR /* same io address, read=error, write=feature */ -#define HD_PRECOMP HD_FEATURE /* obsolete use of this port - predates IDE */ -#define HD_COMMAND HD_STATUS /* same io address, read=status, write=cmd */ - -#define HD_CMD 0x3f6 /* used for resets */ -#define HD_ALTSTATUS 0x3f6 /* same as HD_STATUS but doesn't clear irq */ - -/* Bits of HD_STATUS */ -#define ERR_STAT 0x01 -#define INDEX_STAT 0x02 -#define ECC_STAT 0x04 /* Corrected error */ -#define DRQ_STAT 0x08 -#define SEEK_STAT 0x10 -#define SERVICE_STAT SEEK_STAT -#define WRERR_STAT 0x20 -#define READY_STAT 0x40 -#define BUSY_STAT 0x80 - -/* Bits for HD_ERROR */ -#define MARK_ERR 0x01 /* Bad address mark */ -#define TRK0_ERR 0x02 /* couldn't find track 0 */ -#define ABRT_ERR 0x04 /* Command aborted */ -#define MCR_ERR 0x08 /* media change request */ -#define ID_ERR 0x10 /* ID field not found */ -#define MC_ERR 0x20 /* media changed */ -#define ECC_ERR 0x40 /* Uncorrectable ECC error */ -#define BBD_ERR 0x80 /* pre-EIDE meaning: block marked bad */ -#define ICRC_ERR 0x80 /* new meaning: CRC error during transfer */ - -static DEFINE_SPINLOCK(hd_lock); -static struct request_queue *hd_queue; - -#define MAJOR_NR HD_MAJOR -#define QUEUE (hd_queue) -#define CURRENT elv_next_request(hd_queue) - -#define TIMEOUT_VALUE (6*HZ) -#define HD_DELAY 0 - -#define MAX_ERRORS 16 /* Max read/write errors/sector */ -#define RESET_FREQ 8 /* Reset controller every 8th retry */ -#define RECAL_FREQ 4 /* Recalibrate every 4th retry */ -#define MAX_HD 2 - -#define STAT_OK (READY_STAT|SEEK_STAT) -#define OK_STATUS(s) (((s)&(STAT_OK|(BUSY_STAT|WRERR_STAT|ERR_STAT)))==STAT_OK) - -static void recal_intr(void); -static void bad_rw_intr(void); - -static int reset; -static int hd_error; - -/* - * This struct defines the HD's and their types. - */ -struct hd_i_struct { - unsigned int head,sect,cyl,wpcom,lzone,ctl; - int unit; - int recalibrate; - int special_op; -}; - -#ifdef HD_TYPE -static struct hd_i_struct hd_info[] = { HD_TYPE }; -static int NR_HD = ((sizeof (hd_info))/(sizeof (struct hd_i_struct))); -#else -static struct hd_i_struct hd_info[MAX_HD]; -static int NR_HD; -#endif - -static struct gendisk *hd_gendisk[MAX_HD]; - -static struct timer_list device_timer; - -#define TIMEOUT_VALUE (6*HZ) - -#define SET_TIMER \ - do { \ - mod_timer(&device_timer, jiffies + TIMEOUT_VALUE); \ - } while (0) - -static void (*do_hd)(void) = NULL; -#define SET_HANDLER(x) \ -if ((do_hd = (x)) != NULL) \ - SET_TIMER; \ -else \ - del_timer(&device_timer); - - -#if (HD_DELAY > 0) - -#include <asm/i8253.h> - -unsigned long last_req; - -unsigned long read_timer(void) -{ - unsigned long t, flags; - int i; - - spin_lock_irqsave(&i8253_lock, flags); - t = jiffies * 11932; - outb_p(0, 0x43); - i = inb_p(0x40); - i |= inb(0x40) << 8; - spin_unlock_irqrestore(&i8253_lock, flags); - return(t - i); -} -#endif - -static void __init hd_setup(char *str, int *ints) -{ - int hdind = 0; - - if (ints[0] != 3) - return; - if (hd_info[0].head != 0) - hdind=1; - hd_info[hdind].head = ints[2]; - hd_info[hdind].sect = ints[3]; - hd_info[hdind].cyl = ints[1]; - hd_info[hdind].wpcom = 0; - hd_info[hdind].lzone = ints[1]; - hd_info[hdind].ctl = (ints[2] > 8 ? 8 : 0); - NR_HD = hdind+1; -} - -static void dump_status (const char *msg, unsigned int stat) -{ - char *name = "hd?"; - if (CURRENT) - name = CURRENT->rq_disk->disk_name; - -#ifdef VERBOSE_ERRORS - printk("%s: %s: status=0x%02x { ", name, msg, stat & 0xff); - if (stat & BUSY_STAT) printk("Busy "); - if (stat & READY_STAT) printk("DriveReady "); - if (stat & WRERR_STAT) printk("WriteFault "); - if (stat & SEEK_STAT) printk("SeekComplete "); - if (stat & DRQ_STAT) printk("DataRequest "); - if (stat & ECC_STAT) printk("CorrectedError "); - if (stat & INDEX_STAT) printk("Index "); - if (stat & ERR_STAT) printk("Error "); - printk("}\n"); - if ((stat & ERR_STAT) == 0) { - hd_error = 0; - } else { - hd_error = inb(HD_ERROR); - printk("%s: %s: error=0x%02x { ", name, msg, hd_error & 0xff); - if (hd_error & BBD_ERR) printk("BadSector "); - if (hd_error & ECC_ERR) printk("UncorrectableError "); - if (hd_error & ID_ERR) printk("SectorIdNotFound "); - if (hd_error & ABRT_ERR) printk("DriveStatusError "); - if (hd_error & TRK0_ERR) printk("TrackZeroNotFound "); - if (hd_error & MARK_ERR) printk("AddrMarkNotFound "); - printk("}"); - if (hd_error & (BBD_ERR|ECC_ERR|ID_ERR|MARK_ERR)) { - printk(", CHS=%d/%d/%d", (inb(HD_HCYL)<<8) + inb(HD_LCYL), - inb(HD_CURRENT) & 0xf, inb(HD_SECTOR)); - if (CURRENT) - printk(", sector=%ld", CURRENT->sector); - } - printk("\n"); - } -#else - printk("%s: %s: status=0x%02x.\n", name, msg, stat & 0xff); - if ((stat & ERR_STAT) == 0) { - hd_error = 0; - } else { - hd_error = inb(HD_ERROR); - printk("%s: %s: error=0x%02x.\n", name, msg, hd_error & 0xff); - } -#endif -} - -static void check_status(void) -{ - int i = inb_p(HD_STATUS); - - if (!OK_STATUS(i)) { - dump_status("check_status", i); - bad_rw_intr(); - } -} - -static int controller_busy(void) -{ - int retries = 100000; - unsigned char status; - - do { - status = inb_p(HD_STATUS); - } while ((status & BUSY_STAT) && --retries); - return status; -} - -static int status_ok(void) -{ - unsigned char status = inb_p(HD_STATUS); - - if (status & BUSY_STAT) - return 1; /* Ancient, but does it make sense??? */ - if (status & WRERR_STAT) - return 0; - if (!(status & READY_STAT)) - return 0; - if (!(status & SEEK_STAT)) - return 0; - return 1; -} - -static int controller_ready(unsigned int drive, unsigned int head) -{ - int retry = 100; - - do { - if (controller_busy() & BUSY_STAT) - return 0; - outb_p(0xA0 | (drive<<4) | head, HD_CURRENT); - if (status_ok()) - return 1; - } while (--retry); - return 0; -} - - -static void hd_out(struct hd_i_struct *disk, - unsigned int nsect, - unsigned int sect, - unsigned int head, - unsigned int cyl, - unsigned int cmd, - void (*intr_addr)(void)) -{ - unsigned short port; - -#if (HD_DELAY > 0) - while (read_timer() - last_req < HD_DELAY) - /* nothing */; -#endif - if (reset) - return; - if (!controller_ready(disk->unit, head)) { - reset = 1; - return; - } - SET_HANDLER(intr_addr); - outb_p(disk->ctl,HD_CMD); - port=HD_DATA; - outb_p(disk->wpcom>>2,++port); - outb_p(nsect,++port); - outb_p(sect,++port); - outb_p(cyl,++port); - outb_p(cyl>>8,++port); - outb_p(0xA0|(disk->unit<<4)|head,++port); - outb_p(cmd,++port); -} - -static void hd_request (void); - -static int drive_busy(void) -{ - unsigned int i; - unsigned char c; - - for (i = 0; i < 500000 ; i++) { - c = inb_p(HD_STATUS); - if ((c & (BUSY_STAT | READY_STAT | SEEK_STAT)) == STAT_OK) - return 0; - } - dump_status("reset timed out", c); - return 1; -} - -static void reset_controller(void) -{ - int i; - - outb_p(4,HD_CMD); - for(i = 0; i < 1000; i++) barrier(); - outb_p(hd_info[0].ctl & 0x0f,HD_CMD); - for(i = 0; i < 1000; i++) barrier(); - if (drive_busy()) - printk("hd: controller still busy\n"); - else if ((hd_error = inb(HD_ERROR)) != 1) - printk("hd: controller reset failed: %02x\n",hd_error); -} - -static void reset_hd(void) -{ - static int i; - -repeat: - if (reset) { - reset = 0; - i = -1; - reset_controller(); - } else { - check_status(); - if (reset) - goto repeat; - } - if (++i < NR_HD) { - struct hd_i_struct *disk = &hd_info[i]; - disk->special_op = disk->recalibrate = 1; - hd_out(disk,disk->sect,disk->sect,disk->head-1, - disk->cyl,WIN_SPECIFY,&reset_hd); - if (reset) - goto repeat; - } else - hd_request(); -} - -/* - * Ok, don't know what to do with the unexpected interrupts: on some machines - * doing a reset and a retry seems to result in an eternal loop. Right now I - * ignore it, and just set the timeout. - * - * On laptops (and "green" PCs), an unexpected interrupt occurs whenever the - * drive enters "idle", "standby", or "sleep" mode, so if the status looks - * "good", we just ignore the interrupt completely. - */ -static void unexpected_hd_interrupt(void) -{ - unsigned int stat = inb_p(HD_STATUS); - - if (stat & (BUSY_STAT|DRQ_STAT|ECC_STAT|ERR_STAT)) { - dump_status ("unexpected interrupt", stat); - SET_TIMER; - } -} - -/* - * bad_rw_intr() now tries to be a bit smarter and does things - * according to the error returned by the controller. - * -Mika Liljeberg (liljeber@cs.Helsinki.FI) - */ -static void bad_rw_intr(void) -{ - struct request *req = CURRENT; - if (req != NULL) { - struct hd_i_struct *disk = req->rq_disk->private_data; - if (++req->errors >= MAX_ERRORS || (hd_error & BBD_ERR)) { - end_request(req, 0); - disk->special_op = disk->recalibrate = 1; - } else if (req->errors % RESET_FREQ == 0) - reset = 1; - else if ((hd_error & TRK0_ERR) || req->errors % RECAL_FREQ == 0) - disk->special_op = disk->recalibrate = 1; - /* Otherwise just retry */ - } -} - -static inline int wait_DRQ(void) -{ - int retries = 100000, stat; - - while (--retries > 0) - if ((stat = inb_p(HD_STATUS)) & DRQ_STAT) - return 0; - dump_status("wait_DRQ", stat); - return -1; -} - -static void read_intr(void) -{ - struct request *req; - int i, retries = 100000; - - do { - i = (unsigned) inb_p(HD_STATUS); - if (i & BUSY_STAT) - continue; - if (!OK_STATUS(i)) - break; - if (i & DRQ_STAT) - goto ok_to_read; - } while (--retries > 0); - dump_status("read_intr", i); - bad_rw_intr(); - hd_request(); - return; -ok_to_read: - req = CURRENT; - insw(HD_DATA,req->buffer,256); - req->sector++; - req->buffer += 512; - req->errors = 0; - i = --req->nr_sectors; - --req->current_nr_sectors; -#ifdef DEBUG - printk("%s: read: sector %ld, remaining = %ld, buffer=%p\n", - req->rq_disk->disk_name, req->sector, req->nr_sectors, - req->buffer+512)); -#endif - if (req->current_nr_sectors <= 0) - end_request(req, 1); - if (i > 0) { - SET_HANDLER(&read_intr); - return; - } - (void) inb_p(HD_STATUS); -#if (HD_DELAY > 0) - last_req = read_timer(); -#endif - if (elv_next_request(QUEUE)) - hd_request(); - return; -} - -static void write_intr(void) -{ - struct request *req = CURRENT; - int i; - int retries = 100000; - - do { - i = (unsigned) inb_p(HD_STATUS); - if (i & BUSY_STAT) - continue; - if (!OK_STATUS(i)) - break; - if ((req->nr_sectors <= 1) || (i & DRQ_STAT)) - goto ok_to_write; - } while (--retries > 0); - dump_status("write_intr", i); - bad_rw_intr(); - hd_request(); - return; -ok_to_write: - req->sector++; - i = --req->nr_sectors; - --req->current_nr_sectors; - req->buffer += 512; - if (!i || (req->bio && req->current_nr_sectors <= 0)) - end_request(req, 1); - if (i > 0) { - SET_HANDLER(&write_intr); - outsw(HD_DATA,req->buffer,256); - local_irq_enable(); - } else { -#if (HD_DELAY > 0) - last_req = read_timer(); -#endif - hd_request(); - } - return; -} - -static void recal_intr(void) -{ - check_status(); -#if (HD_DELAY > 0) - last_req = read_timer(); -#endif - hd_request(); -} - -/* - * This is another of the error-routines I don't know what to do with. The - * best idea seems to just set reset, and start all over again. - */ -static void hd_times_out(unsigned long dummy) -{ - char *name; - - do_hd = NULL; - - if (!CURRENT) - return; - - disable_irq(HD_IRQ); - local_irq_enable(); - reset = 1; - name = CURRENT->rq_disk->disk_name; - printk("%s: timeout\n", name); - if (++CURRENT->errors >= MAX_ERRORS) { -#ifdef DEBUG - printk("%s: too many errors\n", name); -#endif - end_request(CURRENT, 0); - } - local_irq_disable(); - hd_request(); - enable_irq(HD_IRQ); -} - -static int do_special_op(struct hd_i_struct *disk, struct request *req) -{ - if (disk->recalibrate) { - disk->recalibrate = 0; - hd_out(disk,disk->sect,0,0,0,WIN_RESTORE,&recal_intr); - return reset; - } - if (disk->head > 16) { - printk ("%s: cannot handle device with more than 16 heads - giving up\n", req->rq_disk->disk_name); - end_request(req, 0); - } - disk->special_op = 0; - return 1; -} - -/* - * The driver enables interrupts as much as possible. In order to do this, - * (a) the device-interrupt is disabled before entering hd_request(), - * and (b) the timeout-interrupt is disabled before the sti(). - * - * Interrupts are still masked (by default) whenever we are exchanging - * data/cmds with a drive, because some drives seem to have very poor - * tolerance for latency during I/O. The IDE driver has support to unmask - * interrupts for non-broken hardware, so use that driver if required. - */ -static void hd_request(void) -{ - unsigned int block, nsect, sec, track, head, cyl; - struct hd_i_struct *disk; - struct request *req; - - if (do_hd) - return; -repeat: - del_timer(&device_timer); - local_irq_enable(); - - req = CURRENT; - if (!req) { - do_hd = NULL; - return; - } - - if (reset) { - local_irq_disable(); - reset_hd(); - return; - } - disk = req->rq_disk->private_data; - block = req->sector; - nsect = req->nr_sectors; - if (block >= get_capacity(req->rq_disk) || - ((block+nsect) > get_capacity(req->rq_disk))) { - printk("%s: bad access: block=%d, count=%d\n", - req->rq_disk->disk_name, block, nsect); - end_request(req, 0); - goto repeat; - } - - if (disk->special_op) { - if (do_special_op(disk, req)) - goto repeat; - return; - } - sec = block % disk->sect + 1; - track = block / disk->sect; - head = track % disk->head; - cyl = track / disk->head; -#ifdef DEBUG - printk("%s: %sing: CHS=%d/%d/%d, sectors=%d, buffer=%p\n", - req->rq_disk->disk_name, (req->cmd == READ)?"read":"writ", - cyl, head, sec, nsect, req->buffer); -#endif - if (req->flags & REQ_CMD) { - switch (rq_data_dir(req)) { - case READ: - hd_out(disk,nsect,sec,head,cyl,WIN_READ,&read_intr); - if (reset) - goto repeat; - break; - case WRITE: - hd_out(disk,nsect,sec,head,cyl,WIN_WRITE,&write_intr); - if (reset) - goto repeat; - if (wait_DRQ()) { - bad_rw_intr(); - goto repeat; - } - outsw(HD_DATA,req->buffer,256); - break; - default: - printk("unknown hd-command\n"); - end_request(req, 0); - break; - } - } -} - -static void do_hd_request (request_queue_t * q) -{ - disable_irq(HD_IRQ); - hd_request(); - enable_irq(HD_IRQ); -} - -static int hd_getgeo(struct block_device *bdev, struct hd_geometry *geo) -{ - struct hd_i_struct *disk = bdev->bd_disk->private_data; - - geo->heads = disk->head; - geo->sectors = disk->sect; - geo->cylinders = disk->cyl; - return 0; -} - -/* - * Releasing a block device means we sync() it, so that it can safely - * be forgotten about... - */ - -static irqreturn_t hd_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - void (*handler)(void) = do_hd; - - do_hd = NULL; - del_timer(&device_timer); - if (!handler) - handler = unexpected_hd_interrupt; - handler(); - local_irq_enable(); - return IRQ_HANDLED; -} - -static struct block_device_operations hd_fops = { - .getgeo = hd_getgeo, -}; - -/* - * This is the hard disk IRQ description. The IRQF_DISABLED in sa_flags - * means we run the IRQ-handler with interrupts disabled: this is bad for - * interrupt latency, but anything else has led to problems on some - * machines. - * - * We enable interrupts in some of the routines after making sure it's - * safe. - */ - -static int __init hd_init(void) -{ - int drive; - - if (register_blkdev(MAJOR_NR,"hd")) - return -1; - - hd_queue = blk_init_queue(do_hd_request, &hd_lock); - if (!hd_queue) { - unregister_blkdev(MAJOR_NR,"hd"); - return -ENOMEM; - } - - blk_queue_max_sectors(hd_queue, 255); - init_timer(&device_timer); - device_timer.function = hd_times_out; - blk_queue_hardsect_size(hd_queue, 512); - -#ifdef __i386__ - if (!NR_HD) { - extern struct drive_info drive_info; - unsigned char *BIOS = (unsigned char *) &drive_info; - unsigned long flags; - int cmos_disks; - - for (drive=0 ; drive<2 ; drive++) { - hd_info[drive].cyl = *(unsigned short *) BIOS; - hd_info[drive].head = *(2+BIOS); - hd_info[drive].wpcom = *(unsigned short *) (5+BIOS); - hd_info[drive].ctl = *(8+BIOS); - hd_info[drive].lzone = *(unsigned short *) (12+BIOS); - hd_info[drive].sect = *(14+BIOS); -#ifdef does_not_work_for_everybody_with_scsi_but_helps_ibm_vp - if (hd_info[drive].cyl && NR_HD == drive) - NR_HD++; -#endif - BIOS += 16; - } - - /* - We query CMOS about hard disks : it could be that - we have a SCSI/ESDI/etc controller that is BIOS - compatible with ST-506, and thus showing up in our - BIOS table, but not register compatible, and therefore - not present in CMOS. - - Furthermore, we will assume that our ST-506 drives - <if any> are the primary drives in the system, and - the ones reflected as drive 1 or 2. - - The first drive is stored in the high nibble of CMOS - byte 0x12, the second in the low nibble. This will be - either a 4 bit drive type or 0xf indicating use byte 0x19 - for an 8 bit type, drive 1, 0x1a for drive 2 in CMOS. - - Needless to say, a non-zero value means we have - an AT controller hard disk for that drive. - - Currently the rtc_lock is a bit academic since this - driver is non-modular, but someday... ? Paul G. - */ - - spin_lock_irqsave(&rtc_lock, flags); - cmos_disks = CMOS_READ(0x12); - spin_unlock_irqrestore(&rtc_lock, flags); - - if (cmos_disks & 0xf0) { - if (cmos_disks & 0x0f) - NR_HD = 2; - else - NR_HD = 1; - } - } -#endif /* __i386__ */ -#ifdef __arm__ - if (!NR_HD) { - /* We don't know anything about the drive. This means - * that you *MUST* specify the drive parameters to the - * kernel yourself. - */ - printk("hd: no drives specified - use hd=cyl,head,sectors" - " on kernel command line\n"); - } -#endif - if (!NR_HD) - goto out; - - for (drive=0 ; drive < NR_HD ; drive++) { - struct gendisk *disk = alloc_disk(64); - struct hd_i_struct *p = &hd_info[drive]; - if (!disk) - goto Enomem; - disk->major = MAJOR_NR; - disk->first_minor = drive << 6; - disk->fops = &hd_fops; - sprintf(disk->disk_name, "hd%c", 'a'+drive); - disk->private_data = p; - set_capacity(disk, p->head * p->sect * p->cyl); - disk->queue = hd_queue; - p->unit = drive; - hd_gendisk[drive] = disk; - printk ("%s: %luMB, CHS=%d/%d/%d\n", - disk->disk_name, (unsigned long)get_capacity(disk)/2048, - p->cyl, p->head, p->sect); - } - - if (request_irq(HD_IRQ, hd_interrupt, IRQF_DISABLED, "hd", NULL)) { - printk("hd: unable to get IRQ%d for the hard disk driver\n", - HD_IRQ); - goto out1; - } - if (!request_region(HD_DATA, 8, "hd")) { - printk(KERN_WARNING "hd: port 0x%x busy\n", HD_DATA); - goto out2; - } - if (!request_region(HD_CMD, 1, "hd(cmd)")) { - printk(KERN_WARNING "hd: port 0x%x busy\n", HD_CMD); - goto out3; - } - - /* Let them fly */ - for(drive=0; drive < NR_HD; drive++) - add_disk(hd_gendisk[drive]); - - return 0; - -out3: - release_region(HD_DATA, 8); -out2: - free_irq(HD_IRQ, NULL); -out1: - for (drive = 0; drive < NR_HD; drive++) - put_disk(hd_gendisk[drive]); - NR_HD = 0; -out: - del_timer(&device_timer); - unregister_blkdev(MAJOR_NR,"hd"); - blk_cleanup_queue(hd_queue); - return -1; -Enomem: - while (drive--) - put_disk(hd_gendisk[drive]); - goto out; -} - -static int __init parse_hd_setup (char *line) { - int ints[6]; - - (void) get_options(line, ARRAY_SIZE(ints), ints); - hd_setup(NULL, ints); - - return 1; -} -__setup("hd=", parse_hd_setup); - -module_init(hd_init); diff --git a/drivers/ide/legacy/ide-cs.c b/drivers/ide/legacy/ide-cs.c deleted file mode 100644 index 602797a4420..00000000000 --- a/drivers/ide/legacy/ide-cs.c +++ /dev/null @@ -1,436 +0,0 @@ -/*====================================================================== - - A driver for PCMCIA IDE/ATA disk cards - - ide-cs.c 1.3 2002/10/26 05:45:31 - - The contents of this file are subject to the Mozilla Public - License Version 1.1 (the "License"); you may not use this file - except in compliance with the License. You may obtain a copy of - the License at http://www.mozilla.org/MPL/ - - Software distributed under the License is distributed on an "AS - IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - implied. See the License for the specific language governing - rights and limitations under the License. - - The initial developer of the original code is David A. Hinds - <dahinds@users.sourceforge.net>. Portions created by David A. Hinds - are Copyright (C) 1999 David A. Hinds. All Rights Reserved. - - Alternatively, the contents of this file may be used under the - terms of the GNU General Public License version 2 (the "GPL"), in - which case the provisions of the GPL are applicable instead of the - above. If you wish to allow the use of your version of this file - only under the terms of the GPL and not to allow others to use - your version of this file under the MPL, indicate your decision - by deleting the provisions above and replace them with the notice - and other provisions required by the GPL. If you do not delete - the provisions above, a recipient may use your version of this - file under either the MPL or the GPL. - -======================================================================*/ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/sched.h> -#include <linux/ptrace.h> -#include <linux/slab.h> -#include <linux/string.h> -#include <linux/timer.h> -#include <linux/ioport.h> -#include <linux/ide.h> -#include <linux/hdreg.h> -#include <linux/major.h> -#include <linux/delay.h> -#include <asm/io.h> -#include <asm/system.h> - -#include <pcmcia/cs_types.h> -#include <pcmcia/cs.h> -#include <pcmcia/cistpl.h> -#include <pcmcia/ds.h> -#include <pcmcia/cisreg.h> -#include <pcmcia/ciscode.h> - -/*====================================================================*/ - -/* Module parameters */ - -MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>"); -MODULE_DESCRIPTION("PCMCIA ATA/IDE card driver"); -MODULE_LICENSE("Dual MPL/GPL"); - -#define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0) - -#ifdef PCMCIA_DEBUG -INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG); -#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) -static char *version = -"ide-cs.c 1.3 2002/10/26 05:45:31 (David Hinds)"; -#else -#define DEBUG(n, args...) -#endif - -/*====================================================================*/ - -static const char ide_major[] = { - IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR, - IDE4_MAJOR, IDE5_MAJOR -}; - -typedef struct ide_info_t { - struct pcmcia_device *p_dev; - int ndev; - dev_node_t node; - int hd; -} ide_info_t; - -static void ide_release(struct pcmcia_device *); -static int ide_config(struct pcmcia_device *); - -static void ide_detach(struct pcmcia_device *p_dev); - - - - -/*====================================================================== - - ide_attach() creates an "instance" of the driver, allocating - local data structures for one device. The device is registered - with Card Services. - -======================================================================*/ - -static int ide_probe(struct pcmcia_device *link) -{ - ide_info_t *info; - - DEBUG(0, "ide_attach()\n"); - - /* Create new ide device */ - info = kzalloc(sizeof(*info), GFP_KERNEL); - if (!info) - return -ENOMEM; - - info->p_dev = link; - link->priv = info; - - link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; - link->io.Attributes2 = IO_DATA_PATH_WIDTH_8; - link->io.IOAddrLines = 3; - link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; - link->irq.IRQInfo1 = IRQ_LEVEL_ID; - link->conf.Attributes = CONF_ENABLE_IRQ; - link->conf.IntType = INT_MEMORY_AND_IO; - - return ide_config(link); -} /* ide_attach */ - -/*====================================================================== - - This deletes a driver "instance". The device is de-registered - with Card Services. If it has been released, all local data - structures are freed. Otherwise, the structures will be freed - when the device is released. - -======================================================================*/ - -static void ide_detach(struct pcmcia_device *link) -{ - DEBUG(0, "ide_detach(0x%p)\n", link); - - ide_release(link); - - kfree(link->priv); -} /* ide_detach */ - -static int idecs_register(unsigned long io, unsigned long ctl, unsigned long irq, struct pcmcia_device *handle) -{ - hw_regs_t hw; - memset(&hw, 0, sizeof(hw)); - ide_init_hwif_ports(&hw, io, ctl, NULL); - hw.irq = irq; - hw.chipset = ide_pci; - hw.dev = &handle->dev; - return ide_register_hw_with_fixup(&hw, NULL, ide_undecoded_slave); -} - -/*====================================================================== - - ide_config() is scheduled to run after a CARD_INSERTION event - is received, to configure the PCMCIA socket, and to make the - ide device available to the system. - -======================================================================*/ - -#define CS_CHECK(fn, ret) \ -do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) - -static int ide_config(struct pcmcia_device *link) -{ - ide_info_t *info = link->priv; - tuple_t tuple; - struct { - u_short buf[128]; - cisparse_t parse; - config_info_t conf; - cistpl_cftable_entry_t dflt; - } *stk = NULL; - cistpl_cftable_entry_t *cfg; - int i, pass, last_ret = 0, last_fn = 0, hd, is_kme = 0; - unsigned long io_base, ctl_base; - - DEBUG(0, "ide_config(0x%p)\n", link); - - stk = kzalloc(sizeof(*stk), GFP_KERNEL); - if (!stk) goto err_mem; - cfg = &stk->parse.cftable_entry; - - tuple.TupleData = (cisdata_t *)&stk->buf; - tuple.TupleOffset = 0; - tuple.TupleDataMax = 255; - tuple.Attributes = 0; - tuple.DesiredTuple = CISTPL_CONFIG; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); - CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &stk->parse)); - link->conf.ConfigBase = stk->parse.config.base; - link->conf.Present = stk->parse.config.rmask[0]; - - tuple.DesiredTuple = CISTPL_MANFID; - if (!pcmcia_get_first_tuple(link, &tuple) && - !pcmcia_get_tuple_data(link, &tuple) && - !pcmcia_parse_tuple(link, &tuple, &stk->parse)) - is_kme = ((stk->parse.manfid.manf == MANFID_KME) && - ((stk->parse.manfid.card == PRODID_KME_KXLC005_A) || - (stk->parse.manfid.card == PRODID_KME_KXLC005_B))); - - /* Not sure if this is right... look up the current Vcc */ - CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(link, &stk->conf)); - - pass = io_base = ctl_base = 0; - tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - tuple.Attributes = 0; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); - while (1) { - if (pcmcia_get_tuple_data(link, &tuple) != 0) goto next_entry; - if (pcmcia_parse_tuple(link, &tuple, &stk->parse) != 0) goto next_entry; - - /* Check for matching Vcc, unless we're desperate */ - if (!pass) { - if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) { - if (stk->conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) - goto next_entry; - } else if (stk->dflt.vcc.present & (1 << CISTPL_POWER_VNOM)) { - if (stk->conf.Vcc != stk->dflt.vcc.param[CISTPL_POWER_VNOM] / 10000) - goto next_entry; - } - } - - if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) - link->conf.Vpp = - cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000; - else if (stk->dflt.vpp1.present & (1 << CISTPL_POWER_VNOM)) - link->conf.Vpp = - stk->dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000; - - if ((cfg->io.nwin > 0) || (stk->dflt.io.nwin > 0)) { - cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &stk->dflt.io; - link->conf.ConfigIndex = cfg->index; - link->io.BasePort1 = io->win[0].base; - link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK; - if (!(io->flags & CISTPL_IO_16BIT)) - link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; - if (io->nwin == 2) { - link->io.NumPorts1 = 8; - link->io.BasePort2 = io->win[1].base; - link->io.NumPorts2 = (is_kme) ? 2 : 1; - if (pcmcia_request_io(link, &link->io) != 0) - goto next_entry; - io_base = link->io.BasePort1; - ctl_base = link->io.BasePort2; - } else if ((io->nwin == 1) && (io->win[0].len >= 16)) { - link->io.NumPorts1 = io->win[0].len; - link->io.NumPorts2 = 0; - if (pcmcia_request_io(link, &link->io) != 0) - goto next_entry; - io_base = link->io.BasePort1; - ctl_base = link->io.BasePort1 + 0x0e; - } else goto next_entry; - /* If we've got this far, we're done */ - break; - } - - next_entry: - if (cfg->flags & CISTPL_CFTABLE_DEFAULT) - memcpy(&stk->dflt, cfg, sizeof(stk->dflt)); - if (pass) { - CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(link, &tuple)); - } else if (pcmcia_get_next_tuple(link, &tuple) != 0) { - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); - memset(&stk->dflt, 0, sizeof(stk->dflt)); - pass++; - } - } - - CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); - CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf)); - - /* disable drive interrupts during IDE probe */ - outb(0x02, ctl_base); - - /* special setup for KXLC005 card */ - if (is_kme) - outb(0x81, ctl_base+1); - - /* retry registration in case device is still spinning up */ - for (hd = -1, i = 0; i < 10; i++) { - hd = idecs_register(io_base, ctl_base, link->irq.AssignedIRQ, link); - if (hd >= 0) break; - if (link->io.NumPorts1 == 0x20) { - outb(0x02, ctl_base + 0x10); - hd = idecs_register(io_base + 0x10, ctl_base + 0x10, - link->irq.AssignedIRQ, link); - if (hd >= 0) { - io_base += 0x10; - ctl_base += 0x10; - break; - } - } - msleep(100); - } - - if (hd < 0) { - printk(KERN_NOTICE "ide-cs: ide_register() at 0x%3lx & 0x%3lx" - ", irq %u failed\n", io_base, ctl_base, - link->irq.AssignedIRQ); - goto failed; - } - - info->ndev = 1; - sprintf(info->node.dev_name, "hd%c", 'a' + (hd * 2)); - info->node.major = ide_major[hd]; - info->node.minor = 0; - info->hd = hd; - link->dev_node = &info->node; - printk(KERN_INFO "ide-cs: %s: Vpp = %d.%d\n", - info->node.dev_name, link->conf.Vpp / 10, link->conf.Vpp % 10); - - kfree(stk); - return 0; - -err_mem: - printk(KERN_NOTICE "ide-cs: ide_config failed memory allocation\n"); - goto failed; - -cs_failed: - cs_error(link, last_fn, last_ret); -failed: - kfree(stk); - ide_release(link); - return -ENODEV; -} /* ide_config */ - -/*====================================================================== - - After a card is removed, ide_release() will unregister the net - device, and release the PCMCIA configuration. If the device is - still open, this will be postponed until it is closed. - -======================================================================*/ - -void ide_release(struct pcmcia_device *link) -{ - ide_info_t *info = link->priv; - - DEBUG(0, "ide_release(0x%p)\n", link); - - if (info->ndev) { - /* FIXME: if this fails we need to queue the cleanup somehow - -- need to investigate the required PCMCIA magic */ - ide_unregister(info->hd); - } - info->ndev = 0; - - pcmcia_disable_device(link); -} /* ide_release */ - - -/*====================================================================== - - The card status event handler. Mostly, this schedules other - stuff to run after an event is received. A CARD_REMOVAL event - also sets some flags to discourage the ide drivers from - talking to the ports. - -======================================================================*/ - -static struct pcmcia_device_id ide_ids[] = { - PCMCIA_DEVICE_FUNC_ID(4), - PCMCIA_DEVICE_MANF_CARD(0x0007, 0x0000), /* Hitachi */ - PCMCIA_DEVICE_MANF_CARD(0x0032, 0x0704), - PCMCIA_DEVICE_MANF_CARD(0x0045, 0x0401), - PCMCIA_DEVICE_MANF_CARD(0x0098, 0x0000), /* Toshiba */ - PCMCIA_DEVICE_MANF_CARD(0x00a4, 0x002d), - PCMCIA_DEVICE_MANF_CARD(0x00ce, 0x0000), /* Samsung */ - PCMCIA_DEVICE_MANF_CARD(0x0319, 0x0000), /* Hitachi */ - PCMCIA_DEVICE_MANF_CARD(0x2080, 0x0001), - PCMCIA_DEVICE_MANF_CARD(0x4e01, 0x0200), /* Lexar */ - PCMCIA_DEVICE_PROD_ID123("Caravelle", "PSC-IDE ", "PSC000", 0x8c36137c, 0xd0693ab8, 0x2768a9f0), - PCMCIA_DEVICE_PROD_ID123("CDROM", "IDE", "MCD-601p", 0x1b9179ca, 0xede88951, 0x0d902f74), - PCMCIA_DEVICE_PROD_ID123("PCMCIA", "IDE CARD", "F1", 0x281f1c5d, 0x1907960c, 0xf7fde8b9), - PCMCIA_DEVICE_PROD_ID12("ARGOSY", "CD-ROM", 0x78f308dc, 0x66536591), - PCMCIA_DEVICE_PROD_ID12("ARGOSY", "PnPIDE", 0x78f308dc, 0x0c694728), - PCMCIA_DEVICE_PROD_ID12("CNF CD-M", "CD-ROM", 0x7d93b852, 0x66536591), - PCMCIA_DEVICE_PROD_ID12("Creative Technology Ltd.", "PCMCIA CD-ROM Interface Card", 0xff8c8a45, 0xfe8020c4), - PCMCIA_DEVICE_PROD_ID12("Digital Equipment Corporation.", "Digital Mobile Media CD-ROM", 0x17692a66, 0xef1dcbde), - PCMCIA_DEVICE_PROD_ID12("EXP", "CD+GAME", 0x6f58c983, 0x63c13aaf), - PCMCIA_DEVICE_PROD_ID12("EXP ", "CD-ROM", 0x0a5c52fd, 0x66536591), - PCMCIA_DEVICE_PROD_ID12("EXP ", "PnPIDE", 0x0a5c52fd, 0x0c694728), - PCMCIA_DEVICE_PROD_ID12("FREECOM", "PCCARD-IDE", 0x5714cbf7, 0x48e0ab8e), - PCMCIA_DEVICE_PROD_ID12("HITACHI", "FLASH", 0xf4f43949, 0x9eb86aae), - PCMCIA_DEVICE_PROD_ID12("HITACHI", "microdrive", 0xf4f43949, 0xa6d76178), - PCMCIA_DEVICE_PROD_ID12("IBM", "microdrive", 0xb569a6e5, 0xa6d76178), - PCMCIA_DEVICE_PROD_ID12("IBM", "IBM17JSSFP20", 0xb569a6e5, 0xf2508753), - PCMCIA_DEVICE_PROD_ID12("IO DATA", "CBIDE2 ", 0x547e66dc, 0x8671043b), - PCMCIA_DEVICE_PROD_ID12("IO DATA", "PCIDE", 0x547e66dc, 0x5c5ab149), - PCMCIA_DEVICE_PROD_ID12("IO DATA", "PCIDEII", 0x547e66dc, 0xb3662674), - PCMCIA_DEVICE_PROD_ID12("LOOKMEET", "CBIDE2 ", 0xe37be2b5, 0x8671043b), - PCMCIA_DEVICE_PROD_ID2("NinjaATA-", 0xebe0bd79), - PCMCIA_DEVICE_PROD_ID12("PCMCIA", "CD-ROM", 0x281f1c5d, 0x66536591), - PCMCIA_DEVICE_PROD_ID12("PCMCIA", "PnPIDE", 0x281f1c5d, 0x0c694728), - PCMCIA_DEVICE_PROD_ID12("SHUTTLE TECHNOLOGY LTD.", "PCCARD-IDE/ATAPI Adapter", 0x4a3f0ba0, 0x322560e1), - PCMCIA_DEVICE_PROD_ID12("TOSHIBA", "MK2001MPL", 0xb4585a1a, 0x3489e003), - PCMCIA_DEVICE_PROD_ID1("TRANSCEND 512M ", 0xd0909443), - PCMCIA_DEVICE_PROD_ID12("WIT", "IDE16", 0x244e5994, 0x3e232852), - PCMCIA_DEVICE_PROD_ID1("STI Flash", 0xe4a13209), - PCMCIA_DEVICE_PROD_ID12("STI", "Flash 5.0", 0xbf2df18d, 0x8cb57a0e), - PCMCIA_MFC_DEVICE_PROD_ID12(1, "SanDisk", "ConnectPlus", 0x7a954bd9, 0x74be00c6), - PCMCIA_DEVICE_NULL, -}; -MODULE_DEVICE_TABLE(pcmcia, ide_ids); - -static struct pcmcia_driver ide_cs_driver = { - .owner = THIS_MODULE, - .drv = { - .name = "ide-cs", - }, - .probe = ide_probe, - .remove = ide_detach, - .id_table = ide_ids, -}; - -static int __init init_ide_cs(void) -{ - return pcmcia_register_driver(&ide_cs_driver); -} - -static void __exit exit_ide_cs(void) -{ - pcmcia_unregister_driver(&ide_cs_driver); -} - -late_initcall(init_ide_cs); -module_exit(exit_ide_cs); diff --git a/drivers/ide/legacy/macide.c b/drivers/ide/legacy/macide.c deleted file mode 100644 index d655da74914..00000000000 --- a/drivers/ide/legacy/macide.c +++ /dev/null @@ -1,154 +0,0 @@ -/* - * linux/drivers/ide/legacy/macide.c -- Macintosh IDE Driver - * - * Copyright (C) 1998 by Michael Schmitz - * - * This driver was written based on information obtained from the MacOS IDE - * driver binary by Mikael Forselius - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive for - * more details. - */ - -#include <linux/types.h> -#include <linux/mm.h> -#include <linux/interrupt.h> -#include <linux/blkdev.h> -#include <linux/hdreg.h> -#include <linux/delay.h> -#include <linux/ide.h> - -#include <asm/machw.h> -#include <asm/macintosh.h> -#include <asm/macints.h> -#include <asm/mac_baboon.h> - -#define IDE_BASE 0x50F1A000 /* Base address of IDE controller */ - -/* - * Generic IDE registers as offsets from the base - * These match MkLinux so they should be correct. - */ - -#define IDE_DATA 0x00 -#define IDE_ERROR 0x04 /* see err-bits */ -#define IDE_NSECTOR 0x08 /* nr of sectors to read/write */ -#define IDE_SECTOR 0x0c /* starting sector */ -#define IDE_LCYL 0x10 /* starting cylinder */ -#define IDE_HCYL 0x14 /* high byte of starting cyl */ -#define IDE_SELECT 0x18 /* 101dhhhh , d=drive, hhhh=head */ -#define IDE_STATUS 0x1c /* see status-bits */ -#define IDE_CONTROL 0x38 /* control/altstatus */ - -/* - * Mac-specific registers - */ - -/* - * this register is odd; it doesn't seem to do much and it's - * not word-aligned like virtually every other hardware register - * on the Mac... - */ - -#define IDE_IFR 0x101 /* (0x101) IDE interrupt flags on Quadra: - * - * Bit 0+1: some interrupt flags - * Bit 2+3: some interrupt enable - * Bit 4: ?? - * Bit 5: IDE interrupt flag (any hwif) - * Bit 6: maybe IDE interrupt enable (any hwif) ?? - * Bit 7: Any interrupt condition - */ - -volatile unsigned char *ide_ifr = (unsigned char *) (IDE_BASE + IDE_IFR); - -static int macide_offsets[IDE_NR_PORTS] = { - IDE_DATA, IDE_ERROR, IDE_NSECTOR, IDE_SECTOR, IDE_LCYL, - IDE_HCYL, IDE_SELECT, IDE_STATUS, IDE_CONTROL -}; - -int macide_ack_intr(ide_hwif_t* hwif) -{ - if (*ide_ifr & 0x20) { - *ide_ifr &= ~0x20; - return 1; - } - return 0; -} - -#ifdef CONFIG_BLK_DEV_MAC_MEDIABAY -static void macide_mediabay_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - int state = baboon->mb_status & 0x04; - - printk(KERN_INFO "macide: media bay %s detected\n", state? "removal":"insertion"); -} -#endif - -/* - * Probe for a Macintosh IDE interface - */ - -void macide_init(void) -{ - hw_regs_t hw; - ide_hwif_t *hwif; - int index = -1; - - switch (macintosh_config->ide_type) { - case MAC_IDE_QUADRA: - ide_setup_ports(&hw, IDE_BASE, macide_offsets, - 0, 0, macide_ack_intr, -// quadra_ide_iops, - IRQ_NUBUS_F); - index = ide_register_hw(&hw, &hwif); - break; - case MAC_IDE_PB: - ide_setup_ports(&hw, IDE_BASE, macide_offsets, - 0, 0, macide_ack_intr, -// macide_pb_iops, - IRQ_NUBUS_C); - index = ide_register_hw(&hw, &hwif); - break; - case MAC_IDE_BABOON: - ide_setup_ports(&hw, BABOON_BASE, macide_offsets, - 0, 0, NULL, -// macide_baboon_iops, - IRQ_BABOON_1); - index = ide_register_hw(&hw, &hwif); - if (index == -1) break; - if (macintosh_config->ident == MAC_MODEL_PB190) { - - /* Fix breakage in ide-disk.c: drive capacity */ - /* is not initialized for drives without a */ - /* hardware ID, and we can't get that without */ - /* probing the drive which freezes a 190. */ - - ide_drive_t *drive = &ide_hwifs[index].drives[0]; - drive->capacity64 = drive->cyl*drive->head*drive->sect; - -#ifdef CONFIG_BLK_DEV_MAC_MEDIABAY - request_irq(IRQ_BABOON_2, macide_mediabay_interrupt, - IRQ_FLG_FAST, "mediabay", - macide_mediabay_interrupt); -#endif - } - break; - - default: - return; - } - - if (index != -1) { - hwif->mmio = 2; - if (macintosh_config->ide_type == MAC_IDE_QUADRA) - printk(KERN_INFO "ide%d: Macintosh Quadra IDE interface\n", index); - else if (macintosh_config->ide_type == MAC_IDE_PB) - printk(KERN_INFO "ide%d: Macintosh Powerbook IDE interface\n", index); - else if (macintosh_config->ide_type == MAC_IDE_BABOON) - printk(KERN_INFO "ide%d: Macintosh Powerbook Baboon IDE interface\n", index); - else - printk(KERN_INFO "ide%d: Unknown Macintosh IDE interface\n", index); - } -} diff --git a/drivers/ide/legacy/q40ide.c b/drivers/ide/legacy/q40ide.c deleted file mode 100644 index 434a94faa3b..00000000000 --- a/drivers/ide/legacy/q40ide.c +++ /dev/null @@ -1,151 +0,0 @@ -/* - * linux/drivers/ide/legacy/q40ide.c -- Q40 I/O port IDE Driver - * - * (c) Richard Zidlicky - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive for - * more details. - * - * - */ - -#include <linux/types.h> -#include <linux/mm.h> -#include <linux/interrupt.h> -#include <linux/blkdev.h> -#include <linux/hdreg.h> - -#include <linux/ide.h> - - /* - * Bases of the IDE interfaces - */ - -#define Q40IDE_NUM_HWIFS 2 - -#define PCIDE_BASE1 0x1f0 -#define PCIDE_BASE2 0x170 -#define PCIDE_BASE3 0x1e8 -#define PCIDE_BASE4 0x168 -#define PCIDE_BASE5 0x1e0 -#define PCIDE_BASE6 0x160 - -static const unsigned long pcide_bases[Q40IDE_NUM_HWIFS] = { - PCIDE_BASE1, PCIDE_BASE2, /* PCIDE_BASE3, PCIDE_BASE4 , PCIDE_BASE5, - PCIDE_BASE6 */ -}; - - - /* - * Offsets from one of the above bases - */ - -/* used to do addr translation here but it is easier to do in setup ports */ -/*#define IDE_OFF_B(x) ((unsigned long)Q40_ISA_IO_B((IDE_##x##_OFFSET)))*/ - -#define IDE_OFF_B(x) ((unsigned long)((IDE_##x##_OFFSET))) -#define IDE_OFF_W(x) ((unsigned long)((IDE_##x##_OFFSET))) - -static const int pcide_offsets[IDE_NR_PORTS] = { - IDE_OFF_W(DATA), IDE_OFF_B(ERROR), IDE_OFF_B(NSECTOR), IDE_OFF_B(SECTOR), - IDE_OFF_B(LCYL), IDE_OFF_B(HCYL), 6 /*IDE_OFF_B(CURRENT)*/, IDE_OFF_B(STATUS), - 518/*IDE_OFF(CMD)*/ -}; - -static int q40ide_default_irq(unsigned long base) -{ - switch (base) { - case 0x1f0: return 14; - case 0x170: return 15; - case 0x1e8: return 11; - default: - return 0; - } -} - - -/* - * This is very similar to ide_setup_ports except that addresses - * are pretranslated for q40 ISA access - */ -void q40_ide_setup_ports ( hw_regs_t *hw, - unsigned long base, int *offsets, - unsigned long ctrl, unsigned long intr, - ide_ack_intr_t *ack_intr, -/* - * ide_io_ops_t *iops, - */ - int irq) -{ - int i; - - memset(hw, 0, sizeof(hw_regs_t)); - for (i = 0; i < IDE_NR_PORTS; i++) { - /* BIG FAT WARNING: - assumption: only DATA port is ever used in 16 bit mode */ - if ( i==0 ) - hw->io_ports[i] = Q40_ISA_IO_W(base + offsets[i]); - else - hw->io_ports[i] = Q40_ISA_IO_B(base + offsets[i]); - } - - hw->irq = irq; - hw->dma = NO_DMA; - hw->ack_intr = ack_intr; -/* - * hw->iops = iops; - */ -} - - - -/* - * the static array is needed to have the name reported in /proc/ioports, - * hwif->name unfortunately isn´t available yet - */ -static const char *q40_ide_names[Q40IDE_NUM_HWIFS]={ - "ide0", "ide1" -}; - -/* - * Probe for Q40 IDE interfaces - */ - -void q40ide_init(void) -{ - int i; - ide_hwif_t *hwif; - int index; - const char *name; - - if (!MACH_IS_Q40) - return ; - - for (i = 0; i < Q40IDE_NUM_HWIFS; i++) { - hw_regs_t hw; - - name = q40_ide_names[i]; - if (!request_region(pcide_bases[i], 8, name)) { - printk("could not reserve ports %lx-%lx for %s\n", - pcide_bases[i],pcide_bases[i]+8,name); - continue; - } - if (!request_region(pcide_bases[i]+0x206, 1, name)) { - printk("could not reserve port %lx for %s\n", - pcide_bases[i]+0x206,name); - release_region(pcide_bases[i], 8); - continue; - } - q40_ide_setup_ports(&hw,(unsigned long) pcide_bases[i], (int *)pcide_offsets, - pcide_bases[i]+0x206, - 0, NULL, -// m68kide_iops, - q40ide_default_irq(pcide_bases[i])); - index = ide_register_hw(&hw, &hwif); - // **FIXME** - if (index != -1) - hwif->mmio = 2; - } -} - diff --git a/drivers/ide/legacy/qd65xx.c b/drivers/ide/legacy/qd65xx.c deleted file mode 100644 index d3c3bc2640e..00000000000 --- a/drivers/ide/legacy/qd65xx.c +++ /dev/null @@ -1,510 +0,0 @@ -/* - * linux/drivers/ide/legacy/qd65xx.c Version 0.07 Sep 30, 2001 - * - * Copyright (C) 1996-2001 Linus Torvalds & author (see below) - */ - -/* - * Version 0.03 Cleaned auto-tune, added probe - * Version 0.04 Added second channel tuning - * Version 0.05 Enhanced tuning ; added qd6500 support - * Version 0.06 Added dos driver's list - * Version 0.07 Second channel bug fix - * - * QDI QD6500/QD6580 EIDE controller fast support - * - * Please set local bus speed using kernel parameter idebus - * for example, "idebus=33" stands for 33Mhz VLbus - * To activate controller support, use "ide0=qd65xx" - * To enable tuning, use "ide0=autotune" - * To enable second channel tuning (qd6580 only), use "ide1=autotune" - */ - -/* - * Rewritten from the work of Colten Edwards <pje120@cs.usask.ca> by - * Samuel Thibault <samuel.thibault@fnac.net> - */ - -#undef REALLY_SLOW_IO /* most systems can safely undef this */ - -#include <linux/module.h> -#include <linux/types.h> -#include <linux/kernel.h> -#include <linux/delay.h> -#include <linux/timer.h> -#include <linux/mm.h> -#include <linux/ioport.h> -#include <linux/blkdev.h> -#include <linux/hdreg.h> -#include <linux/ide.h> -#include <linux/init.h> -#include <asm/system.h> -#include <asm/io.h> - -#include "qd65xx.h" - -/* - * I/O ports are 0x30-0x31 (and 0x32-0x33 for qd6580) - * or 0xb0-0xb1 (and 0xb2-0xb3 for qd6580) - * -- qd6500 is a single IDE interface - * -- qd6580 is a dual IDE interface - * - * More research on qd6580 being done by willmore@cig.mot.com (David) - * More Information given by Petr Soucek (petr@ryston.cz) - * http://www.ryston.cz/petr/vlb - */ - -/* - * base: Timer1 - * - * - * base+0x01: Config (R/O) - * - * bit 0: ide baseport: 1 = 0x1f0 ; 0 = 0x170 (only useful for qd6500) - * bit 1: qd65xx baseport: 1 = 0xb0 ; 0 = 0x30 - * bit 2: ID3: bus speed: 1 = <=33MHz ; 0 = >33MHz - * bit 3: qd6500: 1 = disabled, 0 = enabled - * qd6580: 1 - * upper nibble: - * qd6500: 1100 - * qd6580: either 1010 or 0101 - * - * - * base+0x02: Timer2 (qd6580 only) - * - * - * base+0x03: Control (qd6580 only) - * - * bits 0-3 must always be set 1 - * bit 4 must be set 1, but is set 0 by dos driver while measuring vlb clock - * bit 0 : 1 = Only primary port enabled : channel 0 for hda, channel 1 for hdb - * 0 = Primary and Secondary ports enabled : channel 0 for hda & hdb - * channel 1 for hdc & hdd - * bit 1 : 1 = only disks on primary port - * 0 = disks & ATAPI devices on primary port - * bit 2-4 : always 0 - * bit 5 : status, but of what ? - * bit 6 : always set 1 by dos driver - * bit 7 : set 1 for non-ATAPI devices on primary port - * (maybe read-ahead and post-write buffer ?) - */ - -static int timings[4]={-1,-1,-1,-1}; /* stores current timing for each timer */ - -static void qd_write_reg (u8 content, unsigned long reg) -{ - unsigned long flags; - - spin_lock_irqsave(&ide_lock, flags); - outb(content,reg); - spin_unlock_irqrestore(&ide_lock, flags); -} - -static u8 __init qd_read_reg (unsigned long reg) -{ - unsigned long flags; - u8 read; - - spin_lock_irqsave(&ide_lock, flags); - read = inb(reg); - spin_unlock_irqrestore(&ide_lock, flags); - return read; -} - -/* - * qd_select: - * - * This routine is invoked from ide.c to prepare for access to a given drive. - */ - -static void qd_select (ide_drive_t *drive) -{ - u8 index = (( (QD_TIMREG(drive)) & 0x80 ) >> 7) | - (QD_TIMREG(drive) & 0x02); - - if (timings[index] != QD_TIMING(drive)) - qd_write_reg(timings[index] = QD_TIMING(drive), QD_TIMREG(drive)); -} - -/* - * qd6500_compute_timing - * - * computes the timing value where - * lower nibble represents active time, in count of VLB clocks - * upper nibble represents recovery time, in count of VLB clocks - */ - -static u8 qd6500_compute_timing (ide_hwif_t *hwif, int active_time, int recovery_time) -{ - u8 active_cycle,recovery_cycle; - - if (system_bus_clock()<=33) { - active_cycle = 9 - IDE_IN(active_time * system_bus_clock() / 1000 + 1, 2, 9); - recovery_cycle = 15 - IDE_IN(recovery_time * system_bus_clock() / 1000 + 1, 0, 15); - } else { - active_cycle = 8 - IDE_IN(active_time * system_bus_clock() / 1000 + 1, 1, 8); - recovery_cycle = 18 - IDE_IN(recovery_time * system_bus_clock() / 1000 + 1, 3, 18); - } - - return((recovery_cycle<<4) | 0x08 | active_cycle); -} - -/* - * qd6580_compute_timing - * - * idem for qd6580 - */ - -static u8 qd6580_compute_timing (int active_time, int recovery_time) -{ - u8 active_cycle = 17 - IDE_IN(active_time * system_bus_clock() / 1000 + 1, 2, 17); - u8 recovery_cycle = 15 - IDE_IN(recovery_time * system_bus_clock() / 1000 + 1, 2, 15); - - return((recovery_cycle<<4) | active_cycle); -} - -/* - * qd_find_disk_type - * - * tries to find timing from dos driver's table - */ - -static int qd_find_disk_type (ide_drive_t *drive, - int *active_time, int *recovery_time) -{ - struct qd65xx_timing_s *p; - char model[40]; - - if (!*drive->id->model) return 0; - - strncpy(model,drive->id->model,40); - ide_fixstring(model,40,1); /* byte-swap */ - - for (p = qd65xx_timing ; p->offset != -1 ; p++) { - if (!strncmp(p->model, model+p->offset, 4)) { - printk(KERN_DEBUG "%s: listed !\n", drive->name); - *active_time = p->active; - *recovery_time = p->recovery; - return 1; - } - } - return 0; -} - -/* - * qd_timing_ok: - * - * check whether timings don't conflict - */ - -static int qd_timing_ok (ide_drive_t drives[]) -{ - return (IDE_IMPLY(drives[0].present && drives[1].present, - IDE_IMPLY(QD_TIMREG(drives) == QD_TIMREG(drives+1), - QD_TIMING(drives) == QD_TIMING(drives+1)))); - /* if same timing register, must be same timing */ -} - -/* - * qd_set_timing: - * - * records the timing, and enables selectproc as needed - */ - -static void qd_set_timing (ide_drive_t *drive, u8 timing) -{ - ide_hwif_t *hwif = HWIF(drive); - - drive->drive_data &= 0xff00; - drive->drive_data |= timing; - if (qd_timing_ok(hwif->drives)) { - qd_select(drive); /* selects once */ - hwif->selectproc = NULL; - } else - hwif->selectproc = &qd_select; - - printk(KERN_DEBUG "%s: %#x\n", drive->name, timing); -} - -/* - * qd6500_tune_drive - */ - -static void qd6500_tune_drive (ide_drive_t *drive, u8 pio) -{ - int active_time = 175; - int recovery_time = 415; /* worst case values from the dos driver */ - - if (drive->id && !qd_find_disk_type(drive, &active_time, &recovery_time) - && drive->id->tPIO && (drive->id->field_valid & 0x02) - && drive->id->eide_pio >= 240) { - - printk(KERN_INFO "%s: PIO mode%d\n", drive->name, - drive->id->tPIO); - active_time = 110; - recovery_time = drive->id->eide_pio - 120; - } - - qd_set_timing(drive, qd6500_compute_timing(HWIF(drive), active_time, recovery_time)); -} - -/* - * qd6580_tune_drive - */ - -static void qd6580_tune_drive (ide_drive_t *drive, u8 pio) -{ - ide_pio_data_t d; - int base = HWIF(drive)->select_data; - int active_time = 175; - int recovery_time = 415; /* worst case values from the dos driver */ - - if (drive->id && !qd_find_disk_type(drive, &active_time, &recovery_time)) { - pio = ide_get_best_pio_mode(drive, pio, 255, &d); - pio = min_t(u8, pio, 4); - - switch (pio) { - case 0: break; - case 3: - if (d.cycle_time >= 110) { - active_time = 86; - recovery_time = d.cycle_time - 102; - } else - printk(KERN_WARNING "%s: Strange recovery time !\n",drive->name); - break; - case 4: - if (d.cycle_time >= 69) { - active_time = 70; - recovery_time = d.cycle_time - 61; - } else - printk(KERN_WARNING "%s: Strange recovery time !\n",drive->name); - break; - default: - if (d.cycle_time >= 180) { - active_time = 110; - recovery_time = d.cycle_time - 120; - } else { - active_time = ide_pio_timings[pio].active_time; - recovery_time = d.cycle_time - -active_time; - } - } - printk(KERN_INFO "%s: PIO mode%d\n", drive->name,pio); - } - - if (!HWIF(drive)->channel && drive->media != ide_disk) { - qd_write_reg(0x5f, QD_CONTROL_PORT); - printk(KERN_WARNING "%s: ATAPI: disabled read-ahead FIFO " - "and post-write buffer on %s.\n", - drive->name, HWIF(drive)->name); - } - - qd_set_timing(drive, qd6580_compute_timing(active_time, recovery_time)); -} - -/* - * qd_testreg - * - * tests if the given port is a register - */ - -static int __init qd_testreg(int port) -{ - u8 savereg; - u8 readreg; - unsigned long flags; - - spin_lock_irqsave(&ide_lock, flags); - savereg = inb_p(port); - outb_p(QD_TESTVAL, port); /* safe value */ - readreg = inb_p(port); - outb(savereg, port); - spin_unlock_irqrestore(&ide_lock, flags); - - if (savereg == QD_TESTVAL) { - printk(KERN_ERR "Outch ! the probe for qd65xx isn't reliable !\n"); - printk(KERN_ERR "Please contact maintainers to tell about your hardware\n"); - printk(KERN_ERR "Assuming qd65xx is not present.\n"); - return 1; - } - - return (readreg != QD_TESTVAL); -} - -/* - * qd_setup: - * - * called to setup an ata channel : adjusts attributes & links for tuning - */ - -static void __init qd_setup(ide_hwif_t *hwif, int base, int config, - unsigned int data0, unsigned int data1, - void (*tuneproc) (ide_drive_t *, u8 pio)) -{ - hwif->chipset = ide_qd65xx; - hwif->channel = hwif->index; - hwif->select_data = base; - hwif->config_data = config; - hwif->drives[0].drive_data = data0; - hwif->drives[1].drive_data = data1; - hwif->drives[0].io_32bit = - hwif->drives[1].io_32bit = 1; - hwif->tuneproc = tuneproc; - probe_hwif_init(hwif); -} - -/* - * qd_unsetup: - * - * called to unsetup an ata channel : back to default values, unlinks tuning - */ -/* -static void __exit qd_unsetup(ide_hwif_t *hwif) -{ - u8 config = hwif->config_data; - int base = hwif->select_data; - void *tuneproc = (void *) hwif->tuneproc; - - if (hwif->chipset != ide_qd65xx) - return; - - printk(KERN_NOTICE "%s: back to defaults\n", hwif->name); - - hwif->selectproc = NULL; - hwif->tuneproc = NULL; - - if (tuneproc == (void *) qd6500_tune_drive) { - // will do it for both - qd_write_reg(QD6500_DEF_DATA, QD_TIMREG(&hwif->drives[0])); - } else if (tuneproc == (void *) qd6580_tune_drive) { - if (QD_CONTROL(hwif) & QD_CONTR_SEC_DISABLED) { - qd_write_reg(QD6580_DEF_DATA, QD_TIMREG(&hwif->drives[0])); - qd_write_reg(QD6580_DEF_DATA2, QD_TIMREG(&hwif->drives[1])); - } else { - qd_write_reg(hwif->channel ? QD6580_DEF_DATA2 : QD6580_DEF_DATA, QD_TIMREG(&hwif->drives[0])); - } - } else { - printk(KERN_WARNING "Unknown qd65xx tuning fonction !\n"); - printk(KERN_WARNING "keeping settings !\n"); - } -} -*/ - -/* - * qd_probe: - * - * looks at the specified baseport, and if qd found, registers & initialises it - * return 1 if another qd may be probed - */ - -static int __init qd_probe(int base) -{ - ide_hwif_t *hwif; - u8 config; - u8 unit; - - config = qd_read_reg(QD_CONFIG_PORT); - - if (! ((config & QD_CONFIG_BASEPORT) >> 1 == (base == 0xb0)) ) - return 1; - - unit = ! (config & QD_CONFIG_IDE_BASEPORT); - - if ((config & 0xf0) == QD_CONFIG_QD6500) { - - if (qd_testreg(base)) return 1; /* bad register */ - - /* qd6500 found */ - - hwif = &ide_hwifs[unit]; - printk(KERN_NOTICE "%s: qd6500 at %#x\n", hwif->name, base); - printk(KERN_DEBUG "qd6500: config=%#x, ID3=%u\n", - config, QD_ID3); - - if (config & QD_CONFIG_DISABLED) { - printk(KERN_WARNING "qd6500 is disabled !\n"); - return 1; - } - - qd_setup(hwif, base, config, QD6500_DEF_DATA, QD6500_DEF_DATA, - &qd6500_tune_drive); - - create_proc_ide_interfaces(); - - return 1; - } - - if (((config & 0xf0) == QD_CONFIG_QD6580_A) || - ((config & 0xf0) == QD_CONFIG_QD6580_B)) { - - u8 control; - - if (qd_testreg(base) || qd_testreg(base+0x02)) return 1; - /* bad registers */ - - /* qd6580 found */ - - control = qd_read_reg(QD_CONTROL_PORT); - - printk(KERN_NOTICE "qd6580 at %#x\n", base); - printk(KERN_DEBUG "qd6580: config=%#x, control=%#x, ID3=%u\n", - config, control, QD_ID3); - - if (control & QD_CONTR_SEC_DISABLED) { - /* secondary disabled */ - - hwif = &ide_hwifs[unit]; - printk(KERN_INFO "%s: qd6580: single IDE board\n", - hwif->name); - qd_setup(hwif, base, config | (control << 8), - QD6580_DEF_DATA, QD6580_DEF_DATA2, - &qd6580_tune_drive); - qd_write_reg(QD_DEF_CONTR,QD_CONTROL_PORT); - - create_proc_ide_interfaces(); - - return 1; - } else { - ide_hwif_t *mate; - - hwif = &ide_hwifs[0]; - mate = &ide_hwifs[1]; - /* secondary enabled */ - printk(KERN_INFO "%s&%s: qd6580: dual IDE board\n", - hwif->name, mate->name); - - qd_setup(hwif, base, config | (control << 8), - QD6580_DEF_DATA, QD6580_DEF_DATA, - &qd6580_tune_drive); - qd_setup(mate, base, config | (control << 8), - QD6580_DEF_DATA2, QD6580_DEF_DATA2, - &qd6580_tune_drive); - qd_write_reg(QD_DEF_CONTR,QD_CONTROL_PORT); - - create_proc_ide_interfaces(); - - return 0; /* no other qd65xx possible */ - } - } - /* no qd65xx found */ - return 1; -} - -/* Can be called directly from ide.c. */ -int __init qd65xx_init(void) -{ - if (qd_probe(0x30)) - qd_probe(0xb0); - if (ide_hwifs[0].chipset != ide_qd65xx && - ide_hwifs[1].chipset != ide_qd65xx) - return -ENODEV; - return 0; -} - -#ifdef MODULE -module_init(qd65xx_init); -#endif - -MODULE_AUTHOR("Samuel Thibault"); -MODULE_DESCRIPTION("support of qd65xx vlb ide chipset"); -MODULE_LICENSE("GPL"); diff --git a/drivers/ide/macide.c b/drivers/ide/macide.c new file mode 100644 index 00000000000..adc5fe9daaf --- /dev/null +++ b/drivers/ide/macide.c @@ -0,0 +1,141 @@ +/* + * Macintosh IDE Driver + * + * Copyright (C) 1998 by Michael Schmitz + * + * This driver was written based on information obtained from the MacOS IDE + * driver binary by Mikael Forselius + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + */ + +#include <linux/types.h> +#include <linux/mm.h> +#include <linux/interrupt.h> +#include <linux/blkdev.h> +#include <linux/delay.h> +#include <linux/ide.h> +#include <linux/module.h> + +#include <asm/macintosh.h> +#include <asm/macints.h> +#include <asm/mac_baboon.h> + +#define IDE_BASE 0x50F1A000 /* Base address of IDE controller */ + +/* + * Generic IDE registers as offsets from the base + * These match MkLinux so they should be correct. + */ + +#define IDE_CONTROL 0x38 /* control/altstatus */ + +/* + * Mac-specific registers + */ + +/* + * this register is odd; it doesn't seem to do much and it's + * not word-aligned like virtually every other hardware register + * on the Mac... + */ + +#define IDE_IFR 0x101 /* (0x101) IDE interrupt flags on Quadra: + * + * Bit 0+1: some interrupt flags + * Bit 2+3: some interrupt enable + * Bit 4: ?? + * Bit 5: IDE interrupt flag (any hwif) + * Bit 6: maybe IDE interrupt enable (any hwif) ?? + * Bit 7: Any interrupt condition + */ + +volatile unsigned char *ide_ifr = (unsigned char *) (IDE_BASE + IDE_IFR); + +int macide_test_irq(ide_hwif_t *hwif) +{ + if (*ide_ifr & 0x20) + return 1; + return 0; +} + +static void macide_clear_irq(ide_drive_t *drive) +{ + *ide_ifr &= ~0x20; +} + +static void __init macide_setup_ports(struct ide_hw *hw, unsigned long base, + int irq) +{ + int i; + + memset(hw, 0, sizeof(*hw)); + + for (i = 0; i < 8; i++) + hw->io_ports_array[i] = base + i * 4; + + hw->io_ports.ctl_addr = base + IDE_CONTROL; + + hw->irq = irq; +} + +static const struct ide_port_ops macide_port_ops = { + .clear_irq = macide_clear_irq, + .test_irq = macide_test_irq, +}; + +static const struct ide_port_info macide_port_info = { + .port_ops = &macide_port_ops, + .host_flags = IDE_HFLAG_MMIO | IDE_HFLAG_NO_DMA, + .irq_flags = IRQF_SHARED, + .chipset = ide_generic, +}; + +static const char *mac_ide_name[] = + { "Quadra", "Powerbook", "Powerbook Baboon" }; + +/* + * Probe for a Macintosh IDE interface + */ + +static int __init macide_init(void) +{ + unsigned long base; + int irq; + struct ide_hw hw, *hws[] = { &hw }; + struct ide_port_info d = macide_port_info; + + if (!MACH_IS_MAC) + return -ENODEV; + + switch (macintosh_config->ide_type) { + case MAC_IDE_QUADRA: + base = IDE_BASE; + irq = IRQ_NUBUS_F; + break; + case MAC_IDE_PB: + base = IDE_BASE; + irq = IRQ_NUBUS_C; + break; + case MAC_IDE_BABOON: + base = BABOON_BASE; + d.port_ops = NULL; + irq = IRQ_BABOON_1; + break; + default: + return -ENODEV; + } + + printk(KERN_INFO "ide: Macintosh %s IDE controller\n", + mac_ide_name[macintosh_config->ide_type - 1]); + + macide_setup_ports(&hw, base, irq); + + return ide_host_add(&d, hws, 1, NULL); +} + +module_init(macide_init); + +MODULE_LICENSE("GPL"); diff --git a/drivers/ide/mips/Makefile b/drivers/ide/mips/Makefile deleted file mode 100644 index 677c7b2bac9..00000000000 --- a/drivers/ide/mips/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -obj-$(CONFIG_BLK_DEV_IDE_SWARM) += swarm.o -obj-$(CONFIG_BLK_DEV_IDE_AU1XXX) += au1xxx-ide.o - -EXTRA_CFLAGS := -Idrivers/ide diff --git a/drivers/ide/mips/au1xxx-ide.c b/drivers/ide/mips/au1xxx-ide.c deleted file mode 100644 index c7854ea57b5..00000000000 --- a/drivers/ide/mips/au1xxx-ide.c +++ /dev/null @@ -1,821 +0,0 @@ -/* - * linux/drivers/ide/mips/au1xxx-ide.c version 01.30.00 Aug. 02 2005 - * - * BRIEF MODULE DESCRIPTION - * AMD Alchemy Au1xxx IDE interface routines over the Static Bus - * - * Copyright (c) 2003-2005 AMD, Personal Connectivity Solutions - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by the Free Software - * Foundation; either version 2 of the License, or (at your option) any later - * version. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Note: for more information, please refer "AMD Alchemy Au1200/Au1550 IDE - * Interface and Linux Device Driver" Application Note. - */ -#undef REALLY_SLOW_IO /* most systems can safely undef this */ - -#include <linux/types.h> -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/delay.h> -#include <linux/platform_device.h> - -#include <linux/init.h> -#include <linux/ide.h> -#include <linux/sysdev.h> - -#include <linux/dma-mapping.h> - -#include "ide-timing.h" - -#include <asm/io.h> -#include <asm/mach-au1x00/au1xxx.h> -#include <asm/mach-au1x00/au1xxx_dbdma.h> - -#include <asm/mach-au1x00/au1xxx_ide.h> - -#define DRV_NAME "au1200-ide" -#define DRV_VERSION "1.0" -#define DRV_AUTHOR "Enrico Walther <enrico.walther@amd.com> / Pete Popov <ppopov@embeddedalley.com>" - -/* enable the burstmode in the dbdma */ -#define IDE_AU1XXX_BURSTMODE 1 - -static _auide_hwif auide_hwif; -static int dbdma_init_done; - -#if defined(CONFIG_BLK_DEV_IDE_AU1XXX_PIO_DBDMA) - -void auide_insw(unsigned long port, void *addr, u32 count) -{ - _auide_hwif *ahwif = &auide_hwif; - chan_tab_t *ctp; - au1x_ddma_desc_t *dp; - - if(!put_dest_flags(ahwif->rx_chan, (void*)addr, count << 1, - DDMA_FLAGS_NOIE)) { - printk(KERN_ERR "%s failed %d\n", __FUNCTION__, __LINE__); - return; - } - ctp = *((chan_tab_t **)ahwif->rx_chan); - dp = ctp->cur_ptr; - while (dp->dscr_cmd0 & DSCR_CMD0_V) - ; - ctp->cur_ptr = au1xxx_ddma_get_nextptr_virt(dp); -} - -void auide_outsw(unsigned long port, void *addr, u32 count) -{ - _auide_hwif *ahwif = &auide_hwif; - chan_tab_t *ctp; - au1x_ddma_desc_t *dp; - - if(!put_source_flags(ahwif->tx_chan, (void*)addr, - count << 1, DDMA_FLAGS_NOIE)) { - printk(KERN_ERR "%s failed %d\n", __FUNCTION__, __LINE__); - return; - } - ctp = *((chan_tab_t **)ahwif->tx_chan); - dp = ctp->cur_ptr; - while (dp->dscr_cmd0 & DSCR_CMD0_V) - ; - ctp->cur_ptr = au1xxx_ddma_get_nextptr_virt(dp); -} - -#endif - -static void auide_tune_drive(ide_drive_t *drive, byte pio) -{ - int mem_sttime; - int mem_stcfg; - u8 speed; - - /* get the best pio mode for the drive */ - pio = ide_get_best_pio_mode(drive, pio, 4, NULL); - - printk(KERN_INFO "%s: setting Au1XXX IDE to PIO mode%d\n", - drive->name, pio); - - mem_sttime = 0; - mem_stcfg = au_readl(MEM_STCFG2); - - /* set pio mode! */ - switch(pio) { - case 0: - mem_sttime = SBC_IDE_TIMING(PIO0); - - /* set configuration for RCS2# */ - mem_stcfg |= TS_MASK; - mem_stcfg &= ~TCSOE_MASK; - mem_stcfg &= ~TOECS_MASK; - mem_stcfg |= SBC_IDE_PIO0_TCSOE | SBC_IDE_PIO0_TOECS; - break; - - case 1: - mem_sttime = SBC_IDE_TIMING(PIO1); - - /* set configuration for RCS2# */ - mem_stcfg |= TS_MASK; - mem_stcfg &= ~TCSOE_MASK; - mem_stcfg &= ~TOECS_MASK; - mem_stcfg |= SBC_IDE_PIO1_TCSOE | SBC_IDE_PIO1_TOECS; - break; - - case 2: - mem_sttime = SBC_IDE_TIMING(PIO2); - - /* set configuration for RCS2# */ - mem_stcfg &= ~TS_MASK; - mem_stcfg &= ~TCSOE_MASK; - mem_stcfg &= ~TOECS_MASK; - mem_stcfg |= SBC_IDE_PIO2_TCSOE | SBC_IDE_PIO2_TOECS; - break; - - case 3: - mem_sttime = SBC_IDE_TIMING(PIO3); - - /* set configuration for RCS2# */ - mem_stcfg &= ~TS_MASK; - mem_stcfg &= ~TCSOE_MASK; - mem_stcfg &= ~TOECS_MASK; - mem_stcfg |= SBC_IDE_PIO3_TCSOE | SBC_IDE_PIO3_TOECS; - - break; - - case 4: - mem_sttime = SBC_IDE_TIMING(PIO4); - - /* set configuration for RCS2# */ - mem_stcfg &= ~TS_MASK; - mem_stcfg &= ~TCSOE_MASK; - mem_stcfg &= ~TOECS_MASK; - mem_stcfg |= SBC_IDE_PIO4_TCSOE | SBC_IDE_PIO4_TOECS; - break; - } - - au_writel(mem_sttime,MEM_STTIME2); - au_writel(mem_stcfg,MEM_STCFG2); - - speed = pio + XFER_PIO_0; - ide_config_drive_speed(drive, speed); -} - -static int auide_tune_chipset (ide_drive_t *drive, u8 speed) -{ - int mem_sttime; - int mem_stcfg; - unsigned long mode; - -#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA - if (ide_use_dma(drive)) - mode = ide_dma_speed(drive, 0); -#endif - - mem_sttime = 0; - mem_stcfg = au_readl(MEM_STCFG2); - - if (speed >= XFER_PIO_0 && speed <= XFER_PIO_4) { - auide_tune_drive(drive, speed - XFER_PIO_0); - return 0; - } - - switch(speed) { -#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA - case XFER_MW_DMA_2: - mem_sttime = SBC_IDE_TIMING(MDMA2); - - /* set configuration for RCS2# */ - mem_stcfg &= ~TS_MASK; - mem_stcfg &= ~TCSOE_MASK; - mem_stcfg &= ~TOECS_MASK; - mem_stcfg |= SBC_IDE_MDMA2_TCSOE | SBC_IDE_MDMA2_TOECS; - - mode = XFER_MW_DMA_2; - break; - case XFER_MW_DMA_1: - mem_sttime = SBC_IDE_TIMING(MDMA1); - - /* set configuration for RCS2# */ - mem_stcfg &= ~TS_MASK; - mem_stcfg &= ~TCSOE_MASK; - mem_stcfg &= ~TOECS_MASK; - mem_stcfg |= SBC_IDE_MDMA1_TCSOE | SBC_IDE_MDMA1_TOECS; - - mode = XFER_MW_DMA_1; - break; - case XFER_MW_DMA_0: - mem_sttime = SBC_IDE_TIMING(MDMA0); - - /* set configuration for RCS2# */ - mem_stcfg |= TS_MASK; - mem_stcfg &= ~TCSOE_MASK; - mem_stcfg &= ~TOECS_MASK; - mem_stcfg |= SBC_IDE_MDMA0_TCSOE | SBC_IDE_MDMA0_TOECS; - - mode = XFER_MW_DMA_0; - break; -#endif - default: - return 1; - } - - if (ide_config_drive_speed(drive, mode)) - return 1; - - au_writel(mem_sttime,MEM_STTIME2); - au_writel(mem_stcfg,MEM_STCFG2); - - return 0; -} - -/* - * Multi-Word DMA + DbDMA functions - */ - -#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA - -static int auide_build_sglist(ide_drive_t *drive, struct request *rq) -{ - ide_hwif_t *hwif = drive->hwif; - _auide_hwif *ahwif = (_auide_hwif*)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; - - return dma_map_sg(ahwif->dev, sg, hwif->sg_nents, - hwif->sg_dma_direction); -} - -static int auide_build_dmatable(ide_drive_t *drive) -{ - int i, iswrite, count = 0; - ide_hwif_t *hwif = HWIF(drive); - - struct request *rq = HWGROUP(drive)->rq; - - _auide_hwif *ahwif = (_auide_hwif*)hwif->hwif_data; - struct scatterlist *sg; - - iswrite = (rq_data_dir(rq) == WRITE); - /* Save for interrupt context */ - ahwif->drive = drive; - - /* Build sglist */ - hwif->sg_nents = i = auide_build_sglist(drive, rq); - - if (!i) - return 0; - - /* fill the descriptors */ - sg = hwif->sg_table; - while (i && sg_dma_len(sg)) { - u32 cur_addr; - u32 cur_len; - - cur_addr = sg_dma_address(sg); - cur_len = sg_dma_len(sg); - - while (cur_len) { - u32 flags = DDMA_FLAGS_NOIE; - unsigned int tc = (cur_len < 0xfe00)? cur_len: 0xfe00; - - if (++count >= PRD_ENTRIES) { - printk(KERN_WARNING "%s: DMA table too small\n", - drive->name); - goto use_pio_instead; - } - - /* Lets enable intr for the last descriptor only */ - if (1==i) - flags = DDMA_FLAGS_IE; - else - flags = DDMA_FLAGS_NOIE; - - if (iswrite) { - if(!put_source_flags(ahwif->tx_chan, - (void*)(page_address(sg->page) - + sg->offset), - tc, flags)) { - printk(KERN_ERR "%s failed %d\n", - __FUNCTION__, __LINE__); - } - } else - { - if(!put_dest_flags(ahwif->rx_chan, - (void*)(page_address(sg->page) - + sg->offset), - tc, flags)) { - printk(KERN_ERR "%s failed %d\n", - __FUNCTION__, __LINE__); - } - } - - cur_addr += tc; - cur_len -= tc; - } - sg++; - i--; - } - - if (count) - return 1; - - use_pio_instead: - dma_unmap_sg(ahwif->dev, - hwif->sg_table, - hwif->sg_nents, - hwif->sg_dma_direction); - - return 0; /* revert to PIO for this request */ -} - -static int auide_dma_end(ide_drive_t *drive) -{ - ide_hwif_t *hwif = HWIF(drive); - _auide_hwif *ahwif = (_auide_hwif*)hwif->hwif_data; - - if (hwif->sg_nents) { - dma_unmap_sg(ahwif->dev, hwif->sg_table, hwif->sg_nents, - hwif->sg_dma_direction); - hwif->sg_nents = 0; - } - - return 0; -} - -static void auide_dma_start(ide_drive_t *drive ) -{ -} - - -static void auide_dma_exec_cmd(ide_drive_t *drive, u8 command) -{ - /* issue cmd to drive */ - ide_execute_command(drive, command, &ide_dma_intr, - (2*WAIT_CMD), NULL); -} - -static int auide_dma_setup(ide_drive_t *drive) -{ - struct request *rq = HWGROUP(drive)->rq; - - if (!auide_build_dmatable(drive)) { - ide_map_sg(drive, rq); - return 1; - } - - drive->waiting_for_dma = 1; - return 0; -} - -static int auide_dma_check(ide_drive_t *drive) -{ - u8 speed; - -#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA - - if( dbdma_init_done == 0 ){ - auide_hwif.white_list = ide_in_drive_list(drive->id, - dma_white_list); - auide_hwif.black_list = ide_in_drive_list(drive->id, - dma_black_list); - auide_hwif.drive = drive; - auide_ddma_init(&auide_hwif); - dbdma_init_done = 1; - } -#endif - - /* Is the drive in our DMA black list? */ - - if ( auide_hwif.black_list ) { - drive->using_dma = 0; - - /* Borrowed the warning message from ide-dma.c */ - - printk(KERN_WARNING "%s: Disabling DMA for %s (blacklisted)\n", - drive->name, drive->id->model); - } - else - drive->using_dma = 1; - - speed = ide_find_best_mode(drive, XFER_PIO | XFER_MWDMA); - - if (drive->autodma && (speed & XFER_MODE) != XFER_PIO) - return HWIF(drive)->ide_dma_on(drive); - - return HWIF(drive)->ide_dma_off_quietly(drive); -} - -static int auide_dma_test_irq(ide_drive_t *drive) -{ - if (drive->waiting_for_dma == 0) - printk(KERN_WARNING "%s: ide_dma_test_irq \ - called while not waiting\n", drive->name); - - /* If dbdma didn't execute the STOP command yet, the - * active bit is still set - */ - drive->waiting_for_dma++; - if (drive->waiting_for_dma >= DMA_WAIT_TIMEOUT) { - printk(KERN_WARNING "%s: timeout waiting for ddma to \ - complete\n", drive->name); - return 1; - } - udelay(10); - return 0; -} - -static int auide_dma_host_on(ide_drive_t *drive) -{ - return 0; -} - -static int auide_dma_on(ide_drive_t *drive) -{ - drive->using_dma = 1; - return auide_dma_host_on(drive); -} - - -static int auide_dma_host_off(ide_drive_t *drive) -{ - return 0; -} - -static int auide_dma_off_quietly(ide_drive_t *drive) -{ - drive->using_dma = 0; - return auide_dma_host_off(drive); -} - -static int auide_dma_lostirq(ide_drive_t *drive) -{ - printk(KERN_ERR "%s: IRQ lost\n", drive->name); - return 0; -} - -static void auide_ddma_tx_callback(int irq, void *param) -{ - _auide_hwif *ahwif = (_auide_hwif*)param; - ahwif->drive->waiting_for_dma = 0; -} - -static void auide_ddma_rx_callback(int irq, void *param) -{ - _auide_hwif *ahwif = (_auide_hwif*)param; - ahwif->drive->waiting_for_dma = 0; -} - -#endif /* end CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA */ - -static void auide_init_dbdma_dev(dbdev_tab_t *dev, u32 dev_id, u32 tsize, u32 devwidth, u32 flags) -{ - dev->dev_id = dev_id; - dev->dev_physaddr = (u32)AU1XXX_ATA_PHYS_ADDR; - dev->dev_intlevel = 0; - dev->dev_intpolarity = 0; - dev->dev_tsize = tsize; - dev->dev_devwidth = devwidth; - dev->dev_flags = flags; -} - -#if defined(CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA) - -static int auide_dma_timeout(ide_drive_t *drive) -{ -// printk("%s\n", __FUNCTION__); - - printk(KERN_ERR "%s: DMA timeout occurred: ", drive->name); - - if (HWIF(drive)->ide_dma_test_irq(drive)) - return 0; - - return HWIF(drive)->ide_dma_end(drive); -} - - -static int auide_ddma_init(_auide_hwif *auide) { - - dbdev_tab_t source_dev_tab, target_dev_tab; - u32 dev_id, tsize, devwidth, flags; - ide_hwif_t *hwif = auide->hwif; - - dev_id = AU1XXX_ATA_DDMA_REQ; - - if (auide->white_list || auide->black_list) { - tsize = 8; - devwidth = 32; - } - else { - tsize = 1; - devwidth = 16; - - printk(KERN_ERR "au1xxx-ide: %s is not on ide driver whitelist.\n",auide_hwif.drive->id->model); - printk(KERN_ERR " please read 'Documentation/mips/AU1xxx_IDE.README'"); - } - -#ifdef IDE_AU1XXX_BURSTMODE - flags = DEV_FLAGS_SYNC | DEV_FLAGS_BURSTABLE; -#else - flags = DEV_FLAGS_SYNC; -#endif - - /* setup dev_tab for tx channel */ - auide_init_dbdma_dev( &source_dev_tab, - dev_id, - tsize, devwidth, DEV_FLAGS_OUT | flags); - auide->tx_dev_id = au1xxx_ddma_add_device( &source_dev_tab ); - - auide_init_dbdma_dev( &source_dev_tab, - dev_id, - tsize, devwidth, DEV_FLAGS_IN | flags); - auide->rx_dev_id = au1xxx_ddma_add_device( &source_dev_tab ); - - /* We also need to add a target device for the DMA */ - auide_init_dbdma_dev( &target_dev_tab, - (u32)DSCR_CMD0_ALWAYS, - tsize, devwidth, DEV_FLAGS_ANYUSE); - auide->target_dev_id = au1xxx_ddma_add_device(&target_dev_tab); - - /* Get a channel for TX */ - auide->tx_chan = au1xxx_dbdma_chan_alloc(auide->target_dev_id, - auide->tx_dev_id, - auide_ddma_tx_callback, - (void*)auide); - - /* Get a channel for RX */ - auide->rx_chan = au1xxx_dbdma_chan_alloc(auide->rx_dev_id, - auide->target_dev_id, - auide_ddma_rx_callback, - (void*)auide); - - auide->tx_desc_head = (void*)au1xxx_dbdma_ring_alloc(auide->tx_chan, - NUM_DESCRIPTORS); - auide->rx_desc_head = (void*)au1xxx_dbdma_ring_alloc(auide->rx_chan, - NUM_DESCRIPTORS); - - hwif->dmatable_cpu = dma_alloc_coherent(auide->dev, - PRD_ENTRIES * PRD_BYTES, /* 1 Page */ - &hwif->dmatable_dma, GFP_KERNEL); - - au1xxx_dbdma_start( auide->tx_chan ); - au1xxx_dbdma_start( auide->rx_chan ); - - return 0; -} -#else - -static int auide_ddma_init( _auide_hwif *auide ) -{ - dbdev_tab_t source_dev_tab; - int flags; - -#ifdef IDE_AU1XXX_BURSTMODE - flags = DEV_FLAGS_SYNC | DEV_FLAGS_BURSTABLE; -#else - flags = DEV_FLAGS_SYNC; -#endif - - /* setup dev_tab for tx channel */ - auide_init_dbdma_dev( &source_dev_tab, - (u32)DSCR_CMD0_ALWAYS, - 8, 32, DEV_FLAGS_OUT | flags); - auide->tx_dev_id = au1xxx_ddma_add_device( &source_dev_tab ); - - auide_init_dbdma_dev( &source_dev_tab, - (u32)DSCR_CMD0_ALWAYS, - 8, 32, DEV_FLAGS_IN | flags); - auide->rx_dev_id = au1xxx_ddma_add_device( &source_dev_tab ); - - /* Get a channel for TX */ - auide->tx_chan = au1xxx_dbdma_chan_alloc(DSCR_CMD0_ALWAYS, - auide->tx_dev_id, - NULL, - (void*)auide); - - /* Get a channel for RX */ - auide->rx_chan = au1xxx_dbdma_chan_alloc(auide->rx_dev_id, - DSCR_CMD0_ALWAYS, - NULL, - (void*)auide); - - auide->tx_desc_head = (void*)au1xxx_dbdma_ring_alloc(auide->tx_chan, - NUM_DESCRIPTORS); - auide->rx_desc_head = (void*)au1xxx_dbdma_ring_alloc(auide->rx_chan, - NUM_DESCRIPTORS); - - au1xxx_dbdma_start( auide->tx_chan ); - au1xxx_dbdma_start( auide->rx_chan ); - - return 0; -} -#endif - -static void auide_setup_ports(hw_regs_t *hw, _auide_hwif *ahwif) -{ - int i; - unsigned long *ata_regs = hw->io_ports; - - /* FIXME? */ - for (i = 0; i < IDE_CONTROL_OFFSET; i++) { - *ata_regs++ = ahwif->regbase + (i << AU1XXX_ATA_REG_OFFSET); - } - - /* set the Alternative Status register */ - *ata_regs = ahwif->regbase + (14 << AU1XXX_ATA_REG_OFFSET); -} - -static int au_ide_probe(struct device *dev) -{ - struct platform_device *pdev = to_platform_device(dev); - _auide_hwif *ahwif = &auide_hwif; - ide_hwif_t *hwif; - struct resource *res; - int ret = 0; - -#if defined(CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA) - char *mode = "MWDMA2"; -#elif defined(CONFIG_BLK_DEV_IDE_AU1XXX_PIO_DBDMA) - char *mode = "PIO+DDMA(offload)"; -#endif - - memset(&auide_hwif, 0, sizeof(_auide_hwif)); - auide_hwif.dev = 0; - - ahwif->dev = dev; - ahwif->irq = platform_get_irq(pdev, 0); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - - if (res == NULL) { - pr_debug("%s %d: no base address\n", DRV_NAME, pdev->id); - ret = -ENODEV; - goto out; - } - if (ahwif->irq < 0) { - pr_debug("%s %d: no IRQ\n", DRV_NAME, pdev->id); - ret = -ENODEV; - goto out; - } - - if (!request_mem_region (res->start, res->end-res->start, pdev->name)) { - pr_debug("%s: request_mem_region failed\n", DRV_NAME); - ret = -EBUSY; - goto out; - } - - ahwif->regbase = (u32)ioremap(res->start, res->end-res->start); - if (ahwif->regbase == 0) { - ret = -ENOMEM; - goto out; - } - - /* FIXME: This might possibly break PCMCIA IDE devices */ - - hwif = &ide_hwifs[pdev->id]; - hw_regs_t *hw = &hwif->hw; - hwif->irq = hw->irq = ahwif->irq; - hwif->chipset = ide_au1xxx; - - auide_setup_ports(hw, ahwif); - memcpy(hwif->io_ports, hw->io_ports, sizeof(hwif->io_ports)); - - hwif->ultra_mask = 0x0; /* Disable Ultra DMA */ -#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA - hwif->mwdma_mask = 0x07; /* Multimode-2 DMA */ - hwif->swdma_mask = 0x00; -#else - hwif->mwdma_mask = 0x0; - hwif->swdma_mask = 0x0; -#endif - - hwif->noprobe = 0; - hwif->drives[0].unmask = 1; - hwif->drives[1].unmask = 1; - - /* hold should be on in all cases */ - hwif->hold = 1; - hwif->mmio = 2; - - /* If the user has selected DDMA assisted copies, - then set up a few local I/O function entry points - */ - -#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_PIO_DBDMA - hwif->INSW = auide_insw; - hwif->OUTSW = auide_outsw; -#endif - - hwif->tuneproc = &auide_tune_drive; - hwif->speedproc = &auide_tune_chipset; - -#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA - hwif->ide_dma_off_quietly = &auide_dma_off_quietly; - hwif->ide_dma_timeout = &auide_dma_timeout; - - hwif->ide_dma_check = &auide_dma_check; - hwif->dma_exec_cmd = &auide_dma_exec_cmd; - hwif->dma_start = &auide_dma_start; - hwif->ide_dma_end = &auide_dma_end; - hwif->dma_setup = &auide_dma_setup; - hwif->ide_dma_test_irq = &auide_dma_test_irq; - hwif->ide_dma_host_off = &auide_dma_host_off; - hwif->ide_dma_host_on = &auide_dma_host_on; - hwif->ide_dma_lostirq = &auide_dma_lostirq; - hwif->ide_dma_on = &auide_dma_on; - - hwif->autodma = 1; - hwif->drives[0].autodma = hwif->autodma; - hwif->drives[1].autodma = hwif->autodma; - hwif->atapi_dma = 1; - -#else /* !CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA */ - hwif->autodma = 0; - hwif->channel = 0; - hwif->hold = 1; - hwif->select_data = 0; /* no chipset-specific code */ - hwif->config_data = 0; /* no chipset-specific code */ - - hwif->drives[0].autodma = 0; - hwif->drives[0].autotune = 1; /* 1=autotune, 2=noautotune, 0=default */ -#endif - hwif->drives[0].no_io_32bit = 1; - - auide_hwif.hwif = hwif; - hwif->hwif_data = &auide_hwif; - -#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_PIO_DBDMA - auide_ddma_init(&auide_hwif); - dbdma_init_done = 1; -#endif - - probe_hwif_init(hwif); - dev_set_drvdata(dev, hwif); - - printk(KERN_INFO "Au1xxx IDE(builtin) configured for %s\n", mode ); - - out: - return ret; -} - -static int au_ide_remove(struct device *dev) -{ - struct platform_device *pdev = to_platform_device(dev); - struct resource *res; - ide_hwif_t *hwif = dev_get_drvdata(dev); - _auide_hwif *ahwif = &auide_hwif; - - ide_unregister(hwif - ide_hwifs); - - iounmap((void *)ahwif->regbase); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(res->start, res->end - res->start); - - return 0; -} - -static struct device_driver au1200_ide_driver = { - .name = "au1200-ide", - .bus = &platform_bus_type, - .probe = au_ide_probe, - .remove = au_ide_remove, -}; - -static int __init au_ide_init(void) -{ - return driver_register(&au1200_ide_driver); -} - -static void __exit au_ide_exit(void) -{ - driver_unregister(&au1200_ide_driver); -} - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("AU1200 IDE driver"); - -module_init(au_ide_init); -module_exit(au_ide_exit); diff --git a/drivers/ide/mips/swarm.c b/drivers/ide/mips/swarm.c deleted file mode 100644 index 66f6064f464..00000000000 --- a/drivers/ide/mips/swarm.c +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Copyright (C) 2001, 2002, 2003 Broadcom Corporation - * Copyright (C) 2004 MontaVista Software Inc. - * Author: Manish Lachwani, mlachwani@mvista.com - * Copyright (C) 2004 MIPS Technologies, Inc. All rights reserved. - * Author: Maciej W. Rozycki <macro@mips.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* - * Derived loosely from ide-pmac.c, so: - * Copyright (C) 1998 Paul Mackerras. - * Copyright (C) 1995-1998 Mark Lord - */ - -/* - * Boards with SiByte processors so far have supported IDE devices via - * the Generic Bus, PCI bus, and built-in PCMCIA interface. In all - * cases, byte-swapping must be avoided for these devices (whereas - * other PCI devices, for example, will require swapping). Any - * SiByte-targetted kernel including IDE support will include this - * file. Probing of a Generic Bus for an IDE device is controlled by - * the definition of "SIBYTE_HAVE_IDE", which is provided by - * <asm/sibyte/board.h> for Broadcom boards. - */ - -#include <linux/ide.h> -#include <linux/ioport.h> -#include <linux/kernel.h> -#include <linux/types.h> -#include <linux/platform_device.h> - -#include <asm/io.h> - -#include <asm/sibyte/board.h> -#include <asm/sibyte/sb1250_genbus.h> -#include <asm/sibyte/sb1250_regs.h> - -#define DRV_NAME "ide-swarm" - -static char swarm_ide_string[] = DRV_NAME; - -static struct resource swarm_ide_resource = { - .name = "SWARM GenBus IDE", - .flags = IORESOURCE_MEM, -}; - -static struct platform_device *swarm_ide_dev; - -/* - * swarm_ide_probe - if the board header indicates the existence of - * Generic Bus IDE, allocate a HWIF for it. - */ -static int __devinit swarm_ide_probe(struct device *dev) -{ - ide_hwif_t *hwif; - u8 __iomem *base; - phys_t offset, size; - int i; - - if (!SIBYTE_HAVE_IDE) - return -ENODEV; - - /* Find an empty slot. */ - for (i = 0; i < MAX_HWIFS; i++) - if (!ide_hwifs[i].io_ports[IDE_DATA_OFFSET]) - break; - if (i >= MAX_HWIFS) { - printk(KERN_ERR DRV_NAME ": no free slot for interface\n"); - return -ENOMEM; - } - - hwif = ide_hwifs + i; - - base = ioremap(A_IO_EXT_BASE, 0x800); - offset = __raw_readq(base + R_IO_EXT_REG(R_IO_EXT_START_ADDR, IDE_CS)); - size = __raw_readq(base + R_IO_EXT_REG(R_IO_EXT_MULT_SIZE, IDE_CS)); - iounmap(base); - - offset = G_IO_START_ADDR(offset) << S_IO_ADDRBASE; - size = (G_IO_MULT_SIZE(size) + 1) << S_IO_REGSIZE; - if (offset < A_PHYS_GENBUS || offset >= A_PHYS_GENBUS_END) { - printk(KERN_INFO DRV_NAME - ": IDE interface at GenBus disabled\n"); - return -EBUSY; - } - - printk(KERN_INFO DRV_NAME ": IDE interface at GenBus slot %i\n", - IDE_CS); - - swarm_ide_resource.start = offset; - swarm_ide_resource.end = offset + size - 1; - if (request_resource(&iomem_resource, &swarm_ide_resource)) { - printk(KERN_ERR DRV_NAME - ": can't request I/O memory resource\n"); - return -EBUSY; - } - - base = ioremap(offset, size); - - /* Setup MMIO ops. */ - default_hwif_mmiops(hwif); - /* Prevent resource map manipulation. */ - hwif->mmio = 2; - hwif->noprobe = 0; - - for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) - hwif->hw.io_ports[i] = - (unsigned long)(base + ((0x1f0 + i) << 5)); - hwif->hw.io_ports[IDE_CONTROL_OFFSET] = - (unsigned long)(base + (0x3f6 << 5)); - hwif->hw.irq = K_INT_GB_IDE; - - memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports)); - hwif->irq = hwif->hw.irq; - - dev_set_drvdata(dev, hwif); - - return 0; -} - -static struct device_driver swarm_ide_driver = { - .name = swarm_ide_string, - .bus = &platform_bus_type, - .probe = swarm_ide_probe, -}; - -static void swarm_ide_platform_release(struct device *device) -{ - struct platform_device *pldev; - - /* free device */ - pldev = to_platform_device(device); - kfree(pldev); -} - -static int __devinit swarm_ide_init_module(void) -{ - struct platform_device *pldev; - int err; - - printk(KERN_INFO "SWARM IDE driver\n"); - - if (driver_register(&swarm_ide_driver)) { - printk(KERN_ERR "Driver registration failed\n"); - err = -ENODEV; - goto out; - } - - if (!(pldev = kmalloc(sizeof (*pldev), GFP_KERNEL))) { - err = -ENOMEM; - goto out_unregister_driver; - } - - memset (pldev, 0, sizeof (*pldev)); - pldev->name = swarm_ide_string; - pldev->id = 0; - pldev->dev.release = swarm_ide_platform_release; - - if (platform_device_register(pldev)) { - err = -ENODEV; - goto out_free_pldev; - } - - if (!pldev->dev.driver) { - /* - * The driver was not bound to this device, there was - * no hardware at this address. Unregister it, as the - * release fuction will take care of freeing the - * allocated structure - */ - platform_device_unregister (pldev); - } - - swarm_ide_dev = pldev; - - return 0; - -out_free_pldev: - kfree(pldev); - -out_unregister_driver: - driver_unregister(&swarm_ide_driver); -out: - return err; -} - -module_init(swarm_ide_init_module); diff --git a/drivers/ide/ns87415.c b/drivers/ide/ns87415.c new file mode 100644 index 00000000000..392fd106edf --- /dev/null +++ b/drivers/ide/ns87415.c @@ -0,0 +1,349 @@ +/* + * Copyright (C) 1997-1998 Mark Lord <mlord@pobox.com> + * Copyright (C) 1998 Eddie C. Dost <ecd@skynet.be> + * Copyright (C) 1999-2000 Andre Hedrick <andre@linux-ide.org> + * Copyright (C) 2004 Grant Grundler <grundler at parisc-linux.org> + * + * Inspired by an earlier effort from David S. Miller <davem@redhat.com> + */ + +#include <linux/module.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/interrupt.h> +#include <linux/pci.h> +#include <linux/delay.h> +#include <linux/ide.h> +#include <linux/init.h> + +#include <asm/io.h> + +#define DRV_NAME "ns87415" + +#ifdef CONFIG_SUPERIO +/* SUPERIO 87560 is a PoS chip that NatSem denies exists. + * Unfortunately, it's built-in on all Astro-based PA-RISC workstations + * which use the integrated NS87514 cell for CD-ROM support. + * i.e we have to support for CD-ROM installs. + * See drivers/parisc/superio.c for more gory details. + */ +#include <asm/superio.h> + +#define SUPERIO_IDE_MAX_RETRIES 25 + +/* Because of a defect in Super I/O, all reads of the PCI DMA status + * registers, IDE status register and the IDE select register need to be + * retried + */ +static u8 superio_ide_inb (unsigned long port) +{ + u8 tmp; + int retries = SUPERIO_IDE_MAX_RETRIES; + + /* printk(" [ reading port 0x%x with retry ] ", port); */ + + do { + tmp = inb(port); + if (tmp == 0) + udelay(50); + } while (tmp == 0 && retries-- > 0); + + return tmp; +} + +static u8 superio_read_status(ide_hwif_t *hwif) +{ + return superio_ide_inb(hwif->io_ports.status_addr); +} + +static u8 superio_dma_sff_read_status(ide_hwif_t *hwif) +{ + return superio_ide_inb(hwif->dma_base + ATA_DMA_STATUS); +} + +static void superio_tf_read(ide_drive_t *drive, struct ide_taskfile *tf, + u8 valid) +{ + struct ide_io_ports *io_ports = &drive->hwif->io_ports; + + if (valid & IDE_VALID_ERROR) + tf->error = inb(io_ports->feature_addr); + if (valid & IDE_VALID_NSECT) + tf->nsect = inb(io_ports->nsect_addr); + if (valid & IDE_VALID_LBAL) + tf->lbal = inb(io_ports->lbal_addr); + if (valid & IDE_VALID_LBAM) + tf->lbam = inb(io_ports->lbam_addr); + if (valid & IDE_VALID_LBAH) + tf->lbah = inb(io_ports->lbah_addr); + if (valid & IDE_VALID_DEVICE) + tf->device = superio_ide_inb(io_ports->device_addr); +} + +static void ns87415_dev_select(ide_drive_t *drive); + +static const struct ide_tp_ops superio_tp_ops = { + .exec_command = ide_exec_command, + .read_status = superio_read_status, + .read_altstatus = ide_read_altstatus, + .write_devctl = ide_write_devctl, + + .dev_select = ns87415_dev_select, + .tf_load = ide_tf_load, + .tf_read = superio_tf_read, + + .input_data = ide_input_data, + .output_data = ide_output_data, +}; + +static void superio_init_iops(struct hwif_s *hwif) +{ + struct pci_dev *pdev = to_pci_dev(hwif->dev); + u32 dma_stat; + u8 port = hwif->channel, tmp; + + dma_stat = (pci_resource_start(pdev, 4) & ~3) + (!port ? 2 : 0xa); + + /* Clear error/interrupt, enable dma */ + tmp = superio_ide_inb(dma_stat); + outb(tmp | 0x66, dma_stat); +} +#else +#define superio_dma_sff_read_status ide_dma_sff_read_status +#endif + +static unsigned int ns87415_count = 0, ns87415_control[MAX_HWIFS] = { 0 }; + +/* + * This routine either enables/disables (according to IDE_DFLAG_PRESENT) + * the IRQ associated with the port, + * and selects either PIO or DMA handshaking for the next I/O operation. + */ +static void ns87415_prepare_drive (ide_drive_t *drive, unsigned int use_dma) +{ + ide_hwif_t *hwif = drive->hwif; + struct pci_dev *dev = to_pci_dev(hwif->dev); + unsigned int bit, other, new, *old = (unsigned int *) hwif->select_data; + unsigned long flags; + + local_irq_save(flags); + new = *old; + + /* Adjust IRQ enable bit */ + bit = 1 << (8 + hwif->channel); + + if (drive->dev_flags & IDE_DFLAG_PRESENT) + new &= ~bit; + else + new |= bit; + + /* Select PIO or DMA, DMA may only be selected for one drive/channel. */ + bit = 1 << (20 + (drive->dn & 1) + (hwif->channel << 1)); + other = 1 << (20 + (1 - (drive->dn & 1)) + (hwif->channel << 1)); + new = use_dma ? ((new & ~other) | bit) : (new & ~bit); + + if (new != *old) { + unsigned char stat; + + /* + * Don't change DMA engine settings while Write Buffers + * are busy. + */ + (void) pci_read_config_byte(dev, 0x43, &stat); + while (stat & 0x03) { + udelay(1); + (void) pci_read_config_byte(dev, 0x43, &stat); + } + + *old = new; + (void) pci_write_config_dword(dev, 0x40, new); + + /* + * And let things settle... + */ + udelay(10); + } + + local_irq_restore(flags); +} + +static void ns87415_dev_select(ide_drive_t *drive) +{ + ns87415_prepare_drive(drive, + !!(drive->dev_flags & IDE_DFLAG_USING_DMA)); + + outb(drive->select | ATA_DEVICE_OBS, drive->hwif->io_ports.device_addr); +} + +static void ns87415_dma_start(ide_drive_t *drive) +{ + ns87415_prepare_drive(drive, 1); + ide_dma_start(drive); +} + +static int ns87415_dma_end(ide_drive_t *drive) +{ + ide_hwif_t *hwif = drive->hwif; + u8 dma_stat = 0, dma_cmd = 0; + + dma_stat = hwif->dma_ops->dma_sff_read_status(hwif); + /* get DMA command mode */ + dma_cmd = inb(hwif->dma_base + ATA_DMA_CMD); + /* stop DMA */ + outb(dma_cmd & ~1, hwif->dma_base + ATA_DMA_CMD); + /* from ERRATA: clear the INTR & ERROR bits */ + dma_cmd = inb(hwif->dma_base + ATA_DMA_CMD); + outb(dma_cmd | 6, hwif->dma_base + ATA_DMA_CMD); + + ns87415_prepare_drive(drive, 0); + + /* verify good DMA status */ + return (dma_stat & 7) != 4; +} + +static void init_hwif_ns87415 (ide_hwif_t *hwif) +{ + struct pci_dev *dev = to_pci_dev(hwif->dev); + unsigned int ctrl, using_inta; + u8 progif; +#ifdef __sparc_v9__ + int timeout; + u8 stat; +#endif + + /* + * We cannot probe for IRQ: both ports share common IRQ on INTA. + * Also, leave IRQ masked during drive probing, to prevent infinite + * interrupts from a potentially floating INTA.. + * + * IRQs get unmasked in dev_select() when drive is first used. + */ + (void) pci_read_config_dword(dev, 0x40, &ctrl); + (void) pci_read_config_byte(dev, 0x09, &progif); + /* is irq in "native" mode? */ + using_inta = progif & (1 << (hwif->channel << 1)); + if (!using_inta) + using_inta = ctrl & (1 << (4 + hwif->channel)); + if (hwif->mate) { + hwif->select_data = hwif->mate->select_data; + } else { + hwif->select_data = (unsigned long) + &ns87415_control[ns87415_count++]; + ctrl |= (1 << 8) | (1 << 9); /* mask both IRQs */ + if (using_inta) + ctrl &= ~(1 << 6); /* unmask INTA */ + *((unsigned int *)hwif->select_data) = ctrl; + (void) pci_write_config_dword(dev, 0x40, ctrl); + + /* + * Set prefetch size to 512 bytes for both ports, + * but don't turn on/off prefetching here. + */ + pci_write_config_byte(dev, 0x55, 0xee); + +#ifdef __sparc_v9__ + /* + * XXX: Reset the device, if we don't it will not respond to + * dev_select() properly during first ide_probe_port(). + */ + timeout = 10000; + outb(12, hwif->io_ports.ctl_addr); + udelay(10); + outb(8, hwif->io_ports.ctl_addr); + do { + udelay(50); + stat = hwif->tp_ops->read_status(hwif); + if (stat == 0xff) + break; + } while ((stat & ATA_BUSY) && --timeout); +#endif + } + + if (!using_inta) + hwif->irq = pci_get_legacy_ide_irq(dev, hwif->channel); + + if (!hwif->dma_base) + return; + + outb(0x60, hwif->dma_base + ATA_DMA_STATUS); +} + +static const struct ide_tp_ops ns87415_tp_ops = { + .exec_command = ide_exec_command, + .read_status = ide_read_status, + .read_altstatus = ide_read_altstatus, + .write_devctl = ide_write_devctl, + + .dev_select = ns87415_dev_select, + .tf_load = ide_tf_load, + .tf_read = ide_tf_read, + + .input_data = ide_input_data, + .output_data = ide_output_data, +}; + +static const struct ide_dma_ops ns87415_dma_ops = { + .dma_host_set = ide_dma_host_set, + .dma_setup = ide_dma_setup, + .dma_start = ns87415_dma_start, + .dma_end = ns87415_dma_end, + .dma_test_irq = ide_dma_test_irq, + .dma_lost_irq = ide_dma_lost_irq, + .dma_timer_expiry = ide_dma_sff_timer_expiry, + .dma_sff_read_status = superio_dma_sff_read_status, +}; + +static const struct ide_port_info ns87415_chipset = { + .name = DRV_NAME, + .init_hwif = init_hwif_ns87415, + .tp_ops = &ns87415_tp_ops, + .dma_ops = &ns87415_dma_ops, + .host_flags = IDE_HFLAG_TRUST_BIOS_FOR_DMA | + IDE_HFLAG_NO_ATAPI_DMA, +}; + +static int ns87415_init_one(struct pci_dev *dev, const struct pci_device_id *id) +{ + struct ide_port_info d = ns87415_chipset; + +#ifdef CONFIG_SUPERIO + if (PCI_SLOT(dev->devfn) == 0xE) { + /* Built-in - assume it's under superio. */ + d.init_iops = superio_init_iops; + d.tp_ops = &superio_tp_ops; + } +#endif + return ide_pci_init_one(dev, &d, NULL); +} + +static const struct pci_device_id ns87415_pci_tbl[] = { + { PCI_VDEVICE(NS, PCI_DEVICE_ID_NS_87415), 0 }, + { 0, }, +}; +MODULE_DEVICE_TABLE(pci, ns87415_pci_tbl); + +static struct pci_driver ns87415_pci_driver = { + .name = "NS87415_IDE", + .id_table = ns87415_pci_tbl, + .probe = ns87415_init_one, + .remove = ide_pci_remove, + .suspend = ide_pci_suspend, + .resume = ide_pci_resume, +}; + +static int __init ns87415_ide_init(void) +{ + return ide_pci_register_driver(&ns87415_pci_driver); +} + +static void __exit ns87415_ide_exit(void) +{ + pci_unregister_driver(&ns87415_pci_driver); +} + +module_init(ns87415_ide_init); +module_exit(ns87415_ide_exit); + +MODULE_AUTHOR("Mark Lord, Eddie Dost, Andre Hedrick"); +MODULE_DESCRIPTION("PCI driver module for NS87415 IDE"); +MODULE_LICENSE("GPL"); diff --git a/drivers/ide/opti621.c b/drivers/ide/opti621.c new file mode 100644 index 00000000000..26a45007e53 --- /dev/null +++ b/drivers/ide/opti621.c @@ -0,0 +1,178 @@ +/* + * Copyright (C) 1996-1998 Linus Torvalds & authors (see below) + */ + +/* + * Authors: + * Jaromir Koutek <miri@punknet.cz>, + * Jan Harkes <jaharkes@cwi.nl>, + * Mark Lord <mlord@pobox.com> + * Some parts of code are from ali14xx.c and from rz1000.c. + */ + +#include <linux/types.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/pci.h> +#include <linux/ide.h> + +#include <asm/io.h> + +#define DRV_NAME "opti621" + +#define READ_REG 0 /* index of Read cycle timing register */ +#define WRITE_REG 1 /* index of Write cycle timing register */ +#define CNTRL_REG 3 /* index of Control register */ +#define STRAP_REG 5 /* index of Strap register */ +#define MISC_REG 6 /* index of Miscellaneous register */ + +static int reg_base; + +static DEFINE_SPINLOCK(opti621_lock); + +/* Write value to register reg, base of register + * is at reg_base (0x1f0 primary, 0x170 secondary, + * if not changed by PCI configuration). + * This is from setupvic.exe program. + */ +static void write_reg(u8 value, int reg) +{ + inw(reg_base + 1); + inw(reg_base + 1); + outb(3, reg_base + 2); + outb(value, reg_base + reg); + outb(0x83, reg_base + 2); +} + +/* Read value from register reg, base of register + * is at reg_base (0x1f0 primary, 0x170 secondary, + * if not changed by PCI configuration). + * This is from setupvic.exe program. + */ +static u8 read_reg(int reg) +{ + u8 ret = 0; + + inw(reg_base + 1); + inw(reg_base + 1); + outb(3, reg_base + 2); + ret = inb(reg_base + reg); + outb(0x83, reg_base + 2); + + return ret; +} + +static void opti621_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) +{ + ide_drive_t *pair = ide_get_pair_dev(drive); + unsigned long flags; + unsigned long mode = drive->pio_mode, pair_mode; + const u8 pio = mode - XFER_PIO_0; + u8 tim, misc, addr_pio = pio, clk; + + /* DRDY is default 2 (by OPTi Databook) */ + static const u8 addr_timings[2][5] = { + { 0x20, 0x10, 0x00, 0x00, 0x00 }, /* 33 MHz */ + { 0x10, 0x10, 0x00, 0x00, 0x00 }, /* 25 MHz */ + }; + static const u8 data_rec_timings[2][5] = { + { 0x5b, 0x45, 0x32, 0x21, 0x20 }, /* 33 MHz */ + { 0x48, 0x34, 0x21, 0x10, 0x10 } /* 25 MHz */ + }; + + ide_set_drivedata(drive, (void *)mode); + + if (pair) { + pair_mode = (unsigned long)ide_get_drivedata(pair); + if (pair_mode && pair_mode < mode) + addr_pio = pair_mode - XFER_PIO_0; + } + + spin_lock_irqsave(&opti621_lock, flags); + + reg_base = hwif->io_ports.data_addr; + + /* allow Register-B */ + outb(0xc0, reg_base + CNTRL_REG); + /* hmm, setupvic.exe does this ;-) */ + outb(0xff, reg_base + 5); + /* if reads 0xff, adapter not exist? */ + (void)inb(reg_base + CNTRL_REG); + /* if reads 0xc0, no interface exist? */ + read_reg(CNTRL_REG); + + /* check CLK speed */ + clk = read_reg(STRAP_REG) & 1; + + printk(KERN_INFO "%s: CLK = %d MHz\n", hwif->name, clk ? 25 : 33); + + tim = data_rec_timings[clk][pio]; + misc = addr_timings[clk][addr_pio]; + + /* select Index-0/1 for Register-A/B */ + write_reg(drive->dn & 1, MISC_REG); + /* set read cycle timings */ + write_reg(tim, READ_REG); + /* set write cycle timings */ + write_reg(tim, WRITE_REG); + + /* use Register-A for drive 0 */ + /* use Register-B for drive 1 */ + write_reg(0x85, CNTRL_REG); + + /* set address setup, DRDY timings, */ + /* and read prefetch for both drives */ + write_reg(misc, MISC_REG); + + spin_unlock_irqrestore(&opti621_lock, flags); +} + +static const struct ide_port_ops opti621_port_ops = { + .set_pio_mode = opti621_set_pio_mode, +}; + +static const struct ide_port_info opti621_chipset = { + .name = DRV_NAME, + .enablebits = { {0x45, 0x80, 0x00}, {0x40, 0x08, 0x00} }, + .port_ops = &opti621_port_ops, + .host_flags = IDE_HFLAG_NO_DMA, + .pio_mask = ATA_PIO4, +}; + +static int opti621_init_one(struct pci_dev *dev, const struct pci_device_id *id) +{ + return ide_pci_init_one(dev, &opti621_chipset, NULL); +} + +static const struct pci_device_id opti621_pci_tbl[] = { + { PCI_VDEVICE(OPTI, PCI_DEVICE_ID_OPTI_82C621), 0 }, + { PCI_VDEVICE(OPTI, PCI_DEVICE_ID_OPTI_82C825), 0 }, + { 0, }, +}; +MODULE_DEVICE_TABLE(pci, opti621_pci_tbl); + +static struct pci_driver opti621_pci_driver = { + .name = "Opti621_IDE", + .id_table = opti621_pci_tbl, + .probe = opti621_init_one, + .remove = ide_pci_remove, + .suspend = ide_pci_suspend, + .resume = ide_pci_resume, +}; + +static int __init opti621_ide_init(void) +{ + return ide_pci_register_driver(&opti621_pci_driver); +} + +static void __exit opti621_ide_exit(void) +{ + pci_unregister_driver(&opti621_pci_driver); +} + +module_init(opti621_ide_init); +module_exit(opti621_ide_exit); + +MODULE_AUTHOR("Jaromir Koutek, Jan Harkes, Mark Lord"); +MODULE_DESCRIPTION("PCI driver module for Opti621 IDE"); +MODULE_LICENSE("GPL"); diff --git a/drivers/ide/palm_bk3710.c b/drivers/ide/palm_bk3710.c new file mode 100644 index 00000000000..ba20d18c037 --- /dev/null +++ b/drivers/ide/palm_bk3710.c @@ -0,0 +1,399 @@ +/* + * Palmchip bk3710 IDE controller + * + * Copyright (C) 2006 Texas Instruments. + * Copyright (C) 2007 MontaVista Software, Inc., <source@mvista.com> + * + * ---------------------------------------------------------------------------- + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * ---------------------------------------------------------------------------- + * + */ + +#include <linux/types.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/ioport.h> +#include <linux/ide.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/clk.h> +#include <linux/platform_device.h> + +/* Offset of the primary interface registers */ +#define IDE_PALM_ATA_PRI_REG_OFFSET 0x1F0 + +/* Primary Control Offset */ +#define IDE_PALM_ATA_PRI_CTL_OFFSET 0x3F6 + +#define BK3710_BMICP 0x00 +#define BK3710_BMISP 0x02 +#define BK3710_BMIDTP 0x04 +#define BK3710_IDETIMP 0x40 +#define BK3710_IDESTATUS 0x47 +#define BK3710_UDMACTL 0x48 +#define BK3710_MISCCTL 0x50 +#define BK3710_REGSTB 0x54 +#define BK3710_REGRCVR 0x58 +#define BK3710_DATSTB 0x5C +#define BK3710_DATRCVR 0x60 +#define BK3710_DMASTB 0x64 +#define BK3710_DMARCVR 0x68 +#define BK3710_UDMASTB 0x6C +#define BK3710_UDMATRP 0x70 +#define BK3710_UDMAENV 0x74 +#define BK3710_IORDYTMP 0x78 + +static unsigned ideclk_period; /* in nanoseconds */ + +struct palm_bk3710_udmatiming { + unsigned int rptime; /* tRP -- Ready to pause time (nsec) */ + unsigned int cycletime; /* tCYCTYP2/2 -- avg Cycle Time (nsec) */ + /* tENV is always a minimum of 20 nsec */ +}; + +static const struct palm_bk3710_udmatiming palm_bk3710_udmatimings[6] = { + { 160, 240 / 2 }, /* UDMA Mode 0 */ + { 125, 160 / 2 }, /* UDMA Mode 1 */ + { 100, 120 / 2 }, /* UDMA Mode 2 */ + { 100, 90 / 2 }, /* UDMA Mode 3 */ + { 100, 60 / 2 }, /* UDMA Mode 4 */ + { 85, 40 / 2 }, /* UDMA Mode 5 */ +}; + +static void palm_bk3710_setudmamode(void __iomem *base, unsigned int dev, + unsigned int mode) +{ + u8 tenv, trp, t0; + u32 val32; + u16 val16; + + /* DMA Data Setup */ + t0 = DIV_ROUND_UP(palm_bk3710_udmatimings[mode].cycletime, + ideclk_period) - 1; + tenv = DIV_ROUND_UP(20, ideclk_period) - 1; + trp = DIV_ROUND_UP(palm_bk3710_udmatimings[mode].rptime, + ideclk_period) - 1; + + /* udmastb Ultra DMA Access Strobe Width */ + val32 = readl(base + BK3710_UDMASTB) & (0xFF << (dev ? 0 : 8)); + val32 |= (t0 << (dev ? 8 : 0)); + writel(val32, base + BK3710_UDMASTB); + + /* udmatrp Ultra DMA Ready to Pause Time */ + val32 = readl(base + BK3710_UDMATRP) & (0xFF << (dev ? 0 : 8)); + val32 |= (trp << (dev ? 8 : 0)); + writel(val32, base + BK3710_UDMATRP); + + /* udmaenv Ultra DMA envelop Time */ + val32 = readl(base + BK3710_UDMAENV) & (0xFF << (dev ? 0 : 8)); + val32 |= (tenv << (dev ? 8 : 0)); + writel(val32, base + BK3710_UDMAENV); + + /* Enable UDMA for Device */ + val16 = readw(base + BK3710_UDMACTL) | (1 << dev); + writew(val16, base + BK3710_UDMACTL); +} + +static void palm_bk3710_setdmamode(void __iomem *base, unsigned int dev, + unsigned short min_cycle, + unsigned int mode) +{ + u8 td, tkw, t0; + u32 val32; + u16 val16; + struct ide_timing *t; + int cycletime; + + t = ide_timing_find_mode(mode); + cycletime = max_t(int, t->cycle, min_cycle); + + /* DMA Data Setup */ + t0 = DIV_ROUND_UP(cycletime, ideclk_period); + td = DIV_ROUND_UP(t->active, ideclk_period); + tkw = t0 - td - 1; + td -= 1; + + val32 = readl(base + BK3710_DMASTB) & (0xFF << (dev ? 0 : 8)); + val32 |= (td << (dev ? 8 : 0)); + writel(val32, base + BK3710_DMASTB); + + val32 = readl(base + BK3710_DMARCVR) & (0xFF << (dev ? 0 : 8)); + val32 |= (tkw << (dev ? 8 : 0)); + writel(val32, base + BK3710_DMARCVR); + + /* Disable UDMA for Device */ + val16 = readw(base + BK3710_UDMACTL) & ~(1 << dev); + writew(val16, base + BK3710_UDMACTL); +} + +static void palm_bk3710_setpiomode(void __iomem *base, ide_drive_t *mate, + unsigned int dev, unsigned int cycletime, + unsigned int mode) +{ + u8 t2, t2i, t0; + u32 val32; + struct ide_timing *t; + + t = ide_timing_find_mode(XFER_PIO_0 + mode); + + /* PIO Data Setup */ + t0 = DIV_ROUND_UP(cycletime, ideclk_period); + t2 = DIV_ROUND_UP(t->active, ideclk_period); + + t2i = t0 - t2 - 1; + t2 -= 1; + + val32 = readl(base + BK3710_DATSTB) & (0xFF << (dev ? 0 : 8)); + val32 |= (t2 << (dev ? 8 : 0)); + writel(val32, base + BK3710_DATSTB); + + val32 = readl(base + BK3710_DATRCVR) & (0xFF << (dev ? 0 : 8)); + val32 |= (t2i << (dev ? 8 : 0)); + writel(val32, base + BK3710_DATRCVR); + + if (mate) { + u8 mode2 = mate->pio_mode - XFER_PIO_0; + + if (mode2 < mode) + mode = mode2; + } + + /* TASKFILE Setup */ + t0 = DIV_ROUND_UP(t->cyc8b, ideclk_period); + t2 = DIV_ROUND_UP(t->act8b, ideclk_period); + + t2i = t0 - t2 - 1; + t2 -= 1; + + val32 = readl(base + BK3710_REGSTB) & (0xFF << (dev ? 0 : 8)); + val32 |= (t2 << (dev ? 8 : 0)); + writel(val32, base + BK3710_REGSTB); + + val32 = readl(base + BK3710_REGRCVR) & (0xFF << (dev ? 0 : 8)); + val32 |= (t2i << (dev ? 8 : 0)); + writel(val32, base + BK3710_REGRCVR); +} + +static void palm_bk3710_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive) +{ + int is_slave = drive->dn & 1; + void __iomem *base = (void __iomem *)hwif->dma_base; + const u8 xferspeed = drive->dma_mode; + + if (xferspeed >= XFER_UDMA_0) { + palm_bk3710_setudmamode(base, is_slave, + xferspeed - XFER_UDMA_0); + } else { + palm_bk3710_setdmamode(base, is_slave, + drive->id[ATA_ID_EIDE_DMA_MIN], + xferspeed); + } +} + +static void palm_bk3710_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) +{ + unsigned int cycle_time; + int is_slave = drive->dn & 1; + ide_drive_t *mate; + void __iomem *base = (void __iomem *)hwif->dma_base; + const u8 pio = drive->pio_mode - XFER_PIO_0; + + /* + * Obtain the drive PIO data for tuning the Palm Chip registers + */ + cycle_time = ide_pio_cycle_time(drive, pio); + mate = ide_get_pair_dev(drive); + palm_bk3710_setpiomode(base, mate, is_slave, cycle_time, pio); +} + +static void palm_bk3710_chipinit(void __iomem *base) +{ + /* + * REVISIT: the ATA reset signal needs to be managed through a + * GPIO, which means it should come from platform_data. Until + * we get and use such information, we have to trust that things + * have been reset before we get here. + */ + + /* + * Program the IDETIMP Register Value based on the following assumptions + * + * (ATA_IDETIMP_IDEEN , ENABLE ) | + * (ATA_IDETIMP_PREPOST1 , DISABLE) | + * (ATA_IDETIMP_PREPOST0 , DISABLE) | + * + * DM6446 silicon rev 2.1 and earlier have no observed net benefit + * from enabling prefetch/postwrite. + */ + writew(BIT(15), base + BK3710_IDETIMP); + + /* + * UDMACTL Ultra-ATA DMA Control + * (ATA_UDMACTL_UDMAP1 , 0 ) | + * (ATA_UDMACTL_UDMAP0 , 0 ) + * + */ + writew(0, base + BK3710_UDMACTL); + + /* + * MISCCTL Miscellaneous Conrol Register + * (ATA_MISCCTL_HWNHLD1P , 1 cycle) + * (ATA_MISCCTL_HWNHLD0P , 1 cycle) + * (ATA_MISCCTL_TIMORIDE , 1) + */ + writel(0x001, base + BK3710_MISCCTL); + + /* + * IORDYTMP IORDY Timer for Primary Register + * (ATA_IORDYTMP_IORDYTMP , 0xffff ) + */ + writel(0xFFFF, base + BK3710_IORDYTMP); + + /* + * Configure BMISP Register + * (ATA_BMISP_DMAEN1 , DISABLE ) | + * (ATA_BMISP_DMAEN0 , DISABLE ) | + * (ATA_BMISP_IORDYINT , CLEAR) | + * (ATA_BMISP_INTRSTAT , CLEAR) | + * (ATA_BMISP_DMAERROR , CLEAR) + */ + writew(0, base + BK3710_BMISP); + + palm_bk3710_setpiomode(base, NULL, 0, 600, 0); + palm_bk3710_setpiomode(base, NULL, 1, 600, 0); +} + +static u8 palm_bk3710_cable_detect(ide_hwif_t *hwif) +{ + return ATA_CBL_PATA80; +} + +static int palm_bk3710_init_dma(ide_hwif_t *hwif, const struct ide_port_info *d) +{ + printk(KERN_INFO " %s: MMIO-DMA\n", hwif->name); + + if (ide_allocate_dma_engine(hwif)) + return -1; + + hwif->dma_base = hwif->io_ports.data_addr - IDE_PALM_ATA_PRI_REG_OFFSET; + + return 0; +} + +static const struct ide_port_ops palm_bk3710_ports_ops = { + .set_pio_mode = palm_bk3710_set_pio_mode, + .set_dma_mode = palm_bk3710_set_dma_mode, + .cable_detect = palm_bk3710_cable_detect, +}; + +static struct ide_port_info palm_bk3710_port_info = { + .init_dma = palm_bk3710_init_dma, + .port_ops = &palm_bk3710_ports_ops, + .dma_ops = &sff_dma_ops, + .host_flags = IDE_HFLAG_MMIO, + .pio_mask = ATA_PIO4, + .mwdma_mask = ATA_MWDMA2, + .chipset = ide_palm3710, +}; + +static int __init palm_bk3710_probe(struct platform_device *pdev) +{ + struct clk *clk; + struct resource *mem, *irq; + void __iomem *base; + unsigned long rate, mem_size; + int i, rc; + struct ide_hw hw, *hws[] = { &hw }; + + clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(clk)) + return -ENODEV; + + clk_enable(clk); + rate = clk_get_rate(clk); + + /* NOTE: round *down* to meet minimum timings; we count in clocks */ + ideclk_period = 1000000000UL / rate; + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (mem == NULL) { + printk(KERN_ERR "failed to get memory region resource\n"); + return -ENODEV; + } + + irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (irq == NULL) { + printk(KERN_ERR "failed to get IRQ resource\n"); + return -ENODEV; + } + + mem_size = resource_size(mem); + if (request_mem_region(mem->start, mem_size, "palm_bk3710") == NULL) { + printk(KERN_ERR "failed to request memory region\n"); + return -EBUSY; + } + + base = ioremap(mem->start, mem_size); + if (!base) { + printk(KERN_ERR "failed to map IO memory\n"); + release_mem_region(mem->start, mem_size); + return -ENOMEM; + } + + /* Configure the Palm Chip controller */ + palm_bk3710_chipinit(base); + + memset(&hw, 0, sizeof(hw)); + for (i = 0; i < IDE_NR_PORTS - 2; i++) + hw.io_ports_array[i] = (unsigned long) + (base + IDE_PALM_ATA_PRI_REG_OFFSET + i); + hw.io_ports.ctl_addr = (unsigned long) + (base + IDE_PALM_ATA_PRI_CTL_OFFSET); + hw.irq = irq->start; + hw.dev = &pdev->dev; + + palm_bk3710_port_info.udma_mask = rate < 100000000 ? ATA_UDMA4 : + ATA_UDMA5; + + /* Register the IDE interface with Linux */ + rc = ide_host_add(&palm_bk3710_port_info, hws, 1, NULL); + if (rc) + goto out; + + return 0; +out: + printk(KERN_WARNING "Palm Chip BK3710 IDE Register Fail\n"); + return rc; +} + +/* work with hotplug and coldplug */ +MODULE_ALIAS("platform:palm_bk3710"); + +static struct platform_driver platform_bk_driver = { + .driver = { + .name = "palm_bk3710", + .owner = THIS_MODULE, + }, +}; + +static int __init palm_bk3710_init(void) +{ + return platform_driver_probe(&platform_bk_driver, palm_bk3710_probe); +} + +module_init(palm_bk3710_init); +MODULE_LICENSE("GPL"); diff --git a/drivers/ide/pci/Makefile b/drivers/ide/pci/Makefile deleted file mode 100644 index f35d684edc2..00000000000 --- a/drivers/ide/pci/Makefile +++ /dev/null @@ -1,36 +0,0 @@ - -obj-$(CONFIG_BLK_DEV_AEC62XX) += aec62xx.o -obj-$(CONFIG_BLK_DEV_ALI15X3) += alim15x3.o -obj-$(CONFIG_BLK_DEV_AMD74XX) += amd74xx.o -obj-$(CONFIG_BLK_DEV_ATIIXP) += atiixp.o -obj-$(CONFIG_BLK_DEV_CMD64X) += cmd64x.o -obj-$(CONFIG_BLK_DEV_CS5520) += cs5520.o -obj-$(CONFIG_BLK_DEV_CS5530) += cs5530.o -obj-$(CONFIG_BLK_DEV_CS5535) += cs5535.o -obj-$(CONFIG_BLK_DEV_SC1200) += sc1200.o -obj-$(CONFIG_BLK_DEV_CY82C693) += cy82c693.o -obj-$(CONFIG_BLK_DEV_HPT34X) += hpt34x.o -obj-$(CONFIG_BLK_DEV_HPT366) += hpt366.o -#obj-$(CONFIG_BLK_DEV_HPT37X) += hpt37x.o -obj-$(CONFIG_BLK_DEV_IT8172) += it8172.o -obj-$(CONFIG_BLK_DEV_IT821X) += it821x.o -obj-$(CONFIG_BLK_DEV_NS87415) += ns87415.o -obj-$(CONFIG_BLK_DEV_OPTI621) += opti621.o -obj-$(CONFIG_BLK_DEV_PDC202XX_OLD) += pdc202xx_old.o -obj-$(CONFIG_BLK_DEV_PDC202XX_NEW) += pdc202xx_new.o -obj-$(CONFIG_BLK_DEV_PIIX) += piix.o -obj-$(CONFIG_BLK_DEV_RZ1000) += rz1000.o -obj-$(CONFIG_BLK_DEV_SVWKS) += serverworks.o -obj-$(CONFIG_BLK_DEV_SGIIOC4) += sgiioc4.o -obj-$(CONFIG_BLK_DEV_SIIMAGE) += siimage.o -obj-$(CONFIG_BLK_DEV_SIS5513) += sis5513.o -obj-$(CONFIG_BLK_DEV_SL82C105) += sl82c105.o -obj-$(CONFIG_BLK_DEV_SLC90E66) += slc90e66.o -obj-$(CONFIG_BLK_DEV_TRIFLEX) += triflex.o -obj-$(CONFIG_BLK_DEV_TRM290) += trm290.o -obj-$(CONFIG_BLK_DEV_VIA82CXXX) += via82cxxx.o - -# Must appear at the end of the block -obj-$(CONFIG_BLK_DEV_GENERIC) += generic.o - -EXTRA_CFLAGS := -Idrivers/ide diff --git a/drivers/ide/pci/aec62xx.c b/drivers/ide/pci/aec62xx.c deleted file mode 100644 index f286079d233..00000000000 --- a/drivers/ide/pci/aec62xx.c +++ /dev/null @@ -1,453 +0,0 @@ -/* - * linux/drivers/ide/pci/aec62xx.c Version 0.11 March 27, 2002 - * - * Copyright (C) 1999-2002 Andre Hedrick <andre@linux-ide.org> - * - */ - -#include <linux/module.h> -#include <linux/types.h> -#include <linux/pci.h> -#include <linux/delay.h> -#include <linux/hdreg.h> -#include <linux/ide.h> -#include <linux/init.h> - -#include <asm/io.h> - -struct chipset_bus_clock_list_entry { - u8 xfer_speed; - u8 chipset_settings; - u8 ultra_settings; -}; - -static const struct chipset_bus_clock_list_entry aec6xxx_33_base [] = { - { XFER_UDMA_6, 0x31, 0x07 }, - { XFER_UDMA_5, 0x31, 0x06 }, - { XFER_UDMA_4, 0x31, 0x05 }, - { XFER_UDMA_3, 0x31, 0x04 }, - { XFER_UDMA_2, 0x31, 0x03 }, - { XFER_UDMA_1, 0x31, 0x02 }, - { XFER_UDMA_0, 0x31, 0x01 }, - - { XFER_MW_DMA_2, 0x31, 0x00 }, - { XFER_MW_DMA_1, 0x31, 0x00 }, - { XFER_MW_DMA_0, 0x0a, 0x00 }, - { XFER_PIO_4, 0x31, 0x00 }, - { XFER_PIO_3, 0x33, 0x00 }, - { XFER_PIO_2, 0x08, 0x00 }, - { XFER_PIO_1, 0x0a, 0x00 }, - { XFER_PIO_0, 0x00, 0x00 }, - { 0, 0x00, 0x00 } -}; - -static const struct chipset_bus_clock_list_entry aec6xxx_34_base [] = { - { XFER_UDMA_6, 0x41, 0x06 }, - { XFER_UDMA_5, 0x41, 0x05 }, - { XFER_UDMA_4, 0x41, 0x04 }, - { XFER_UDMA_3, 0x41, 0x03 }, - { XFER_UDMA_2, 0x41, 0x02 }, - { XFER_UDMA_1, 0x41, 0x01 }, - { XFER_UDMA_0, 0x41, 0x01 }, - - { XFER_MW_DMA_2, 0x41, 0x00 }, - { XFER_MW_DMA_1, 0x42, 0x00 }, - { XFER_MW_DMA_0, 0x7a, 0x00 }, - { XFER_PIO_4, 0x41, 0x00 }, - { XFER_PIO_3, 0x43, 0x00 }, - { XFER_PIO_2, 0x78, 0x00 }, - { XFER_PIO_1, 0x7a, 0x00 }, - { XFER_PIO_0, 0x70, 0x00 }, - { 0, 0x00, 0x00 } -}; - -#define BUSCLOCK(D) \ - ((struct chipset_bus_clock_list_entry *) pci_get_drvdata((D))) - - -/* - * TO DO: active tuning and correction of cards without a bios. - */ -static u8 pci_bus_clock_list (u8 speed, struct chipset_bus_clock_list_entry * chipset_table) -{ - for ( ; chipset_table->xfer_speed ; chipset_table++) - if (chipset_table->xfer_speed == speed) { - return chipset_table->chipset_settings; - } - return chipset_table->chipset_settings; -} - -static u8 pci_bus_clock_list_ultra (u8 speed, struct chipset_bus_clock_list_entry * chipset_table) -{ - for ( ; chipset_table->xfer_speed ; chipset_table++) - if (chipset_table->xfer_speed == speed) { - return chipset_table->ultra_settings; - } - return chipset_table->ultra_settings; -} - -static u8 aec62xx_ratemask (ide_drive_t *drive) -{ - ide_hwif_t *hwif = HWIF(drive); - u8 mode; - - switch(hwif->pci_dev->device) { - case PCI_DEVICE_ID_ARTOP_ATP865: - case PCI_DEVICE_ID_ARTOP_ATP865R: - mode = (hwif->INB(((hwif->channel) ? - hwif->mate->dma_status : - hwif->dma_status)) & 0x10) ? 4 : 3; - break; - case PCI_DEVICE_ID_ARTOP_ATP860: - case PCI_DEVICE_ID_ARTOP_ATP860R: - mode = 2; - break; - case PCI_DEVICE_ID_ARTOP_ATP850UF: - default: - return 1; - } - - if (!eighty_ninty_three(drive)) - mode = min(mode, (u8)1); - return mode; -} - -static int aec6210_tune_chipset (ide_drive_t *drive, u8 xferspeed) -{ - ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; - u16 d_conf = 0; - u8 speed = ide_rate_filter(aec62xx_ratemask(drive), xferspeed); - u8 ultra = 0, ultra_conf = 0; - u8 tmp0 = 0, tmp1 = 0, tmp2 = 0; - unsigned long flags; - - local_irq_save(flags); - /* 0x40|(2*drive->dn): Active, 0x41|(2*drive->dn): Recovery */ - pci_read_config_word(dev, 0x40|(2*drive->dn), &d_conf); - tmp0 = pci_bus_clock_list(speed, BUSCLOCK(dev)); - d_conf = ((tmp0 & 0xf0) << 4) | (tmp0 & 0xf); - pci_write_config_word(dev, 0x40|(2*drive->dn), d_conf); - - tmp1 = 0x00; - tmp2 = 0x00; - pci_read_config_byte(dev, 0x54, &ultra); - tmp1 = ((0x00 << (2*drive->dn)) | (ultra & ~(3 << (2*drive->dn)))); - ultra_conf = pci_bus_clock_list_ultra(speed, BUSCLOCK(dev)); - tmp2 = ((ultra_conf << (2*drive->dn)) | (tmp1 & ~(3 << (2*drive->dn)))); - pci_write_config_byte(dev, 0x54, tmp2); - local_irq_restore(flags); - return(ide_config_drive_speed(drive, speed)); -} - -static int aec6260_tune_chipset (ide_drive_t *drive, u8 xferspeed) -{ - ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; - u8 speed = ide_rate_filter(aec62xx_ratemask(drive), xferspeed); - u8 unit = (drive->select.b.unit & 0x01); - u8 tmp1 = 0, tmp2 = 0; - u8 ultra = 0, drive_conf = 0, ultra_conf = 0; - unsigned long flags; - - local_irq_save(flags); - /* high 4-bits: Active, low 4-bits: Recovery */ - pci_read_config_byte(dev, 0x40|drive->dn, &drive_conf); - drive_conf = pci_bus_clock_list(speed, BUSCLOCK(dev)); - pci_write_config_byte(dev, 0x40|drive->dn, drive_conf); - - pci_read_config_byte(dev, (0x44|hwif->channel), &ultra); - tmp1 = ((0x00 << (4*unit)) | (ultra & ~(7 << (4*unit)))); - ultra_conf = pci_bus_clock_list_ultra(speed, BUSCLOCK(dev)); - tmp2 = ((ultra_conf << (4*unit)) | (tmp1 & ~(7 << (4*unit)))); - pci_write_config_byte(dev, (0x44|hwif->channel), tmp2); - local_irq_restore(flags); - return(ide_config_drive_speed(drive, speed)); -} - -static int aec62xx_tune_chipset (ide_drive_t *drive, u8 speed) -{ - switch (HWIF(drive)->pci_dev->device) { - case PCI_DEVICE_ID_ARTOP_ATP865: - case PCI_DEVICE_ID_ARTOP_ATP865R: - case PCI_DEVICE_ID_ARTOP_ATP860: - case PCI_DEVICE_ID_ARTOP_ATP860R: - return ((int) aec6260_tune_chipset(drive, speed)); - case PCI_DEVICE_ID_ARTOP_ATP850UF: - return ((int) aec6210_tune_chipset(drive, speed)); - default: - return -1; - } -} - -static int config_chipset_for_dma (ide_drive_t *drive) -{ - u8 speed = ide_dma_speed(drive, aec62xx_ratemask(drive)); - - if (!(speed)) - return 0; - - (void) aec62xx_tune_chipset(drive, speed); - return ide_dma_enable(drive); -} - -static void aec62xx_tune_drive (ide_drive_t *drive, u8 pio) -{ - u8 speed = 0; - u8 new_pio = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL); - - switch(pio) { - case 5: speed = new_pio; break; - case 4: speed = XFER_PIO_4; break; - case 3: speed = XFER_PIO_3; break; - case 2: speed = XFER_PIO_2; break; - case 1: speed = XFER_PIO_1; break; - default: speed = XFER_PIO_0; break; - } - (void) aec62xx_tune_chipset(drive, speed); -} - -static int aec62xx_config_drive_xfer_rate (ide_drive_t *drive) -{ - ide_hwif_t *hwif = HWIF(drive); - struct hd_driveid *id = drive->id; - - if ((id->capability & 1) && drive->autodma) { - - if (ide_use_dma(drive)) { - if (config_chipset_for_dma(drive)) - return hwif->ide_dma_on(drive); - } - - goto fast_ata_pio; - - } else if ((id->capability & 8) || (id->field_valid & 2)) { -fast_ata_pio: - aec62xx_tune_drive(drive, 5); - return hwif->ide_dma_off_quietly(drive); - } - /* IORDY not supported */ - return 0; -} - -static int aec62xx_irq_timeout (ide_drive_t *drive) -{ - ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; - - switch(dev->device) { - case PCI_DEVICE_ID_ARTOP_ATP860: - case PCI_DEVICE_ID_ARTOP_ATP860R: - case PCI_DEVICE_ID_ARTOP_ATP865: - case PCI_DEVICE_ID_ARTOP_ATP865R: - printk(" AEC62XX time out "); - default: - break; - } - return 0; -} - -static unsigned int __devinit init_chipset_aec62xx(struct pci_dev *dev, const char *name) -{ - int bus_speed = system_bus_clock(); - - if (dev->resource[PCI_ROM_RESOURCE].start) { - pci_write_config_dword(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE); - printk(KERN_INFO "%s: ROM enabled at 0x%08lx\n", name, - (unsigned long)dev->resource[PCI_ROM_RESOURCE].start); - } - - if (bus_speed <= 33) - pci_set_drvdata(dev, (void *) aec6xxx_33_base); - else - pci_set_drvdata(dev, (void *) aec6xxx_34_base); - - /* These are necessary to get AEC6280 Macintosh cards to work */ - if ((dev->device == PCI_DEVICE_ID_ARTOP_ATP865) || - (dev->device == PCI_DEVICE_ID_ARTOP_ATP865R)) { - u8 reg49h = 0, reg4ah = 0; - /* Clear reset and test bits. */ - pci_read_config_byte(dev, 0x49, ®49h); - pci_write_config_byte(dev, 0x49, reg49h & ~0x30); - /* Enable chip interrupt output. */ - pci_read_config_byte(dev, 0x4a, ®4ah); - pci_write_config_byte(dev, 0x4a, reg4ah & ~0x01); - /* Enable burst mode. */ - pci_read_config_byte(dev, 0x4a, ®4ah); - pci_write_config_byte(dev, 0x4a, reg4ah | 0x80); - } - - return dev->irq; -} - -static void __devinit init_hwif_aec62xx(ide_hwif_t *hwif) -{ - hwif->autodma = 0; - hwif->tuneproc = &aec62xx_tune_drive; - hwif->speedproc = &aec62xx_tune_chipset; - - if (hwif->pci_dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) { - hwif->serialized = hwif->channel; - hwif->no_dsc = 1; - } - - if (hwif->mate) - hwif->mate->serialized = hwif->serialized; - - if (!hwif->dma_base) { - hwif->drives[0].autotune = 1; - hwif->drives[1].autotune = 1; - return; - } - - hwif->ultra_mask = 0x7f; - hwif->mwdma_mask = 0x07; - hwif->swdma_mask = 0x07; - - hwif->ide_dma_check = &aec62xx_config_drive_xfer_rate; - hwif->ide_dma_lostirq = &aec62xx_irq_timeout; - hwif->ide_dma_timeout = &aec62xx_irq_timeout; - if (!noautodma) - hwif->autodma = 1; - hwif->drives[0].autodma = hwif->autodma; - hwif->drives[1].autodma = hwif->autodma; -} - -static void __devinit init_dma_aec62xx(ide_hwif_t *hwif, unsigned long dmabase) -{ - struct pci_dev *dev = hwif->pci_dev; - - if (dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) { - u8 reg54h = 0; - unsigned long flags; - - spin_lock_irqsave(&ide_lock, flags); - pci_read_config_byte(dev, 0x54, ®54h); - pci_write_config_byte(dev, 0x54, reg54h & ~(hwif->channel ? 0xF0 : 0x0F)); - spin_unlock_irqrestore(&ide_lock, flags); - } else { - u8 ata66 = 0; - pci_read_config_byte(hwif->pci_dev, 0x49, &ata66); - if (!(hwif->udma_four)) - hwif->udma_four = (ata66&(hwif->channel?0x02:0x01))?0:1; - } - - ide_setup_dma(hwif, dmabase, 8); -} - -static int __devinit init_setup_aec62xx(struct pci_dev *dev, ide_pci_device_t *d) -{ - return ide_setup_pci_device(dev, d); -} - -static int __devinit init_setup_aec6x80(struct pci_dev *dev, ide_pci_device_t *d) -{ - unsigned long bar4reg = pci_resource_start(dev, 4); - - if (inb(bar4reg+2) & 0x10) { - strcpy(d->name, "AEC6880"); - if (dev->device == PCI_DEVICE_ID_ARTOP_ATP865R) - strcpy(d->name, "AEC6880R"); - } else { - strcpy(d->name, "AEC6280"); - if (dev->device == PCI_DEVICE_ID_ARTOP_ATP865R) - strcpy(d->name, "AEC6280R"); - } - - return ide_setup_pci_device(dev, d); -} - -static ide_pci_device_t aec62xx_chipsets[] __devinitdata = { - { /* 0 */ - .name = "AEC6210", - .init_setup = init_setup_aec62xx, - .init_chipset = init_chipset_aec62xx, - .init_hwif = init_hwif_aec62xx, - .init_dma = init_dma_aec62xx, - .channels = 2, - .autodma = AUTODMA, - .enablebits = {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}}, - .bootable = OFF_BOARD, - },{ /* 1 */ - .name = "AEC6260", - .init_setup = init_setup_aec62xx, - .init_chipset = init_chipset_aec62xx, - .init_hwif = init_hwif_aec62xx, - .init_dma = init_dma_aec62xx, - .channels = 2, - .autodma = NOAUTODMA, - .bootable = OFF_BOARD, - },{ /* 2 */ - .name = "AEC6260R", - .init_setup = init_setup_aec62xx, - .init_chipset = init_chipset_aec62xx, - .init_hwif = init_hwif_aec62xx, - .init_dma = init_dma_aec62xx, - .channels = 2, - .autodma = AUTODMA, - .enablebits = {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}}, - .bootable = NEVER_BOARD, - },{ /* 3 */ - .name = "AEC6X80", - .init_setup = init_setup_aec6x80, - .init_chipset = init_chipset_aec62xx, - .init_hwif = init_hwif_aec62xx, - .init_dma = init_dma_aec62xx, - .channels = 2, - .autodma = AUTODMA, - .bootable = OFF_BOARD, - },{ /* 4 */ - .name = "AEC6X80R", - .init_setup = init_setup_aec6x80, - .init_chipset = init_chipset_aec62xx, - .init_hwif = init_hwif_aec62xx, - .init_dma = init_dma_aec62xx, - .channels = 2, - .autodma = AUTODMA, - .enablebits = {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}}, - .bootable = OFF_BOARD, - } -}; - -/** - * aec62xx_init_one - called when a AEC is found - * @dev: the aec62xx device - * @id: the matching pci id - * - * Called when the PCI registration layer (or the IDE initialization) - * finds a device matching our IDE device tables. - */ - -static int __devinit aec62xx_init_one(struct pci_dev *dev, const struct pci_device_id *id) -{ - ide_pci_device_t *d = &aec62xx_chipsets[id->driver_data]; - - return d->init_setup(dev, d); -} - -static struct pci_device_id aec62xx_pci_tbl[] = { - { PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP850UF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP860, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 }, - { PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP860R, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2 }, - { PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP865, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3 }, - { PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP865R, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 }, - { 0, }, -}; -MODULE_DEVICE_TABLE(pci, aec62xx_pci_tbl); - -static struct pci_driver driver = { - .name = "AEC62xx_IDE", - .id_table = aec62xx_pci_tbl, - .probe = aec62xx_init_one, -}; - -static int aec62xx_ide_init(void) -{ - return ide_pci_register_driver(&driver); -} - -module_init(aec62xx_ide_init); - -MODULE_AUTHOR("Andre Hedrick"); -MODULE_DESCRIPTION("PCI driver module for ARTOP AEC62xx IDE"); -MODULE_LICENSE("GPL"); diff --git a/drivers/ide/pci/alim15x3.c b/drivers/ide/pci/alim15x3.c deleted file mode 100644 index d419e4bb54f..00000000000 --- a/drivers/ide/pci/alim15x3.c +++ /dev/null @@ -1,919 +0,0 @@ -/* - * linux/drivers/ide/pci/alim15x3.c Version 0.17 2003/01/02 - * - * Copyright (C) 1998-2000 Michel Aubry, Maintainer - * Copyright (C) 1998-2000 Andrzej Krzysztofowicz, Maintainer - * Copyright (C) 1999-2000 CJ, cjtsai@ali.com.tw, Maintainer - * - * Copyright (C) 1998-2000 Andre Hedrick (andre@linux-ide.org) - * May be copied or modified under the terms of the GNU General Public License - * Copyright (C) 2002 Alan Cox <alan@redhat.com> - * ALi (now ULi M5228) support by Clear Zhang <Clear.Zhang@ali.com.tw> - * - * (U)DMA capable version of ali 1533/1543(C), 1535(D) - * - ********************************************************************** - * 9/7/99 --Parts from the above author are included and need to be - * converted into standard interface, once I finish the thought. - * - * Recent changes - * Don't use LBA48 mode on ALi <= 0xC4 - * Don't poke 0x79 with a non ALi northbridge - * Don't flip undefined bits on newer chipsets (fix Fujitsu laptop hang) - * Allow UDMA6 on revisions > 0xC4 - * - * Documentation - * Chipset documentation available under NDA only - * - */ - -#include <linux/module.h> -#include <linux/types.h> -#include <linux/kernel.h> -#include <linux/pci.h> -#include <linux/delay.h> -#include <linux/hdreg.h> -#include <linux/ide.h> -#include <linux/init.h> - -#include <asm/io.h> - -#define DISPLAY_ALI_TIMINGS - -/* - * ALi devices are not plug in. Otherwise these static values would - * need to go. They ought to go away anyway - */ - -static u8 m5229_revision; -static u8 chip_is_1543c_e; -static struct pci_dev *isa_dev; - -#if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) -#include <linux/stat.h> -#include <linux/proc_fs.h> - -static u8 ali_proc = 0; - -static struct pci_dev *bmide_dev; - -static char *fifo[4] = { - "FIFO Off", - "FIFO On ", - "DMA mode", - "PIO mode" }; - -static char *udmaT[8] = { - "1.5T", - " 2T", - "2.5T", - " 3T", - "3.5T", - " 4T", - " 6T", - " 8T" -}; - -static char *channel_status[8] = { - "OK ", - "busy ", - "DRQ ", - "DRQ busy ", - "error ", - "error busy ", - "error DRQ ", - "error DRQ busy" -}; - -/** - * ali_get_info - generate proc file for ALi IDE - * @buffer: buffer to fill - * @addr: address of user start in buffer - * @offset: offset into 'file' - * @count: buffer count - * - * Walks the Ali devices and outputs summary data on the tuning and - * anything else that will help with debugging - */ - -static int ali_get_info (char *buffer, char **addr, off_t offset, int count) -{ - unsigned long bibma; - u8 reg53h, reg5xh, reg5yh, reg5xh1, reg5yh1, c0, c1, rev, tmp; - char *q, *p = buffer; - - /* fetch rev. */ - pci_read_config_byte(bmide_dev, 0x08, &rev); - if (rev >= 0xc1) /* M1543C or newer */ - udmaT[7] = " ???"; - else - fifo[3] = " ??? "; - - /* first fetch bibma: */ - - bibma = pci_resource_start(bmide_dev, 4); - - /* - * at that point bibma+0x2 et bibma+0xa are byte - * registers to investigate: - */ - c0 = inb(bibma + 0x02); - c1 = inb(bibma + 0x0a); - - p += sprintf(p, - "\n Ali M15x3 Chipset.\n"); - p += sprintf(p, - " ------------------\n"); - pci_read_config_byte(bmide_dev, 0x78, ®53h); - p += sprintf(p, "PCI Clock: %d.\n", reg53h); - - pci_read_config_byte(bmide_dev, 0x53, ®53h); - p += sprintf(p, - "CD_ROM FIFO:%s, CD_ROM DMA:%s\n", - (reg53h & 0x02) ? "Yes" : "No ", - (reg53h & 0x01) ? "Yes" : "No " ); - pci_read_config_byte(bmide_dev, 0x74, ®53h); - p += sprintf(p, - "FIFO Status: contains %d Words, runs%s%s\n\n", - (reg53h & 0x3f), - (reg53h & 0x40) ? " OVERWR" : "", - (reg53h & 0x80) ? " OVERRD." : "." ); - - p += sprintf(p, - "-------------------primary channel" - "-------------------secondary channel" - "---------\n\n"); - - pci_read_config_byte(bmide_dev, 0x09, ®53h); - p += sprintf(p, - "channel status: %s" - " %s\n", - (reg53h & 0x20) ? "On " : "Off", - (reg53h & 0x10) ? "On " : "Off" ); - - p += sprintf(p, - "both channels togth: %s" - " %s\n", - (c0&0x80) ? "No " : "Yes", - (c1&0x80) ? "No " : "Yes" ); - - pci_read_config_byte(bmide_dev, 0x76, ®53h); - p += sprintf(p, - "Channel state: %s %s\n", - channel_status[reg53h & 0x07], - channel_status[(reg53h & 0x70) >> 4] ); - - pci_read_config_byte(bmide_dev, 0x58, ®5xh); - pci_read_config_byte(bmide_dev, 0x5c, ®5yh); - p += sprintf(p, - "Add. Setup Timing: %dT" - " %dT\n", - (reg5xh & 0x07) ? (reg5xh & 0x07) : 8, - (reg5yh & 0x07) ? (reg5yh & 0x07) : 8 ); - - pci_read_config_byte(bmide_dev, 0x59, ®5xh); - pci_read_config_byte(bmide_dev, 0x5d, ®5yh); - p += sprintf(p, - "Command Act. Count: %dT" - " %dT\n" - "Command Rec. Count: %dT" - " %dT\n\n", - (reg5xh & 0x70) ? ((reg5xh & 0x70) >> 4) : 8, - (reg5yh & 0x70) ? ((reg5yh & 0x70) >> 4) : 8, - (reg5xh & 0x0f) ? (reg5xh & 0x0f) : 16, - (reg5yh & 0x0f) ? (reg5yh & 0x0f) : 16 ); - - p += sprintf(p, - "----------------drive0-----------drive1" - "------------drive0-----------drive1------\n\n"); - p += sprintf(p, - "DMA enabled: %s %s" - " %s %s\n", - (c0&0x20) ? "Yes" : "No ", - (c0&0x40) ? "Yes" : "No ", - (c1&0x20) ? "Yes" : "No ", - (c1&0x40) ? "Yes" : "No " ); - - pci_read_config_byte(bmide_dev, 0x54, ®5xh); - pci_read_config_byte(bmide_dev, 0x55, ®5yh); - q = "FIFO threshold: %2d Words %2d Words" - " %2d Words %2d Words\n"; - if (rev < 0xc1) { - if ((rev == 0x20) && - (pci_read_config_byte(bmide_dev, 0x4f, &tmp), (tmp &= 0x20))) { - p += sprintf(p, q, 8, 8, 8, 8); - } else { - p += sprintf(p, q, - (reg5xh & 0x03) + 12, - ((reg5xh & 0x30)>>4) + 12, - (reg5yh & 0x03) + 12, - ((reg5yh & 0x30)>>4) + 12 ); - } - } else { - int t1 = (tmp = (reg5xh & 0x03)) ? (tmp << 3) : 4; - int t2 = (tmp = ((reg5xh & 0x30)>>4)) ? (tmp << 3) : 4; - int t3 = (tmp = (reg5yh & 0x03)) ? (tmp << 3) : 4; - int t4 = (tmp = ((reg5yh & 0x30)>>4)) ? (tmp << 3) : 4; - p += sprintf(p, q, t1, t2, t3, t4); - } - -#if 0 - p += sprintf(p, - "FIFO threshold: %2d Words %2d Words" - " %2d Words %2d Words\n", - (reg5xh & 0x03) + 12, - ((reg5xh & 0x30)>>4) + 12, - (reg5yh & 0x03) + 12, - ((reg5yh & 0x30)>>4) + 12 ); -#endif - - p += sprintf(p, - "FIFO mode: %s %s %s %s\n", - fifo[((reg5xh & 0x0c) >> 2)], - fifo[((reg5xh & 0xc0) >> 6)], - fifo[((reg5yh & 0x0c) >> 2)], - fifo[((reg5yh & 0xc0) >> 6)] ); - - pci_read_config_byte(bmide_dev, 0x5a, ®5xh); - pci_read_config_byte(bmide_dev, 0x5b, ®5xh1); - pci_read_config_byte(bmide_dev, 0x5e, ®5yh); - pci_read_config_byte(bmide_dev, 0x5f, ®5yh1); - - p += sprintf(p,/* - "------------------drive0-----------drive1" - "------------drive0-----------drive1------\n")*/ - "Dt RW act. Cnt %2dT %2dT" - " %2dT %2dT\n" - "Dt RW rec. Cnt %2dT %2dT" - " %2dT %2dT\n\n", - (reg5xh & 0x70) ? ((reg5xh & 0x70) >> 4) : 8, - (reg5xh1 & 0x70) ? ((reg5xh1 & 0x70) >> 4) : 8, - (reg5yh & 0x70) ? ((reg5yh & 0x70) >> 4) : 8, - (reg5yh1 & 0x70) ? ((reg5yh1 & 0x70) >> 4) : 8, - (reg5xh & 0x0f) ? (reg5xh & 0x0f) : 16, - (reg5xh1 & 0x0f) ? (reg5xh1 & 0x0f) : 16, - (reg5yh & 0x0f) ? (reg5yh & 0x0f) : 16, - (reg5yh1 & 0x0f) ? (reg5yh1 & 0x0f) : 16 ); - - p += sprintf(p, - "-----------------------------------UDMA Timings" - "--------------------------------\n\n"); - - pci_read_config_byte(bmide_dev, 0x56, ®5xh); - pci_read_config_byte(bmide_dev, 0x57, ®5yh); - p += sprintf(p, - "UDMA: %s %s" - " %s %s\n" - "UDMA timings: %s %s" - " %s %s\n\n", - (reg5xh & 0x08) ? "OK" : "No", - (reg5xh & 0x80) ? "OK" : "No", - (reg5yh & 0x08) ? "OK" : "No", - (reg5yh & 0x80) ? "OK" : "No", - udmaT[(reg5xh & 0x07)], - udmaT[(reg5xh & 0x70) >> 4], - udmaT[reg5yh & 0x07], - udmaT[(reg5yh & 0x70) >> 4] ); - - return p-buffer; /* => must be less than 4k! */ -} -#endif /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */ - -/** - * ali15x3_tune_drive - set up a drive - * @drive: drive to tune - * @pio: unused - * - * Select the best PIO timing for the drive in question. Then - * program the controller for this drive set up - */ - -static void ali15x3_tune_drive (ide_drive_t *drive, u8 pio) -{ - ide_pio_data_t d; - ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; - int s_time, a_time, c_time; - u8 s_clc, a_clc, r_clc; - unsigned long flags; - int bus_speed = system_bus_clock(); - int port = hwif->channel ? 0x5c : 0x58; - int portFIFO = hwif->channel ? 0x55 : 0x54; - u8 cd_dma_fifo = 0; - int unit = drive->select.b.unit & 1; - - pio = ide_get_best_pio_mode(drive, pio, 5, &d); - s_time = ide_pio_timings[pio].setup_time; - a_time = ide_pio_timings[pio].active_time; - if ((s_clc = (s_time * bus_speed + 999) / 1000) >= 8) - s_clc = 0; - if ((a_clc = (a_time * bus_speed + 999) / 1000) >= 8) - a_clc = 0; - c_time = ide_pio_timings[pio].cycle_time; - -#if 0 - if ((r_clc = ((c_time - s_time - a_time) * bus_speed + 999) / 1000) >= 16) - r_clc = 0; -#endif - - if (!(r_clc = (c_time * bus_speed + 999) / 1000 - a_clc - s_clc)) { - r_clc = 1; - } else { - if (r_clc >= 16) - r_clc = 0; - } - local_irq_save(flags); - - /* - * PIO mode => ATA FIFO on, ATAPI FIFO off - */ - pci_read_config_byte(dev, portFIFO, &cd_dma_fifo); - if (drive->media==ide_disk) { - if (unit) { - pci_write_config_byte(dev, portFIFO, (cd_dma_fifo & 0x0F) | 0x50); - } else { - pci_write_config_byte(dev, portFIFO, (cd_dma_fifo & 0xF0) | 0x05); - } - } else { - if (unit) { - pci_write_config_byte(dev, portFIFO, cd_dma_fifo & 0x0F); - } else { - pci_write_config_byte(dev, portFIFO, cd_dma_fifo & 0xF0); - } - } - - pci_write_config_byte(dev, port, s_clc); - pci_write_config_byte(dev, port+drive->select.b.unit+2, (a_clc << 4) | r_clc); - local_irq_restore(flags); - - /* - * setup active rec - * { 70, 165, 365 }, PIO Mode 0 - * { 50, 125, 208 }, PIO Mode 1 - * { 30, 100, 110 }, PIO Mode 2 - * { 30, 80, 70 }, PIO Mode 3 with IORDY - * { 25, 70, 25 }, PIO Mode 4 with IORDY ns - * { 20, 50, 30 } PIO Mode 5 with IORDY (nonstandard) - */ - -} - -/** - * ali15x3_can_ultra - check for ultra DMA support - * @drive: drive to do the check - * - * Check the drive and controller revisions. Return 0 if UDMA is - * not available, or 1 if UDMA can be used. The actual rules for - * the ALi are - * No UDMA on revisions <= 0x20 - * Disk only for revisions < 0xC2 - * Not WDC drives for revisions < 0xC2 - * - * FIXME: WDC ifdef needs to die - */ - -static u8 ali15x3_can_ultra (ide_drive_t *drive) -{ -#ifndef CONFIG_WDC_ALI15X3 - struct hd_driveid *id = drive->id; -#endif /* CONFIG_WDC_ALI15X3 */ - - if (m5229_revision <= 0x20) { - return 0; - } else if ((m5229_revision < 0xC2) && -#ifndef CONFIG_WDC_ALI15X3 - ((chip_is_1543c_e && strstr(id->model, "WDC ")) || - (drive->media!=ide_disk))) { -#else /* CONFIG_WDC_ALI15X3 */ - (drive->media!=ide_disk)) { -#endif /* CONFIG_WDC_ALI15X3 */ - return 0; - } else { - return 1; - } -} - -/** - * ali15x3_ratemask - generate DMA mode list - * @drive: drive to compute against - * - * Generate a list of the available DMA modes for the drive. - * FIXME: this function contains lots of bogus masking we can dump - * - * Return the highest available mode (UDMA33, UDMA66, UDMA100,..) - */ - -static u8 ali15x3_ratemask (ide_drive_t *drive) -{ - u8 mode = 0, can_ultra = ali15x3_can_ultra(drive); - - if (m5229_revision > 0xC4 && can_ultra) { - mode = 4; - } else if (m5229_revision == 0xC4 && can_ultra) { - mode = 3; - } else if (m5229_revision >= 0xC2 && can_ultra) { - mode = 2; - } else if (can_ultra) { - return 1; - } else { - return 0; - } - - /* - * If the drive sees no suitable cable then UDMA 33 - * is the highest permitted mode - */ - - if (!eighty_ninty_three(drive)) - mode = min(mode, (u8)1); - return mode; -} - -/** - * ali15x3_tune_chipset - set up chiset for new speed - * @drive: drive to configure for - * @xferspeed: desired speed - * - * Configure the hardware for the desired IDE transfer mode. - * We also do the needed drive configuration through helpers - */ - -static int ali15x3_tune_chipset (ide_drive_t *drive, u8 xferspeed) -{ - ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; - u8 speed = ide_rate_filter(ali15x3_ratemask(drive), xferspeed); - u8 speed1 = speed; - u8 unit = (drive->select.b.unit & 0x01); - u8 tmpbyte = 0x00; - int m5229_udma = (hwif->channel) ? 0x57 : 0x56; - - if (speed == XFER_UDMA_6) - speed1 = 0x47; - - if (speed < XFER_UDMA_0) { - u8 ultra_enable = (unit) ? 0x7f : 0xf7; - /* - * clear "ultra enable" bit - */ - pci_read_config_byte(dev, m5229_udma, &tmpbyte); - tmpbyte &= ultra_enable; - pci_write_config_byte(dev, m5229_udma, tmpbyte); - - if (speed < XFER_SW_DMA_0) - ali15x3_tune_drive(drive, speed); - } else { - pci_read_config_byte(dev, m5229_udma, &tmpbyte); - tmpbyte &= (0x0f << ((1-unit) << 2)); - /* - * enable ultra dma and set timing - */ - tmpbyte |= ((0x08 | ((4-speed1)&0x07)) << (unit << 2)); - pci_write_config_byte(dev, m5229_udma, tmpbyte); - if (speed >= XFER_UDMA_3) { - pci_read_config_byte(dev, 0x4b, &tmpbyte); - tmpbyte |= 1; - pci_write_config_byte(dev, 0x4b, tmpbyte); - } - } - return (ide_config_drive_speed(drive, speed)); -} - - -/** - * config_chipset_for_dma - set up DMA mode - * @drive: drive to configure for - * - * Place a drive into DMA mode and tune the chipset for - * the selected speed. - * - * Returns true if DMA mode can be used - */ - -static int config_chipset_for_dma (ide_drive_t *drive) -{ - u8 speed = ide_dma_speed(drive, ali15x3_ratemask(drive)); - - if (!(speed)) - return 0; - - (void) ali15x3_tune_chipset(drive, speed); - return ide_dma_enable(drive); -} - -/** - * ali15x3_config_drive_for_dma - configure for DMA - * @drive: drive to configure - * - * Configure a drive for DMA operation. If DMA is not possible we - * drop the drive into PIO mode instead. - * - * FIXME: exactly what are we trying to return here - */ - -static int ali15x3_config_drive_for_dma(ide_drive_t *drive) -{ - ide_hwif_t *hwif = HWIF(drive); - struct hd_driveid *id = drive->id; - - if ((m5229_revision<=0x20) && (drive->media!=ide_disk)) - return hwif->ide_dma_off_quietly(drive); - - drive->init_speed = 0; - - if ((id != NULL) && ((id->capability & 1) != 0) && drive->autodma) { - /* Consult the list of known "bad" drives */ - if (__ide_dma_bad_drive(drive)) - goto ata_pio; - if ((id->field_valid & 4) && (m5229_revision >= 0xC2)) { - if (id->dma_ultra & hwif->ultra_mask) { - /* Force if Capable UltraDMA */ - int dma = config_chipset_for_dma(drive); - if ((id->field_valid & 2) && !dma) - goto try_dma_modes; - } - } else if (id->field_valid & 2) { -try_dma_modes: - if ((id->dma_mword & hwif->mwdma_mask) || - (id->dma_1word & hwif->swdma_mask)) { - /* Force if Capable regular DMA modes */ - if (!config_chipset_for_dma(drive)) - goto no_dma_set; - } - } else if (__ide_dma_good_drive(drive) && - (id->eide_dma_time < 150)) { - /* Consult the list of known "good" drives */ - if (!config_chipset_for_dma(drive)) - goto no_dma_set; - } else { - goto ata_pio; - } - } else { -ata_pio: - hwif->tuneproc(drive, 255); -no_dma_set: - return hwif->ide_dma_off_quietly(drive); - } - return hwif->ide_dma_on(drive); -} - -/** - * ali15x3_dma_setup - begin a DMA phase - * @drive: target device - * - * Returns 1 if the DMA cannot be performed, zero on success. - */ - -static int ali15x3_dma_setup(ide_drive_t *drive) -{ - if (m5229_revision < 0xC2 && drive->media != ide_disk) { - if (rq_data_dir(drive->hwif->hwgroup->rq)) - return 1; /* try PIO instead of DMA */ - } - return ide_dma_setup(drive); -} - -/** - * init_chipset_ali15x3 - Initialise an ALi IDE controller - * @dev: PCI device - * @name: Name of the controller - * - * This function initializes the ALI IDE controller and where - * appropriate also sets up the 1533 southbridge. - */ - -static unsigned int __devinit init_chipset_ali15x3 (struct pci_dev *dev, const char *name) -{ - unsigned long flags; - u8 tmpbyte; - struct pci_dev *north = pci_find_slot(0, PCI_DEVFN(0,0)); - - pci_read_config_byte(dev, PCI_REVISION_ID, &m5229_revision); - - isa_dev = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL); - -#if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) - if (!ali_proc) { - ali_proc = 1; - bmide_dev = dev; - ide_pci_create_host_proc("ali", ali_get_info); - } -#endif /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */ - - local_irq_save(flags); - - if (m5229_revision < 0xC2) { - /* - * revision 0x20 (1543-E, 1543-F) - * revision 0xC0, 0xC1 (1543C-C, 1543C-D, 1543C-E) - * clear CD-ROM DMA write bit, m5229, 0x4b, bit 7 - */ - pci_read_config_byte(dev, 0x4b, &tmpbyte); - /* - * clear bit 7 - */ - pci_write_config_byte(dev, 0x4b, tmpbyte & 0x7F); - local_irq_restore(flags); - return 0; - } - - /* - * 1543C-B?, 1535, 1535D, 1553 - * Note 1: not all "motherboard" support this detection - * Note 2: if no udma 66 device, the detection may "error". - * but in this case, we will not set the device to - * ultra 66, the detection result is not important - */ - - /* - * enable "Cable Detection", m5229, 0x4b, bit3 - */ - pci_read_config_byte(dev, 0x4b, &tmpbyte); - pci_write_config_byte(dev, 0x4b, tmpbyte | 0x08); - - /* - * We should only tune the 1533 enable if we are using an ALi - * North bridge. We might have no north found on some zany - * box without a device at 0:0.0. The ALi bridge will be at - * 0:0.0 so if we didn't find one we know what is cooking. - */ - if (north && north->vendor != PCI_VENDOR_ID_AL) { - local_irq_restore(flags); - return 0; - } - - if (m5229_revision < 0xC5 && isa_dev) - { - /* - * set south-bridge's enable bit, m1533, 0x79 - */ - - pci_read_config_byte(isa_dev, 0x79, &tmpbyte); - if (m5229_revision == 0xC2) { - /* - * 1543C-B0 (m1533, 0x79, bit 2) - */ - pci_write_config_byte(isa_dev, 0x79, tmpbyte | 0x04); - } else if (m5229_revision >= 0xC3) { - /* - * 1553/1535 (m1533, 0x79, bit 1) - */ - pci_write_config_byte(isa_dev, 0x79, tmpbyte | 0x02); - } - } - local_irq_restore(flags); - return 0; -} - -/** - * ata66_ali15x3 - check for UDMA 66 support - * @hwif: IDE interface - * - * This checks if the controller and the cable are capable - * of UDMA66 transfers. It doesn't check the drives. - * But see note 2 below! - * - * FIXME: frobs bits that are not defined on newer ALi devicea - */ - -static unsigned int __devinit ata66_ali15x3 (ide_hwif_t *hwif) -{ - struct pci_dev *dev = hwif->pci_dev; - unsigned int ata66 = 0; - u8 cable_80_pin[2] = { 0, 0 }; - - unsigned long flags; - u8 tmpbyte; - - local_irq_save(flags); - - if (m5229_revision >= 0xC2) { - /* - * Ultra66 cable detection (from Host View) - * m5229, 0x4a, bit0: primary, bit1: secondary 80 pin - */ - pci_read_config_byte(dev, 0x4a, &tmpbyte); - /* - * 0x4a, bit0 is 0 => primary channel - * has 80-pin (from host view) - */ - if (!(tmpbyte & 0x01)) cable_80_pin[0] = 1; - /* - * 0x4a, bit1 is 0 => secondary channel - * has 80-pin (from host view) - */ - if (!(tmpbyte & 0x02)) cable_80_pin[1] = 1; - /* - * Allow ata66 if cable of current channel has 80 pins - */ - ata66 = (hwif->channel)?cable_80_pin[1]:cable_80_pin[0]; - } else { - /* - * check m1533, 0x5e, bit 1~4 == 1001 => & 00011110 = 00010010 - */ - pci_read_config_byte(isa_dev, 0x5e, &tmpbyte); - chip_is_1543c_e = ((tmpbyte & 0x1e) == 0x12) ? 1: 0; - } - - /* - * CD_ROM DMA on (m5229, 0x53, bit0) - * Enable this bit even if we want to use PIO - * PIO FIFO off (m5229, 0x53, bit1) - * The hardware will use 0x54h and 0x55h to control PIO FIFO - * (Not on later devices it seems) - * - * 0x53 changes meaning on later revs - we must no touch - * bit 1 on them. Need to check if 0x20 is the right break - */ - - pci_read_config_byte(dev, 0x53, &tmpbyte); - - if(m5229_revision <= 0x20) - tmpbyte = (tmpbyte & (~0x02)) | 0x01; - else if (m5229_revision == 0xc7 || m5229_revision == 0xc8) - tmpbyte |= 0x03; - else - tmpbyte |= 0x01; - - pci_write_config_byte(dev, 0x53, tmpbyte); - - local_irq_restore(flags); - - return(ata66); -} - -/** - * init_hwif_common_ali15x3 - Set up ALI IDE hardware - * @hwif: IDE interface - * - * Initialize the IDE structure side of the ALi 15x3 driver. - */ - -static void __devinit init_hwif_common_ali15x3 (ide_hwif_t *hwif) -{ - hwif->autodma = 0; - hwif->tuneproc = &ali15x3_tune_drive; - hwif->speedproc = &ali15x3_tune_chipset; - - /* don't use LBA48 DMA on ALi devices before rev 0xC5 */ - hwif->no_lba48_dma = (m5229_revision <= 0xC4) ? 1 : 0; - - if (!hwif->dma_base) { - hwif->drives[0].autotune = 1; - hwif->drives[1].autotune = 1; - return; - } - - hwif->atapi_dma = 1; - - if (m5229_revision > 0x20) - hwif->ultra_mask = 0x7f; - hwif->mwdma_mask = 0x07; - hwif->swdma_mask = 0x07; - - if (m5229_revision >= 0x20) { - /* - * M1543C or newer for DMAing - */ - hwif->ide_dma_check = &ali15x3_config_drive_for_dma; - hwif->dma_setup = &ali15x3_dma_setup; - if (!noautodma) - hwif->autodma = 1; - if (!(hwif->udma_four)) - hwif->udma_four = ata66_ali15x3(hwif); - } - hwif->drives[0].autodma = hwif->autodma; - hwif->drives[1].autodma = hwif->autodma; -} - -/** - * init_hwif_ali15x3 - Initialize the ALI IDE x86 stuff - * @hwif: interface to configure - * - * Obtain the IRQ tables for an ALi based IDE solution on the PC - * class platforms. This part of the code isn't applicable to the - * Sparc systems - */ - -static void __devinit init_hwif_ali15x3 (ide_hwif_t *hwif) -{ - u8 ideic, inmir; - s8 irq_routing_table[] = { -1, 9, 3, 10, 4, 5, 7, 6, - 1, 11, 0, 12, 0, 14, 0, 15 }; - int irq = -1; - - if (hwif->pci_dev->device == PCI_DEVICE_ID_AL_M5229) - hwif->irq = hwif->channel ? 15 : 14; - - if (isa_dev) { - /* - * read IDE interface control - */ - pci_read_config_byte(isa_dev, 0x58, &ideic); - - /* bit0, bit1 */ - ideic = ideic & 0x03; - - /* get IRQ for IDE Controller */ - if ((hwif->channel && ideic == 0x03) || - (!hwif->channel && !ideic)) { - /* - * get SIRQ1 routing table - */ - pci_read_config_byte(isa_dev, 0x44, &inmir); - inmir = inmir & 0x0f; - irq = irq_routing_table[inmir]; - } else if (hwif->channel && !(ideic & 0x01)) { - /* - * get SIRQ2 routing table - */ - pci_read_config_byte(isa_dev, 0x75, &inmir); - inmir = inmir & 0x0f; - irq = irq_routing_table[inmir]; - } - if(irq >= 0) - hwif->irq = irq; - } - - init_hwif_common_ali15x3(hwif); -} - -/** - * init_dma_ali15x3 - set up DMA on ALi15x3 - * @hwif: IDE interface - * @dmabase: DMA interface base PCI address - * - * Set up the DMA functionality on the ALi 15x3. For the ALi - * controllers this is generic so we can let the generic code do - * the actual work. - */ - -static void __devinit init_dma_ali15x3 (ide_hwif_t *hwif, unsigned long dmabase) -{ - if (m5229_revision < 0x20) - return; - if (!(hwif->channel)) - hwif->OUTB(hwif->INB(dmabase+2) & 0x60, dmabase+2); - ide_setup_dma(hwif, dmabase, 8); -} - -static ide_pci_device_t ali15x3_chipset __devinitdata = { - .name = "ALI15X3", - .init_chipset = init_chipset_ali15x3, - .init_hwif = init_hwif_ali15x3, - .init_dma = init_dma_ali15x3, - .channels = 2, - .autodma = AUTODMA, - .bootable = ON_BOARD, -}; - -/** - * alim15x3_init_one - set up an ALi15x3 IDE controller - * @dev: PCI device to set up - * - * Perform the actual set up for an ALi15x3 that has been found by the - * hot plug layer. - */ - -static int __devinit alim15x3_init_one(struct pci_dev *dev, const struct pci_device_id *id) -{ - static struct pci_device_id ati_rs100[] = { - { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RS100) }, - { }, - }; - - ide_pci_device_t *d = &ali15x3_chipset; - - if (pci_dev_present(ati_rs100)) - printk(KERN_WARNING "alim15x3: ATI Radeon IGP Northbridge is not yet fully tested.\n"); - -#if defined(CONFIG_SPARC64) - d->init_hwif = init_hwif_common_ali15x3; -#endif /* CONFIG_SPARC64 */ - return ide_setup_pci_device(dev, d); -} - - -static struct pci_device_id alim15x3_pci_tbl[] = { - { PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M5229, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M5228, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { 0, }, -}; -MODULE_DEVICE_TABLE(pci, alim15x3_pci_tbl); - -static struct pci_driver driver = { - .name = "ALI15x3_IDE", - .id_table = alim15x3_pci_tbl, - .probe = alim15x3_init_one, -}; - -static int ali15x3_ide_init(void) -{ - return ide_pci_register_driver(&driver); -} - -module_init(ali15x3_ide_init); - -MODULE_AUTHOR("Michael Aubry, Andrzej Krzysztofowicz, CJ, Andre Hedrick, Alan Cox"); -MODULE_DESCRIPTION("PCI driver module for ALi 15x3 IDE"); -MODULE_LICENSE("GPL"); diff --git a/drivers/ide/pci/amd74xx.c b/drivers/ide/pci/amd74xx.c deleted file mode 100644 index 2b0ea8b6608..00000000000 --- a/drivers/ide/pci/amd74xx.c +++ /dev/null @@ -1,553 +0,0 @@ -/* - * Version 2.13 - * - * AMD 755/756/766/8111 and nVidia nForce/2/2s/3/3s/CK804/MCP04 - * IDE driver for Linux. - * - * Copyright (c) 2000-2002 Vojtech Pavlik - * - * Based on the work of: - * Andre Hedrick - */ - -/* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - */ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/ioport.h> -#include <linux/blkdev.h> -#include <linux/pci.h> -#include <linux/init.h> -#include <linux/ide.h> -#include <asm/io.h> - -#include "ide-timing.h" - -#define DISPLAY_AMD_TIMINGS - -#define AMD_IDE_ENABLE (0x00 + amd_config->base) -#define AMD_IDE_CONFIG (0x01 + amd_config->base) -#define AMD_CABLE_DETECT (0x02 + amd_config->base) -#define AMD_DRIVE_TIMING (0x08 + amd_config->base) -#define AMD_8BIT_TIMING (0x0e + amd_config->base) -#define AMD_ADDRESS_SETUP (0x0c + amd_config->base) -#define AMD_UDMA_TIMING (0x10 + amd_config->base) - -#define AMD_UDMA 0x07 -#define AMD_UDMA_33 0x01 -#define AMD_UDMA_66 0x02 -#define AMD_UDMA_100 0x03 -#define AMD_UDMA_133 0x04 -#define AMD_CHECK_SWDMA 0x08 -#define AMD_BAD_SWDMA 0x10 -#define AMD_BAD_FIFO 0x20 -#define AMD_CHECK_SERENADE 0x40 - -/* - * AMD SouthBridge chips. - */ - -static struct amd_ide_chip { - unsigned short id; - unsigned long base; - unsigned char flags; -} amd_ide_chips[] = { - { PCI_DEVICE_ID_AMD_COBRA_7401, 0x40, AMD_UDMA_33 | AMD_BAD_SWDMA }, - { PCI_DEVICE_ID_AMD_VIPER_7409, 0x40, AMD_UDMA_66 | AMD_CHECK_SWDMA }, - { PCI_DEVICE_ID_AMD_VIPER_7411, 0x40, AMD_UDMA_100 | AMD_BAD_FIFO }, - { PCI_DEVICE_ID_AMD_OPUS_7441, 0x40, AMD_UDMA_100 }, - { PCI_DEVICE_ID_AMD_8111_IDE, 0x40, AMD_UDMA_133 | AMD_CHECK_SERENADE }, - { PCI_DEVICE_ID_NVIDIA_NFORCE_IDE, 0x50, AMD_UDMA_100 }, - { PCI_DEVICE_ID_NVIDIA_NFORCE2_IDE, 0x50, AMD_UDMA_133 }, - { PCI_DEVICE_ID_NVIDIA_NFORCE2S_IDE, 0x50, AMD_UDMA_133 }, - { PCI_DEVICE_ID_NVIDIA_NFORCE2S_SATA, 0x50, AMD_UDMA_133 }, - { PCI_DEVICE_ID_NVIDIA_NFORCE3_IDE, 0x50, AMD_UDMA_133 }, - { PCI_DEVICE_ID_NVIDIA_NFORCE3S_IDE, 0x50, AMD_UDMA_133 }, - { PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA, 0x50, AMD_UDMA_133 }, - { PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA2, 0x50, AMD_UDMA_133 }, - { PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_IDE, 0x50, AMD_UDMA_133 }, - { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE, 0x50, AMD_UDMA_133 }, - { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_IDE, 0x50, AMD_UDMA_133 }, - { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_IDE, 0x50, AMD_UDMA_133 }, - { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_IDE, 0x50, AMD_UDMA_133 }, - { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP65_IDE, 0x50, AMD_UDMA_133 }, - { PCI_DEVICE_ID_AMD_CS5536_IDE, 0x40, AMD_UDMA_100 }, - { 0 } -}; - -static struct amd_ide_chip *amd_config; -static ide_pci_device_t *amd_chipset; -static unsigned int amd_80w; -static unsigned int amd_clock; - -static char *amd_dma[] = { "MWDMA16", "UDMA33", "UDMA66", "UDMA100", "UDMA133" }; -static unsigned char amd_cyc2udma[] = { 6, 6, 5, 4, 0, 1, 1, 2, 2, 3, 3, 3, 3, 3, 3, 7 }; - -/* - * AMD /proc entry. - */ - -#ifdef CONFIG_PROC_FS - -#include <linux/stat.h> -#include <linux/proc_fs.h> - -static u8 amd74xx_proc; - -static unsigned char amd_udma2cyc[] = { 4, 6, 8, 10, 3, 2, 1, 15 }; -static unsigned long amd_base; -static struct pci_dev *bmide_dev; -extern int (*amd74xx_display_info)(char *, char **, off_t, int); /* ide-proc.c */ - -#define amd_print(format, arg...) p += sprintf(p, format "\n" , ## arg) -#define amd_print_drive(name, format, arg...)\ - p += sprintf(p, name); for (i = 0; i < 4; i++) p += sprintf(p, format, ## arg); p += sprintf(p, "\n"); - -static int amd74xx_get_info(char *buffer, char **addr, off_t offset, int count) -{ - int speed[4], cycle[4], setup[4], active[4], recover[4], den[4], - uen[4], udma[4], active8b[4], recover8b[4]; - struct pci_dev *dev = bmide_dev; - unsigned int v, u, i; - unsigned short c, w; - unsigned char t; - int len; - char *p = buffer; - - amd_print("----------AMD BusMastering IDE Configuration----------------"); - - amd_print("Driver Version: 2.13"); - amd_print("South Bridge: %s", pci_name(bmide_dev)); - - pci_read_config_byte(dev, PCI_REVISION_ID, &t); - amd_print("Revision: IDE %#x", t); - amd_print("Highest DMA rate: %s", amd_dma[amd_config->flags & AMD_UDMA]); - - amd_print("BM-DMA base: %#lx", amd_base); - amd_print("PCI clock: %d.%dMHz", amd_clock / 1000, amd_clock / 100 % 10); - - amd_print("-----------------------Primary IDE-------Secondary IDE------"); - - pci_read_config_byte(dev, AMD_IDE_CONFIG, &t); - amd_print("Prefetch Buffer: %10s%20s", (t & 0x80) ? "yes" : "no", (t & 0x20) ? "yes" : "no"); - amd_print("Post Write Buffer: %10s%20s", (t & 0x40) ? "yes" : "no", (t & 0x10) ? "yes" : "no"); - - pci_read_config_byte(dev, AMD_IDE_ENABLE, &t); - amd_print("Enabled: %10s%20s", (t & 0x02) ? "yes" : "no", (t & 0x01) ? "yes" : "no"); - - c = inb(amd_base + 0x02) | (inb(amd_base + 0x0a) << 8); - amd_print("Simplex only: %10s%20s", (c & 0x80) ? "yes" : "no", (c & 0x8000) ? "yes" : "no"); - - amd_print("Cable Type: %10s%20s", (amd_80w & 1) ? "80w" : "40w", (amd_80w & 2) ? "80w" : "40w"); - - if (!amd_clock) - return p - buffer; - - amd_print("-------------------drive0----drive1----drive2----drive3-----"); - - pci_read_config_byte(dev, AMD_ADDRESS_SETUP, &t); - pci_read_config_dword(dev, AMD_DRIVE_TIMING, &v); - pci_read_config_word(dev, AMD_8BIT_TIMING, &w); - pci_read_config_dword(dev, AMD_UDMA_TIMING, &u); - - for (i = 0; i < 4; i++) { - setup[i] = ((t >> ((3 - i) << 1)) & 0x3) + 1; - recover8b[i] = ((w >> ((1 - (i >> 1)) << 3)) & 0xf) + 1; - active8b[i] = ((w >> (((1 - (i >> 1)) << 3) + 4)) & 0xf) + 1; - active[i] = ((v >> (((3 - i) << 3) + 4)) & 0xf) + 1; - recover[i] = ((v >> ((3 - i) << 3)) & 0xf) + 1; - - udma[i] = amd_udma2cyc[((u >> ((3 - i) << 3)) & 0x7)]; - uen[i] = ((u >> ((3 - i) << 3)) & 0x40) ? 1 : 0; - den[i] = (c & ((i & 1) ? 0x40 : 0x20) << ((i & 2) << 2)); - - if (den[i] && uen[i] && udma[i] == 1) { - speed[i] = amd_clock * 3; - cycle[i] = 666666 / amd_clock; - continue; - } - - if (den[i] && uen[i] && udma[i] == 15) { - speed[i] = amd_clock * 4; - cycle[i] = 500000 / amd_clock; - continue; - } - - speed[i] = 4 * amd_clock / ((den[i] && uen[i]) ? udma[i] : (active[i] + recover[i]) * 2); - cycle[i] = 1000000 * ((den[i] && uen[i]) ? udma[i] : (active[i] + recover[i]) * 2) / amd_clock / 2; - } - - amd_print_drive("Transfer Mode: ", "%10s", den[i] ? (uen[i] ? "UDMA" : "DMA") : "PIO"); - - amd_print_drive("Address Setup: ", "%8dns", 1000000 * setup[i] / amd_clock); - amd_print_drive("Cmd Active: ", "%8dns", 1000000 * active8b[i] / amd_clock); - amd_print_drive("Cmd Recovery: ", "%8dns", 1000000 * recover8b[i] / amd_clock); - amd_print_drive("Data Active: ", "%8dns", 1000000 * active[i] / amd_clock); - amd_print_drive("Data Recovery: ", "%8dns", 1000000 * recover[i] / amd_clock); - amd_print_drive("Cycle Time: ", "%8dns", cycle[i]); - amd_print_drive("Transfer Rate: ", "%4d.%dMB/s", speed[i] / 1000, speed[i] / 100 % 10); - - /* hoping p - buffer is less than 4K... */ - len = (p - buffer) - offset; - *addr = buffer + offset; - - return len > count ? count : len; -} - -#endif - -/* - * amd_set_speed() writes timing values to the chipset registers - */ - -static void amd_set_speed(struct pci_dev *dev, unsigned char dn, struct ide_timing *timing) -{ - unsigned char t; - - pci_read_config_byte(dev, AMD_ADDRESS_SETUP, &t); - t = (t & ~(3 << ((3 - dn) << 1))) | ((FIT(timing->setup, 1, 4) - 1) << ((3 - dn) << 1)); - pci_write_config_byte(dev, AMD_ADDRESS_SETUP, t); - - pci_write_config_byte(dev, AMD_8BIT_TIMING + (1 - (dn >> 1)), - ((FIT(timing->act8b, 1, 16) - 1) << 4) | (FIT(timing->rec8b, 1, 16) - 1)); - - pci_write_config_byte(dev, AMD_DRIVE_TIMING + (3 - dn), - ((FIT(timing->active, 1, 16) - 1) << 4) | (FIT(timing->recover, 1, 16) - 1)); - - switch (amd_config->flags & AMD_UDMA) { - case AMD_UDMA_33: t = timing->udma ? (0xc0 | (FIT(timing->udma, 2, 5) - 2)) : 0x03; break; - case AMD_UDMA_66: t = timing->udma ? (0xc0 | amd_cyc2udma[FIT(timing->udma, 2, 10)]) : 0x03; break; - case AMD_UDMA_100: t = timing->udma ? (0xc0 | amd_cyc2udma[FIT(timing->udma, 1, 10)]) : 0x03; break; - case AMD_UDMA_133: t = timing->udma ? (0xc0 | amd_cyc2udma[FIT(timing->udma, 1, 15)]) : 0x03; break; - default: return; - } - - pci_write_config_byte(dev, AMD_UDMA_TIMING + (3 - dn), t); -} - -/* - * amd_set_drive() computes timing values configures the drive and - * the chipset to a desired transfer mode. It also can be called - * by upper layers. - */ - -static int amd_set_drive(ide_drive_t *drive, u8 speed) -{ - ide_drive_t *peer = HWIF(drive)->drives + (~drive->dn & 1); - struct ide_timing t, p; - int T, UT; - - if (speed != XFER_PIO_SLOW && speed != drive->current_speed) - if (ide_config_drive_speed(drive, speed)) - printk(KERN_WARNING "ide%d: Drive %d didn't accept speed setting. Oh, well.\n", - drive->dn >> 1, drive->dn & 1); - - T = 1000000000 / amd_clock; - UT = T / min_t(int, max_t(int, amd_config->flags & AMD_UDMA, 1), 2); - - ide_timing_compute(drive, speed, &t, T, UT); - - if (peer->present) { - ide_timing_compute(peer, peer->current_speed, &p, T, UT); - ide_timing_merge(&p, &t, &t, IDE_TIMING_8BIT); - } - - if (speed == XFER_UDMA_5 && amd_clock <= 33333) t.udma = 1; - if (speed == XFER_UDMA_6 && amd_clock <= 33333) t.udma = 15; - - amd_set_speed(HWIF(drive)->pci_dev, drive->dn, &t); - - if (!drive->init_speed) - drive->init_speed = speed; - drive->current_speed = speed; - - return 0; -} - -/* - * amd74xx_tune_drive() is a callback from upper layers for - * PIO-only tuning. - */ - -static void amd74xx_tune_drive(ide_drive_t *drive, u8 pio) -{ - if (pio == 255) { - amd_set_drive(drive, ide_find_best_mode(drive, XFER_PIO | XFER_EPIO)); - return; - } - - amd_set_drive(drive, XFER_PIO_0 + min_t(byte, pio, 5)); -} - -/* - * amd74xx_dmaproc() is a callback from upper layers that can do - * a lot, but we use it for DMA/PIO tuning only, delegating everything - * else to the default ide_dmaproc(). - */ - -static int amd74xx_ide_dma_check(ide_drive_t *drive) -{ - int w80 = HWIF(drive)->udma_four; - - u8 speed = ide_find_best_mode(drive, - XFER_PIO | XFER_EPIO | XFER_MWDMA | XFER_UDMA | - ((amd_config->flags & AMD_BAD_SWDMA) ? 0 : XFER_SWDMA) | - (w80 && (amd_config->flags & AMD_UDMA) >= AMD_UDMA_66 ? XFER_UDMA_66 : 0) | - (w80 && (amd_config->flags & AMD_UDMA) >= AMD_UDMA_100 ? XFER_UDMA_100 : 0) | - (w80 && (amd_config->flags & AMD_UDMA) >= AMD_UDMA_133 ? XFER_UDMA_133 : 0)); - - amd_set_drive(drive, speed); - - if (drive->autodma && (speed & XFER_MODE) != XFER_PIO) - return HWIF(drive)->ide_dma_on(drive); - return HWIF(drive)->ide_dma_off_quietly(drive); -} - -/* - * The initialization callback. Here we determine the IDE chip type - * and initialize its drive independent registers. - */ - -static unsigned int __devinit init_chipset_amd74xx(struct pci_dev *dev, const char *name) -{ - unsigned char t; - unsigned int u; - int i; - -/* - * Check for bad SWDMA. - */ - - if (amd_config->flags & AMD_CHECK_SWDMA) { - pci_read_config_byte(dev, PCI_REVISION_ID, &t); - if (t <= 7) - amd_config->flags |= AMD_BAD_SWDMA; - } - -/* - * Check 80-wire cable presence. - */ - - switch (amd_config->flags & AMD_UDMA) { - - case AMD_UDMA_133: - case AMD_UDMA_100: - pci_read_config_byte(dev, AMD_CABLE_DETECT, &t); - pci_read_config_dword(dev, AMD_UDMA_TIMING, &u); - amd_80w = ((t & 0x3) ? 1 : 0) | ((t & 0xc) ? 2 : 0); - for (i = 24; i >= 0; i -= 8) - if (((u >> i) & 4) && !(amd_80w & (1 << (1 - (i >> 4))))) { - printk(KERN_WARNING "%s: BIOS didn't set cable bits correctly. Enabling workaround.\n", - amd_chipset->name); - amd_80w |= (1 << (1 - (i >> 4))); - } - break; - - case AMD_UDMA_66: - /* no host side cable detection */ - amd_80w = 0x03; - break; - } - -/* - * Take care of prefetch & postwrite. - */ - - pci_read_config_byte(dev, AMD_IDE_CONFIG, &t); - pci_write_config_byte(dev, AMD_IDE_CONFIG, - (amd_config->flags & AMD_BAD_FIFO) ? (t & 0x0f) : (t | 0xf0)); - -/* - * Take care of incorrectly wired Serenade mainboards. - */ - - if ((amd_config->flags & AMD_CHECK_SERENADE) && - dev->subsystem_vendor == PCI_VENDOR_ID_AMD && - dev->subsystem_device == PCI_DEVICE_ID_AMD_SERENADE) - amd_config->flags = AMD_UDMA_100; - -/* - * Determine the system bus clock. - */ - - amd_clock = system_bus_clock() * 1000; - - switch (amd_clock) { - case 33000: amd_clock = 33333; break; - case 37000: amd_clock = 37500; break; - case 41000: amd_clock = 41666; break; - } - - if (amd_clock < 20000 || amd_clock > 50000) { - printk(KERN_WARNING "%s: User given PCI clock speed impossible (%d), using 33 MHz instead.\n", - amd_chipset->name, amd_clock); - amd_clock = 33333; - } - -/* - * Print the boot message. - */ - - pci_read_config_byte(dev, PCI_REVISION_ID, &t); - printk(KERN_INFO "%s: %s (rev %02x) %s controller\n", - amd_chipset->name, pci_name(dev), t, amd_dma[amd_config->flags & AMD_UDMA]); - -/* - * Register /proc/ide/amd74xx entry - */ - -#if defined(DISPLAY_AMD_TIMINGS) && defined(CONFIG_PROC_FS) - if (!amd74xx_proc) { - amd_base = pci_resource_start(dev, 4); - bmide_dev = dev; - ide_pci_create_host_proc("amd74xx", amd74xx_get_info); - amd74xx_proc = 1; - } -#endif /* DISPLAY_AMD_TIMINGS && CONFIG_PROC_FS */ - - return dev->irq; -} - -static void __devinit init_hwif_amd74xx(ide_hwif_t *hwif) -{ - int i; - - if (hwif->irq == 0) /* 0 is bogus but will do for now */ - hwif->irq = pci_get_legacy_ide_irq(hwif->pci_dev, hwif->channel); - - hwif->autodma = 0; - - hwif->tuneproc = &amd74xx_tune_drive; - hwif->speedproc = &amd_set_drive; - - for (i = 0; i < 2; i++) { - hwif->drives[i].io_32bit = 1; - hwif->drives[i].unmask = 1; - hwif->drives[i].autotune = 1; - hwif->drives[i].dn = hwif->channel * 2 + i; - } - - if (!hwif->dma_base) - return; - - hwif->atapi_dma = 1; - hwif->ultra_mask = 0x7f; - hwif->mwdma_mask = 0x07; - hwif->swdma_mask = 0x07; - - if (!hwif->udma_four) - hwif->udma_four = (amd_80w >> hwif->channel) & 1; - hwif->ide_dma_check = &amd74xx_ide_dma_check; - if (!noautodma) - hwif->autodma = 1; - hwif->drives[0].autodma = hwif->autodma; - hwif->drives[1].autodma = hwif->autodma; -} - -#define DECLARE_AMD_DEV(name_str) \ - { \ - .name = name_str, \ - .init_chipset = init_chipset_amd74xx, \ - .init_hwif = init_hwif_amd74xx, \ - .channels = 2, \ - .autodma = AUTODMA, \ - .enablebits = {{0x40,0x02,0x02}, {0x40,0x01,0x01}}, \ - .bootable = ON_BOARD, \ - } - -#define DECLARE_NV_DEV(name_str) \ - { \ - .name = name_str, \ - .init_chipset = init_chipset_amd74xx, \ - .init_hwif = init_hwif_amd74xx, \ - .channels = 2, \ - .autodma = AUTODMA, \ - .enablebits = {{0x50,0x02,0x02}, {0x50,0x01,0x01}}, \ - .bootable = ON_BOARD, \ - } - -static ide_pci_device_t amd74xx_chipsets[] __devinitdata = { - /* 0 */ DECLARE_AMD_DEV("AMD7401"), - /* 1 */ DECLARE_AMD_DEV("AMD7409"), - /* 2 */ DECLARE_AMD_DEV("AMD7411"), - /* 3 */ DECLARE_AMD_DEV("AMD7441"), - /* 4 */ DECLARE_AMD_DEV("AMD8111"), - - /* 5 */ DECLARE_NV_DEV("NFORCE"), - /* 6 */ DECLARE_NV_DEV("NFORCE2"), - /* 7 */ DECLARE_NV_DEV("NFORCE2-U400R"), - /* 8 */ DECLARE_NV_DEV("NFORCE2-U400R-SATA"), - /* 9 */ DECLARE_NV_DEV("NFORCE3-150"), - /* 10 */ DECLARE_NV_DEV("NFORCE3-250"), - /* 11 */ DECLARE_NV_DEV("NFORCE3-250-SATA"), - /* 12 */ DECLARE_NV_DEV("NFORCE3-250-SATA2"), - /* 13 */ DECLARE_NV_DEV("NFORCE-CK804"), - /* 14 */ DECLARE_NV_DEV("NFORCE-MCP04"), - /* 15 */ DECLARE_NV_DEV("NFORCE-MCP51"), - /* 16 */ DECLARE_NV_DEV("NFORCE-MCP55"), - /* 17 */ DECLARE_NV_DEV("NFORCE-MCP61"), - /* 18 */ DECLARE_NV_DEV("NFORCE-MCP65"), - /* 19 */ DECLARE_AMD_DEV("AMD5536"), -}; - -static int __devinit amd74xx_probe(struct pci_dev *dev, const struct pci_device_id *id) -{ - amd_chipset = amd74xx_chipsets + id->driver_data; - amd_config = amd_ide_chips + id->driver_data; - if (dev->device != amd_config->id) { - printk(KERN_ERR "%s: assertion 0x%02x == 0x%02x failed !\n", - pci_name(dev), dev->device, amd_config->id); - return -ENODEV; - } - return ide_setup_pci_device(dev, amd_chipset); -} - -static struct pci_device_id amd74xx_pci_tbl[] = { - { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_COBRA_7401, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7409, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 }, - { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7411, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2 }, - { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_OPUS_7441, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3 }, - { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 7 }, -#ifdef CONFIG_BLK_DEV_IDE_SATA - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_SATA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 }, -#endif - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 9 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 10 }, -#ifdef CONFIG_BLK_DEV_IDE_SATA - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 11 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 12 }, -#endif - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 13 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 14 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 15 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 16 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 17 }, - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP65_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 18 }, - { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 19 }, - { 0, }, -}; -MODULE_DEVICE_TABLE(pci, amd74xx_pci_tbl); - -static struct pci_driver driver = { - .name = "AMD_IDE", - .id_table = amd74xx_pci_tbl, - .probe = amd74xx_probe, -}; - -static int amd74xx_ide_init(void) -{ - return ide_pci_register_driver(&driver); -} - -module_init(amd74xx_ide_init); - -MODULE_AUTHOR("Vojtech Pavlik"); -MODULE_DESCRIPTION("AMD PCI IDE driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/ide/pci/atiixp.c b/drivers/ide/pci/atiixp.c deleted file mode 100644 index a574de5f083..00000000000 --- a/drivers/ide/pci/atiixp.c +++ /dev/null @@ -1,370 +0,0 @@ -/* - * linux/drivers/ide/pci/atiixp.c Version 0.01-bart2 Feb. 26, 2004 - * - * Copyright (C) 2003 ATI Inc. <hyu@ati.com> - * Copyright (C) 2004 Bartlomiej Zolnierkiewicz - * - */ - -#include <linux/types.h> -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/ioport.h> -#include <linux/pci.h> -#include <linux/hdreg.h> -#include <linux/ide.h> -#include <linux/delay.h> -#include <linux/init.h> - -#include <asm/io.h> - -#define ATIIXP_IDE_PIO_TIMING 0x40 -#define ATIIXP_IDE_MDMA_TIMING 0x44 -#define ATIIXP_IDE_PIO_CONTROL 0x48 -#define ATIIXP_IDE_PIO_MODE 0x4a -#define ATIIXP_IDE_UDMA_CONTROL 0x54 -#define ATIIXP_IDE_UDMA_MODE 0x56 - -typedef struct { - u8 command_width; - u8 recover_width; -} atiixp_ide_timing; - -static atiixp_ide_timing pio_timing[] = { - { 0x05, 0x0d }, - { 0x04, 0x07 }, - { 0x03, 0x04 }, - { 0x02, 0x02 }, - { 0x02, 0x00 }, -}; - -static atiixp_ide_timing mdma_timing[] = { - { 0x07, 0x07 }, - { 0x02, 0x01 }, - { 0x02, 0x00 }, -}; - -static int save_mdma_mode[4]; - -/** - * atiixp_ratemask - compute rate mask for ATIIXP IDE - * @drive: IDE drive to compute for - * - * Returns the available modes for the ATIIXP IDE controller. - */ - -static u8 atiixp_ratemask(ide_drive_t *drive) -{ - u8 mode = 3; - - if (!eighty_ninty_three(drive)) - mode = min(mode, (u8)1); - return mode; -} - -/** - * atiixp_dma_2_pio - return the PIO mode matching DMA - * @xfer_rate: transfer speed - * - * Returns the nearest equivalent PIO timing for the PIO or DMA - * mode requested by the controller. - */ - -static u8 atiixp_dma_2_pio(u8 xfer_rate) { - switch(xfer_rate) { - case XFER_UDMA_6: - case XFER_UDMA_5: - case XFER_UDMA_4: - case XFER_UDMA_3: - case XFER_UDMA_2: - case XFER_UDMA_1: - case XFER_UDMA_0: - case XFER_MW_DMA_2: - case XFER_PIO_4: - return 4; - case XFER_MW_DMA_1: - case XFER_PIO_3: - return 3; - case XFER_SW_DMA_2: - case XFER_PIO_2: - return 2; - case XFER_MW_DMA_0: - case XFER_SW_DMA_1: - case XFER_SW_DMA_0: - case XFER_PIO_1: - case XFER_PIO_0: - case XFER_PIO_SLOW: - default: - return 0; - } -} - -static int atiixp_ide_dma_host_on(ide_drive_t *drive) -{ - struct pci_dev *dev = drive->hwif->pci_dev; - unsigned long flags; - u16 tmp16; - - spin_lock_irqsave(&ide_lock, flags); - - pci_read_config_word(dev, ATIIXP_IDE_UDMA_CONTROL, &tmp16); - if (save_mdma_mode[drive->dn]) - tmp16 &= ~(1 << drive->dn); - else - tmp16 |= (1 << drive->dn); - pci_write_config_word(dev, ATIIXP_IDE_UDMA_CONTROL, tmp16); - - spin_unlock_irqrestore(&ide_lock, flags); - - return __ide_dma_host_on(drive); -} - -static int atiixp_ide_dma_host_off(ide_drive_t *drive) -{ - struct pci_dev *dev = drive->hwif->pci_dev; - unsigned long flags; - u16 tmp16; - - spin_lock_irqsave(&ide_lock, flags); - - pci_read_config_word(dev, ATIIXP_IDE_UDMA_CONTROL, &tmp16); - tmp16 &= ~(1 << drive->dn); - pci_write_config_word(dev, ATIIXP_IDE_UDMA_CONTROL, tmp16); - - spin_unlock_irqrestore(&ide_lock, flags); - - return __ide_dma_host_off(drive); -} - -/** - * atiixp_tune_drive - tune a drive attached to a ATIIXP - * @drive: drive to tune - * @pio: desired PIO mode - * - * Set the interface PIO mode. - */ - -static void atiixp_tuneproc(ide_drive_t *drive, u8 pio) -{ - struct pci_dev *dev = drive->hwif->pci_dev; - unsigned long flags; - int timing_shift = (drive->dn & 2) ? 16 : 0 + (drive->dn & 1) ? 0 : 8; - u32 pio_timing_data; - u16 pio_mode_data; - - spin_lock_irqsave(&ide_lock, flags); - - pci_read_config_word(dev, ATIIXP_IDE_PIO_MODE, &pio_mode_data); - pio_mode_data &= ~(0x07 << (drive->dn * 4)); - pio_mode_data |= (pio << (drive->dn * 4)); - pci_write_config_word(dev, ATIIXP_IDE_PIO_MODE, pio_mode_data); - - pci_read_config_dword(dev, ATIIXP_IDE_PIO_TIMING, &pio_timing_data); - pio_timing_data &= ~(0xff << timing_shift); - pio_timing_data |= (pio_timing[pio].recover_width << timing_shift) | - (pio_timing[pio].command_width << (timing_shift + 4)); - pci_write_config_dword(dev, ATIIXP_IDE_PIO_TIMING, pio_timing_data); - - spin_unlock_irqrestore(&ide_lock, flags); -} - -/** - * atiixp_tune_chipset - tune a ATIIXP interface - * @drive: IDE drive to tune - * @xferspeed: speed to configure - * - * Set a ATIIXP interface channel to the desired speeds. This involves - * requires the right timing data into the ATIIXP configuration space - * then setting the drive parameters appropriately - */ - -static int atiixp_speedproc(ide_drive_t *drive, u8 xferspeed) -{ - struct pci_dev *dev = drive->hwif->pci_dev; - unsigned long flags; - int timing_shift = (drive->dn & 2) ? 16 : 0 + (drive->dn & 1) ? 0 : 8; - u32 tmp32; - u16 tmp16; - u8 speed, pio; - - speed = ide_rate_filter(atiixp_ratemask(drive), xferspeed); - - spin_lock_irqsave(&ide_lock, flags); - - save_mdma_mode[drive->dn] = 0; - if (speed >= XFER_UDMA_0) { - pci_read_config_word(dev, ATIIXP_IDE_UDMA_MODE, &tmp16); - tmp16 &= ~(0x07 << (drive->dn * 4)); - tmp16 |= ((speed & 0x07) << (drive->dn * 4)); - pci_write_config_word(dev, ATIIXP_IDE_UDMA_MODE, tmp16); - } else { - if ((speed >= XFER_MW_DMA_0) && (speed <= XFER_MW_DMA_2)) { - save_mdma_mode[drive->dn] = speed; - pci_read_config_dword(dev, ATIIXP_IDE_MDMA_TIMING, &tmp32); - tmp32 &= ~(0xff << timing_shift); - tmp32 |= (mdma_timing[speed & 0x03].recover_width << timing_shift) | - (mdma_timing[speed & 0x03].command_width << (timing_shift + 4)); - pci_write_config_dword(dev, ATIIXP_IDE_MDMA_TIMING, tmp32); - } - } - - spin_unlock_irqrestore(&ide_lock, flags); - - if (speed >= XFER_SW_DMA_0) - pio = atiixp_dma_2_pio(speed); - else - pio = speed - XFER_PIO_0; - - atiixp_tuneproc(drive, pio); - - return ide_config_drive_speed(drive, speed); -} - -/** - * atiixp_config_drive_for_dma - configure drive for DMA - * @drive: IDE drive to configure - * - * Set up a ATIIXP interface channel for the best available speed. - * We prefer UDMA if it is available and then MWDMA. If DMA is - * not available we switch to PIO and return 0. - */ - -static int atiixp_config_drive_for_dma(ide_drive_t *drive) -{ - u8 speed = ide_dma_speed(drive, atiixp_ratemask(drive)); - - /* If no DMA speed was available then disable DMA and use PIO. */ - if (!speed) { - u8 tspeed = ide_get_best_pio_mode(drive, 255, 5, NULL); - speed = atiixp_dma_2_pio(XFER_PIO_0 + tspeed) + XFER_PIO_0; - } - - (void) atiixp_speedproc(drive, speed); - return ide_dma_enable(drive); -} - -/** - * atiixp_dma_check - set up an IDE device - * @drive: IDE drive to configure - * - * Set up the ATIIXP interface for the best available speed on this - * interface, preferring DMA to PIO. - */ - -static int atiixp_dma_check(ide_drive_t *drive) -{ - ide_hwif_t *hwif = HWIF(drive); - struct hd_driveid *id = drive->id; - u8 tspeed, speed; - - drive->init_speed = 0; - - if ((id->capability & 1) && drive->autodma) { - - if (ide_use_dma(drive)) { - if (atiixp_config_drive_for_dma(drive)) - return hwif->ide_dma_on(drive); - } - - goto fast_ata_pio; - - } else if ((id->capability & 8) || (id->field_valid & 2)) { -fast_ata_pio: - tspeed = ide_get_best_pio_mode(drive, 255, 5, NULL); - speed = atiixp_dma_2_pio(XFER_PIO_0 + tspeed) + XFER_PIO_0; - hwif->speedproc(drive, speed); - return hwif->ide_dma_off_quietly(drive); - } - /* IORDY not supported */ - return 0; -} - -/** - * init_hwif_atiixp - fill in the hwif for the ATIIXP - * @hwif: IDE interface - * - * Set up the ide_hwif_t for the ATIIXP interface according to the - * capabilities of the hardware. - */ - -static void __devinit init_hwif_atiixp(ide_hwif_t *hwif) -{ - if (!hwif->irq) - hwif->irq = hwif->channel ? 15 : 14; - - hwif->autodma = 0; - hwif->tuneproc = &atiixp_tuneproc; - hwif->speedproc = &atiixp_speedproc; - hwif->drives[0].autotune = 1; - hwif->drives[1].autotune = 1; - - if (!hwif->dma_base) - return; - - hwif->atapi_dma = 1; - hwif->ultra_mask = 0x3f; - hwif->mwdma_mask = 0x06; - hwif->swdma_mask = 0x04; - - /* FIXME: proper cable detection needed */ - hwif->udma_four = 1; - hwif->ide_dma_host_on = &atiixp_ide_dma_host_on; - hwif->ide_dma_host_off = &atiixp_ide_dma_host_off; - hwif->ide_dma_check = &atiixp_dma_check; - if (!noautodma) - hwif->autodma = 1; - - hwif->drives[1].autodma = hwif->autodma; - hwif->drives[0].autodma = hwif->autodma; -} - -static ide_pci_device_t atiixp_pci_info[] __devinitdata = { - { /* 0 */ - .name = "ATIIXP", - .init_hwif = init_hwif_atiixp, - .channels = 2, - .autodma = AUTODMA, - .enablebits = {{0x48,0x01,0x00}, {0x48,0x08,0x00}}, - .bootable = ON_BOARD, - } -}; - -/** - * atiixp_init_one - called when a ATIIXP is found - * @dev: the atiixp device - * @id: the matching pci id - * - * Called when the PCI registration layer (or the IDE initialization) - * finds a device matching our IDE device tables. - */ - -static int __devinit atiixp_init_one(struct pci_dev *dev, const struct pci_device_id *id) -{ - return ide_setup_pci_device(dev, &atiixp_pci_info[id->driver_data]); -} - -static struct pci_device_id atiixp_pci_tbl[] = { - { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP200_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP300_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP400_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP600_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - { 0, }, -}; -MODULE_DEVICE_TABLE(pci, atiixp_pci_tbl); - -static struct pci_driver driver = { - .name = "ATIIXP_IDE", - .id_table = atiixp_pci_tbl, - .probe = atiixp_init_one, -}; - -static int atiixp_ide_init(void) -{ - return ide_pci_register_driver(&driver); -} - -module_init(atiixp_ide_init); - -MODULE_AUTHOR("HUI YU"); -MODULE_DESCRIPTION("PCI driver module for ATI IXP IDE"); -MODULE_LICENSE("GPL"); diff --git a/drivers/ide/pci/cmd64x.c b/drivers/ide/pci/cmd64x.c deleted file mode 100644 index 20c32716bbc..00000000000 --- a/drivers/ide/pci/cmd64x.c +++ /dev/null @@ -1,805 +0,0 @@ -/* $Id: cmd64x.c,v 1.21 2000/01/30 23:23:16 - * - * linux/drivers/ide/pci/cmd64x.c Version 1.30 Sept 10, 2002 - * - * cmd64x.c: Enable interrupts at initialization time on Ultra/PCI machines. - * Note, this driver is not used at all on other systems because - * there the "BIOS" has done all of the following already. - * Due to massive hardware bugs, UltraDMA is only supported - * on the 646U2 and not on the 646U. - * - * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be) - * Copyright (C) 1998 David S. Miller (davem@redhat.com) - * - * Copyright (C) 1999-2002 Andre Hedrick <andre@linux-ide.org> - */ - -#include <linux/module.h> -#include <linux/types.h> -#include <linux/pci.h> -#include <linux/delay.h> -#include <linux/hdreg.h> -#include <linux/ide.h> -#include <linux/init.h> - -#include <asm/io.h> - -#define DISPLAY_CMD64X_TIMINGS - -#define CMD_DEBUG 0 - -#if CMD_DEBUG -#define cmdprintk(x...) printk(x) -#else -#define cmdprintk(x...) -#endif - -/* - * CMD64x specific registers definition. - */ -#define CFR 0x50 -#define CFR_INTR_CH0 0x02 -#define CNTRL 0x51 -#define CNTRL_DIS_RA0 0x40 -#define CNTRL_DIS_RA1 0x80 -#define CNTRL_ENA_2ND 0x08 - -#define CMDTIM 0x52 -#define ARTTIM0 0x53 -#define DRWTIM0 0x54 -#define ARTTIM1 0x55 -#define DRWTIM1 0x56 -#define ARTTIM23 0x57 -#define ARTTIM23_DIS_RA2 0x04 -#define ARTTIM23_DIS_RA3 0x08 -#define ARTTIM23_INTR_CH1 0x10 -#define ARTTIM2 0x57 -#define ARTTIM3 0x57 -#define DRWTIM23 0x58 -#define DRWTIM2 0x58 -#define BRST 0x59 -#define DRWTIM3 0x5b - -#define BMIDECR0 0x70 -#define MRDMODE 0x71 -#define MRDMODE_INTR_CH0 0x04 -#define MRDMODE_INTR_CH1 0x08 -#define MRDMODE_BLK_CH0 0x10 -#define MRDMODE_BLK_CH1 0x20 -#define BMIDESR0 0x72 -#define UDIDETCR0 0x73 -#define DTPR0 0x74 -#define BMIDECR1 0x78 -#define BMIDECSR 0x79 -#define BMIDESR1 0x7A -#define UDIDETCR1 0x7B -#define DTPR1 0x7C - -#if defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS) -#include <linux/stat.h> -#include <linux/proc_fs.h> - -static u8 cmd64x_proc = 0; - -#define CMD_MAX_DEVS 5 - -static struct pci_dev *cmd_devs[CMD_MAX_DEVS]; -static int n_cmd_devs; - -static char * print_cmd64x_get_info (char *buf, struct pci_dev *dev, int index) -{ - char *p = buf; - - u8 reg53 = 0, reg54 = 0, reg55 = 0, reg56 = 0; /* primary */ - u8 reg57 = 0, reg58 = 0, reg5b; /* secondary */ - u8 reg72 = 0, reg73 = 0; /* primary */ - u8 reg7a = 0, reg7b = 0; /* secondary */ - u8 reg50 = 0, reg71 = 0; /* extra */ - - p += sprintf(p, "\nController: %d\n", index); - p += sprintf(p, "CMD%x Chipset.\n", dev->device); - (void) pci_read_config_byte(dev, CFR, ®50); - (void) pci_read_config_byte(dev, ARTTIM0, ®53); - (void) pci_read_config_byte(dev, DRWTIM0, ®54); - (void) pci_read_config_byte(dev, ARTTIM1, ®55); - (void) pci_read_config_byte(dev, DRWTIM1, ®56); - (void) pci_read_config_byte(dev, ARTTIM2, ®57); - (void) pci_read_config_byte(dev, DRWTIM2, ®58); - (void) pci_read_config_byte(dev, DRWTIM3, ®5b); - (void) pci_read_config_byte(dev, MRDMODE, ®71); - (void) pci_read_config_byte(dev, BMIDESR0, ®72); - (void) pci_read_config_byte(dev, UDIDETCR0, ®73); - (void) pci_read_config_byte(dev, BMIDESR1, ®7a); - (void) pci_read_config_byte(dev, UDIDETCR1, ®7b); - - p += sprintf(p, "--------------- Primary Channel " - "---------------- Secondary Channel " - "-------------\n"); - p += sprintf(p, " %sabled " - " %sabled\n", - (reg72&0x80)?"dis":" en", - (reg7a&0x80)?"dis":" en"); - p += sprintf(p, "--------------- drive0 " - "--------- drive1 -------- drive0 " - "---------- drive1 ------\n"); - p += sprintf(p, "DMA enabled: %s %s" - " %s %s\n", - (reg72&0x20)?"yes":"no ", (reg72&0x40)?"yes":"no ", - (reg7a&0x20)?"yes":"no ", (reg7a&0x40)?"yes":"no "); - - p += sprintf(p, "DMA Mode: %s(%s) %s(%s)", - (reg72&0x20)?((reg73&0x01)?"UDMA":" DMA"):" PIO", - (reg72&0x20)?( - ((reg73&0x30)==0x30)?(((reg73&0x35)==0x35)?"3":"0"): - ((reg73&0x20)==0x20)?(((reg73&0x25)==0x25)?"3":"1"): - ((reg73&0x10)==0x10)?(((reg73&0x15)==0x15)?"4":"2"): - ((reg73&0x00)==0x00)?(((reg73&0x05)==0x05)?"5":"2"): - "X"):"?", - (reg72&0x40)?((reg73&0x02)?"UDMA":" DMA"):" PIO", - (reg72&0x40)?( - ((reg73&0xC0)==0xC0)?(((reg73&0xC5)==0xC5)?"3":"0"): - ((reg73&0x80)==0x80)?(((reg73&0x85)==0x85)?"3":"1"): - ((reg73&0x40)==0x40)?(((reg73&0x4A)==0x4A)?"4":"2"): - ((reg73&0x00)==0x00)?(((reg73&0x0A)==0x0A)?"5":"2"): - "X"):"?"); - p += sprintf(p, " %s(%s) %s(%s)\n", - (reg7a&0x20)?((reg7b&0x01)?"UDMA":" DMA"):" PIO", - (reg7a&0x20)?( - ((reg7b&0x30)==0x30)?(((reg7b&0x35)==0x35)?"3":"0"): - ((reg7b&0x20)==0x20)?(((reg7b&0x25)==0x25)?"3":"1"): - ((reg7b&0x10)==0x10)?(((reg7b&0x15)==0x15)?"4":"2"): - ((reg7b&0x00)==0x00)?(((reg7b&0x05)==0x05)?"5":"2"): - "X"):"?", - (reg7a&0x40)?((reg7b&0x02)?"UDMA":" DMA"):" PIO", - (reg7a&0x40)?( - ((reg7b&0xC0)==0xC0)?(((reg7b&0xC5)==0xC5)?"3":"0"): - ((reg7b&0x80)==0x80)?(((reg7b&0x85)==0x85)?"3":"1"): - ((reg7b&0x40)==0x40)?(((reg7b&0x4A)==0x4A)?"4":"2"): - ((reg7b&0x00)==0x00)?(((reg7b&0x0A)==0x0A)?"5":"2"): - "X"):"?" ); - p += sprintf(p, "PIO Mode: %s %s" - " %s %s\n", - "?", "?", "?", "?"); - p += sprintf(p, " %s %s\n", - (reg50 & CFR_INTR_CH0) ? "interrupting" : "polling ", - (reg57 & ARTTIM23_INTR_CH1) ? "interrupting" : "polling"); - p += sprintf(p, " %s %s\n", - (reg71 & MRDMODE_INTR_CH0) ? "pending" : "clear ", - (reg71 & MRDMODE_INTR_CH1) ? "pending" : "clear"); - p += sprintf(p, " %s %s\n", - (reg71 & MRDMODE_BLK_CH0) ? "blocked" : "enabled", - (reg71 & MRDMODE_BLK_CH1) ? "blocked" : "enabled"); - - return (char *)p; -} - -static int cmd64x_get_info (char *buffer, char **addr, off_t offset, int count) -{ - char *p = buffer; - int i; - - p += sprintf(p, "\n"); - for (i = 0; i < n_cmd_devs; i++) { - struct pci_dev *dev = cmd_devs[i]; - p = print_cmd64x_get_info(p, dev, i); - } - return p-buffer; /* => must be less than 4k! */ -} - -#endif /* defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS) */ - -/* - * This routine writes the prepared setup/active/recovery counts - * for a drive into the cmd646 chipset registers to active them. - */ -static void program_drive_counts (ide_drive_t *drive, int setup_count, int active_count, int recovery_count) -{ - unsigned long flags; - struct pci_dev *dev = HWIF(drive)->pci_dev; - ide_drive_t *drives = HWIF(drive)->drives; - u8 temp_b; - static const u8 setup_counts[] = {0x40, 0x40, 0x40, 0x80, 0, 0xc0}; - static const u8 recovery_counts[] = - {15, 15, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 0}; - static const u8 arttim_regs[2][2] = { - { ARTTIM0, ARTTIM1 }, - { ARTTIM23, ARTTIM23 } - }; - static const u8 drwtim_regs[2][2] = { - { DRWTIM0, DRWTIM1 }, - { DRWTIM2, DRWTIM3 } - }; - int channel = (int) HWIF(drive)->channel; - int slave = (drives != drive); /* Is this really the best way to determine this?? */ - - cmdprintk("program_drive_count parameters = s(%d),a(%d),r(%d),p(%d)\n", - setup_count, active_count, recovery_count, drive->present); - /* - * Set up address setup count registers. - * Primary interface has individual count/timing registers for - * each drive. Secondary interface has one common set of registers, - * for address setup so we merge these timings, using the slowest - * value. - */ - if (channel) { - drive->drive_data = setup_count; - setup_count = max(drives[0].drive_data, - drives[1].drive_data); - cmdprintk("Secondary interface, setup_count = %d\n", - setup_count); - } - - /* - * Convert values to internal chipset representation - */ - setup_count = (setup_count > 5) ? 0xc0 : (int) setup_counts[setup_count]; - active_count &= 0xf; /* Remember, max value is 16 */ - recovery_count = (int) recovery_counts[recovery_count]; - - cmdprintk("Final values = %d,%d,%d\n", - setup_count, active_count, recovery_count); - - /* - * Now that everything is ready, program the new timings - */ - local_irq_save(flags); - /* - * Program the address_setup clocks into ARTTIM reg, - * and then the active/recovery counts into the DRWTIM reg - */ - (void) pci_read_config_byte(dev, arttim_regs[channel][slave], &temp_b); - (void) pci_write_config_byte(dev, arttim_regs[channel][slave], - ((u8) setup_count) | (temp_b & 0x3f)); - (void) pci_write_config_byte(dev, drwtim_regs[channel][slave], - (u8) ((active_count << 4) | recovery_count)); - cmdprintk ("Write %x to %x\n", - ((u8) setup_count) | (temp_b & 0x3f), - arttim_regs[channel][slave]); - cmdprintk ("Write %x to %x\n", - (u8) ((active_count << 4) | recovery_count), - drwtim_regs[channel][slave]); - local_irq_restore(flags); -} - -/* - * Attempts to set the interface PIO mode. - * The preferred method of selecting PIO modes (e.g. mode 4) is - * "echo 'piomode:4' > /proc/ide/hdx/settings". Special cases are - * 8: prefetch off, 9: prefetch on, 255: auto-select best mode. - * Called with 255 at boot time. - */ - -static void cmd64x_tuneproc (ide_drive_t *drive, u8 mode_wanted) -{ - int setup_time, active_time, recovery_time; - int clock_time, pio_mode, cycle_time; - u8 recovery_count2, cycle_count; - int setup_count, active_count, recovery_count; - int bus_speed = system_bus_clock(); - /*byte b;*/ - ide_pio_data_t d; - - switch (mode_wanted) { - case 8: /* set prefetch off */ - case 9: /* set prefetch on */ - mode_wanted &= 1; - /*set_prefetch_mode(index, mode_wanted);*/ - cmdprintk("%s: %sabled cmd640 prefetch\n", - drive->name, mode_wanted ? "en" : "dis"); - return; - } - - mode_wanted = ide_get_best_pio_mode (drive, mode_wanted, 5, &d); - pio_mode = d.pio_mode; - cycle_time = d.cycle_time; - - /* - * I copied all this complicated stuff from cmd640.c and made a few - * minor changes. For now I am just going to pray that it is correct. - */ - if (pio_mode > 5) - pio_mode = 5; - setup_time = ide_pio_timings[pio_mode].setup_time; - active_time = ide_pio_timings[pio_mode].active_time; - recovery_time = cycle_time - (setup_time + active_time); - clock_time = 1000 / bus_speed; - cycle_count = (cycle_time + clock_time - 1) / clock_time; - - setup_count = (setup_time + clock_time - 1) / clock_time; - - active_count = (active_time + clock_time - 1) / clock_time; - - recovery_count = (recovery_time + clock_time - 1) / clock_time; - recovery_count2 = cycle_count - (setup_count + active_count); - if (recovery_count2 > recovery_count) - recovery_count = recovery_count2; - if (recovery_count > 16) { - active_count += recovery_count - 16; - recovery_count = 16; - } - if (active_count > 16) - active_count = 16; /* maximum allowed by cmd646 */ - - /* - * In a perfect world, we might set the drive pio mode here - * (using WIN_SETFEATURE) before continuing. - * - * But we do not, because: - * 1) this is the wrong place to do it - * (proper is do_special() in ide.c) - * 2) in practice this is rarely, if ever, necessary - */ - program_drive_counts (drive, setup_count, active_count, recovery_count); - - cmdprintk("%s: selected cmd646 PIO mode%d : %d (%dns)%s, " - "clocks=%d/%d/%d\n", - drive->name, pio_mode, mode_wanted, cycle_time, - d.overridden ? " (overriding vendor mode)" : "", - setup_count, active_count, recovery_count); -} - -static u8 cmd64x_ratemask (ide_drive_t *drive) -{ - struct pci_dev *dev = HWIF(drive)->pci_dev; - u8 mode = 0; - - switch(dev->device) { - case PCI_DEVICE_ID_CMD_649: - mode = 3; - break; - case PCI_DEVICE_ID_CMD_648: - mode = 2; - break; - case PCI_DEVICE_ID_CMD_643: - return 0; - - case PCI_DEVICE_ID_CMD_646: - { - unsigned int class_rev = 0; - pci_read_config_dword(dev, - PCI_CLASS_REVISION, &class_rev); - class_rev &= 0xff; - /* - * UltraDMA only supported on PCI646U and PCI646U2, which - * correspond to revisions 0x03, 0x05 and 0x07 respectively. - * Actually, although the CMD tech support people won't - * tell me the details, the 0x03 revision cannot support - * UDMA correctly without hardware modifications, and even - * then it only works with Quantum disks due to some - * hold time assumptions in the 646U part which are fixed - * in the 646U2. - * - * So we only do UltraDMA on revision 0x05 and 0x07 chipsets. - */ - switch(class_rev) { - case 0x07: - case 0x05: - return 1; - case 0x03: - case 0x01: - default: - return 0; - } - } - } - if (!eighty_ninty_three(drive)) - mode = min(mode, (u8)1); - return mode; -} - -static void config_cmd64x_chipset_for_pio (ide_drive_t *drive, u8 set_speed) -{ - u8 speed = 0x00; - u8 set_pio = ide_get_best_pio_mode(drive, 4, 5, NULL); - - cmd64x_tuneproc(drive, set_pio); - speed = XFER_PIO_0 + set_pio; - if (set_speed) - (void) ide_config_drive_speed(drive, speed); -} - -static void config_chipset_for_pio (ide_drive_t *drive, u8 set_speed) -{ - config_cmd64x_chipset_for_pio(drive, set_speed); -} - -static int cmd64x_tune_chipset (ide_drive_t *drive, u8 xferspeed) -{ - ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; - - u8 unit = (drive->select.b.unit & 0x01); - u8 regU = 0, pciU = (hwif->channel) ? UDIDETCR1 : UDIDETCR0; - u8 regD = 0, pciD = (hwif->channel) ? BMIDESR1 : BMIDESR0; - - u8 speed = ide_rate_filter(cmd64x_ratemask(drive), xferspeed); - - if (speed > XFER_PIO_4) { - (void) pci_read_config_byte(dev, pciD, ®D); - (void) pci_read_config_byte(dev, pciU, ®U); - regD &= ~(unit ? 0x40 : 0x20); - regU &= ~(unit ? 0xCA : 0x35); - (void) pci_write_config_byte(dev, pciD, regD); - (void) pci_write_config_byte(dev, pciU, regU); - (void) pci_read_config_byte(dev, pciD, ®D); - (void) pci_read_config_byte(dev, pciU, ®U); - } - - switch(speed) { - case XFER_UDMA_5: regU |= (unit ? 0x0A : 0x05); break; - case XFER_UDMA_4: regU |= (unit ? 0x4A : 0x15); break; - case XFER_UDMA_3: regU |= (unit ? 0x8A : 0x25); break; - case XFER_UDMA_2: regU |= (unit ? 0x42 : 0x11); break; - case XFER_UDMA_1: regU |= (unit ? 0x82 : 0x21); break; - case XFER_UDMA_0: regU |= (unit ? 0xC2 : 0x31); break; - case XFER_MW_DMA_2: regD |= (unit ? 0x40 : 0x10); break; - case XFER_MW_DMA_1: regD |= (unit ? 0x80 : 0x20); break; - case XFER_MW_DMA_0: regD |= (unit ? 0xC0 : 0x30); break; - case XFER_SW_DMA_2: regD |= (unit ? 0x40 : 0x10); break; - case XFER_SW_DMA_1: regD |= (unit ? 0x80 : 0x20); break; - case XFER_SW_DMA_0: regD |= (unit ? 0xC0 : 0x30); break; - case XFER_PIO_4: cmd64x_tuneproc(drive, 4); break; - case XFER_PIO_3: cmd64x_tuneproc(drive, 3); break; - case XFER_PIO_2: cmd64x_tuneproc(drive, 2); break; - case XFER_PIO_1: cmd64x_tuneproc(drive, 1); break; - case XFER_PIO_0: cmd64x_tuneproc(drive, 0); break; - - default: - return 1; - } - - if (speed > XFER_PIO_4) { - (void) pci_write_config_byte(dev, pciU, regU); - regD |= (unit ? 0x40 : 0x20); - (void) pci_write_config_byte(dev, pciD, regD); - } - - return (ide_config_drive_speed(drive, speed)); -} - -static int config_chipset_for_dma (ide_drive_t *drive) -{ - u8 speed = ide_dma_speed(drive, cmd64x_ratemask(drive)); - - config_chipset_for_pio(drive, !speed); - - if (!speed) - return 0; - - if(ide_set_xfer_rate(drive, speed)) - return 0; - - if (!drive->init_speed) - drive->init_speed = speed; - - return ide_dma_enable(drive); -} - -static int cmd64x_config_drive_for_dma (ide_drive_t *drive) -{ - ide_hwif_t *hwif = HWIF(drive); - struct hd_driveid *id = drive->id; - - if ((id != NULL) && ((id->capability & 1) != 0) && drive->autodma) { - - if (ide_use_dma(drive)) { - if (config_chipset_for_dma(drive)) - return hwif->ide_dma_on(drive); - } - - goto fast_ata_pio; - - } else if ((id->capability & 8) || (id->field_valid & 2)) { -fast_ata_pio: - config_chipset_for_pio(drive, 1); - return hwif->ide_dma_off_quietly(drive); - } - /* IORDY not supported */ - return 0; -} - -static int cmd64x_alt_dma_status (struct pci_dev *dev) -{ - switch(dev->device) { - case PCI_DEVICE_ID_CMD_648: - case PCI_DEVICE_ID_CMD_649: - return 1; - default: - break; - } - return 0; -} - -static int cmd64x_ide_dma_end (ide_drive_t *drive) -{ - u8 dma_stat = 0, dma_cmd = 0; - ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; - - drive->waiting_for_dma = 0; - /* read DMA command state */ - dma_cmd = hwif->INB(hwif->dma_command); - /* stop DMA */ - hwif->OUTB((dma_cmd & ~1), hwif->dma_command); - /* get DMA status */ - dma_stat = hwif->INB(hwif->dma_status); - /* clear the INTR & ERROR bits */ - hwif->OUTB(dma_stat|6, hwif->dma_status); - if (cmd64x_alt_dma_status(dev)) { - u8 dma_intr = 0; - u8 dma_mask = (hwif->channel) ? ARTTIM23_INTR_CH1 : - CFR_INTR_CH0; - u8 dma_reg = (hwif->channel) ? ARTTIM2 : CFR; - (void) pci_read_config_byte(dev, dma_reg, &dma_intr); - /* clear the INTR bit */ - (void) pci_write_config_byte(dev, dma_reg, dma_intr|dma_mask); - } - /* purge DMA mappings */ - ide_destroy_dmatable(drive); - /* verify good DMA status */ - return (dma_stat & 7) != 4; -} - -static int cmd64x_ide_dma_test_irq (ide_drive_t *drive) -{ - ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; - u8 dma_alt_stat = 0, mask = (hwif->channel) ? MRDMODE_INTR_CH1 : - MRDMODE_INTR_CH0; - u8 dma_stat = hwif->INB(hwif->dma_status); - - (void) pci_read_config_byte(dev, MRDMODE, &dma_alt_stat); -#ifdef DEBUG - printk("%s: dma_stat: 0x%02x dma_alt_stat: " - "0x%02x mask: 0x%02x\n", drive->name, - dma_stat, dma_alt_stat, mask); -#endif - if (!(dma_alt_stat & mask)) - return 0; - - /* return 1 if INTR asserted */ - if ((dma_stat & 4) == 4) - return 1; - - return 0; -} - -/* - * ASUS P55T2P4D with CMD646 chipset revision 0x01 requires the old - * event order for DMA transfers. - */ - -static int cmd646_1_ide_dma_end (ide_drive_t *drive) -{ - ide_hwif_t *hwif = HWIF(drive); - u8 dma_stat = 0, dma_cmd = 0; - - drive->waiting_for_dma = 0; - /* get DMA status */ - dma_stat = hwif->INB(hwif->dma_status); - /* read DMA command state */ - dma_cmd = hwif->INB(hwif->dma_command); - /* stop DMA */ - hwif->OUTB((dma_cmd & ~1), hwif->dma_command); - /* clear the INTR & ERROR bits */ - hwif->OUTB(dma_stat|6, hwif->dma_status); - /* and free any DMA resources */ - ide_destroy_dmatable(drive); - /* verify good DMA status */ - return (dma_stat & 7) != 4; -} - -static unsigned int __devinit init_chipset_cmd64x(struct pci_dev *dev, const char *name) -{ - u32 class_rev = 0; - u8 mrdmode = 0; - - pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev); - class_rev &= 0xff; - - switch(dev->device) { - case PCI_DEVICE_ID_CMD_643: - break; - case PCI_DEVICE_ID_CMD_646: - printk(KERN_INFO "%s: chipset revision 0x%02X, ", name, class_rev); - switch(class_rev) { - case 0x07: - case 0x05: - printk("UltraDMA Capable"); - break; - case 0x03: - printk("MultiWord DMA Force Limited"); - break; - case 0x01: - default: - printk("MultiWord DMA Limited, IRQ workaround enabled"); - break; - } - printk("\n"); - break; - case PCI_DEVICE_ID_CMD_648: - case PCI_DEVICE_ID_CMD_649: - break; - default: - break; - } - - /* Set a good latency timer and cache line size value. */ - (void) pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64); - /* FIXME: pci_set_master() to ensure a good latency timer value */ - - /* Setup interrupts. */ - (void) pci_read_config_byte(dev, MRDMODE, &mrdmode); - mrdmode &= ~(0x30); - (void) pci_write_config_byte(dev, MRDMODE, mrdmode); - - /* Use MEMORY READ LINE for reads. - * NOTE: Although not mentioned in the PCI0646U specs, - * these bits are write only and won't be read - * back as set or not. The PCI0646U2 specs clarify - * this point. - */ - (void) pci_write_config_byte(dev, MRDMODE, mrdmode | 0x02); - - /* Set reasonable active/recovery/address-setup values. */ - (void) pci_write_config_byte(dev, ARTTIM0, 0x40); - (void) pci_write_config_byte(dev, DRWTIM0, 0x3f); - (void) pci_write_config_byte(dev, ARTTIM1, 0x40); - (void) pci_write_config_byte(dev, DRWTIM1, 0x3f); -#ifdef __i386__ - (void) pci_write_config_byte(dev, ARTTIM23, 0x1c); -#else - (void) pci_write_config_byte(dev, ARTTIM23, 0x5c); -#endif - (void) pci_write_config_byte(dev, DRWTIM23, 0x3f); - (void) pci_write_config_byte(dev, DRWTIM3, 0x3f); -#ifdef CONFIG_PPC - (void) pci_write_config_byte(dev, UDIDETCR0, 0xf0); -#endif /* CONFIG_PPC */ - -#if defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS) - - cmd_devs[n_cmd_devs++] = dev; - - if (!cmd64x_proc) { - cmd64x_proc = 1; - ide_pci_create_host_proc("cmd64x", cmd64x_get_info); - } -#endif /* DISPLAY_CMD64X_TIMINGS && CONFIG_PROC_FS */ - - return 0; -} - -static unsigned int __devinit ata66_cmd64x(ide_hwif_t *hwif) -{ - u8 ata66 = 0, mask = (hwif->channel) ? 0x02 : 0x01; - - switch(hwif->pci_dev->device) { - case PCI_DEVICE_ID_CMD_643: - case PCI_DEVICE_ID_CMD_646: - return ata66; - default: - break; - } - pci_read_config_byte(hwif->pci_dev, BMIDECSR, &ata66); - return (ata66 & mask) ? 1 : 0; -} - -static void __devinit init_hwif_cmd64x(ide_hwif_t *hwif) -{ - struct pci_dev *dev = hwif->pci_dev; - unsigned int class_rev; - - hwif->autodma = 0; - pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev); - class_rev &= 0xff; - - hwif->tuneproc = &cmd64x_tuneproc; - hwif->speedproc = &cmd64x_tune_chipset; - - if (!hwif->dma_base) { - hwif->drives[0].autotune = 1; - hwif->drives[1].autotune = 1; - return; - } - - hwif->atapi_dma = 1; - - hwif->ultra_mask = 0x3f; - hwif->mwdma_mask = 0x07; - hwif->swdma_mask = 0x07; - - if (dev->device == PCI_DEVICE_ID_CMD_643) - hwif->ultra_mask = 0x80; - if (dev->device == PCI_DEVICE_ID_CMD_646) - hwif->ultra_mask = (class_rev > 0x04) ? 0x07 : 0x80; - if (dev->device == PCI_DEVICE_ID_CMD_648) - hwif->ultra_mask = 0x1f; - - hwif->ide_dma_check = &cmd64x_config_drive_for_dma; - if (!(hwif->udma_four)) - hwif->udma_four = ata66_cmd64x(hwif); - - if (dev->device == PCI_DEVICE_ID_CMD_646) { - hwif->chipset = ide_cmd646; - if (class_rev == 0x01) { - hwif->ide_dma_end = &cmd646_1_ide_dma_end; - } else { - hwif->ide_dma_end = &cmd64x_ide_dma_end; - hwif->ide_dma_test_irq = &cmd64x_ide_dma_test_irq; - } - } else { - hwif->ide_dma_end = &cmd64x_ide_dma_end; - hwif->ide_dma_test_irq = &cmd64x_ide_dma_test_irq; - } - - - if (!noautodma) - hwif->autodma = 1; - hwif->drives[0].autodma = hwif->autodma; - hwif->drives[1].autodma = hwif->autodma; -} - -static ide_pci_device_t cmd64x_chipsets[] __devinitdata = { - { /* 0 */ - .name = "CMD643", - .init_chipset = init_chipset_cmd64x, - .init_hwif = init_hwif_cmd64x, - .channels = 2, - .autodma = AUTODMA, - .bootable = ON_BOARD, - },{ /* 1 */ - .name = "CMD646", - .init_chipset = init_chipset_cmd64x, - .init_hwif = init_hwif_cmd64x, - .channels = 2, - .autodma = AUTODMA, - .enablebits = {{0x00,0x00,0x00}, {0x51,0x80,0x80}}, - .bootable = ON_BOARD, - },{ /* 2 */ - .name = "CMD648", - .init_chipset = init_chipset_cmd64x, - .init_hwif = init_hwif_cmd64x, - .channels = 2, - .autodma = AUTODMA, - .bootable = ON_BOARD, - },{ /* 3 */ - .name = "CMD649", - .init_chipset = init_chipset_cmd64x, - .init_hwif = init_hwif_cmd64x, - .channels = 2, - .autodma = AUTODMA, - .bootable = ON_BOARD, - } -}; - -static int __devinit cmd64x_init_one(struct pci_dev *dev, const struct pci_device_id *id) -{ - return ide_setup_pci_device(dev, &cmd64x_chipsets[id->driver_data]); -} - -static struct pci_device_id cmd64x_pci_tbl[] = { - { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_643, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_646, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1}, - { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_648, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2}, - { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_649, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3}, - { 0, }, -}; -MODULE_DEVICE_TABLE(pci, cmd64x_pci_tbl); - -static struct pci_driver driver = { - .name = "CMD64x_IDE", - .id_table = cmd64x_pci_tbl, - .probe = cmd64x_init_one, -}; - -static int cmd64x_ide_init(void) -{ - return ide_pci_register_driver(&driver); -} - -module_init(cmd64x_ide_init); - -MODULE_AUTHOR("Eddie Dost, David Miller, Andre Hedrick"); -MODULE_DESCRIPTION("PCI driver module for CMD64x IDE"); -MODULE_LICENSE("GPL"); diff --git a/drivers/ide/pci/cs5520.c b/drivers/ide/pci/cs5520.c deleted file mode 100644 index 079f7c86726..00000000000 --- a/drivers/ide/pci/cs5520.c +++ /dev/null @@ -1,272 +0,0 @@ -/* - * IDE tuning and bus mastering support for the CS5510/CS5520 - * chipsets - * - * The CS5510/CS5520 are slightly unusual devices. Unlike the - * typical IDE controllers they do bus mastering with the drive in - * PIO mode and smarter silicon. - * - * The practical upshot of this is that we must always tune the - * drive for the right PIO mode. We must also ignore all the blacklists - * and the drive bus mastering DMA information. - * - * *** This driver is strictly experimental *** - * - * (c) Copyright Red Hat Inc 2002 - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * For the avoidance of doubt the "preferred form" of this code is one which - * is in an open non patent encumbered format. Where cryptographic key signing - * forms part of the process of creating an executable the information - * including keys needed to generate an equivalently functional executable - * are deemed to be part of the source code. - * - */ - -#include <linux/module.h> -#include <linux/types.h> -#include <linux/kernel.h> -#include <linux/delay.h> -#include <linux/timer.h> -#include <linux/mm.h> -#include <linux/ioport.h> -#include <linux/blkdev.h> -#include <linux/hdreg.h> - -#include <linux/interrupt.h> -#include <linux/init.h> -#include <linux/pci.h> -#include <linux/ide.h> -#include <linux/dma-mapping.h> - -#include <asm/io.h> -#include <asm/irq.h> - -struct pio_clocks -{ - int address; - int assert; - int recovery; -}; - -static struct pio_clocks cs5520_pio_clocks[]={ - {3, 6, 11}, - {2, 5, 6}, - {1, 4, 3}, - {1, 3, 2}, - {1, 2, 1} -}; - -static int cs5520_tune_chipset(ide_drive_t *drive, u8 xferspeed) -{ - ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *pdev = hwif->pci_dev; - u8 speed = min((u8)XFER_PIO_4, xferspeed); - int pio = speed; - u8 reg; - int controller = drive->dn > 1 ? 1 : 0; - int error; - - switch(speed) - { - case XFER_PIO_4: - case XFER_PIO_3: - case XFER_PIO_2: - case XFER_PIO_1: - case XFER_PIO_0: - pio -= XFER_PIO_0; - break; - default: - pio = 0; - printk(KERN_ERR "cs55x0: bad ide timing.\n"); - } - - printk("PIO clocking = %d\n", pio); - - /* FIXME: if DMA = 1 do we need to set the DMA bit here ? */ - - /* 8bit CAT/CRT - 8bit command timing for channel */ - pci_write_config_byte(pdev, 0x62 + controller, - (cs5520_pio_clocks[pio].recovery << 4) | - (cs5520_pio_clocks[pio].assert)); - - /* 0x64 - 16bit Primary, 0x68 - 16bit Secondary */ - - /* FIXME: should these use address ? */ - /* Data read timing */ - pci_write_config_byte(pdev, 0x64 + 4*controller + (drive->dn&1), - (cs5520_pio_clocks[pio].recovery << 4) | - (cs5520_pio_clocks[pio].assert)); - /* Write command timing */ - pci_write_config_byte(pdev, 0x66 + 4*controller + (drive->dn&1), - (cs5520_pio_clocks[pio].recovery << 4) | - (cs5520_pio_clocks[pio].assert)); - - /* Set the DMA enable/disable flag */ - reg = inb(hwif->dma_base + 0x02 + 8*controller); - reg |= 1<<((drive->dn&1)+5); - outb(reg, hwif->dma_base + 0x02 + 8*controller); - - error = ide_config_drive_speed(drive, speed); - /* ATAPI is harder so leave it for now */ - if(!error && drive->media == ide_disk) - error = hwif->ide_dma_on(drive); - - return error; -} - -static void cs5520_tune_drive(ide_drive_t *drive, u8 pio) -{ - pio = ide_get_best_pio_mode(drive, pio, 4, NULL); - cs5520_tune_chipset(drive, (XFER_PIO_0 + pio)); -} - -static int cs5520_config_drive_xfer_rate(ide_drive_t *drive) -{ - ide_hwif_t *hwif = HWIF(drive); - - /* Tune the drive for PIO modes up to PIO 4 */ - cs5520_tune_drive(drive, 4); - /* Then tell the core to use DMA operations */ - return hwif->ide_dma_on(drive); -} - -/* - * We provide a callback for our nonstandard DMA location - */ - -static void __devinit cs5520_init_setup_dma(struct pci_dev *dev, ide_pci_device_t *d, ide_hwif_t *hwif) -{ - unsigned long bmide = pci_resource_start(dev, 2); /* Not the usual 4 */ - if(hwif->mate && hwif->mate->dma_base) /* Second channel at primary + 8 */ - bmide += 8; - ide_setup_dma(hwif, bmide, 8); -} - -/* - * We wrap the DMA activate to set the vdma flag. This is needed - * so that the IDE DMA layer issues PIO not DMA commands over the - * DMA channel - */ - -static int cs5520_dma_on(ide_drive_t *drive) -{ - drive->vdma = 1; - return 0; -} - -static void __devinit init_hwif_cs5520(ide_hwif_t *hwif) -{ - hwif->tuneproc = &cs5520_tune_drive; - hwif->speedproc = &cs5520_tune_chipset; - hwif->ide_dma_check = &cs5520_config_drive_xfer_rate; - hwif->ide_dma_on = &cs5520_dma_on; - - if(!noautodma) - hwif->autodma = 1; - - if(!hwif->dma_base) - { - hwif->drives[0].autotune = 1; - hwif->drives[1].autotune = 1; - return; - } - - hwif->atapi_dma = 0; - hwif->ultra_mask = 0; - hwif->swdma_mask = 0; - hwif->mwdma_mask = 0; - - hwif->drives[0].autodma = hwif->autodma; - hwif->drives[1].autodma = hwif->autodma; -} - -#define DECLARE_CS_DEV(name_str) \ - { \ - .name = name_str, \ - .init_setup_dma = cs5520_init_setup_dma, \ - .init_hwif = init_hwif_cs5520, \ - .channels = 2, \ - .autodma = AUTODMA, \ - .bootable = ON_BOARD, \ - .flags = IDEPCI_FLAG_ISA_PORTS, \ - } - -static ide_pci_device_t cyrix_chipsets[] __devinitdata = { - /* 0 */ DECLARE_CS_DEV("Cyrix 5510"), - /* 1 */ DECLARE_CS_DEV("Cyrix 5520") -}; - -/* - * The 5510/5520 are a bit weird. They don't quite set up the way - * the PCI helper layer expects so we must do much of the set up - * work longhand. - */ - -static int __devinit cs5520_init_one(struct pci_dev *dev, const struct pci_device_id *id) -{ - ata_index_t index; - ide_pci_device_t *d = &cyrix_chipsets[id->driver_data]; - - ide_setup_pci_noise(dev, d); - - /* We must not grab the entire device, it has 'ISA' space in its - BARS too and we will freak out other bits of the kernel */ - if (pci_enable_device_bars(dev, 1<<2)) { - printk(KERN_WARNING "%s: Unable to enable 55x0.\n", d->name); - return -ENODEV; - } - pci_set_master(dev); - if (pci_set_dma_mask(dev, DMA_32BIT_MASK)) { - printk(KERN_WARNING "cs5520: No suitable DMA available.\n"); - return -ENODEV; - } - - index.all = 0xf0f0; - - /* - * Now the chipset is configured we can let the core - * do all the device setup for us - */ - - ide_pci_setup_ports(dev, d, 14, &index); - - if((index.b.low & 0xf0) != 0xf0) - probe_hwif_init(&ide_hwifs[index.b.low]); - if((index.b.high & 0xf0) != 0xf0) - probe_hwif_init(&ide_hwifs[index.b.high]); - return 0; -} - -static struct pci_device_id cs5520_pci_tbl[] = { - { PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5510, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - { PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5520, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1}, - { 0, }, -}; -MODULE_DEVICE_TABLE(pci, cs5520_pci_tbl); - -static struct pci_driver driver = { - .name = "Cyrix_IDE", - .id_table = cs5520_pci_tbl, - .probe = cs5520_init_one, -}; - -static int cs5520_ide_init(void) -{ - return ide_pci_register_driver(&driver); -} - -module_init(cs5520_ide_init); - -MODULE_AUTHOR("Alan Cox"); -MODULE_DESCRIPTION("PCI driver module for Cyrix 5510/5520 IDE"); -MODULE_LICENSE("GPL"); diff --git a/drivers/ide/pci/cs5530.c b/drivers/ide/pci/cs5530.c deleted file mode 100644 index 380bb28c7c5..00000000000 --- a/drivers/ide/pci/cs5530.c +++ /dev/null @@ -1,383 +0,0 @@ -/* - * linux/drivers/ide/pci/cs5530.c Version 0.7 Sept 10, 2002 - * - * Copyright (C) 2000 Andre Hedrick <andre@linux-ide.org> - * Ditto of GNU General Public License. - * - * Copyright (C) 2000 Mark Lord <mlord@pobox.com> - * May be copied or modified under the terms of the GNU General Public License - * - * Development of this chipset driver was funded - * by the nice folks at National Semiconductor. - * - * Documentation: - * CS5530 documentation available from National Semiconductor. - */ - -#include <linux/module.h> -#include <linux/types.h> -#include <linux/kernel.h> -#include <linux/delay.h> -#include <linux/timer.h> -#include <linux/mm.h> -#include <linux/ioport.h> -#include <linux/blkdev.h> -#include <linux/hdreg.h> -#include <linux/interrupt.h> -#include <linux/pci.h> -#include <linux/init.h> -#include <linux/ide.h> -#include <asm/io.h> -#include <asm/irq.h> - -/** - * cs5530_xfer_set_mode - set a new transfer mode at the drive - * @drive: drive to tune - * @mode: new mode - * - * Logging wrapper to the IDE driver speed configuration. This can - * probably go away now. - */ - -static int cs5530_set_xfer_mode (ide_drive_t *drive, u8 mode) -{ - printk(KERN_DEBUG "%s: cs5530_set_xfer_mode(%s)\n", - drive->name, ide_xfer_verbose(mode)); - return (ide_config_drive_speed(drive, mode)); -} - -/* - * Here are the standard PIO mode 0-4 timings for each "format". - * Format-0 uses fast data reg timings, with slower command reg timings. - * Format-1 uses fast timings for all registers, but won't work with all drives. - */ -static unsigned int cs5530_pio_timings[2][5] = { - {0x00009172, 0x00012171, 0x00020080, 0x00032010, 0x00040010}, - {0xd1329172, 0x71212171, 0x30200080, 0x20102010, 0x00100010} -}; - -/* - * After chip reset, the PIO timings are set to 0x0000e132, which is not valid. - */ -#define CS5530_BAD_PIO(timings) (((timings)&~0x80000000)==0x0000e132) -#define CS5530_BASEREG(hwif) (((hwif)->dma_base & ~0xf) + ((hwif)->channel ? 0x30 : 0x20)) - -/** - * cs5530_tuneproc - select/set PIO modes - * - * cs5530_tuneproc() handles selection/setting of PIO modes - * for both the chipset and drive. - * - * The ide_init_cs5530() routine guarantees that all drives - * will have valid default PIO timings set up before we get here. - */ - -static void cs5530_tuneproc (ide_drive_t *drive, u8 pio) /* pio=255 means "autotune" */ -{ - ide_hwif_t *hwif = HWIF(drive); - unsigned int format; - unsigned long basereg = CS5530_BASEREG(hwif); - static u8 modes[5] = { XFER_PIO_0, XFER_PIO_1, XFER_PIO_2, XFER_PIO_3, XFER_PIO_4}; - - pio = ide_get_best_pio_mode(drive, pio, 4, NULL); - if (!cs5530_set_xfer_mode(drive, modes[pio])) { - format = (hwif->INL(basereg+4) >> 31) & 1; - hwif->OUTL(cs5530_pio_timings[format][pio], - basereg+(drive->select.b.unit<<3)); - } -} - -/** - * cs5530_config_dma - select/set DMA and UDMA modes - * @drive: drive to tune - * - * cs5530_config_dma() handles selection/setting of DMA/UDMA modes - * for both the chipset and drive. The CS5530 has limitations about - * mixing DMA/UDMA on the same cable. - */ - -static int cs5530_config_dma (ide_drive_t *drive) -{ - int udma_ok = 1, mode = 0; - ide_hwif_t *hwif = HWIF(drive); - int unit = drive->select.b.unit; - ide_drive_t *mate = &hwif->drives[unit^1]; - struct hd_driveid *id = drive->id; - unsigned int reg, timings; - unsigned long basereg; - - /* - * Default to DMA-off in case we run into trouble here. - */ - hwif->ide_dma_off_quietly(drive); - /* turn off DMA while we fiddle */ - hwif->ide_dma_host_off(drive); - /* clear DMA_capable bit */ - - /* - * The CS5530 specifies that two drives sharing a cable cannot - * mix UDMA/MDMA. It has to be one or the other, for the pair, - * though different timings can still be chosen for each drive. - * We could set the appropriate timing bits on the fly, - * but that might be a bit confusing. So, for now we statically - * handle this requirement by looking at our mate drive to see - * what it is capable of, before choosing a mode for our own drive. - * - * Note: This relies on the fact we never fail from UDMA to MWDMA_2 - * but instead drop to PIO - */ - if (mate->present) { - struct hd_driveid *mateid = mate->id; - if (mateid && (mateid->capability & 1) && - !__ide_dma_bad_drive(mate)) { - if ((mateid->field_valid & 4) && - (mateid->dma_ultra & 7)) - udma_ok = 1; - else if ((mateid->field_valid & 2) && - (mateid->dma_mword & 7)) - udma_ok = 0; - else - udma_ok = 1; - } - } - - /* - * Now see what the current drive is capable of, - * selecting UDMA only if the mate said it was ok. - */ - if (id && (id->capability & 1) && drive->autodma && - !__ide_dma_bad_drive(drive)) { - if (udma_ok && (id->field_valid & 4) && (id->dma_ultra & 7)) { - if (id->dma_ultra & 4) - mode = XFER_UDMA_2; - else if (id->dma_ultra & 2) - mode = XFER_UDMA_1; - else if (id->dma_ultra & 1) - mode = XFER_UDMA_0; - } - if (!mode && (id->field_valid & 2) && (id->dma_mword & 7)) { - if (id->dma_mword & 4) - mode = XFER_MW_DMA_2; - else if (id->dma_mword & 2) - mode = XFER_MW_DMA_1; - else if (id->dma_mword & 1) - mode = XFER_MW_DMA_0; - } - } - - /* - * Tell the drive to switch to the new mode; abort on failure. - */ - if (!mode || cs5530_set_xfer_mode(drive, mode)) - return 1; /* failure */ - - /* - * Now tune the chipset to match the drive: - */ - switch (mode) { - case XFER_UDMA_0: timings = 0x00921250; break; - case XFER_UDMA_1: timings = 0x00911140; break; - case XFER_UDMA_2: timings = 0x00911030; break; - case XFER_MW_DMA_0: timings = 0x00077771; break; - case XFER_MW_DMA_1: timings = 0x00012121; break; - case XFER_MW_DMA_2: timings = 0x00002020; break; - default: - printk(KERN_ERR "%s: cs5530_config_dma: huh? mode=%02x\n", - drive->name, mode); - return 1; /* failure */ - } - basereg = CS5530_BASEREG(hwif); - reg = hwif->INL(basereg+4); /* get drive0 config register */ - timings |= reg & 0x80000000; /* preserve PIO format bit */ - if (unit == 0) { /* are we configuring drive0? */ - hwif->OUTL(timings, basereg+4); /* write drive0 config register */ - } else { - if (timings & 0x00100000) - reg |= 0x00100000; /* enable UDMA timings for both drives */ - else - reg &= ~0x00100000; /* disable UDMA timings for both drives */ - hwif->OUTL(reg, basereg+4); /* write drive0 config register */ - hwif->OUTL(timings, basereg+12); /* write drive1 config register */ - } - (void) hwif->ide_dma_host_on(drive); - /* set DMA_capable bit */ - - /* - * Finally, turn DMA on in software, and exit. - */ - return hwif->ide_dma_on(drive); /* success */ -} - -/** - * init_chipset_5530 - set up 5530 bridge - * @dev: PCI device - * @name: device name - * - * Initialize the cs5530 bridge for reliable IDE DMA operation. - */ - -static unsigned int __devinit init_chipset_cs5530 (struct pci_dev *dev, const char *name) -{ - struct pci_dev *master_0 = NULL, *cs5530_0 = NULL; - unsigned long flags; - - dev = NULL; - while ((dev = pci_find_device(PCI_VENDOR_ID_CYRIX, PCI_ANY_ID, dev)) != NULL) { - switch (dev->device) { - case PCI_DEVICE_ID_CYRIX_PCI_MASTER: - master_0 = dev; - break; - case PCI_DEVICE_ID_CYRIX_5530_LEGACY: - cs5530_0 = dev; - break; - } - } - if (!master_0) { - printk(KERN_ERR "%s: unable to locate PCI MASTER function\n", name); - return 0; - } - if (!cs5530_0) { - printk(KERN_ERR "%s: unable to locate CS5530 LEGACY function\n", name); - return 0; - } - - spin_lock_irqsave(&ide_lock, flags); - /* all CPUs (there should only be one CPU with this chipset) */ - - /* - * Enable BusMaster and MemoryWriteAndInvalidate for the cs5530: - * --> OR 0x14 into 16-bit PCI COMMAND reg of function 0 of the cs5530 - */ - - pci_set_master(cs5530_0); - pci_set_mwi(cs5530_0); - - /* - * Set PCI CacheLineSize to 16-bytes: - * --> Write 0x04 into 8-bit PCI CACHELINESIZE reg of function 0 of the cs5530 - */ - - pci_write_config_byte(cs5530_0, PCI_CACHE_LINE_SIZE, 0x04); - - /* - * Disable trapping of UDMA register accesses (Win98 hack): - * --> Write 0x5006 into 16-bit reg at offset 0xd0 of function 0 of the cs5530 - */ - - pci_write_config_word(cs5530_0, 0xd0, 0x5006); - - /* - * Bit-1 at 0x40 enables MemoryWriteAndInvalidate on internal X-bus: - * The other settings are what is necessary to get the register - * into a sane state for IDE DMA operation. - */ - - pci_write_config_byte(master_0, 0x40, 0x1e); - - /* - * Set max PCI burst size (16-bytes seems to work best): - * 16bytes: set bit-1 at 0x41 (reg value of 0x16) - * all others: clear bit-1 at 0x41, and do: - * 128bytes: OR 0x00 at 0x41 - * 256bytes: OR 0x04 at 0x41 - * 512bytes: OR 0x08 at 0x41 - * 1024bytes: OR 0x0c at 0x41 - */ - - pci_write_config_byte(master_0, 0x41, 0x14); - - /* - * These settings are necessary to get the chip - * into a sane state for IDE DMA operation. - */ - - pci_write_config_byte(master_0, 0x42, 0x00); - pci_write_config_byte(master_0, 0x43, 0xc1); - - spin_unlock_irqrestore(&ide_lock, flags); - - return 0; -} - -/** - * init_hwif_cs5530 - initialise an IDE channel - * @hwif: IDE to initialize - * - * This gets invoked by the IDE driver once for each channel. It - * performs channel-specific pre-initialization before drive probing. - */ - -static void __devinit init_hwif_cs5530 (ide_hwif_t *hwif) -{ - unsigned long basereg; - u32 d0_timings; - hwif->autodma = 0; - - if (hwif->mate) - hwif->serialized = hwif->mate->serialized = 1; - - hwif->tuneproc = &cs5530_tuneproc; - basereg = CS5530_BASEREG(hwif); - d0_timings = hwif->INL(basereg+0); - if (CS5530_BAD_PIO(d0_timings)) { - /* PIO timings not initialized? */ - hwif->OUTL(cs5530_pio_timings[(d0_timings>>31)&1][0], basereg+0); - if (!hwif->drives[0].autotune) - hwif->drives[0].autotune = 1; - /* needs autotuning later */ - } - if (CS5530_BAD_PIO(hwif->INL(basereg+8))) { - /* PIO timings not initialized? */ - hwif->OUTL(cs5530_pio_timings[(d0_timings>>31)&1][0], basereg+8); - if (!hwif->drives[1].autotune) - hwif->drives[1].autotune = 1; - /* needs autotuning later */ - } - - hwif->atapi_dma = 1; - hwif->ultra_mask = 0x07; - hwif->mwdma_mask = 0x07; - - hwif->ide_dma_check = &cs5530_config_dma; - if (!noautodma) - hwif->autodma = 1; - hwif->drives[0].autodma = hwif->autodma; - hwif->drives[1].autodma = hwif->autodma; -} - -static ide_pci_device_t cs5530_chipset __devinitdata = { - .name = "CS5530", - .init_chipset = init_chipset_cs5530, - .init_hwif = init_hwif_cs5530, - .channels = 2, - .autodma = AUTODMA, - .bootable = ON_BOARD, -}; - -static int __devinit cs5530_init_one(struct pci_dev *dev, const struct pci_device_id *id) -{ - return ide_setup_pci_device(dev, &cs5530_chipset); -} - -static struct pci_device_id cs5530_pci_tbl[] = { - { PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - { 0, }, -}; -MODULE_DEVICE_TABLE(pci, cs5530_pci_tbl); - -static struct pci_driver driver = { - .name = "CS5530 IDE", - .id_table = cs5530_pci_tbl, - .probe = cs5530_init_one, -}; - -static int cs5530_ide_init(void) -{ - return ide_pci_register_driver(&driver); -} - -module_init(cs5530_ide_init); - -MODULE_AUTHOR("Mark Lord"); -MODULE_DESCRIPTION("PCI driver module for Cyrix/NS 5530 IDE"); -MODULE_LICENSE("GPL"); diff --git a/drivers/ide/pci/cs5535.c b/drivers/ide/pci/cs5535.c deleted file mode 100644 index 5c5aec28e67..00000000000 --- a/drivers/ide/pci/cs5535.c +++ /dev/null @@ -1,304 +0,0 @@ -/* - * linux/drivers/ide/pci/cs5535.c - * - * Copyright (C) 2004-2005 Advanced Micro Devices, Inc. - * - * History: - * 09/20/2005 - Jaya Kumar <jayakumar.ide@gmail.com> - * - Reworked tuneproc, set_drive, misc mods to prep for mainline - * - Work was sponsored by CIS (M) Sdn Bhd. - * Ported to Kernel 2.6.11 on June 26, 2005 by - * Wolfgang Zuleger <wolfgang.zuleger@gmx.de> - * Alexander Kiausch <alex.kiausch@t-online.de> - * Originally developed by AMD for 2.4/2.6 - * - * Development of this chipset driver was funded - * by the nice folks at National Semiconductor/AMD. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * Documentation: - * CS5535 documentation available from AMD - */ - -#include <linux/module.h> -#include <linux/pci.h> -#include <linux/ide.h> - -#include "ide-timing.h" - -#define MSR_ATAC_BASE 0x51300000 -#define ATAC_GLD_MSR_CAP (MSR_ATAC_BASE+0) -#define ATAC_GLD_MSR_CONFIG (MSR_ATAC_BASE+0x01) -#define ATAC_GLD_MSR_SMI (MSR_ATAC_BASE+0x02) -#define ATAC_GLD_MSR_ERROR (MSR_ATAC_BASE+0x03) -#define ATAC_GLD_MSR_PM (MSR_ATAC_BASE+0x04) -#define ATAC_GLD_MSR_DIAG (MSR_ATAC_BASE+0x05) -#define ATAC_IO_BAR (MSR_ATAC_BASE+0x08) -#define ATAC_RESET (MSR_ATAC_BASE+0x10) -#define ATAC_CH0D0_PIO (MSR_ATAC_BASE+0x20) -#define ATAC_CH0D0_DMA (MSR_ATAC_BASE+0x21) -#define ATAC_CH0D1_PIO (MSR_ATAC_BASE+0x22) -#define ATAC_CH0D1_DMA (MSR_ATAC_BASE+0x23) -#define ATAC_PCI_ABRTERR (MSR_ATAC_BASE+0x24) -#define ATAC_BM0_CMD_PRIM 0x00 -#define ATAC_BM0_STS_PRIM 0x02 -#define ATAC_BM0_PRD 0x04 -#define CS5535_CABLE_DETECT 0x48 - -/* Format I PIO settings. We seperate out cmd and data for safer timings */ - -static unsigned int cs5535_pio_cmd_timings[5] = -{ 0xF7F4, 0x53F3, 0x13F1, 0x5131, 0x1131 }; -static unsigned int cs5535_pio_dta_timings[5] = -{ 0xF7F4, 0xF173, 0x8141, 0x5131, 0x1131 }; - -static unsigned int cs5535_mwdma_timings[3] = -{ 0x7F0FFFF3, 0x7F035352, 0x7f024241 }; - -static unsigned int cs5535_udma_timings[5] = -{ 0x7F7436A1, 0x7F733481, 0x7F723261, 0x7F713161, 0x7F703061 }; - -/* Macros to check if the register is the reset value - reset value is an - invalid timing and indicates the register has not been set previously */ - -#define CS5535_BAD_PIO(timings) ( (timings&~0x80000000UL) == 0x00009172 ) -#define CS5535_BAD_DMA(timings) ( (timings & 0x000FFFFF) == 0x00077771 ) - -/**** - * cs5535_set_speed - Configure the chipset to the new speed - * @drive: Drive to set up - * @speed: desired speed - * - * cs5535_set_speed() configures the chipset to a new speed. - */ -static void cs5535_set_speed(ide_drive_t *drive, u8 speed) -{ - - u32 reg = 0, dummy; - int unit = drive->select.b.unit; - - - /* Set the PIO timings */ - if ((speed & XFER_MODE) == XFER_PIO) { - u8 pioa; - u8 piob; - u8 cmd; - - pioa = speed - XFER_PIO_0; - piob = ide_get_best_pio_mode(&(drive->hwif->drives[!unit]), - 255, 4, NULL); - cmd = pioa < piob ? pioa : piob; - - /* Write the speed of the current drive */ - reg = (cs5535_pio_cmd_timings[cmd] << 16) | - cs5535_pio_dta_timings[pioa]; - wrmsr(unit ? ATAC_CH0D1_PIO : ATAC_CH0D0_PIO, reg, 0); - - /* And if nessesary - change the speed of the other drive */ - rdmsr(unit ? ATAC_CH0D0_PIO : ATAC_CH0D1_PIO, reg, dummy); - - if (((reg >> 16) & cs5535_pio_cmd_timings[cmd]) != - cs5535_pio_cmd_timings[cmd]) { - reg &= 0x0000FFFF; - reg |= cs5535_pio_cmd_timings[cmd] << 16; - wrmsr(unit ? ATAC_CH0D0_PIO : ATAC_CH0D1_PIO, reg, 0); - } - - /* Set bit 31 of the DMA register for PIO format 1 timings */ - rdmsr(unit ? ATAC_CH0D1_DMA : ATAC_CH0D0_DMA, reg, dummy); - wrmsr(unit ? ATAC_CH0D1_DMA : ATAC_CH0D0_DMA, - reg | 0x80000000UL, 0); - } else { - rdmsr(unit ? ATAC_CH0D1_DMA : ATAC_CH0D0_DMA, reg, dummy); - - reg &= 0x80000000UL; /* Preserve the PIO format bit */ - - if (speed >= XFER_UDMA_0 && speed <= XFER_UDMA_7) - reg |= cs5535_udma_timings[speed - XFER_UDMA_0]; - else if (speed >= XFER_MW_DMA_0 && speed <= XFER_MW_DMA_2) - reg |= cs5535_mwdma_timings[speed - XFER_MW_DMA_0]; - else - return; - - wrmsr(unit ? ATAC_CH0D1_DMA : ATAC_CH0D0_DMA, reg, 0); - } -} - -static u8 cs5535_ratemask(ide_drive_t *drive) -{ - /* eighty93 will return 1 if it's 80core and capable of - exceeding udma2, 0 otherwise. we need ratemask to set - the max speed and if we can > udma2 then we return 2 - which selects speed_max as udma4 which is the 5535's max - speed, and 1 selects udma2 which is the max for 40c */ - if (!eighty_ninty_three(drive)) - return 1; - - return 2; -} - - -/**** - * cs5535_set_drive - Configure the drive to the new speed - * @drive: Drive to set up - * @speed: desired speed - * - * cs5535_set_drive() configures the drive and the chipset to a - * new speed. It also can be called by upper layers. - */ -static int cs5535_set_drive(ide_drive_t *drive, u8 speed) -{ - speed = ide_rate_filter(cs5535_ratemask(drive), speed); - ide_config_drive_speed(drive, speed); - cs5535_set_speed(drive, speed); - - return 0; -} - -/**** - * cs5535_tuneproc - PIO setup - * @drive: drive to set up - * @pio: mode to use (255 for 'best possible') - * - * A callback from the upper layers for PIO-only tuning. - */ -static void cs5535_tuneproc(ide_drive_t *drive, u8 xferspeed) -{ - u8 modes[] = { XFER_PIO_0, XFER_PIO_1, XFER_PIO_2, XFER_PIO_3, - XFER_PIO_4 }; - - /* cs5535 max pio is pio 4, best_pio will check the blacklist. - i think we don't need to rate_filter the incoming xferspeed - since we know we're only going to choose pio */ - xferspeed = ide_get_best_pio_mode(drive, xferspeed, 4, NULL); - ide_config_drive_speed(drive, modes[xferspeed]); - cs5535_set_speed(drive, xferspeed); -} - -static int cs5535_config_drive_for_dma(ide_drive_t *drive) -{ - u8 speed; - - speed = ide_dma_speed(drive, cs5535_ratemask(drive)); - - /* If no DMA speed was available then let dma_check hit pio */ - if (!speed) { - return 0; - } - - cs5535_set_drive(drive, speed); - return ide_dma_enable(drive); -} - -static int cs5535_dma_check(ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - struct hd_driveid *id = drive->id; - u8 speed; - - drive->init_speed = 0; - - if ((id->capability & 1) && drive->autodma) { - if (ide_use_dma(drive)) { - if (cs5535_config_drive_for_dma(drive)) - return hwif->ide_dma_on(drive); - } - - goto fast_ata_pio; - - } else if ((id->capability & 8) || (id->field_valid & 2)) { -fast_ata_pio: - speed = ide_get_best_pio_mode(drive, 255, 4, NULL); - cs5535_set_drive(drive, speed); - return hwif->ide_dma_off_quietly(drive); - } - /* IORDY not supported */ - return 0; -} - -static u8 __devinit cs5535_cable_detect(struct pci_dev *dev) -{ - u8 bit; - - /* if a 80 wire cable was detected */ - pci_read_config_byte(dev, CS5535_CABLE_DETECT, &bit); - return (bit & 1); -} - -/**** - * init_hwif_cs5535 - Initialize one ide cannel - * @hwif: Channel descriptor - * - * This gets invoked by the IDE driver once for each channel. It - * performs channel-specific pre-initialization before drive probing. - * - */ -static void __devinit init_hwif_cs5535(ide_hwif_t *hwif) -{ - int i; - - hwif->autodma = 0; - - hwif->tuneproc = &cs5535_tuneproc; - hwif->speedproc = &cs5535_set_drive; - hwif->ide_dma_check = &cs5535_dma_check; - - hwif->atapi_dma = 1; - hwif->ultra_mask = 0x1F; - hwif->mwdma_mask = 0x07; - - - hwif->udma_four = cs5535_cable_detect(hwif->pci_dev); - - if (!noautodma) - hwif->autodma = 1; - - /* just setting autotune and not worrying about bios timings */ - for (i = 0; i < 2; i++) { - hwif->drives[i].autotune = 1; - hwif->drives[i].autodma = hwif->autodma; - } -} - -static ide_pci_device_t cs5535_chipset __devinitdata = { - .name = "CS5535", - .init_hwif = init_hwif_cs5535, - .channels = 1, - .autodma = AUTODMA, - .bootable = ON_BOARD, -}; - -static int __devinit cs5535_init_one(struct pci_dev *dev, - const struct pci_device_id *id) -{ - return ide_setup_pci_device(dev, &cs5535_chipset); -} - -static struct pci_device_id cs5535_pci_tbl[] = -{ - { PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_IDE, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, - { 0, }, -}; - -MODULE_DEVICE_TABLE(pci, cs5535_pci_tbl); - -static struct pci_driver driver = { - .name = "CS5535_IDE", - .id_table = cs5535_pci_tbl, - .probe = cs5535_init_one, -}; - -static int __init cs5535_ide_init(void) -{ - return ide_pci_register_driver(&driver); -} - -module_init(cs5535_ide_init); - -MODULE_AUTHOR("AMD"); -MODULE_DESCRIPTION("PCI driver module for AMD/NS CS5535 IDE"); -MODULE_LICENSE("GPL"); diff --git a/drivers/ide/pci/cy82c693.c b/drivers/ide/pci/cy82c693.c deleted file mode 100644 index 120929fbe7a..00000000000 --- a/drivers/ide/pci/cy82c693.c +++ /dev/null @@ -1,530 +0,0 @@ -/* - * linux/drivers/ide/pci/cy82c693.c Version 0.40 Sep. 10, 2002 - * - * Copyright (C) 1998-2000 Andreas S. Krebs (akrebs@altavista.net), Maintainer - * Copyright (C) 1998-2002 Andre Hedrick <andre@linux-ide.org>, Integrator - * - * CYPRESS CY82C693 chipset IDE controller - * - * The CY82C693 chipset is used on Digital's PC-Alpha 164SX boards. - * Writing the driver was quite simple, since most of the job is - * done by the generic pci-ide support. - * The hard part was finding the CY82C693's datasheet on Cypress's - * web page :-(. But Altavista solved this problem :-). - * - * - * Notes: - * - I recently got a 16.8G IBM DTTA, so I was able to test it with - * a large and fast disk - the results look great, so I'd say the - * driver is working fine :-) - * hdparm -t reports 8.17 MB/sec at about 6% CPU usage for the DTTA - * - this is my first linux driver, so there's probably a lot of room - * for optimizations and bug fixing, so feel free to do it. - * - use idebus=xx parameter to set PCI bus speed - needed to calc - * timings for PIO modes (default will be 40) - * - if using PIO mode it's a good idea to set the PIO mode and - * 32-bit I/O support (if possible), e.g. hdparm -p2 -c1 /dev/hda - * - I had some problems with my IBM DHEA with PIO modes < 2 - * (lost interrupts) ????? - * - first tests with DMA look okay, they seem to work, but there is a - * problem with sound - the BusMaster IDE TimeOut should fixed this - * - * Ancient History: - * AMH@1999-08-24: v0.34 init_cy82c693_chip moved to pci_init_cy82c693 - * ASK@1999-01-23: v0.33 made a few minor code clean ups - * removed DMA clock speed setting by default - * added boot message - * ASK@1998-11-01: v0.32 added support to set BusMaster IDE TimeOut - * added support to set DMA Controller Clock Speed - * ASK@1998-10-31: v0.31 fixed problem with setting to high DMA modes - * on some drives. - * ASK@1998-10-29: v0.3 added support to set DMA modes - * ASK@1998-10-28: v0.2 added support to set PIO modes - * ASK@1998-10-27: v0.1 first version - chipset detection - * - */ - -#include <linux/module.h> -#include <linux/types.h> -#include <linux/pci.h> -#include <linux/delay.h> -#include <linux/ide.h> -#include <linux/init.h> - -#include <asm/io.h> - -/* the current version */ -#define CY82_VERSION "CY82C693U driver v0.34 99-13-12 Andreas S. Krebs (akrebs@altavista.net)" - -/* - * The following are used to debug the driver. - */ -#define CY82C693_DEBUG_LOGS 0 -#define CY82C693_DEBUG_INFO 0 - -/* define CY82C693_SETDMA_CLOCK to set DMA Controller Clock Speed to ATCLK */ -#undef CY82C693_SETDMA_CLOCK - -/* - * NOTE: the value for busmaster timeout is tricky and I got it by - * trial and error! By using a to low value will cause DMA timeouts - * and drop IDE performance, and by using a to high value will cause - * audio playback to scatter. - * If you know a better value or how to calc it, please let me know. - */ - -/* twice the value written in cy82c693ub datasheet */ -#define BUSMASTER_TIMEOUT 0x50 -/* - * the value above was tested on my machine and it seems to work okay - */ - -/* here are the offset definitions for the registers */ -#define CY82_IDE_CMDREG 0x04 -#define CY82_IDE_ADDRSETUP 0x48 -#define CY82_IDE_MASTER_IOR 0x4C -#define CY82_IDE_MASTER_IOW 0x4D -#define CY82_IDE_SLAVE_IOR 0x4E -#define CY82_IDE_SLAVE_IOW 0x4F -#define CY82_IDE_MASTER_8BIT 0x50 -#define CY82_IDE_SLAVE_8BIT 0x51 - -#define CY82_INDEX_PORT 0x22 -#define CY82_DATA_PORT 0x23 - -#define CY82_INDEX_CTRLREG1 0x01 -#define CY82_INDEX_CHANNEL0 0x30 -#define CY82_INDEX_CHANNEL1 0x31 -#define CY82_INDEX_TIMEOUT 0x32 - -/* the max PIO mode - from datasheet */ -#define CY82C693_MAX_PIO 4 - -/* the min and max PCI bus speed in MHz - from datasheet */ -#define CY82C963_MIN_BUS_SPEED 25 -#define CY82C963_MAX_BUS_SPEED 33 - -/* the struct for the PIO mode timings */ -typedef struct pio_clocks_s { - u8 address_time; /* Address setup (clocks) */ - u8 time_16r; /* clocks for 16bit IOR (0xF0=Active/data, 0x0F=Recovery) */ - u8 time_16w; /* clocks for 16bit IOW (0xF0=Active/data, 0x0F=Recovery) */ - u8 time_8; /* clocks for 8bit (0xF0=Active/data, 0x0F=Recovery) */ -} pio_clocks_t; - -/* - * calc clocks using bus_speed - * returns (rounded up) time in bus clocks for time in ns - */ -static int calc_clk (int time, int bus_speed) -{ - int clocks; - - clocks = (time*bus_speed+999)/1000 -1; - - if (clocks < 0) - clocks = 0; - - if (clocks > 0x0F) - clocks = 0x0F; - - return clocks; -} - -/* - * compute the values for the clock registers for PIO - * mode and pci_clk [MHz] speed - * - * NOTE: for mode 0,1 and 2 drives 8-bit IDE command control registers are used - * for mode 3 and 4 drives 8 and 16-bit timings are the same - * - */ -static void compute_clocks (u8 pio, pio_clocks_t *p_pclk) -{ - int clk1, clk2; - int bus_speed = system_bus_clock(); /* get speed of PCI bus */ - - /* we don't check against CY82C693's min and max speed, - * so you can play with the idebus=xx parameter - */ - - if (pio > CY82C693_MAX_PIO) - pio = CY82C693_MAX_PIO; - - /* let's calc the address setup time clocks */ - p_pclk->address_time = (u8)calc_clk(ide_pio_timings[pio].setup_time, bus_speed); - - /* let's calc the active and recovery time clocks */ - clk1 = calc_clk(ide_pio_timings[pio].active_time, bus_speed); - - /* calc recovery timing */ - clk2 = ide_pio_timings[pio].cycle_time - - ide_pio_timings[pio].active_time - - ide_pio_timings[pio].setup_time; - - clk2 = calc_clk(clk2, bus_speed); - - clk1 = (clk1<<4)|clk2; /* combine active and recovery clocks */ - - /* note: we use the same values for 16bit IOR and IOW - * those are all the same, since I don't have other - * timings than those from ide-lib.c - */ - - p_pclk->time_16r = (u8)clk1; - p_pclk->time_16w = (u8)clk1; - - /* what are good values for 8bit ?? */ - p_pclk->time_8 = (u8)clk1; -} - -/* - * set DMA mode a specific channel for CY82C693 - */ - -static void cy82c693_dma_enable (ide_drive_t *drive, int mode, int single) -{ - u8 index = 0, data = 0; - - if (mode>2) /* make sure we set a valid mode */ - mode = 2; - - if (mode > drive->id->tDMA) /* to be absolutly sure we have a valid mode */ - mode = drive->id->tDMA; - - index = (HWIF(drive)->channel==0) ? CY82_INDEX_CHANNEL0 : CY82_INDEX_CHANNEL1; - -#if CY82C693_DEBUG_LOGS - /* for debug let's show the previous values */ - - HWIF(drive)->OUTB(index, CY82_INDEX_PORT); - data = HWIF(drive)->INB(CY82_DATA_PORT); - - printk (KERN_INFO "%s (ch=%d, dev=%d): DMA mode is %d (single=%d)\n", - drive->name, HWIF(drive)->channel, drive->select.b.unit, - (data&0x3), ((data>>2)&1)); -#endif /* CY82C693_DEBUG_LOGS */ - - data = (u8)mode|(u8)(single<<2); - - HWIF(drive)->OUTB(index, CY82_INDEX_PORT); - HWIF(drive)->OUTB(data, CY82_DATA_PORT); - -#if CY82C693_DEBUG_INFO - printk(KERN_INFO "%s (ch=%d, dev=%d): set DMA mode to %d (single=%d)\n", - drive->name, HWIF(drive)->channel, drive->select.b.unit, - mode, single); -#endif /* CY82C693_DEBUG_INFO */ - - /* - * note: below we set the value for Bus Master IDE TimeOut Register - * I'm not absolutly sure what this does, but it solved my problem - * with IDE DMA and sound, so I now can play sound and work with - * my IDE driver at the same time :-) - * - * If you know the correct (best) value for this register please - * let me know - ASK - */ - - data = BUSMASTER_TIMEOUT; - HWIF(drive)->OUTB(CY82_INDEX_TIMEOUT, CY82_INDEX_PORT); - HWIF(drive)->OUTB(data, CY82_DATA_PORT); - -#if CY82C693_DEBUG_INFO - printk (KERN_INFO "%s: Set IDE Bus Master TimeOut Register to 0x%X\n", - drive->name, data); -#endif /* CY82C693_DEBUG_INFO */ -} - -/* - * used to set DMA mode for CY82C693 (single and multi modes) - */ -static int cy82c693_ide_dma_on (ide_drive_t *drive) -{ - struct hd_driveid *id = drive->id; - -#if CY82C693_DEBUG_INFO - printk (KERN_INFO "dma_on: %s\n", drive->name); -#endif /* CY82C693_DEBUG_INFO */ - - if (id != NULL) { - /* Enable DMA on any drive that has DMA - * (multi or single) enabled - */ - if (id->field_valid & 2) { /* regular DMA */ - int mmode, smode; - - mmode = id->dma_mword & (id->dma_mword >> 8); - smode = id->dma_1word & (id->dma_1word >> 8); - - if (mmode != 0) { - /* enable multi */ - cy82c693_dma_enable(drive, (mmode >> 1), 0); - } else if (smode != 0) { - /* enable single */ - cy82c693_dma_enable(drive, (smode >> 1), 1); - } - } - } - return __ide_dma_on(drive); -} - -/* - * tune ide drive - set PIO mode - */ -static void cy82c693_tune_drive (ide_drive_t *drive, u8 pio) -{ - ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; - pio_clocks_t pclk; - unsigned int addrCtrl; - - /* select primary or secondary channel */ - if (hwif->index > 0) { /* drive is on the secondary channel */ - dev = pci_find_slot(dev->bus->number, dev->devfn+1); - if (!dev) { - printk(KERN_ERR "%s: tune_drive: " - "Cannot find secondary interface!\n", - drive->name); - return; - } - } - -#if CY82C693_DEBUG_LOGS - /* for debug let's show the register values */ - - if (drive->select.b.unit == 0) { - /* - * get master drive registers - * address setup control register - * is 32 bit !!! - */ - pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl); - addrCtrl &= 0x0F; - - /* now let's get the remaining registers */ - pci_read_config_byte(dev, CY82_IDE_MASTER_IOR, &pclk.time_16r); - pci_read_config_byte(dev, CY82_IDE_MASTER_IOW, &pclk.time_16w); - pci_read_config_byte(dev, CY82_IDE_MASTER_8BIT, &pclk.time_8); - } else { - /* - * set slave drive registers - * address setup control register - * is 32 bit !!! - */ - pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl); - - addrCtrl &= 0xF0; - addrCtrl >>= 4; - - /* now let's get the remaining registers */ - pci_read_config_byte(dev, CY82_IDE_SLAVE_IOR, &pclk.time_16r); - pci_read_config_byte(dev, CY82_IDE_SLAVE_IOW, &pclk.time_16w); - pci_read_config_byte(dev, CY82_IDE_SLAVE_8BIT, &pclk.time_8); - } - - printk(KERN_INFO "%s (ch=%d, dev=%d): PIO timing is " - "(addr=0x%X, ior=0x%X, iow=0x%X, 8bit=0x%X)\n", - drive->name, hwif->channel, drive->select.b.unit, - addrCtrl, pclk.time_16r, pclk.time_16w, pclk.time_8); -#endif /* CY82C693_DEBUG_LOGS */ - - /* first let's calc the pio modes */ - pio = ide_get_best_pio_mode(drive, pio, CY82C693_MAX_PIO, NULL); - -#if CY82C693_DEBUG_INFO - printk (KERN_INFO "%s: Selected PIO mode %d\n", drive->name, pio); -#endif /* CY82C693_DEBUG_INFO */ - - /* let's calc the values for this PIO mode */ - compute_clocks(pio, &pclk); - - /* now let's write the clocks registers */ - if (drive->select.b.unit == 0) { - /* - * set master drive - * address setup control register - * is 32 bit !!! - */ - pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl); - - addrCtrl &= (~0xF); - addrCtrl |= (unsigned int)pclk.address_time; - pci_write_config_dword(dev, CY82_IDE_ADDRSETUP, addrCtrl); - - /* now let's set the remaining registers */ - pci_write_config_byte(dev, CY82_IDE_MASTER_IOR, pclk.time_16r); - pci_write_config_byte(dev, CY82_IDE_MASTER_IOW, pclk.time_16w); - pci_write_config_byte(dev, CY82_IDE_MASTER_8BIT, pclk.time_8); - - addrCtrl &= 0xF; - } else { - /* - * set slave drive - * address setup control register - * is 32 bit !!! - */ - pci_read_config_dword(dev, CY82_IDE_ADDRSETUP, &addrCtrl); - - addrCtrl &= (~0xF0); - addrCtrl |= ((unsigned int)pclk.address_time<<4); - pci_write_config_dword(dev, CY82_IDE_ADDRSETUP, addrCtrl); - - /* now let's set the remaining registers */ - pci_write_config_byte(dev, CY82_IDE_SLAVE_IOR, pclk.time_16r); - pci_write_config_byte(dev, CY82_IDE_SLAVE_IOW, pclk.time_16w); - pci_write_config_byte(dev, CY82_IDE_SLAVE_8BIT, pclk.time_8); - - addrCtrl >>= 4; - addrCtrl &= 0xF; - } - -#if CY82C693_DEBUG_INFO - printk(KERN_INFO "%s (ch=%d, dev=%d): set PIO timing to " - "(addr=0x%X, ior=0x%X, iow=0x%X, 8bit=0x%X)\n", - drive->name, hwif->channel, drive->select.b.unit, - addrCtrl, pclk.time_16r, pclk.time_16w, pclk.time_8); -#endif /* CY82C693_DEBUG_INFO */ -} - -/* - * this function is called during init and is used to setup the cy82c693 chip - */ -static unsigned int __devinit init_chipset_cy82c693(struct pci_dev *dev, const char *name) -{ - if (PCI_FUNC(dev->devfn) != 1) - return 0; - -#ifdef CY82C693_SETDMA_CLOCK - u8 data = 0; -#endif /* CY82C693_SETDMA_CLOCK */ - - /* write info about this verion of the driver */ - printk(KERN_INFO CY82_VERSION "\n"); - -#ifdef CY82C693_SETDMA_CLOCK - /* okay let's set the DMA clock speed */ - - outb(CY82_INDEX_CTRLREG1, CY82_INDEX_PORT); - data = inb(CY82_DATA_PORT); - -#if CY82C693_DEBUG_INFO - printk(KERN_INFO "%s: Peripheral Configuration Register: 0x%X\n", - name, data); -#endif /* CY82C693_DEBUG_INFO */ - - /* - * for some reason sometimes the DMA controller - * speed is set to ATCLK/2 ???? - we fix this here - * - * note: i don't know what causes this strange behaviour, - * but even changing the dma speed doesn't solve it :-( - * the ide performance is still only half the normal speed - * - * if anybody knows what goes wrong with my machine, please - * let me know - ASK - */ - - data |= 0x03; - - outb(CY82_INDEX_CTRLREG1, CY82_INDEX_PORT); - outb(data, CY82_DATA_PORT); - -#if CY82C693_DEBUG_INFO - printk (KERN_INFO "%s: New Peripheral Configuration Register: 0x%X\n", - name, data); -#endif /* CY82C693_DEBUG_INFO */ - -#endif /* CY82C693_SETDMA_CLOCK */ - return 0; -} - -/* - * the init function - called for each ide channel once - */ -static void __devinit init_hwif_cy82c693(ide_hwif_t *hwif) -{ - hwif->autodma = 0; - - hwif->chipset = ide_cy82c693; - hwif->tuneproc = &cy82c693_tune_drive; - - if (!hwif->dma_base) { - hwif->drives[0].autotune = 1; - hwif->drives[1].autotune = 1; - return; - } - - hwif->atapi_dma = 1; - hwif->mwdma_mask = 0x04; - hwif->swdma_mask = 0x04; - - hwif->ide_dma_on = &cy82c693_ide_dma_on; - if (!noautodma) - hwif->autodma = 1; - hwif->drives[0].autodma = hwif->autodma; - hwif->drives[1].autodma = hwif->autodma; -} - -static __devinitdata ide_hwif_t *primary; - -static void __devinit init_iops_cy82c693(ide_hwif_t *hwif) -{ - if (PCI_FUNC(hwif->pci_dev->devfn) == 1) - primary = hwif; - else { - hwif->mate = primary; - hwif->channel = 1; - } -} - -static ide_pci_device_t cy82c693_chipsets[] __devinitdata = { - { /* 0 */ - .name = "CY82C693", - .init_chipset = init_chipset_cy82c693, - .init_iops = init_iops_cy82c693, - .init_hwif = init_hwif_cy82c693, - .channels = 1, - .autodma = AUTODMA, - .bootable = ON_BOARD, - } -}; - -static int __devinit cy82c693_init_one(struct pci_dev *dev, const struct pci_device_id *id) -{ - ide_pci_device_t *d = &cy82c693_chipsets[id->driver_data]; - struct pci_dev *dev2; - int ret = -ENODEV; - - /* CY82C693 is more than only a IDE controller. - Function 1 is primary IDE channel, function 2 - secondary. */ - if ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE && - PCI_FUNC(dev->devfn) == 1) { - dev2 = pci_find_slot(dev->bus->number, dev->devfn + 1); - ret = ide_setup_pci_devices(dev, dev2, d); - } - return ret; -} - -static struct pci_device_id cy82c693_pci_tbl[] = { - { PCI_VENDOR_ID_CONTAQ, PCI_DEVICE_ID_CONTAQ_82C693, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - { 0, }, -}; -MODULE_DEVICE_TABLE(pci, cy82c693_pci_tbl); - -static struct pci_driver driver = { - .name = "Cypress_IDE", - .id_table = cy82c693_pci_tbl, - .probe = cy82c693_init_one, -}; - -static int cy82c693_ide_init(void) -{ - return ide_pci_register_driver(&driver); -} - -module_init(cy82c693_ide_init); - -MODULE_AUTHOR("Andreas Krebs, Andre Hedrick"); -MODULE_DESCRIPTION("PCI driver module for the Cypress CY82C693 IDE"); -MODULE_LICENSE("GPL"); diff --git a/drivers/ide/pci/generic.c b/drivers/ide/pci/generic.c deleted file mode 100644 index 78810ba982e..00000000000 --- a/drivers/ide/pci/generic.c +++ /dev/null @@ -1,301 +0,0 @@ -/* - * linux/drivers/ide/pci/generic.c Version 0.11 December 30, 2002 - * - * Copyright (C) 2001-2002 Andre Hedrick <andre@linux-ide.org> - * Portions (C) Copyright 2002 Red Hat Inc <alan@redhat.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * For the avoidance of doubt the "preferred form" of this code is one which - * is in an open non patent encumbered format. Where cryptographic key signing - * forms part of the process of creating an executable the information - * including keys needed to generate an equivalently functional executable - * are deemed to be part of the source code. - */ - -#undef REALLY_SLOW_IO /* most systems can safely undef this */ - -#include <linux/config.h> /* for CONFIG_BLK_DEV_IDEPCI */ -#include <linux/types.h> -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/delay.h> -#include <linux/timer.h> -#include <linux/mm.h> -#include <linux/ioport.h> -#include <linux/blkdev.h> -#include <linux/hdreg.h> -#include <linux/pci.h> -#include <linux/ide.h> -#include <linux/init.h> - -#include <asm/io.h> - -static int ide_generic_all; /* Set to claim all devices */ - -#ifndef MODULE -static int __init ide_generic_all_on(char *unused) -{ - ide_generic_all = 1; - printk(KERN_INFO "IDE generic will claim all unknown PCI IDE storage controllers.\n"); - return 1; -} -__setup("all-generic-ide", ide_generic_all_on); -#endif - -static void __devinit init_hwif_generic (ide_hwif_t *hwif) -{ - switch(hwif->pci_dev->device) { - case PCI_DEVICE_ID_UMC_UM8673F: - case PCI_DEVICE_ID_UMC_UM8886A: - case PCI_DEVICE_ID_UMC_UM8886BF: - hwif->irq = hwif->channel ? 15 : 14; - break; - default: - break; - } - - if (!(hwif->dma_base)) - return; - - hwif->atapi_dma = 1; - hwif->ultra_mask = 0x7f; - hwif->mwdma_mask = 0x07; - hwif->swdma_mask = 0x07; - - if (!noautodma) - hwif->autodma = 1; - hwif->drives[0].autodma = hwif->autodma; - hwif->drives[1].autodma = hwif->autodma; -} - -#if 0 - /* Logic to add back later on */ - - if ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE) { - ide_pci_device_t *unknown = unknown_chipset; - init_setup_unknown(dev, unknown); - return 1; - } - return 0; -#endif - -static ide_pci_device_t generic_chipsets[] __devinitdata = { - { /* 0 */ - .name = "Unknown", - .init_hwif = init_hwif_generic, - .channels = 2, - .autodma = AUTODMA, - .bootable = ON_BOARD, - },{ /* 1 */ - .name = "NS87410", - .init_hwif = init_hwif_generic, - .channels = 2, - .autodma = AUTODMA, - .enablebits = {{0x43,0x08,0x08}, {0x47,0x08,0x08}}, - .bootable = ON_BOARD, - },{ /* 2 */ - .name = "SAMURAI", - .init_hwif = init_hwif_generic, - .channels = 2, - .autodma = AUTODMA, - .bootable = ON_BOARD, - },{ /* 3 */ - .name = "HT6565", - .init_hwif = init_hwif_generic, - .channels = 2, - .autodma = AUTODMA, - .bootable = ON_BOARD, - },{ /* 4 */ - .name = "UM8673F", - .init_hwif = init_hwif_generic, - .channels = 2, - .autodma = NODMA, - .bootable = ON_BOARD, - },{ /* 5 */ - .name = "UM8886A", - .init_hwif = init_hwif_generic, - .channels = 2, - .autodma = NODMA, - .bootable = ON_BOARD, - },{ /* 6 */ - .name = "UM8886BF", - .init_hwif = init_hwif_generic, - .channels = 2, - .autodma = NODMA, - .bootable = ON_BOARD, - },{ /* 7 */ - .name = "HINT_IDE", - .init_hwif = init_hwif_generic, - .channels = 2, - .autodma = AUTODMA, - .bootable = ON_BOARD, - },{ /* 8 */ - .name = "VIA_IDE", - .init_hwif = init_hwif_generic, - .channels = 2, - .autodma = NOAUTODMA, - .bootable = ON_BOARD, - },{ /* 9 */ - .name = "OPTI621V", - .init_hwif = init_hwif_generic, - .channels = 2, - .autodma = NOAUTODMA, - .bootable = ON_BOARD, - },{ /* 10 */ - .name = "VIA8237SATA", - .init_hwif = init_hwif_generic, - .channels = 2, - .autodma = AUTODMA, - .bootable = OFF_BOARD, - },{ /* 11 */ - .name = "Piccolo0102", - .init_hwif = init_hwif_generic, - .channels = 2, - .autodma = NOAUTODMA, - .bootable = ON_BOARD, - },{ /* 12 */ - .name = "Piccolo0103", - .init_hwif = init_hwif_generic, - .channels = 2, - .autodma = NOAUTODMA, - .bootable = ON_BOARD, - },{ /* 13 */ - .name = "Piccolo0105", - .init_hwif = init_hwif_generic, - .channels = 2, - .autodma = NOAUTODMA, - .bootable = ON_BOARD, - },{ /* 14 */ - .name = "Revolution", - .init_hwif = init_hwif_generic, - .channels = 2, - .autodma = AUTODMA, - .bootable = OFF_BOARD, - },{ /* 15 */ - .name = "JMB361", - .init_hwif = init_hwif_generic, - .channels = 2, - .autodma = AUTODMA, - .bootable = OFF_BOARD, - },{ /* 16 */ - .name = "JMB363", - .init_hwif = init_hwif_generic, - .channels = 2, - .autodma = AUTODMA, - .bootable = OFF_BOARD, - },{ /* 17 */ - .name = "JMB365", - .init_hwif = init_hwif_generic, - .channels = 2, - .autodma = AUTODMA, - .bootable = OFF_BOARD, - },{ /* 18 */ - .name = "JMB366", - .init_hwif = init_hwif_generic, - .channels = 2, - .autodma = AUTODMA, - .bootable = OFF_BOARD, - },{ /* 19 */ - .name = "JMB368", - .init_hwif = init_hwif_generic, - .channels = 2, - .autodma = AUTODMA, - .bootable = OFF_BOARD, - } -}; - -/** - * generic_init_one - called when a PIIX is found - * @dev: the generic device - * @id: the matching pci id - * - * Called when the PCI registration layer (or the IDE initialization) - * finds a device matching our IDE device tables. - */ - -static int __devinit generic_init_one(struct pci_dev *dev, const struct pci_device_id *id) -{ - ide_pci_device_t *d = &generic_chipsets[id->driver_data]; - u16 command; - int ret = -ENODEV; - - /* Don't use the generic entry unless instructed to do so */ - if (id->driver_data == 0 && ide_generic_all == 0) - goto out; - - if (dev->vendor == PCI_VENDOR_ID_UMC && - dev->device == PCI_DEVICE_ID_UMC_UM8886A && - (!(PCI_FUNC(dev->devfn) & 1))) - goto out; /* UM8886A/BF pair */ - - if (dev->vendor == PCI_VENDOR_ID_OPTI && - dev->device == PCI_DEVICE_ID_OPTI_82C558 && - (!(PCI_FUNC(dev->devfn) & 1))) - goto out; - - if (dev->vendor == PCI_VENDOR_ID_JMICRON && PCI_FUNC(dev->devfn) != 1) - goto out; - - pci_read_config_word(dev, PCI_COMMAND, &command); - if (!(command & PCI_COMMAND_IO)) { - printk(KERN_INFO "Skipping disabled %s IDE controller.\n", d->name); - goto out; - } - ret = ide_setup_pci_device(dev, d); -out: - return ret; -} - -static struct pci_device_id generic_pci_tbl[] = { - { PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87410, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1}, - { PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_SAMURAI_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2}, - { PCI_VENDOR_ID_HOLTEK, PCI_DEVICE_ID_HOLTEK_6565, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3}, - { PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8673F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4}, - { PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5}, - { PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886BF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6}, - { PCI_VENDOR_ID_HINT, PCI_DEVICE_ID_HINT_VXPROII_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 7}, - { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C561, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8}, - { PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C558, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 9}, -#ifdef CONFIG_BLK_DEV_IDE_SATA - { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237_SATA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 10}, -#endif - { PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 11}, - { PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 12}, - { PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 13}, - { PCI_VENDOR_ID_NETCELL,PCI_DEVICE_ID_REVOLUTION, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 14}, - { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB361, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 15}, - { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB363, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 16}, - { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB365, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 17}, - { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB366, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 18}, - { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB368, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 19}, - /* Must come last. If you add entries adjust this table appropriately and the init_one code */ - { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xFFFFFF00UL, 0}, - { 0, }, -}; -MODULE_DEVICE_TABLE(pci, generic_pci_tbl); - -static struct pci_driver driver = { - .name = "PCI_IDE", - .id_table = generic_pci_tbl, - .probe = generic_init_one, -}; - -static int generic_ide_init(void) -{ - return ide_pci_register_driver(&driver); -} - -module_init(generic_ide_init); - -MODULE_AUTHOR("Andre Hedrick"); -MODULE_DESCRIPTION("PCI driver module for generic PCI IDE"); -MODULE_LICENSE("GPL"); diff --git a/drivers/ide/pci/hpt34x.c b/drivers/ide/pci/hpt34x.c deleted file mode 100644 index b46cb042290..00000000000 --- a/drivers/ide/pci/hpt34x.c +++ /dev/null @@ -1,277 +0,0 @@ -/* - * linux/drivers/ide/pci/hpt34x.c Version 0.40 Sept 10, 2002 - * - * Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org> - * May be copied or modified under the terms of the GNU General Public License - * - * - * 00:12.0 Unknown mass storage controller: - * Triones Technologies, Inc. - * Unknown device 0003 (rev 01) - * - * hde: UDMA 2 (0x0000 0x0002) (0x0000 0x0010) - * hdf: UDMA 2 (0x0002 0x0012) (0x0010 0x0030) - * hde: DMA 2 (0x0000 0x0002) (0x0000 0x0010) - * hdf: DMA 2 (0x0002 0x0012) (0x0010 0x0030) - * hdg: DMA 1 (0x0012 0x0052) (0x0030 0x0070) - * hdh: DMA 1 (0x0052 0x0252) (0x0070 0x00f0) - * - * ide-pci.c reference - * - * Since there are two cards that report almost identically, - * the only discernable difference is the values reported in pcicmd. - * Booting-BIOS card or HPT363 :: pcicmd == 0x07 - * Non-bootable card or HPT343 :: pcicmd == 0x05 - */ - -#include <linux/module.h> -#include <linux/types.h> -#include <linux/kernel.h> -#include <linux/delay.h> -#include <linux/timer.h> -#include <linux/mm.h> -#include <linux/ioport.h> -#include <linux/blkdev.h> -#include <linux/hdreg.h> -#include <linux/interrupt.h> -#include <linux/pci.h> -#include <linux/init.h> -#include <linux/ide.h> - -#include <asm/io.h> -#include <asm/irq.h> - -#define HPT343_DEBUG_DRIVE_INFO 0 - -static u8 hpt34x_ratemask (ide_drive_t *drive) -{ - return 1; -} - -static void hpt34x_clear_chipset (ide_drive_t *drive) -{ - struct pci_dev *dev = HWIF(drive)->pci_dev; - u32 reg1 = 0, tmp1 = 0, reg2 = 0, tmp2 = 0; - - pci_read_config_dword(dev, 0x44, ®1); - pci_read_config_dword(dev, 0x48, ®2); - tmp1 = ((0x00 << (3*drive->dn)) | (reg1 & ~(7 << (3*drive->dn)))); - tmp2 = (reg2 & ~(0x11 << drive->dn)); - pci_write_config_dword(dev, 0x44, tmp1); - pci_write_config_dword(dev, 0x48, tmp2); -} - -static int hpt34x_tune_chipset (ide_drive_t *drive, u8 xferspeed) -{ - struct pci_dev *dev = HWIF(drive)->pci_dev; - u8 speed = ide_rate_filter(hpt34x_ratemask(drive), xferspeed); - u32 reg1= 0, tmp1 = 0, reg2 = 0, tmp2 = 0; - u8 hi_speed, lo_speed; - - hi_speed = speed >> 4; - lo_speed = speed & 0x0f; - - if (hi_speed & 7) { - hi_speed = (hi_speed & 4) ? 0x01 : 0x10; - } else { - lo_speed <<= 5; - lo_speed >>= 5; - } - - pci_read_config_dword(dev, 0x44, ®1); - pci_read_config_dword(dev, 0x48, ®2); - tmp1 = ((lo_speed << (3*drive->dn)) | (reg1 & ~(7 << (3*drive->dn)))); - tmp2 = ((hi_speed << drive->dn) | reg2); - pci_write_config_dword(dev, 0x44, tmp1); - pci_write_config_dword(dev, 0x48, tmp2); - -#if HPT343_DEBUG_DRIVE_INFO - printk("%s: %s drive%d (0x%04x 0x%04x) (0x%04x 0x%04x)" \ - " (0x%02x 0x%02x)\n", - drive->name, ide_xfer_verbose(speed), - drive->dn, reg1, tmp1, reg2, tmp2, - hi_speed, lo_speed); -#endif /* HPT343_DEBUG_DRIVE_INFO */ - - return(ide_config_drive_speed(drive, speed)); -} - -static void hpt34x_tune_drive (ide_drive_t *drive, u8 pio) -{ - pio = ide_get_best_pio_mode(drive, pio, 5, NULL); - hpt34x_clear_chipset(drive); - (void) hpt34x_tune_chipset(drive, (XFER_PIO_0 + pio)); -} - -/* - * This allows the configuration of ide_pci chipset registers - * for cards that learn about the drive's UDMA, DMA, PIO capabilities - * after the drive is reported by the OS. Initially for designed for - * HPT343 UDMA chipset by HighPoint|Triones Technologies, Inc. - */ - -static int config_chipset_for_dma (ide_drive_t *drive) -{ - u8 speed = ide_dma_speed(drive, hpt34x_ratemask(drive)); - - if (!(speed)) - return 0; - - hpt34x_clear_chipset(drive); - (void) hpt34x_tune_chipset(drive, speed); - return ide_dma_enable(drive); -} - -static int hpt34x_config_drive_xfer_rate (ide_drive_t *drive) -{ - ide_hwif_t *hwif = HWIF(drive); - struct hd_driveid *id = drive->id; - - drive->init_speed = 0; - - if (id && (id->capability & 1) && drive->autodma) { - - if (ide_use_dma(drive)) { - if (config_chipset_for_dma(drive)) -#ifndef CONFIG_HPT34X_AUTODMA - return hwif->ide_dma_off_quietly(drive); -#else - return hwif->ide_dma_on(drive); -#endif - } - - goto fast_ata_pio; - - } else if ((id->capability & 8) || (id->field_valid & 2)) { -fast_ata_pio: - hpt34x_tune_drive(drive, 255); - return hwif->ide_dma_off_quietly(drive); - } - /* IORDY not supported */ - return 0; -} - -/* - * If the BIOS does not set the IO base addaress to XX00, 343 will fail. - */ -#define HPT34X_PCI_INIT_REG 0x80 - -static unsigned int __devinit init_chipset_hpt34x(struct pci_dev *dev, const char *name) -{ - int i = 0; - unsigned long hpt34xIoBase = pci_resource_start(dev, 4); - unsigned long hpt_addr[4] = { 0x20, 0x34, 0x28, 0x3c }; - unsigned long hpt_addr_len[4] = { 7, 3, 7, 3 }; - u16 cmd; - unsigned long flags; - - local_irq_save(flags); - - pci_write_config_byte(dev, HPT34X_PCI_INIT_REG, 0x00); - pci_read_config_word(dev, PCI_COMMAND, &cmd); - - if (cmd & PCI_COMMAND_MEMORY) { - if (pci_resource_start(dev, PCI_ROM_RESOURCE)) { - pci_write_config_dword(dev, PCI_ROM_ADDRESS, - dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE); - printk(KERN_INFO "HPT345: ROM enabled at 0x%08lx\n", - (unsigned long)dev->resource[PCI_ROM_RESOURCE].start); - } - pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xF0); - } else { - pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x20); - } - - /* - * Since 20-23 can be assigned and are R/W, we correct them. - */ - pci_write_config_word(dev, PCI_COMMAND, cmd & ~PCI_COMMAND_IO); - for(i=0; i<4; i++) { - dev->resource[i].start = (hpt34xIoBase + hpt_addr[i]); - dev->resource[i].end = dev->resource[i].start + hpt_addr_len[i]; - dev->resource[i].flags = IORESOURCE_IO; - pci_write_config_dword(dev, - (PCI_BASE_ADDRESS_0 + (i * 4)), - dev->resource[i].start); - } - pci_write_config_word(dev, PCI_COMMAND, cmd); - - local_irq_restore(flags); - - return dev->irq; -} - -static void __devinit init_hwif_hpt34x(ide_hwif_t *hwif) -{ - u16 pcicmd = 0; - - hwif->autodma = 0; - - hwif->tuneproc = &hpt34x_tune_drive; - hwif->speedproc = &hpt34x_tune_chipset; - hwif->no_dsc = 1; - hwif->drives[0].autotune = 1; - hwif->drives[1].autotune = 1; - - pci_read_config_word(hwif->pci_dev, PCI_COMMAND, &pcicmd); - - if (!hwif->dma_base) - return; - - hwif->ultra_mask = 0x07; - hwif->mwdma_mask = 0x07; - hwif->swdma_mask = 0x07; - - hwif->ide_dma_check = &hpt34x_config_drive_xfer_rate; - if (!noautodma) - hwif->autodma = (pcicmd & PCI_COMMAND_MEMORY) ? 1 : 0; - hwif->drives[0].autodma = hwif->autodma; - hwif->drives[1].autodma = hwif->autodma; -} - -static ide_pci_device_t hpt34x_chipset __devinitdata = { - .name = "HPT34X", - .init_chipset = init_chipset_hpt34x, - .init_hwif = init_hwif_hpt34x, - .channels = 2, - .autodma = NOAUTODMA, - .bootable = NEVER_BOARD, - .extra = 16 -}; - -static int __devinit hpt34x_init_one(struct pci_dev *dev, const struct pci_device_id *id) -{ - ide_pci_device_t *d = &hpt34x_chipset; - static char *chipset_names[] = {"HPT343", "HPT345"}; - u16 pcicmd = 0; - - pci_read_config_word(dev, PCI_COMMAND, &pcicmd); - - d->name = chipset_names[(pcicmd & PCI_COMMAND_MEMORY) ? 1 : 0]; - d->bootable = (pcicmd & PCI_COMMAND_MEMORY) ? OFF_BOARD : NEVER_BOARD; - - return ide_setup_pci_device(dev, d); -} - -static struct pci_device_id hpt34x_pci_tbl[] = { - { PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT343, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - { 0, }, -}; -MODULE_DEVICE_TABLE(pci, hpt34x_pci_tbl); - -static struct pci_driver driver = { - .name = "HPT34x_IDE", - .id_table = hpt34x_pci_tbl, - .probe = hpt34x_init_one, -}; - -static int hpt34x_ide_init(void) -{ - return ide_pci_register_driver(&driver); -} - -module_init(hpt34x_ide_init); - -MODULE_AUTHOR("Andre Hedrick"); -MODULE_DESCRIPTION("PCI driver module for Highpoint 34x IDE"); -MODULE_LICENSE("GPL"); diff --git a/drivers/ide/pci/hpt366.c b/drivers/ide/pci/hpt366.c deleted file mode 100644 index e993a51f250..00000000000 --- a/drivers/ide/pci/hpt366.c +++ /dev/null @@ -1,1737 +0,0 @@ -/* - * linux/drivers/ide/pci/hpt366.c Version 0.36 April 25, 2003 - * - * Copyright (C) 1999-2003 Andre Hedrick <andre@linux-ide.org> - * Portions Copyright (C) 2001 Sun Microsystems, Inc. - * Portions Copyright (C) 2003 Red Hat Inc - * - * Thanks to HighPoint Technologies for their assistance, and hardware. - * Special Thanks to Jon Burchmore in SanDiego for the deep pockets, his - * donation of an ABit BP6 mainboard, processor, and memory acellerated - * development and support. - * - * - * Highpoint have their own driver (source except for the raid part) - * available from http://www.highpoint-tech.com/hpt3xx-opensource-v131.tgz - * This may be useful to anyone wanting to work on the mainstream hpt IDE. - * - * Note that final HPT370 support was done by force extraction of GPL. - * - * - add function for getting/setting power status of drive - * - the HPT370's state machine can get confused. reset it before each dma - * xfer to prevent that from happening. - * - reset state engine whenever we get an error. - * - check for busmaster state at end of dma. - * - use new highpoint timings. - * - detect bus speed using highpoint register. - * - use pll if we don't have a clock table. added a 66MHz table that's - * just 2x the 33MHz table. - * - removed turnaround. NOTE: we never want to switch between pll and - * pci clocks as the chip can glitch in those cases. the highpoint - * approved workaround slows everything down too much to be useful. in - * addition, we would have to serialize access to each chip. - * Adrian Sun <a.sun@sun.com> - * - * add drive timings for 66MHz PCI bus, - * fix ATA Cable signal detection, fix incorrect /proc info - * add /proc display for per-drive PIO/DMA/UDMA mode and - * per-channel ATA-33/66 Cable detect. - * Duncan Laurie <void@sun.com> - * - * fixup /proc output for multiple controllers - * Tim Hockin <thockin@sun.com> - * - * On hpt366: - * Reset the hpt366 on error, reset on dma - * Fix disabling Fast Interrupt hpt366. - * Mike Waychison <crlf@sun.com> - * - * Added support for 372N clocking and clock switching. The 372N needs - * different clocks on read/write. This requires overloading rw_disk and - * other deeply crazy things. Thanks to <http://www.hoerstreich.de> for - * keeping me sane. - * Alan Cox <alan@redhat.com> - * - */ - - -#include <linux/types.h> -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/delay.h> -#include <linux/timer.h> -#include <linux/mm.h> -#include <linux/ioport.h> -#include <linux/blkdev.h> -#include <linux/hdreg.h> - -#include <linux/interrupt.h> -#include <linux/pci.h> -#include <linux/init.h> -#include <linux/ide.h> - -#include <asm/uaccess.h> -#include <asm/io.h> -#include <asm/irq.h> - -/* various tuning parameters */ -#define HPT_RESET_STATE_ENGINE -#undef HPT_DELAY_INTERRUPT -#undef HPT_SERIALIZE_IO - -static const char *quirk_drives[] = { - "QUANTUM FIREBALLlct08 08", - "QUANTUM FIREBALLP KA6.4", - "QUANTUM FIREBALLP LM20.4", - "QUANTUM FIREBALLP LM20.5", - NULL -}; - -static const char *bad_ata100_5[] = { - "IBM-DTLA-307075", - "IBM-DTLA-307060", - "IBM-DTLA-307045", - "IBM-DTLA-307030", - "IBM-DTLA-307020", - "IBM-DTLA-307015", - "IBM-DTLA-305040", - "IBM-DTLA-305030", - "IBM-DTLA-305020", - "IC35L010AVER07-0", - "IC35L020AVER07-0", - "IC35L030AVER07-0", - "IC35L040AVER07-0", - "IC35L060AVER07-0", - "WDC AC310200R", - NULL -}; - -static const char *bad_ata66_4[] = { - "IBM-DTLA-307075", - "IBM-DTLA-307060", - "IBM-DTLA-307045", - "IBM-DTLA-307030", - "IBM-DTLA-307020", - "IBM-DTLA-307015", - "IBM-DTLA-305040", - "IBM-DTLA-305030", - "IBM-DTLA-305020", - "IC35L010AVER07-0", - "IC35L020AVER07-0", - "IC35L030AVER07-0", - "IC35L040AVER07-0", - "IC35L060AVER07-0", - "WDC AC310200R", - NULL -}; - -static const char *bad_ata66_3[] = { - "WDC AC310200R", - NULL -}; - -static const char *bad_ata33[] = { - "Maxtor 92720U8", "Maxtor 92040U6", "Maxtor 91360U4", "Maxtor 91020U3", "Maxtor 90845U3", "Maxtor 90650U2", - "Maxtor 91360D8", "Maxtor 91190D7", "Maxtor 91020D6", "Maxtor 90845D5", "Maxtor 90680D4", "Maxtor 90510D3", "Maxtor 90340D2", - "Maxtor 91152D8", "Maxtor 91008D7", "Maxtor 90845D6", "Maxtor 90840D6", "Maxtor 90720D5", "Maxtor 90648D5", "Maxtor 90576D4", - "Maxtor 90510D4", - "Maxtor 90432D3", "Maxtor 90288D2", "Maxtor 90256D2", - "Maxtor 91000D8", "Maxtor 90910D8", "Maxtor 90875D7", "Maxtor 90840D7", "Maxtor 90750D6", "Maxtor 90625D5", "Maxtor 90500D4", - "Maxtor 91728D8", "Maxtor 91512D7", "Maxtor 91303D6", "Maxtor 91080D5", "Maxtor 90845D4", "Maxtor 90680D4", "Maxtor 90648D3", "Maxtor 90432D2", - NULL -}; - -struct chipset_bus_clock_list_entry { - u8 xfer_speed; - unsigned int chipset_settings; -}; - -/* key for bus clock timings - * bit - * 0:3 data_high_time. inactive time of DIOW_/DIOR_ for PIO and MW - * DMA. cycles = value + 1 - * 4:8 data_low_time. active time of DIOW_/DIOR_ for PIO and MW - * DMA. cycles = value + 1 - * 9:12 cmd_high_time. inactive time of DIOW_/DIOR_ during task file - * register access. - * 13:17 cmd_low_time. active time of DIOW_/DIOR_ during task file - * register access. - * 18:21 udma_cycle_time. clock freq and clock cycles for UDMA xfer. - * during task file register access. - * 22:24 pre_high_time. time to initialize 1st cycle for PIO and MW DMA - * xfer. - * 25:27 cmd_pre_high_time. time to initialize 1st PIO cycle for task - * register access. - * 28 UDMA enable - * 29 DMA enable - * 30 PIO_MST enable. if set, the chip is in bus master mode during - * PIO. - * 31 FIFO enable. - */ -static struct chipset_bus_clock_list_entry forty_base_hpt366[] = { - { XFER_UDMA_4, 0x900fd943 }, - { XFER_UDMA_3, 0x900ad943 }, - { XFER_UDMA_2, 0x900bd943 }, - { XFER_UDMA_1, 0x9008d943 }, - { XFER_UDMA_0, 0x9008d943 }, - - { XFER_MW_DMA_2, 0xa008d943 }, - { XFER_MW_DMA_1, 0xa010d955 }, - { XFER_MW_DMA_0, 0xa010d9fc }, - - { XFER_PIO_4, 0xc008d963 }, - { XFER_PIO_3, 0xc010d974 }, - { XFER_PIO_2, 0xc010d997 }, - { XFER_PIO_1, 0xc010d9c7 }, - { XFER_PIO_0, 0xc018d9d9 }, - { 0, 0x0120d9d9 } -}; - -static struct chipset_bus_clock_list_entry thirty_three_base_hpt366[] = { - { XFER_UDMA_4, 0x90c9a731 }, - { XFER_UDMA_3, 0x90cfa731 }, - { XFER_UDMA_2, 0x90caa731 }, - { XFER_UDMA_1, 0x90cba731 }, - { XFER_UDMA_0, 0x90c8a731 }, - - { XFER_MW_DMA_2, 0xa0c8a731 }, - { XFER_MW_DMA_1, 0xa0c8a732 }, /* 0xa0c8a733 */ - { XFER_MW_DMA_0, 0xa0c8a797 }, - - { XFER_PIO_4, 0xc0c8a731 }, - { XFER_PIO_3, 0xc0c8a742 }, - { XFER_PIO_2, 0xc0d0a753 }, - { XFER_PIO_1, 0xc0d0a7a3 }, /* 0xc0d0a793 */ - { XFER_PIO_0, 0xc0d0a7aa }, /* 0xc0d0a7a7 */ - { 0, 0x0120a7a7 } -}; - -static struct chipset_bus_clock_list_entry twenty_five_base_hpt366[] = { - { XFER_UDMA_4, 0x90c98521 }, - { XFER_UDMA_3, 0x90cf8521 }, - { XFER_UDMA_2, 0x90cf8521 }, - { XFER_UDMA_1, 0x90cb8521 }, - { XFER_UDMA_0, 0x90cb8521 }, - - { XFER_MW_DMA_2, 0xa0ca8521 }, - { XFER_MW_DMA_1, 0xa0ca8532 }, - { XFER_MW_DMA_0, 0xa0ca8575 }, - - { XFER_PIO_4, 0xc0ca8521 }, - { XFER_PIO_3, 0xc0ca8532 }, - { XFER_PIO_2, 0xc0ca8542 }, - { XFER_PIO_1, 0xc0d08572 }, - { XFER_PIO_0, 0xc0d08585 }, - { 0, 0x01208585 } -}; - -/* from highpoint documentation. these are old values */ -static struct chipset_bus_clock_list_entry thirty_three_base_hpt370[] = { -/* { XFER_UDMA_5, 0x1A85F442, 0x16454e31 }, */ - { XFER_UDMA_5, 0x16454e31 }, - { XFER_UDMA_4, 0x16454e31 }, - { XFER_UDMA_3, 0x166d4e31 }, - { XFER_UDMA_2, 0x16494e31 }, - { XFER_UDMA_1, 0x164d4e31 }, - { XFER_UDMA_0, 0x16514e31 }, - - { XFER_MW_DMA_2, 0x26514e21 }, - { XFER_MW_DMA_1, 0x26514e33 }, - { XFER_MW_DMA_0, 0x26514e97 }, - - { XFER_PIO_4, 0x06514e21 }, - { XFER_PIO_3, 0x06514e22 }, - { XFER_PIO_2, 0x06514e33 }, - { XFER_PIO_1, 0x06914e43 }, - { XFER_PIO_0, 0x06914e57 }, - { 0, 0x06514e57 } -}; - -static struct chipset_bus_clock_list_entry sixty_six_base_hpt370[] = { - { XFER_UDMA_5, 0x14846231 }, - { XFER_UDMA_4, 0x14886231 }, - { XFER_UDMA_3, 0x148c6231 }, - { XFER_UDMA_2, 0x148c6231 }, - { XFER_UDMA_1, 0x14906231 }, - { XFER_UDMA_0, 0x14986231 }, - - { XFER_MW_DMA_2, 0x26514e21 }, - { XFER_MW_DMA_1, 0x26514e33 }, - { XFER_MW_DMA_0, 0x26514e97 }, - - { XFER_PIO_4, 0x06514e21 }, - { XFER_PIO_3, 0x06514e22 }, - { XFER_PIO_2, 0x06514e33 }, - { XFER_PIO_1, 0x06914e43 }, - { XFER_PIO_0, 0x06914e57 }, - { 0, 0x06514e57 } -}; - -/* these are the current (4 sep 2001) timings from highpoint */ -static struct chipset_bus_clock_list_entry thirty_three_base_hpt370a[] = { - { XFER_UDMA_5, 0x12446231 }, - { XFER_UDMA_4, 0x12446231 }, - { XFER_UDMA_3, 0x126c6231 }, - { XFER_UDMA_2, 0x12486231 }, - { XFER_UDMA_1, 0x124c6233 }, - { XFER_UDMA_0, 0x12506297 }, - - { XFER_MW_DMA_2, 0x22406c31 }, - { XFER_MW_DMA_1, 0x22406c33 }, - { XFER_MW_DMA_0, 0x22406c97 }, - - { XFER_PIO_4, 0x06414e31 }, - { XFER_PIO_3, 0x06414e42 }, - { XFER_PIO_2, 0x06414e53 }, - { XFER_PIO_1, 0x06814e93 }, - { XFER_PIO_0, 0x06814ea7 }, - { 0, 0x06814ea7 } -}; - -/* 2x 33MHz timings */ -static struct chipset_bus_clock_list_entry sixty_six_base_hpt370a[] = { - { XFER_UDMA_5, 0x1488e673 }, - { XFER_UDMA_4, 0x1488e673 }, - { XFER_UDMA_3, 0x1498e673 }, - { XFER_UDMA_2, 0x1490e673 }, - { XFER_UDMA_1, 0x1498e677 }, - { XFER_UDMA_0, 0x14a0e73f }, - - { XFER_MW_DMA_2, 0x2480fa73 }, - { XFER_MW_DMA_1, 0x2480fa77 }, - { XFER_MW_DMA_0, 0x2480fb3f }, - - { XFER_PIO_4, 0x0c82be73 }, - { XFER_PIO_3, 0x0c82be95 }, - { XFER_PIO_2, 0x0c82beb7 }, - { XFER_PIO_1, 0x0d02bf37 }, - { XFER_PIO_0, 0x0d02bf5f }, - { 0, 0x0d02bf5f } -}; - -static struct chipset_bus_clock_list_entry fifty_base_hpt370a[] = { - { XFER_UDMA_5, 0x12848242 }, - { XFER_UDMA_4, 0x12ac8242 }, - { XFER_UDMA_3, 0x128c8242 }, - { XFER_UDMA_2, 0x120c8242 }, - { XFER_UDMA_1, 0x12148254 }, - { XFER_UDMA_0, 0x121882ea }, - - { XFER_MW_DMA_2, 0x22808242 }, - { XFER_MW_DMA_1, 0x22808254 }, - { XFER_MW_DMA_0, 0x228082ea }, - - { XFER_PIO_4, 0x0a81f442 }, - { XFER_PIO_3, 0x0a81f443 }, - { XFER_PIO_2, 0x0a81f454 }, - { XFER_PIO_1, 0x0ac1f465 }, - { XFER_PIO_0, 0x0ac1f48a }, - { 0, 0x0ac1f48a } -}; - -static struct chipset_bus_clock_list_entry thirty_three_base_hpt372[] = { - { XFER_UDMA_6, 0x1c81dc62 }, - { XFER_UDMA_5, 0x1c6ddc62 }, - { XFER_UDMA_4, 0x1c8ddc62 }, - { XFER_UDMA_3, 0x1c8edc62 }, /* checkme */ - { XFER_UDMA_2, 0x1c91dc62 }, - { XFER_UDMA_1, 0x1c9adc62 }, /* checkme */ - { XFER_UDMA_0, 0x1c82dc62 }, /* checkme */ - - { XFER_MW_DMA_2, 0x2c829262 }, - { XFER_MW_DMA_1, 0x2c829266 }, /* checkme */ - { XFER_MW_DMA_0, 0x2c82922e }, /* checkme */ - - { XFER_PIO_4, 0x0c829c62 }, - { XFER_PIO_3, 0x0c829c84 }, - { XFER_PIO_2, 0x0c829ca6 }, - { XFER_PIO_1, 0x0d029d26 }, - { XFER_PIO_0, 0x0d029d5e }, - { 0, 0x0d029d5e } -}; - -static struct chipset_bus_clock_list_entry fifty_base_hpt372[] = { - { XFER_UDMA_5, 0x12848242 }, - { XFER_UDMA_4, 0x12ac8242 }, - { XFER_UDMA_3, 0x128c8242 }, - { XFER_UDMA_2, 0x120c8242 }, - { XFER_UDMA_1, 0x12148254 }, - { XFER_UDMA_0, 0x121882ea }, - - { XFER_MW_DMA_2, 0x22808242 }, - { XFER_MW_DMA_1, 0x22808254 }, - { XFER_MW_DMA_0, 0x228082ea }, - - { XFER_PIO_4, 0x0a81f442 }, - { XFER_PIO_3, 0x0a81f443 }, - { XFER_PIO_2, 0x0a81f454 }, - { XFER_PIO_1, 0x0ac1f465 }, - { XFER_PIO_0, 0x0ac1f48a }, - { 0, 0x0a81f443 } -}; - -static struct chipset_bus_clock_list_entry sixty_six_base_hpt372[] = { - { XFER_UDMA_6, 0x1c869c62 }, - { XFER_UDMA_5, 0x1cae9c62 }, - { XFER_UDMA_4, 0x1c8a9c62 }, - { XFER_UDMA_3, 0x1c8e9c62 }, - { XFER_UDMA_2, 0x1c929c62 }, - { XFER_UDMA_1, 0x1c9a9c62 }, - { XFER_UDMA_0, 0x1c829c62 }, - - { XFER_MW_DMA_2, 0x2c829c62 }, - { XFER_MW_DMA_1, 0x2c829c66 }, - { XFER_MW_DMA_0, 0x2c829d2e }, - - { XFER_PIO_4, 0x0c829c62 }, - { XFER_PIO_3, 0x0c829c84 }, - { XFER_PIO_2, 0x0c829ca6 }, - { XFER_PIO_1, 0x0d029d26 }, - { XFER_PIO_0, 0x0d029d5e }, - { 0, 0x0d029d26 } -}; - -static struct chipset_bus_clock_list_entry thirty_three_base_hpt374[] = { - { XFER_UDMA_6, 0x12808242 }, - { XFER_UDMA_5, 0x12848242 }, - { XFER_UDMA_4, 0x12ac8242 }, - { XFER_UDMA_3, 0x128c8242 }, - { XFER_UDMA_2, 0x120c8242 }, - { XFER_UDMA_1, 0x12148254 }, - { XFER_UDMA_0, 0x121882ea }, - - { XFER_MW_DMA_2, 0x22808242 }, - { XFER_MW_DMA_1, 0x22808254 }, - { XFER_MW_DMA_0, 0x228082ea }, - - { XFER_PIO_4, 0x0a81f442 }, - { XFER_PIO_3, 0x0a81f443 }, - { XFER_PIO_2, 0x0a81f454 }, - { XFER_PIO_1, 0x0ac1f465 }, - { XFER_PIO_0, 0x0ac1f48a }, - { 0, 0x06814e93 } -}; - -/* FIXME: 50MHz timings for HPT374 */ - -#if 0 -static struct chipset_bus_clock_list_entry sixty_six_base_hpt374[] = { - { XFER_UDMA_6, 0x12406231 }, /* checkme */ - { XFER_UDMA_5, 0x12446231 }, /* 0x14846231 */ - { XFER_UDMA_4, 0x16814ea7 }, /* 0x14886231 */ - { XFER_UDMA_3, 0x16814ea7 }, /* 0x148c6231 */ - { XFER_UDMA_2, 0x16814ea7 }, /* 0x148c6231 */ - { XFER_UDMA_1, 0x16814ea7 }, /* 0x14906231 */ - { XFER_UDMA_0, 0x16814ea7 }, /* 0x14986231 */ - { XFER_MW_DMA_2, 0x16814ea7 }, /* 0x26514e21 */ - { XFER_MW_DMA_1, 0x16814ea7 }, /* 0x26514e97 */ - { XFER_MW_DMA_0, 0x16814ea7 }, /* 0x26514e97 */ - { XFER_PIO_4, 0x06814ea7 }, /* 0x06514e21 */ - { XFER_PIO_3, 0x06814ea7 }, /* 0x06514e22 */ - { XFER_PIO_2, 0x06814ea7 }, /* 0x06514e33 */ - { XFER_PIO_1, 0x06814ea7 }, /* 0x06914e43 */ - { XFER_PIO_0, 0x06814ea7 }, /* 0x06914e57 */ - { 0, 0x06814ea7 } -}; -#endif - -#define HPT366_DEBUG_DRIVE_INFO 0 -#define HPT374_ALLOW_ATA133_6 0 -#define HPT371_ALLOW_ATA133_6 0 -#define HPT302_ALLOW_ATA133_6 0 -#define HPT372_ALLOW_ATA133_6 1 -#define HPT370_ALLOW_ATA100_5 1 -#define HPT366_ALLOW_ATA66_4 1 -#define HPT366_ALLOW_ATA66_3 1 -#define HPT366_MAX_DEVS 8 - -#define F_LOW_PCI_33 0x23 -#define F_LOW_PCI_40 0x29 -#define F_LOW_PCI_50 0x2d -#define F_LOW_PCI_66 0x42 - -/* - * Hold all the highpoint quirks and revision information in one - * place. - */ - -struct hpt_info -{ - u8 max_mode; /* Speeds allowed */ - int revision; /* Chipset revision */ - int flags; /* Chipset properties */ -#define PLL_MODE 1 -#define IS_372N 2 - /* Speed table */ - struct chipset_bus_clock_list_entry *speed; -}; - -/* - * This wants fixing so that we do everything not by classrev - * (which breaks on the newest chips) but by creating an - * enumeration of chip variants and using that - */ - -static __devinit u32 hpt_revision (struct pci_dev *dev) -{ - u32 class_rev; - pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev); - class_rev &= 0xff; - - switch(dev->device) { - /* Remap new 372N onto 372 */ - case PCI_DEVICE_ID_TTI_HPT372N: - class_rev = PCI_DEVICE_ID_TTI_HPT372; break; - case PCI_DEVICE_ID_TTI_HPT374: - class_rev = PCI_DEVICE_ID_TTI_HPT374; break; - case PCI_DEVICE_ID_TTI_HPT371: - class_rev = PCI_DEVICE_ID_TTI_HPT371; break; - case PCI_DEVICE_ID_TTI_HPT302: - class_rev = PCI_DEVICE_ID_TTI_HPT302; break; - case PCI_DEVICE_ID_TTI_HPT372: - class_rev = PCI_DEVICE_ID_TTI_HPT372; break; - default: - break; - } - return class_rev; -} - -static int check_in_drive_lists(ide_drive_t *drive, const char **list); - -static u8 hpt3xx_ratemask (ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - struct hpt_info *info = ide_get_hwifdata(hwif); - u8 mode = 0; - - /* FIXME: TODO - move this to set info->mode once at boot */ - - if (info->revision >= 8) { /* HPT374 */ - mode = (HPT374_ALLOW_ATA133_6) ? 4 : 3; - } else if (info->revision >= 7) { /* HPT371 */ - mode = (HPT371_ALLOW_ATA133_6) ? 4 : 3; - } else if (info->revision >= 6) { /* HPT302 */ - mode = (HPT302_ALLOW_ATA133_6) ? 4 : 3; - } else if (info->revision >= 5) { /* HPT372 */ - mode = (HPT372_ALLOW_ATA133_6) ? 4 : 3; - } else if (info->revision >= 4) { /* HPT370A */ - mode = (HPT370_ALLOW_ATA100_5) ? 3 : 2; - } else if (info->revision >= 3) { /* HPT370 */ - mode = (HPT370_ALLOW_ATA100_5) ? 3 : 2; - mode = (check_in_drive_lists(drive, bad_ata33)) ? 0 : mode; - } else { /* HPT366 and HPT368 */ - mode = (check_in_drive_lists(drive, bad_ata33)) ? 0 : 2; - } - if (!eighty_ninty_three(drive) && mode) - mode = min(mode, (u8)1); - return mode; -} - -/* - * Note for the future; the SATA hpt37x we must set - * either PIO or UDMA modes 0,4,5 - */ - -static u8 hpt3xx_ratefilter (ide_drive_t *drive, u8 speed) -{ - ide_hwif_t *hwif = drive->hwif; - struct hpt_info *info = ide_get_hwifdata(hwif); - u8 mode = hpt3xx_ratemask(drive); - - if (drive->media != ide_disk) - return min(speed, (u8)XFER_PIO_4); - - switch(mode) { - case 0x04: - speed = min(speed, (u8)XFER_UDMA_6); - break; - case 0x03: - speed = min(speed, (u8)XFER_UDMA_5); - if (info->revision >= 5) - break; - if (check_in_drive_lists(drive, bad_ata100_5)) - speed = min(speed, (u8)XFER_UDMA_4); - break; - case 0x02: - speed = min(speed, (u8)XFER_UDMA_4); - /* - * CHECK ME, Does this need to be set to 5 ?? - */ - if (info->revision >= 3) - break; - if ((check_in_drive_lists(drive, bad_ata66_4)) || - (!(HPT366_ALLOW_ATA66_4))) - speed = min(speed, (u8)XFER_UDMA_3); - if ((check_in_drive_lists(drive, bad_ata66_3)) || - (!(HPT366_ALLOW_ATA66_3))) - speed = min(speed, (u8)XFER_UDMA_2); - break; - case 0x01: - speed = min(speed, (u8)XFER_UDMA_2); - /* - * CHECK ME, Does this need to be set to 5 ?? - */ - if (info->revision >= 3) - break; - if (check_in_drive_lists(drive, bad_ata33)) - speed = min(speed, (u8)XFER_MW_DMA_2); - break; - case 0x00: - default: - speed = min(speed, (u8)XFER_MW_DMA_2); - break; - } - return speed; -} - -static int check_in_drive_lists (ide_drive_t *drive, const char **list) -{ - struct hd_driveid *id = drive->id; - - if (quirk_drives == list) { - while (*list) - if (strstr(id->model, *list++)) - return 1; - } else { - while (*list) - if (!strcmp(*list++,id->model)) - return 1; - } - return 0; -} - -static unsigned int pci_bus_clock_list (u8 speed, struct chipset_bus_clock_list_entry * chipset_table) -{ - for ( ; chipset_table->xfer_speed ; chipset_table++) - if (chipset_table->xfer_speed == speed) - return chipset_table->chipset_settings; - return chipset_table->chipset_settings; -} - -static int hpt36x_tune_chipset(ide_drive_t *drive, u8 xferspeed) -{ - ide_hwif_t *hwif = drive->hwif; - struct pci_dev *dev = hwif->pci_dev; - struct hpt_info *info = ide_get_hwifdata(hwif); - u8 speed = hpt3xx_ratefilter(drive, xferspeed); - u8 regtime = (drive->select.b.unit & 0x01) ? 0x44 : 0x40; - u8 regfast = (hwif->channel) ? 0x55 : 0x51; - u8 drive_fast = 0; - u32 reg1 = 0, reg2 = 0; - - /* - * Disable the "fast interrupt" prediction. - */ - pci_read_config_byte(dev, regfast, &drive_fast); - if (drive_fast & 0x80) - pci_write_config_byte(dev, regfast, drive_fast & ~0x80); - - reg2 = pci_bus_clock_list(speed, info->speed); - - /* - * Disable on-chip PIO FIFO/buffer - * (to avoid problems handling I/O errors later) - */ - pci_read_config_dword(dev, regtime, ®1); - if (speed >= XFER_MW_DMA_0) { - reg2 = (reg2 & ~0xc0000000) | (reg1 & 0xc0000000); - } else { - reg2 = (reg2 & ~0x30070000) | (reg1 & 0x30070000); - } - reg2 &= ~0x80000000; - - pci_write_config_dword(dev, regtime, reg2); - - return ide_config_drive_speed(drive, speed); -} - -static int hpt370_tune_chipset(ide_drive_t *drive, u8 xferspeed) -{ - ide_hwif_t *hwif = drive->hwif; - struct pci_dev *dev = hwif->pci_dev; - struct hpt_info *info = ide_get_hwifdata(hwif); - u8 speed = hpt3xx_ratefilter(drive, xferspeed); - u8 regfast = (drive->hwif->channel) ? 0x55 : 0x51; - u8 drive_pci = 0x40 + (drive->dn * 4); - u8 new_fast = 0, drive_fast = 0; - u32 list_conf = 0, drive_conf = 0; - u32 conf_mask = (speed >= XFER_MW_DMA_0) ? 0xc0000000 : 0x30070000; - - /* - * Disable the "fast interrupt" prediction. - * don't holdoff on interrupts. (== 0x01 despite what the docs say) - */ - pci_read_config_byte(dev, regfast, &drive_fast); - new_fast = drive_fast; - if (new_fast & 0x02) - new_fast &= ~0x02; - -#ifdef HPT_DELAY_INTERRUPT - if (new_fast & 0x01) - new_fast &= ~0x01; -#else - if ((new_fast & 0x01) == 0) - new_fast |= 0x01; -#endif - if (new_fast != drive_fast) - pci_write_config_byte(dev, regfast, new_fast); - - list_conf = pci_bus_clock_list(speed, info->speed); - - pci_read_config_dword(dev, drive_pci, &drive_conf); - list_conf = (list_conf & ~conf_mask) | (drive_conf & conf_mask); - - if (speed < XFER_MW_DMA_0) - list_conf &= ~0x80000000; /* Disable on-chip PIO FIFO/buffer */ - pci_write_config_dword(dev, drive_pci, list_conf); - - return ide_config_drive_speed(drive, speed); -} - -static int hpt372_tune_chipset(ide_drive_t *drive, u8 xferspeed) -{ - ide_hwif_t *hwif = drive->hwif; - struct pci_dev *dev = hwif->pci_dev; - struct hpt_info *info = ide_get_hwifdata(hwif); - u8 speed = hpt3xx_ratefilter(drive, xferspeed); - u8 regfast = (drive->hwif->channel) ? 0x55 : 0x51; - u8 drive_fast = 0, drive_pci = 0x40 + (drive->dn * 4); - u32 list_conf = 0, drive_conf = 0; - u32 conf_mask = (speed >= XFER_MW_DMA_0) ? 0xc0000000 : 0x30070000; - - /* - * Disable the "fast interrupt" prediction. - * don't holdoff on interrupts. (== 0x01 despite what the docs say) - */ - pci_read_config_byte(dev, regfast, &drive_fast); - drive_fast &= ~0x07; - pci_write_config_byte(dev, regfast, drive_fast); - - list_conf = pci_bus_clock_list(speed, info->speed); - pci_read_config_dword(dev, drive_pci, &drive_conf); - list_conf = (list_conf & ~conf_mask) | (drive_conf & conf_mask); - if (speed < XFER_MW_DMA_0) - list_conf &= ~0x80000000; /* Disable on-chip PIO FIFO/buffer */ - pci_write_config_dword(dev, drive_pci, list_conf); - - return ide_config_drive_speed(drive, speed); -} - -static int hpt3xx_tune_chipset (ide_drive_t *drive, u8 speed) -{ - ide_hwif_t *hwif = drive->hwif; - struct hpt_info *info = ide_get_hwifdata(hwif); - - if (info->revision >= 8) - return hpt372_tune_chipset(drive, speed); /* not a typo */ - else if (info->revision >= 5) - return hpt372_tune_chipset(drive, speed); - else if (info->revision >= 3) - return hpt370_tune_chipset(drive, speed); - else /* hpt368: hpt_minimum_revision(dev, 2) */ - return hpt36x_tune_chipset(drive, speed); -} - -static void hpt3xx_tune_drive (ide_drive_t *drive, u8 pio) -{ - pio = ide_get_best_pio_mode(drive, 255, pio, NULL); - (void) hpt3xx_tune_chipset(drive, (XFER_PIO_0 + pio)); -} - -/* - * This allows the configuration of ide_pci chipset registers - * for cards that learn about the drive's UDMA, DMA, PIO capabilities - * after the drive is reported by the OS. Initially for designed for - * HPT366 UDMA chipset by HighPoint|Triones Technologies, Inc. - * - * check_in_drive_lists(drive, bad_ata66_4) - * check_in_drive_lists(drive, bad_ata66_3) - * check_in_drive_lists(drive, bad_ata33) - * - */ -static int config_chipset_for_dma (ide_drive_t *drive) -{ - u8 speed = ide_dma_speed(drive, hpt3xx_ratemask(drive)); - ide_hwif_t *hwif = drive->hwif; - struct hpt_info *info = ide_get_hwifdata(hwif); - - if (!speed) - return 0; - - /* If we don't have any timings we can't do a lot */ - if (info->speed == NULL) - return 0; - - (void) hpt3xx_tune_chipset(drive, speed); - return ide_dma_enable(drive); -} - -static int hpt3xx_quirkproc (ide_drive_t *drive) -{ - return ((int) check_in_drive_lists(drive, quirk_drives)); -} - -static void hpt3xx_intrproc (ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - - if (drive->quirk_list) - return; - /* drives in the quirk_list may not like intr setups/cleanups */ - hwif->OUTB(drive->ctl|2, IDE_CONTROL_REG); -} - -static void hpt3xx_maskproc (ide_drive_t *drive, int mask) -{ - ide_hwif_t *hwif = drive->hwif; - struct hpt_info *info = ide_get_hwifdata(hwif); - struct pci_dev *dev = hwif->pci_dev; - - if (drive->quirk_list) { - if (info->revision >= 3) { - u8 reg5a = 0; - pci_read_config_byte(dev, 0x5a, ®5a); - if (((reg5a & 0x10) >> 4) != mask) - pci_write_config_byte(dev, 0x5a, mask ? (reg5a | 0x10) : (reg5a & ~0x10)); - } else { - if (mask) { - disable_irq(hwif->irq); - } else { - enable_irq(hwif->irq); - } - } - } else { - if (IDE_CONTROL_REG) - hwif->OUTB(mask ? (drive->ctl | 2) : - (drive->ctl & ~2), - IDE_CONTROL_REG); - } -} - -static int hpt366_config_drive_xfer_rate (ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - struct hd_driveid *id = drive->id; - - drive->init_speed = 0; - - if ((id->capability & 1) && drive->autodma) { - - if (ide_use_dma(drive)) { - if (config_chipset_for_dma(drive)) - return hwif->ide_dma_on(drive); - } - - goto fast_ata_pio; - - } else if ((id->capability & 8) || (id->field_valid & 2)) { -fast_ata_pio: - hpt3xx_tune_drive(drive, 5); - return hwif->ide_dma_off_quietly(drive); - } - /* IORDY not supported */ - return 0; -} - -/* - * This is specific to the HPT366 UDMA bios chipset - * by HighPoint|Triones Technologies, Inc. - */ -static int hpt366_ide_dma_lostirq (ide_drive_t *drive) -{ - struct pci_dev *dev = HWIF(drive)->pci_dev; - u8 reg50h = 0, reg52h = 0, reg5ah = 0; - - pci_read_config_byte(dev, 0x50, ®50h); - pci_read_config_byte(dev, 0x52, ®52h); - pci_read_config_byte(dev, 0x5a, ®5ah); - printk("%s: (%s) reg50h=0x%02x, reg52h=0x%02x, reg5ah=0x%02x\n", - drive->name, __FUNCTION__, reg50h, reg52h, reg5ah); - if (reg5ah & 0x10) - pci_write_config_byte(dev, 0x5a, reg5ah & ~0x10); - return __ide_dma_lostirq(drive); -} - -static void hpt370_clear_engine (ide_drive_t *drive) -{ - u8 regstate = HWIF(drive)->channel ? 0x54 : 0x50; - pci_write_config_byte(HWIF(drive)->pci_dev, regstate, 0x37); - udelay(10); -} - -static void hpt370_ide_dma_start(ide_drive_t *drive) -{ -#ifdef HPT_RESET_STATE_ENGINE - hpt370_clear_engine(drive); -#endif - ide_dma_start(drive); -} - -static int hpt370_ide_dma_end (ide_drive_t *drive) -{ - ide_hwif_t *hwif = HWIF(drive); - u8 dma_stat = hwif->INB(hwif->dma_status); - - if (dma_stat & 0x01) { - /* wait a little */ - udelay(20); - dma_stat = hwif->INB(hwif->dma_status); - } - if ((dma_stat & 0x01) != 0) - /* fallthrough */ - (void) HWIF(drive)->ide_dma_timeout(drive); - - return __ide_dma_end(drive); -} - -static void hpt370_lostirq_timeout (ide_drive_t *drive) -{ - ide_hwif_t *hwif = HWIF(drive); - u8 bfifo = 0, reginfo = hwif->channel ? 0x56 : 0x52; - u8 dma_stat = 0, dma_cmd = 0; - - pci_read_config_byte(HWIF(drive)->pci_dev, reginfo, &bfifo); - printk(KERN_DEBUG "%s: %d bytes in FIFO\n", drive->name, bfifo); - hpt370_clear_engine(drive); - /* get dma command mode */ - dma_cmd = hwif->INB(hwif->dma_command); - /* stop dma */ - hwif->OUTB(dma_cmd & ~0x1, hwif->dma_command); - dma_stat = hwif->INB(hwif->dma_status); - /* clear errors */ - hwif->OUTB(dma_stat | 0x6, hwif->dma_status); -} - -static int hpt370_ide_dma_timeout (ide_drive_t *drive) -{ - hpt370_lostirq_timeout(drive); - hpt370_clear_engine(drive); - return __ide_dma_timeout(drive); -} - -static int hpt370_ide_dma_lostirq (ide_drive_t *drive) -{ - hpt370_lostirq_timeout(drive); - hpt370_clear_engine(drive); - return __ide_dma_lostirq(drive); -} - -/* returns 1 if DMA IRQ issued, 0 otherwise */ -static int hpt374_ide_dma_test_irq(ide_drive_t *drive) -{ - ide_hwif_t *hwif = HWIF(drive); - u16 bfifo = 0; - u8 reginfo = hwif->channel ? 0x56 : 0x52; - u8 dma_stat; - - pci_read_config_word(hwif->pci_dev, reginfo, &bfifo); - if (bfifo & 0x1FF) { -// printk("%s: %d bytes in FIFO\n", drive->name, bfifo); - return 0; - } - - dma_stat = hwif->INB(hwif->dma_status); - /* return 1 if INTR asserted */ - if ((dma_stat & 4) == 4) - return 1; - - if (!drive->waiting_for_dma) - printk(KERN_WARNING "%s: (%s) called while not waiting\n", - drive->name, __FUNCTION__); - return 0; -} - -static int hpt374_ide_dma_end (ide_drive_t *drive) -{ - struct pci_dev *dev = HWIF(drive)->pci_dev; - ide_hwif_t *hwif = HWIF(drive); - u8 msc_stat = 0, mscreg = hwif->channel ? 0x54 : 0x50; - u8 bwsr_stat = 0, bwsr_mask = hwif->channel ? 0x02 : 0x01; - - pci_read_config_byte(dev, 0x6a, &bwsr_stat); - pci_read_config_byte(dev, mscreg, &msc_stat); - if ((bwsr_stat & bwsr_mask) == bwsr_mask) - pci_write_config_byte(dev, mscreg, msc_stat|0x30); - return __ide_dma_end(drive); -} - -/** - * hpt372n_set_clock - perform clock switching dance - * @drive: Drive to switch - * @mode: Switching mode (0x21 for write, 0x23 otherwise) - * - * Switch the DPLL clock on the HPT372N devices. This is a - * right mess. - */ - -static void hpt372n_set_clock(ide_drive_t *drive, int mode) -{ - ide_hwif_t *hwif = HWIF(drive); - - /* FIXME: should we check for DMA active and BUG() */ - /* Tristate the bus */ - outb(0x80, hwif->dma_base+0x73); - outb(0x80, hwif->dma_base+0x77); - - /* Switch clock and reset channels */ - outb(mode, hwif->dma_base+0x7B); - outb(0xC0, hwif->dma_base+0x79); - - /* Reset state machines */ - outb(0x37, hwif->dma_base+0x70); - outb(0x37, hwif->dma_base+0x74); - - /* Complete reset */ - outb(0x00, hwif->dma_base+0x79); - - /* Reconnect channels to bus */ - outb(0x00, hwif->dma_base+0x73); - outb(0x00, hwif->dma_base+0x77); -} - -/** - * hpt372n_rw_disk - prepare for I/O - * @drive: drive for command - * @rq: block request structure - * - * This is called when a disk I/O is issued to the 372N. - * We need it because of the clock switching. - */ - -static void hpt372n_rw_disk(ide_drive_t *drive, struct request *rq) -{ - ide_hwif_t *hwif = drive->hwif; - int wantclock; - - wantclock = rq_data_dir(rq) ? 0x23 : 0x21; - - if (hwif->config_data != wantclock) { - hpt372n_set_clock(drive, wantclock); - hwif->config_data = wantclock; - } -} - -/* - * Since SUN Cobalt is attempting to do this operation, I should disclose - * this has been a long time ago Thu Jul 27 16:40:57 2000 was the patch date - * HOTSWAP ATA Infrastructure. - */ - -static void hpt3xx_reset (ide_drive_t *drive) -{ -} - -static int hpt3xx_tristate (ide_drive_t * drive, int state) -{ - ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; - u8 reg59h = 0, reset = (hwif->channel) ? 0x80 : 0x40; - u8 regXXh = 0, state_reg= (hwif->channel) ? 0x57 : 0x53; - - pci_read_config_byte(dev, 0x59, ®59h); - pci_read_config_byte(dev, state_reg, ®XXh); - - if (state) { - (void) ide_do_reset(drive); - pci_write_config_byte(dev, state_reg, regXXh|0x80); - pci_write_config_byte(dev, 0x59, reg59h|reset); - } else { - pci_write_config_byte(dev, 0x59, reg59h & ~(reset)); - pci_write_config_byte(dev, state_reg, regXXh & ~(0x80)); - (void) ide_do_reset(drive); - } - return 0; -} - -/* - * set/get power state for a drive. - * turning the power off does the following things: - * 1) soft-reset the drive - * 2) tri-states the ide bus - * - * when we turn things back on, we need to re-initialize things. - */ -#define TRISTATE_BIT 0x8000 -static int hpt370_busproc(ide_drive_t * drive, int state) -{ - ide_hwif_t *hwif = drive->hwif; - struct pci_dev *dev = hwif->pci_dev; - u8 tristate = 0, resetmask = 0, bus_reg = 0; - u16 tri_reg; - - hwif->bus_state = state; - - if (hwif->channel) { - /* secondary channel */ - tristate = 0x56; - resetmask = 0x80; - } else { - /* primary channel */ - tristate = 0x52; - resetmask = 0x40; - } - - /* grab status */ - pci_read_config_word(dev, tristate, &tri_reg); - pci_read_config_byte(dev, 0x59, &bus_reg); - - /* set the state. we don't set it if we don't need to do so. - * make sure that the drive knows that it has failed if it's off */ - switch (state) { - case BUSSTATE_ON: - hwif->drives[0].failures = 0; - hwif->drives[1].failures = 0; - if ((bus_reg & resetmask) == 0) - return 0; - tri_reg &= ~TRISTATE_BIT; - bus_reg &= ~resetmask; - break; - case BUSSTATE_OFF: - hwif->drives[0].failures = hwif->drives[0].max_failures + 1; - hwif->drives[1].failures = hwif->drives[1].max_failures + 1; - if ((tri_reg & TRISTATE_BIT) == 0 && (bus_reg & resetmask)) - return 0; - tri_reg &= ~TRISTATE_BIT; - bus_reg |= resetmask; - break; - case BUSSTATE_TRISTATE: - hwif->drives[0].failures = hwif->drives[0].max_failures + 1; - hwif->drives[1].failures = hwif->drives[1].max_failures + 1; - if ((tri_reg & TRISTATE_BIT) && (bus_reg & resetmask)) - return 0; - tri_reg |= TRISTATE_BIT; - bus_reg |= resetmask; - break; - } - pci_write_config_byte(dev, 0x59, bus_reg); - pci_write_config_word(dev, tristate, tri_reg); - - return 0; -} - -static void __devinit hpt366_clocking(ide_hwif_t *hwif) -{ - u32 reg1 = 0; - struct hpt_info *info = ide_get_hwifdata(hwif); - - pci_read_config_dword(hwif->pci_dev, 0x40, ®1); - - /* detect bus speed by looking at control reg timing: */ - switch((reg1 >> 8) & 7) { - case 5: - info->speed = forty_base_hpt366; - break; - case 9: - info->speed = twenty_five_base_hpt366; - break; - case 7: - default: - info->speed = thirty_three_base_hpt366; - break; - } -} - -static void __devinit hpt37x_clocking(ide_hwif_t *hwif) -{ - struct hpt_info *info = ide_get_hwifdata(hwif); - struct pci_dev *dev = hwif->pci_dev; - int adjust, i; - u16 freq; - u32 pll; - u8 reg5bh; - - /* - * default to pci clock. make sure MA15/16 are set to output - * to prevent drives having problems with 40-pin cables. Needed - * for some drives such as IBM-DTLA which will not enter ready - * state on reset when PDIAG is a input. - * - * ToDo: should we set 0x21 when using PLL mode ? - */ - pci_write_config_byte(dev, 0x5b, 0x23); - - /* - * set up the PLL. we need to adjust it so that it's stable. - * freq = Tpll * 192 / Tpci - * - * Todo. For non x86 should probably check the dword is - * set to 0xABCDExxx indicating the BIOS saved f_CNT - */ - pci_read_config_word(dev, 0x78, &freq); - freq &= 0x1FF; - - /* - * The 372N uses different PCI clock information and has - * some other complications - * On PCI33 timing we must clock switch - * On PCI66 timing we must NOT use the PCI clock - * - * Currently we always set up the PLL for the 372N - */ - - if(info->flags & IS_372N) - { - printk(KERN_INFO "hpt: HPT372N detected, using 372N timing.\n"); - if(freq < 0x55) - pll = F_LOW_PCI_33; - else if(freq < 0x70) - pll = F_LOW_PCI_40; - else if(freq < 0x7F) - pll = F_LOW_PCI_50; - else - pll = F_LOW_PCI_66; - - printk(KERN_INFO "FREQ: %d PLL: %d\n", freq, pll); - - /* We always use the pll not the PCI clock on 372N */ - } - else - { - if(freq < 0x9C) - pll = F_LOW_PCI_33; - else if(freq < 0xb0) - pll = F_LOW_PCI_40; - else if(freq <0xc8) - pll = F_LOW_PCI_50; - else - pll = F_LOW_PCI_66; - - if (pll == F_LOW_PCI_33) { - if (info->revision >= 8) - info->speed = thirty_three_base_hpt374; - else if (info->revision >= 5) - info->speed = thirty_three_base_hpt372; - else if (info->revision >= 4) - info->speed = thirty_three_base_hpt370a; - else - info->speed = thirty_three_base_hpt370; - printk(KERN_DEBUG "HPT37X: using 33MHz PCI clock\n"); - } else if (pll == F_LOW_PCI_40) { - /* Unsupported */ - } else if (pll == F_LOW_PCI_50) { - if (info->revision >= 8) - info->speed = fifty_base_hpt370a; - else if (info->revision >= 5) - info->speed = fifty_base_hpt372; - else if (info->revision >= 4) - info->speed = fifty_base_hpt370a; - else - info->speed = fifty_base_hpt370a; - printk(KERN_DEBUG "HPT37X: using 50MHz PCI clock\n"); - } else { - if (info->revision >= 8) { - printk(KERN_ERR "HPT37x: 66MHz timings are not supported.\n"); - } - else if (info->revision >= 5) - info->speed = sixty_six_base_hpt372; - else if (info->revision >= 4) - info->speed = sixty_six_base_hpt370a; - else - info->speed = sixty_six_base_hpt370; - printk(KERN_DEBUG "HPT37X: using 66MHz PCI clock\n"); - } - } - - /* - * only try the pll if we don't have a table for the clock - * speed that we're running at. NOTE: the internal PLL will - * result in slow reads when using a 33MHz PCI clock. we also - * don't like to use the PLL because it will cause glitches - * on PRST/SRST when the HPT state engine gets reset. - * - * ToDo: Use 66MHz PLL when ATA133 devices are present on a - * 372 device so we can get ATA133 support - */ - if (info->speed) - goto init_hpt37X_done; - - info->flags |= PLL_MODE; - - /* - * FIXME: make this work correctly, esp with 372N as per - * reference driver code. - * - * adjust PLL based upon PCI clock, enable it, and wait for - * stabilization. - */ - adjust = 0; - freq = (pll < F_LOW_PCI_50) ? 2 : 4; - while (adjust++ < 6) { - pci_write_config_dword(dev, 0x5c, (freq + pll) << 16 | - pll | 0x100); - - /* wait for clock stabilization */ - for (i = 0; i < 0x50000; i++) { - pci_read_config_byte(dev, 0x5b, ®5bh); - if (reg5bh & 0x80) { - /* spin looking for the clock to destabilize */ - for (i = 0; i < 0x1000; ++i) { - pci_read_config_byte(dev, 0x5b, - ®5bh); - if ((reg5bh & 0x80) == 0) - goto pll_recal; - } - pci_read_config_dword(dev, 0x5c, &pll); - pci_write_config_dword(dev, 0x5c, - pll & ~0x100); - pci_write_config_byte(dev, 0x5b, 0x21); - if (info->revision >= 8) - info->speed = fifty_base_hpt370a; - else if (info->revision >= 5) - info->speed = fifty_base_hpt372; - else if (info->revision >= 4) - info->speed = fifty_base_hpt370a; - else - info->speed = fifty_base_hpt370a; - printk("HPT37X: using 50MHz internal PLL\n"); - goto init_hpt37X_done; - } - } - if (!pci_get_drvdata(dev)) { - printk("No Clock Stabilization!!!\n"); - return; - } -pll_recal: - if (adjust & 1) - pll -= (adjust >> 1); - else - pll += (adjust >> 1); - } - -init_hpt37X_done: - if (!info->speed) - printk(KERN_ERR "HPT37X%s: unknown bus timing [%d %d].\n", - (info->flags & IS_372N)?"N":"", pll, freq); - /* reset state engine */ - pci_write_config_byte(dev, 0x50, 0x37); - pci_write_config_byte(dev, 0x54, 0x37); - udelay(100); -} - -static int __devinit init_hpt37x(struct pci_dev *dev) -{ - u8 reg5ah; - - pci_read_config_byte(dev, 0x5a, ®5ah); - /* interrupt force enable */ - pci_write_config_byte(dev, 0x5a, (reg5ah & ~0x10)); - return 0; -} - -static int __devinit init_hpt366(struct pci_dev *dev) -{ - u32 reg1 = 0; - u8 drive_fast = 0; - - /* - * Disable the "fast interrupt" prediction. - */ - pci_read_config_byte(dev, 0x51, &drive_fast); - if (drive_fast & 0x80) - pci_write_config_byte(dev, 0x51, drive_fast & ~0x80); - pci_read_config_dword(dev, 0x40, ®1); - - return 0; -} - -static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const char *name) -{ - int ret = 0; - - /* - * FIXME: Not portable. Also, why do we enable the ROM in the first place? - * We don't seem to be using it. - */ - if (dev->resource[PCI_ROM_RESOURCE].start) - pci_write_config_dword(dev, PCI_ROM_ADDRESS, - dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE); - - pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, (L1_CACHE_BYTES / 4)); - pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x78); - pci_write_config_byte(dev, PCI_MIN_GNT, 0x08); - pci_write_config_byte(dev, PCI_MAX_LAT, 0x08); - - if (hpt_revision(dev) >= 3) - ret = init_hpt37x(dev); - else - ret = init_hpt366(dev); - - if (ret) - return ret; - - return dev->irq; -} - -static void __devinit init_hwif_hpt366(ide_hwif_t *hwif) -{ - struct pci_dev *dev = hwif->pci_dev; - struct hpt_info *info = ide_get_hwifdata(hwif); - u8 ata66 = 0, regmask = (hwif->channel) ? 0x01 : 0x02; - - hwif->tuneproc = &hpt3xx_tune_drive; - hwif->speedproc = &hpt3xx_tune_chipset; - hwif->quirkproc = &hpt3xx_quirkproc; - hwif->intrproc = &hpt3xx_intrproc; - hwif->maskproc = &hpt3xx_maskproc; - - if(info->flags & IS_372N) - hwif->rw_disk = &hpt372n_rw_disk; - - /* - * The HPT37x uses the CBLID pins as outputs for MA15/MA16 - * address lines to access an external eeprom. To read valid - * cable detect state the pins must be enabled as inputs. - */ - if (info->revision >= 8 && (PCI_FUNC(dev->devfn) & 1)) { - /* - * HPT374 PCI function 1 - * - set bit 15 of reg 0x52 to enable TCBLID as input - * - set bit 15 of reg 0x56 to enable FCBLID as input - */ - u16 mcr3, mcr6; - pci_read_config_word(dev, 0x52, &mcr3); - pci_read_config_word(dev, 0x56, &mcr6); - pci_write_config_word(dev, 0x52, mcr3 | 0x8000); - pci_write_config_word(dev, 0x56, mcr6 | 0x8000); - /* now read cable id register */ - pci_read_config_byte(dev, 0x5a, &ata66); - pci_write_config_word(dev, 0x52, mcr3); - pci_write_config_word(dev, 0x56, mcr6); - } else if (info->revision >= 3) { - /* - * HPT370/372 and 374 pcifn 0 - * - clear bit 0 of 0x5b to enable P/SCBLID as inputs - */ - u8 scr2; - pci_read_config_byte(dev, 0x5b, &scr2); - pci_write_config_byte(dev, 0x5b, scr2 & ~1); - /* now read cable id register */ - pci_read_config_byte(dev, 0x5a, &ata66); - pci_write_config_byte(dev, 0x5b, scr2); - } else { - pci_read_config_byte(dev, 0x5a, &ata66); - } - -#ifdef DEBUG - printk("HPT366: reg5ah=0x%02x ATA-%s Cable Port%d\n", - ata66, (ata66 & regmask) ? "33" : "66", - PCI_FUNC(hwif->pci_dev->devfn)); -#endif /* DEBUG */ - -#ifdef HPT_SERIALIZE_IO - /* serialize access to this device */ - if (hwif->mate) - hwif->serialized = hwif->mate->serialized = 1; -#endif - - if (info->revision >= 3) { - u8 reg5ah = 0; - pci_write_config_byte(dev, 0x5a, reg5ah & ~0x10); - /* - * set up ioctl for power status. - * note: power affects both - * drives on each channel - */ - hwif->resetproc = &hpt3xx_reset; - hwif->busproc = &hpt370_busproc; - } else if (info->revision >= 2) { - hwif->resetproc = &hpt3xx_reset; - hwif->busproc = &hpt3xx_tristate; - } else { - hwif->resetproc = &hpt3xx_reset; - hwif->busproc = &hpt3xx_tristate; - } - - if (!hwif->dma_base) { - hwif->drives[0].autotune = 1; - hwif->drives[1].autotune = 1; - return; - } - - hwif->ultra_mask = 0x7f; - hwif->mwdma_mask = 0x07; - - if (!(hwif->udma_four)) - hwif->udma_four = ((ata66 & regmask) ? 0 : 1); - hwif->ide_dma_check = &hpt366_config_drive_xfer_rate; - - if (info->revision >= 8) { - hwif->ide_dma_test_irq = &hpt374_ide_dma_test_irq; - hwif->ide_dma_end = &hpt374_ide_dma_end; - } else if (info->revision >= 5) { - hwif->ide_dma_test_irq = &hpt374_ide_dma_test_irq; - hwif->ide_dma_end = &hpt374_ide_dma_end; - } else if (info->revision >= 3) { - hwif->dma_start = &hpt370_ide_dma_start; - hwif->ide_dma_end = &hpt370_ide_dma_end; - hwif->ide_dma_timeout = &hpt370_ide_dma_timeout; - hwif->ide_dma_lostirq = &hpt370_ide_dma_lostirq; - } else if (info->revision >= 2) - hwif->ide_dma_lostirq = &hpt366_ide_dma_lostirq; - else - hwif->ide_dma_lostirq = &hpt366_ide_dma_lostirq; - - if (!noautodma) - hwif->autodma = 1; - hwif->drives[0].autodma = hwif->autodma; - hwif->drives[1].autodma = hwif->autodma; -} - -static void __devinit init_dma_hpt366(ide_hwif_t *hwif, unsigned long dmabase) -{ - struct hpt_info *info = ide_get_hwifdata(hwif); - u8 masterdma = 0, slavedma = 0; - u8 dma_new = 0, dma_old = 0; - u8 primary = hwif->channel ? 0x4b : 0x43; - u8 secondary = hwif->channel ? 0x4f : 0x47; - unsigned long flags; - - if (!dmabase) - return; - - if(info->speed == NULL) { - printk(KERN_WARNING "hpt: no known IDE timings, disabling DMA.\n"); - return; - } - - dma_old = hwif->INB(dmabase+2); - - local_irq_save(flags); - - dma_new = dma_old; - pci_read_config_byte(hwif->pci_dev, primary, &masterdma); - pci_read_config_byte(hwif->pci_dev, secondary, &slavedma); - - if (masterdma & 0x30) dma_new |= 0x20; - if (slavedma & 0x30) dma_new |= 0x40; - if (dma_new != dma_old) - hwif->OUTB(dma_new, dmabase+2); - - local_irq_restore(flags); - - ide_setup_dma(hwif, dmabase, 8); -} - -/* - * We "borrow" this hook in order to set the data structures - * up early enough before dma or init_hwif calls are made. - */ - -static void __devinit init_iops_hpt366(ide_hwif_t *hwif) -{ - struct hpt_info *info = kzalloc(sizeof(struct hpt_info), GFP_KERNEL); - unsigned long dmabase = pci_resource_start(hwif->pci_dev, 4); - u8 did, rid; - - if(info == NULL) { - printk(KERN_WARNING "hpt366: out of memory.\n"); - return; - } - ide_set_hwifdata(hwif, info); - - if(dmabase) { - did = inb(dmabase + 0x22); - rid = inb(dmabase + 0x28); - - if((did == 4 && rid == 6) || (did == 5 && rid > 1)) - info->flags |= IS_372N; - } - - info->revision = hpt_revision(hwif->pci_dev); - - if (info->revision >= 3) - hpt37x_clocking(hwif); - else - hpt366_clocking(hwif); -} - -static int __devinit init_setup_hpt374(struct pci_dev *dev, ide_pci_device_t *d) -{ - struct pci_dev *findev = NULL; - - if (PCI_FUNC(dev->devfn) & 1) - return -ENODEV; - - while ((findev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, findev)) != NULL) { - if ((findev->vendor == dev->vendor) && - (findev->device == dev->device) && - ((findev->devfn - dev->devfn) == 1) && - (PCI_FUNC(findev->devfn) & 1)) { - if (findev->irq != dev->irq) { - /* FIXME: we need a core pci_set_interrupt() */ - findev->irq = dev->irq; - printk(KERN_WARNING "%s: pci-config space interrupt " - "fixed.\n", d->name); - } - return ide_setup_pci_devices(dev, findev, d); - } - } - return ide_setup_pci_device(dev, d); -} - -static int __devinit init_setup_hpt37x(struct pci_dev *dev, ide_pci_device_t *d) -{ - return ide_setup_pci_device(dev, d); -} - -static int __devinit init_setup_hpt366(struct pci_dev *dev, ide_pci_device_t *d) -{ - struct pci_dev *findev = NULL; - u8 pin1 = 0, pin2 = 0; - unsigned int class_rev; - char *chipset_names[] = {"HPT366", "HPT366", "HPT368", - "HPT370", "HPT370A", "HPT372", - "HPT372N" }; - - if (PCI_FUNC(dev->devfn) & 1) - return -ENODEV; - - pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev); - class_rev &= 0xff; - - if(dev->device == PCI_DEVICE_ID_TTI_HPT372N) - class_rev = 6; - - if(class_rev <= 6) - d->name = chipset_names[class_rev]; - - switch(class_rev) { - case 6: - case 5: - case 4: - case 3: - goto init_single; - default: - break; - } - - d->channels = 1; - - pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin1); - while ((findev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, findev)) != NULL) { - if ((findev->vendor == dev->vendor) && - (findev->device == dev->device) && - ((findev->devfn - dev->devfn) == 1) && - (PCI_FUNC(findev->devfn) & 1)) { - pci_read_config_byte(findev, PCI_INTERRUPT_PIN, &pin2); - if ((pin1 != pin2) && (dev->irq == findev->irq)) { - d->bootable = ON_BOARD; - printk("%s: onboard version of chipset, " - "pin1=%d pin2=%d\n", d->name, - pin1, pin2); - } - return ide_setup_pci_devices(dev, findev, d); - } - } -init_single: - return ide_setup_pci_device(dev, d); -} - -static ide_pci_device_t hpt366_chipsets[] __devinitdata = { - { /* 0 */ - .name = "HPT366", - .init_setup = init_setup_hpt366, - .init_chipset = init_chipset_hpt366, - .init_iops = init_iops_hpt366, - .init_hwif = init_hwif_hpt366, - .init_dma = init_dma_hpt366, - .channels = 2, - .autodma = AUTODMA, - .bootable = OFF_BOARD, - .extra = 240 - },{ /* 1 */ - .name = "HPT372A", - .init_setup = init_setup_hpt37x, - .init_chipset = init_chipset_hpt366, - .init_iops = init_iops_hpt366, - .init_hwif = init_hwif_hpt366, - .init_dma = init_dma_hpt366, - .channels = 2, - .autodma = AUTODMA, - .bootable = OFF_BOARD, - },{ /* 2 */ - .name = "HPT302", - .init_setup = init_setup_hpt37x, - .init_chipset = init_chipset_hpt366, - .init_iops = init_iops_hpt366, - .init_hwif = init_hwif_hpt366, - .init_dma = init_dma_hpt366, - .channels = 2, - .autodma = AUTODMA, - .bootable = OFF_BOARD, - },{ /* 3 */ - .name = "HPT371", - .init_setup = init_setup_hpt37x, - .init_chipset = init_chipset_hpt366, - .init_iops = init_iops_hpt366, - .init_hwif = init_hwif_hpt366, - .init_dma = init_dma_hpt366, - .channels = 2, - .autodma = AUTODMA, - .bootable = OFF_BOARD, - },{ /* 4 */ - .name = "HPT374", - .init_setup = init_setup_hpt374, - .init_chipset = init_chipset_hpt366, - .init_iops = init_iops_hpt366, - .init_hwif = init_hwif_hpt366, - .init_dma = init_dma_hpt366, - .channels = 2, /* 4 */ - .autodma = AUTODMA, - .bootable = OFF_BOARD, - },{ /* 5 */ - .name = "HPT372N", - .init_setup = init_setup_hpt37x, - .init_chipset = init_chipset_hpt366, - .init_iops = init_iops_hpt366, - .init_hwif = init_hwif_hpt366, - .init_dma = init_dma_hpt366, - .channels = 2, /* 4 */ - .autodma = AUTODMA, - .bootable = OFF_BOARD, - } -}; - -/** - * hpt366_init_one - called when an HPT366 is found - * @dev: the hpt366 device - * @id: the matching pci id - * - * Called when the PCI registration layer (or the IDE initialization) - * finds a device matching our IDE device tables. - */ - -static int __devinit hpt366_init_one(struct pci_dev *dev, const struct pci_device_id *id) -{ - ide_pci_device_t *d = &hpt366_chipsets[id->driver_data]; - - return d->init_setup(dev, d); -} - -static struct pci_device_id hpt366_pci_tbl[] = { - { PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT366, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - { PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT372, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1}, - { PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT302, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2}, - { PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT371, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3}, - { PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT374, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4}, - { PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT372N, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5}, - { 0, }, -}; -MODULE_DEVICE_TABLE(pci, hpt366_pci_tbl); - -static struct pci_driver driver = { - .name = "HPT366_IDE", - .id_table = hpt366_pci_tbl, - .probe = hpt366_init_one, -}; - -static int hpt366_ide_init(void) -{ - return ide_pci_register_driver(&driver); -} - -module_init(hpt366_ide_init); - -MODULE_AUTHOR("Andre Hedrick"); -MODULE_DESCRIPTION("PCI driver module for Highpoint HPT366 IDE"); -MODULE_LICENSE("GPL"); diff --git a/drivers/ide/pci/it8172.c b/drivers/ide/pci/it8172.c deleted file mode 100644 index 0fc89fafad6..00000000000 --- a/drivers/ide/pci/it8172.c +++ /dev/null @@ -1,307 +0,0 @@ -/* - * - * BRIEF MODULE DESCRIPTION - * IT8172 IDE controller support - * - * Copyright 2000 MontaVista Software Inc. - * Author: MontaVista Software, Inc. - * stevel@mvista.com or source@mvista.com - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include <linux/module.h> -#include <linux/types.h> -#include <linux/kernel.h> -#include <linux/ioport.h> -#include <linux/pci.h> -#include <linux/hdreg.h> -#include <linux/ide.h> -#include <linux/delay.h> -#include <linux/init.h> - -#include <asm/io.h> -#include <asm/it8172/it8172_int.h> - -/* - * Prototypes - */ -static u8 it8172_ratemask (ide_drive_t *drive) -{ - return 1; -} - -static void it8172_tune_drive (ide_drive_t *drive, u8 pio) -{ - ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; - int is_slave = (&hwif->drives[1] == drive); - unsigned long flags; - u16 drive_enables; - u32 drive_timing; - - pio = ide_get_best_pio_mode(drive, pio, 4, NULL); - spin_lock_irqsave(&ide_lock, flags); - pci_read_config_word(dev, 0x40, &drive_enables); - pci_read_config_dword(dev, 0x44, &drive_timing); - - /* - * FIX! The DIOR/DIOW pulse width and recovery times in port 0x44 - * are being left at the default values of 8 PCI clocks (242 nsec - * for a 33 MHz clock). These can be safely shortened at higher - * PIO modes. The DIOR/DIOW pulse width and recovery times only - * apply to PIO modes, not to the DMA modes. - */ - - /* - * Enable port 0x44. The IT8172G spec is confused; it calls - * this register the "Slave IDE Timing Register", but in fact, - * it controls timing for both master and slave drives. - */ - drive_enables |= 0x4000; - - if (is_slave) { - drive_enables &= 0xc006; - if (pio > 1) - /* enable prefetch and IORDY sample-point */ - drive_enables |= 0x0060; - } else { - drive_enables &= 0xc060; - if (pio > 1) - /* enable prefetch and IORDY sample-point */ - drive_enables |= 0x0006; - } - - pci_write_config_word(dev, 0x40, drive_enables); - spin_unlock_irqrestore(&ide_lock, flags); -} - -static u8 it8172_dma_2_pio (u8 xfer_rate) -{ - switch(xfer_rate) { - case XFER_UDMA_5: - case XFER_UDMA_4: - case XFER_UDMA_3: - case XFER_UDMA_2: - case XFER_UDMA_1: - case XFER_UDMA_0: - case XFER_MW_DMA_2: - case XFER_PIO_4: - return 4; - case XFER_MW_DMA_1: - case XFER_PIO_3: - return 3; - case XFER_SW_DMA_2: - case XFER_PIO_2: - return 2; - case XFER_MW_DMA_0: - case XFER_SW_DMA_1: - case XFER_SW_DMA_0: - case XFER_PIO_1: - case XFER_PIO_0: - case XFER_PIO_SLOW: - default: - return 0; - } -} - -static int it8172_tune_chipset (ide_drive_t *drive, u8 xferspeed) -{ - ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; - u8 speed = ide_rate_filter(it8172_ratemask(drive), xferspeed); - int a_speed = 3 << (drive->dn * 4); - int u_flag = 1 << drive->dn; - int u_speed = 0; - u8 reg48, reg4a; - - pci_read_config_byte(dev, 0x48, ®48); - pci_read_config_byte(dev, 0x4a, ®4a); - - /* - * Setting the DMA cycle time to 2 or 3 PCI clocks (60 and 91 nsec - * at 33 MHz PCI clock) seems to cause BadCRC errors during DMA - * transfers on some drives, even though both numbers meet the minimum - * ATAPI-4 spec of 73 and 54 nsec for UDMA 1 and 2 respectively. - * So the faster times are just commented out here. The good news is - * that the slower cycle time has very little affect on transfer - * performance. - */ - - switch(speed) { - case XFER_UDMA_4: - case XFER_UDMA_2: //u_speed = 2 << (drive->dn * 4); break; - case XFER_UDMA_5: - case XFER_UDMA_3: - case XFER_UDMA_1: //u_speed = 1 << (drive->dn * 4); break; - case XFER_UDMA_0: u_speed = 0 << (drive->dn * 4); break; - case XFER_MW_DMA_2: - case XFER_MW_DMA_1: - case XFER_MW_DMA_0: - case XFER_SW_DMA_2: break; - case XFER_PIO_4: - case XFER_PIO_3: - case XFER_PIO_2: - case XFER_PIO_0: break; - default: return -1; - } - - if (speed >= XFER_UDMA_0) { - pci_write_config_byte(dev, 0x48, reg48 | u_flag); - reg4a &= ~a_speed; - pci_write_config_byte(dev, 0x4a, reg4a | u_speed); - } else { - pci_write_config_byte(dev, 0x48, reg48 & ~u_flag); - pci_write_config_byte(dev, 0x4a, reg4a & ~a_speed); - } - - it8172_tune_drive(drive, it8172_dma_2_pio(speed)); - return (ide_config_drive_speed(drive, speed)); -} - -static int it8172_config_chipset_for_dma (ide_drive_t *drive) -{ - u8 speed = ide_dma_speed(drive, it8172_ratemask(drive)); - - if (!(speed)) { - u8 tspeed = ide_get_best_pio_mode(drive, 255, 4, NULL); - speed = it8172_dma_2_pio(XFER_PIO_0 + tspeed); - } - - (void) it8172_tune_chipset(drive, speed); - return ide_dma_enable(drive); -} - -static int it8172_config_drive_xfer_rate (ide_drive_t *drive) -{ - ide_hwif_t *hwif = HWIF(drive); - struct hd_driveid *id = drive->id; - - drive->init_speed = 0; - - if (id && (id->capability & 1) && drive->autodma) { - - if (ide_use_dma(drive)) { - if (it8172_config_chipset_for_dma(drive)) - return hwif->ide_dma_on(drive); - } - - goto fast_ata_pio; - - } else if ((id->capability & 8) || (id->field_valid & 2)) { -fast_ata_pio: - it8172_tune_drive(drive, 5); - return hwif->ide_dma_off_quietly(drive); - } - /* IORDY not supported */ - return 0; -} - -static unsigned int __devinit init_chipset_it8172 (struct pci_dev *dev, const char *name) -{ - unsigned char progif; - - /* - * Place both IDE interfaces into PCI "native" mode - */ - pci_read_config_byte(dev, PCI_CLASS_PROG, &progif); - pci_write_config_byte(dev, PCI_CLASS_PROG, progif | 0x05); - - return IT8172_IDE_IRQ; -} - - -static void __devinit init_hwif_it8172 (ide_hwif_t *hwif) -{ - struct pci_dev* dev = hwif->pci_dev; - unsigned long cmdBase, ctrlBase; - - hwif->autodma = 0; - hwif->tuneproc = &it8172_tune_drive; - hwif->speedproc = &it8172_tune_chipset; - - cmdBase = dev->resource[0].start; - ctrlBase = dev->resource[1].start; - - ide_init_hwif_ports(&hwif->hw, cmdBase, ctrlBase | 2, NULL); - memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports)); - hwif->noprobe = 0; - - if (!hwif->dma_base) { - hwif->drives[0].autotune = 1; - hwif->drives[1].autotune = 1; - return; - } - - hwif->atapi_dma = 1; - hwif->ultra_mask = 0x07; - hwif->mwdma_mask = 0x06; - hwif->swdma_mask = 0x04; - - hwif->ide_dma_check = &it8172_config_drive_xfer_rate; - if (!noautodma) - hwif->autodma = 1; - hwif->drives[0].autodma = hwif->autodma; - hwif->drives[1].autodma = hwif->autodma; -} - -static ide_pci_device_t it8172_chipsets[] __devinitdata = { - { /* 0 */ - .name = "IT8172G", - .init_chipset = init_chipset_it8172, - .init_hwif = init_hwif_it8172, - .channels = 2, - .autodma = AUTODMA, - .enablebits = {{0x00,0x00,0x00}, {0x40,0x00,0x01}}, - .bootable = ON_BOARD, - } -}; - -static int __devinit it8172_init_one(struct pci_dev *dev, const struct pci_device_id *id) -{ - if ((!(PCI_FUNC(dev->devfn) & 1) || - (!((dev->class >> 8) == PCI_CLASS_STORAGE_IDE)))) - return -ENODEV; /* IT8172 is more than an IDE controller */ - return ide_setup_pci_device(dev, &it8172_chipsets[id->driver_data]); -} - -static struct pci_device_id it8172_pci_tbl[] = { - { PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_IT8172G, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - { 0, }, -}; -MODULE_DEVICE_TABLE(pci, it8172_pci_tbl); - -static struct pci_driver driver = { - .name = "IT8172_IDE", - .id_table = it8172_pci_tbl, - .probe = it8172_init_one, -}; - -static int it8172_ide_init(void) -{ - return ide_pci_register_driver(&driver); -} - -module_init(it8172_ide_init); - -MODULE_AUTHOR("SteveL@mvista.com"); -MODULE_DESCRIPTION("PCI driver module for ITE 8172 IDE"); -MODULE_LICENSE("GPL"); diff --git a/drivers/ide/pci/ns87415.c b/drivers/ide/pci/ns87415.c deleted file mode 100644 index d95714bcee4..00000000000 --- a/drivers/ide/pci/ns87415.c +++ /dev/null @@ -1,314 +0,0 @@ -/* - * linux/drivers/ide/pci/ns87415.c Version 2.00 Sep. 10, 2002 - * - * Copyright (C) 1997-1998 Mark Lord <mlord@pobox.com> - * Copyright (C) 1998 Eddie C. Dost <ecd@skynet.be> - * Copyright (C) 1999-2000 Andre Hedrick <andre@linux-ide.org> - * Copyright (C) 2004 Grant Grundler <grundler at parisc-linux.org> - * - * Inspired by an earlier effort from David S. Miller <davem@redhat.com> - */ - -#include <linux/module.h> -#include <linux/types.h> -#include <linux/kernel.h> -#include <linux/timer.h> -#include <linux/mm.h> -#include <linux/ioport.h> -#include <linux/interrupt.h> -#include <linux/blkdev.h> -#include <linux/hdreg.h> -#include <linux/pci.h> -#include <linux/delay.h> -#include <linux/ide.h> -#include <linux/init.h> - -#include <asm/io.h> - -#ifdef CONFIG_SUPERIO -/* SUPERIO 87560 is a PoS chip that NatSem denies exists. - * Unfortunately, it's built-in on all Astro-based PA-RISC workstations - * which use the integrated NS87514 cell for CD-ROM support. - * i.e we have to support for CD-ROM installs. - * See drivers/parisc/superio.c for more gory details. - */ -#include <asm/superio.h> - -static unsigned long superio_ide_status[2]; -static unsigned long superio_ide_select[2]; -static unsigned long superio_ide_dma_status[2]; - -#define SUPERIO_IDE_MAX_RETRIES 25 - -/* Because of a defect in Super I/O, all reads of the PCI DMA status - * registers, IDE status register and the IDE select register need to be - * retried - */ -static u8 superio_ide_inb (unsigned long port) -{ - if (port == superio_ide_status[0] || - port == superio_ide_status[1] || - port == superio_ide_select[0] || - port == superio_ide_select[1] || - port == superio_ide_dma_status[0] || - port == superio_ide_dma_status[1]) { - u8 tmp; - int retries = SUPERIO_IDE_MAX_RETRIES; - - /* printk(" [ reading port 0x%x with retry ] ", port); */ - - do { - tmp = inb(port); - if (tmp == 0) - udelay(50); - } while (tmp == 0 && retries-- > 0); - - return tmp; - } - - return inb(port); -} - -static void __devinit superio_ide_init_iops (struct hwif_s *hwif) -{ - u32 base, dmabase; - u8 tmp; - struct pci_dev *pdev = hwif->pci_dev; - u8 port = hwif->channel; - - base = pci_resource_start(pdev, port * 2) & ~3; - dmabase = pci_resource_start(pdev, 4) & ~3; - - superio_ide_status[port] = base + IDE_STATUS_OFFSET; - superio_ide_select[port] = base + IDE_SELECT_OFFSET; - superio_ide_dma_status[port] = dmabase + (!port ? 2 : 0xa); - - /* Clear error/interrupt, enable dma */ - tmp = superio_ide_inb(superio_ide_dma_status[port]); - outb(tmp | 0x66, superio_ide_dma_status[port]); - - /* We need to override inb to workaround a SuperIO errata */ - hwif->INB = superio_ide_inb; -} - -static void __devinit init_iops_ns87415(ide_hwif_t *hwif) -{ - if (PCI_SLOT(hwif->pci_dev->devfn) == 0xE) { - /* Built-in - assume it's under superio. */ - superio_ide_init_iops(hwif); - } -} -#endif - -static unsigned int ns87415_count = 0, ns87415_control[MAX_HWIFS] = { 0 }; - -/* - * This routine either enables/disables (according to drive->present) - * the IRQ associated with the port (HWIF(drive)), - * and selects either PIO or DMA handshaking for the next I/O operation. - */ -static void ns87415_prepare_drive (ide_drive_t *drive, unsigned int use_dma) -{ - ide_hwif_t *hwif = HWIF(drive); - unsigned int bit, other, new, *old = (unsigned int *) hwif->select_data; - struct pci_dev *dev = hwif->pci_dev; - unsigned long flags; - - local_irq_save(flags); - new = *old; - - /* Adjust IRQ enable bit */ - bit = 1 << (8 + hwif->channel); - new = drive->present ? (new & ~bit) : (new | bit); - - /* Select PIO or DMA, DMA may only be selected for one drive/channel. */ - bit = 1 << (20 + drive->select.b.unit + (hwif->channel << 1)); - other = 1 << (20 + (1 - drive->select.b.unit) + (hwif->channel << 1)); - new = use_dma ? ((new & ~other) | bit) : (new & ~bit); - - if (new != *old) { - unsigned char stat; - - /* - * Don't change DMA engine settings while Write Buffers - * are busy. - */ - (void) pci_read_config_byte(dev, 0x43, &stat); - while (stat & 0x03) { - udelay(1); - (void) pci_read_config_byte(dev, 0x43, &stat); - } - - *old = new; - (void) pci_write_config_dword(dev, 0x40, new); - - /* - * And let things settle... - */ - udelay(10); - } - - local_irq_restore(flags); -} - -static void ns87415_selectproc (ide_drive_t *drive) -{ - ns87415_prepare_drive (drive, drive->using_dma); -} - -static int ns87415_ide_dma_end (ide_drive_t *drive) -{ - ide_hwif_t *hwif = HWIF(drive); - u8 dma_stat = 0, dma_cmd = 0; - - drive->waiting_for_dma = 0; - dma_stat = hwif->INB(hwif->dma_status); - /* get dma command mode */ - dma_cmd = hwif->INB(hwif->dma_command); - /* stop DMA */ - hwif->OUTB(dma_cmd & ~1, hwif->dma_command); - /* from ERRATA: clear the INTR & ERROR bits */ - dma_cmd = hwif->INB(hwif->dma_command); - hwif->OUTB(dma_cmd|6, hwif->dma_command); - /* and free any DMA resources */ - ide_destroy_dmatable(drive); - /* verify good DMA status */ - return (dma_stat & 7) != 4; -} - -static int ns87415_ide_dma_setup(ide_drive_t *drive) -{ - /* select DMA xfer */ - ns87415_prepare_drive(drive, 1); - if (!ide_dma_setup(drive)) - return 0; - /* DMA failed: select PIO xfer */ - ns87415_prepare_drive(drive, 0); - return 1; -} - -static int ns87415_ide_dma_check (ide_drive_t *drive) -{ - if (drive->media != ide_disk) - return HWIF(drive)->ide_dma_off_quietly(drive); - return __ide_dma_check(drive); -} - -static void __devinit init_hwif_ns87415 (ide_hwif_t *hwif) -{ - struct pci_dev *dev = hwif->pci_dev; - unsigned int ctrl, using_inta; - u8 progif; -#ifdef __sparc_v9__ - int timeout; - u8 stat; -#endif - - hwif->autodma = 0; - hwif->selectproc = &ns87415_selectproc; - - /* - * We cannot probe for IRQ: both ports share common IRQ on INTA. - * Also, leave IRQ masked during drive probing, to prevent infinite - * interrupts from a potentially floating INTA.. - * - * IRQs get unmasked in selectproc when drive is first used. - */ - (void) pci_read_config_dword(dev, 0x40, &ctrl); - (void) pci_read_config_byte(dev, 0x09, &progif); - /* is irq in "native" mode? */ - using_inta = progif & (1 << (hwif->channel << 1)); - if (!using_inta) - using_inta = ctrl & (1 << (4 + hwif->channel)); - if (hwif->mate) { - hwif->select_data = hwif->mate->select_data; - } else { - hwif->select_data = (unsigned long) - &ns87415_control[ns87415_count++]; - ctrl |= (1 << 8) | (1 << 9); /* mask both IRQs */ - if (using_inta) - ctrl &= ~(1 << 6); /* unmask INTA */ - *((unsigned int *)hwif->select_data) = ctrl; - (void) pci_write_config_dword(dev, 0x40, ctrl); - - /* - * Set prefetch size to 512 bytes for both ports, - * but don't turn on/off prefetching here. - */ - pci_write_config_byte(dev, 0x55, 0xee); - -#ifdef __sparc_v9__ - /* - * XXX: Reset the device, if we don't it will not respond - * to SELECT_DRIVE() properly during first probe_hwif(). - */ - timeout = 10000; - hwif->OUTB(12, hwif->io_ports[IDE_CONTROL_OFFSET]); - udelay(10); - hwif->OUTB(8, hwif->io_ports[IDE_CONTROL_OFFSET]); - do { - udelay(50); - stat = hwif->INB(hwif->io_ports[IDE_STATUS_OFFSET]); - if (stat == 0xff) - break; - } while ((stat & BUSY_STAT) && --timeout); -#endif - } - - if (!using_inta) - hwif->irq = ide_default_irq(hwif->io_ports[IDE_DATA_OFFSET]); - else if (!hwif->irq && hwif->mate && hwif->mate->irq) - hwif->irq = hwif->mate->irq; /* share IRQ with mate */ - - if (!hwif->dma_base) - return; - - hwif->OUTB(0x60, hwif->dma_status); - hwif->dma_setup = &ns87415_ide_dma_setup; - hwif->ide_dma_check = &ns87415_ide_dma_check; - hwif->ide_dma_end = &ns87415_ide_dma_end; - - if (!noautodma) - hwif->autodma = 1; - hwif->drives[0].autodma = hwif->autodma; - hwif->drives[1].autodma = hwif->autodma; -} - -static ide_pci_device_t ns87415_chipset __devinitdata = { - .name = "NS87415", -#ifdef CONFIG_SUPERIO - .init_iops = init_iops_ns87415, -#endif - .init_hwif = init_hwif_ns87415, - .channels = 2, - .autodma = AUTODMA, - .bootable = ON_BOARD, -}; - -static int __devinit ns87415_init_one(struct pci_dev *dev, const struct pci_device_id *id) -{ - return ide_setup_pci_device(dev, &ns87415_chipset); -} - -static struct pci_device_id ns87415_pci_tbl[] = { - { PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87415, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - { 0, }, -}; -MODULE_DEVICE_TABLE(pci, ns87415_pci_tbl); - -static struct pci_driver driver = { - .name = "NS87415_IDE", - .id_table = ns87415_pci_tbl, - .probe = ns87415_init_one, -}; - -static int ns87415_ide_init(void) -{ - return ide_pci_register_driver(&driver); -} - -module_init(ns87415_ide_init); - -MODULE_AUTHOR("Mark Lord, Eddie Dost, Andre Hedrick"); -MODULE_DESCRIPTION("PCI driver module for NS87415 IDE"); -MODULE_LICENSE("GPL"); diff --git a/drivers/ide/pci/opti621.c b/drivers/ide/pci/opti621.c deleted file mode 100644 index 7a7c2ef78ac..00000000000 --- a/drivers/ide/pci/opti621.c +++ /dev/null @@ -1,394 +0,0 @@ -/* - * linux/drivers/ide/pci/opti621.c Version 0.7 Sept 10, 2002 - * - * Copyright (C) 1996-1998 Linus Torvalds & authors (see below) - */ - -/* - * Authors: - * Jaromir Koutek <miri@punknet.cz>, - * Jan Harkes <jaharkes@cwi.nl>, - * Mark Lord <mlord@pobox.com> - * Some parts of code are from ali14xx.c and from rz1000.c. - * - * OPTi is trademark of OPTi, Octek is trademark of Octek. - * - * I used docs from OPTi databook, from ftp.opti.com, file 9123-0002.ps - * and disassembled/traced setupvic.exe (DOS program). - * It increases kernel code about 2 kB. - * I don't have this card no more, but I hope I can get some in case - * of needed development. - * My card is Octek PIDE 1.01 (on card) or OPTiViC (program). - * It has a place for a secondary connector in circuit, but nothing - * is there. Also BIOS says no address for - * secondary controller (see bellow in ide_init_opti621). - * I've only tested this on my system, which only has one disk. - * It's Western Digital WDAC2850, with PIO mode 3. The PCI bus - * is at 20 MHz (I have DX2/80, I tried PCI at 40, but I got random - * lockups). I tried the OCTEK double speed CD-ROM and - * it does not work! But I can't boot DOS also, so it's probably - * hardware fault. I have connected Conner 80MB, the Seagate 850MB (no - * problems) and Seagate 1GB (as slave, WD as master). My experiences - * with the third, 1GB drive: I got 3MB/s (hdparm), but sometimes - * it slows to about 100kB/s! I don't know why and I have - * not this drive now, so I can't try it again. - * I write this driver because I lost the paper ("manual") with - * settings of jumpers on the card and I have to boot Linux with - * Loadlin except LILO, cause I have to run the setupvic.exe program - * already or I get disk errors (my test: rpm -Vf - * /usr/X11R6/bin/XF86_SVGA - or any big file). - * Some numbers from hdparm -t /dev/hda: - * Timing buffer-cache reads: 32 MB in 3.02 seconds =10.60 MB/sec - * Timing buffered disk reads: 16 MB in 5.52 seconds = 2.90 MB/sec - * I have 4 Megs/s before, but I don't know why (maybe changes - * in hdparm test). - * After release of 0.1, I got some successful reports, so it might work. - * - * The main problem with OPTi is that some timings for master - * and slave must be the same. For example, if you have master - * PIO 3 and slave PIO 0, driver have to set some timings of - * master for PIO 0. Second problem is that opti621_tune_drive - * got only one drive to set, but have to set both drives. - * This is solved in compute_pios. If you don't set - * the second drive, compute_pios use ide_get_best_pio_mode - * for autoselect mode (you can change it to PIO 0, if you want). - * If you then set the second drive to another PIO, the old value - * (automatically selected) will be overrided by yours. - * There is a 25/33MHz switch in configuration - * register, but driver is written for use at any frequency which get - * (use idebus=xx to select PCI bus speed). - * Use ide0=autotune for automatical tune of the PIO modes. - * If you get strange results, do not use this and set PIO manually - * by hdparm. - * - * Version 0.1, Nov 8, 1996 - * by Jaromir Koutek, for 2.1.8. - * Initial version of driver. - * - * Version 0.2 - * Number 0.2 skipped. - * - * Version 0.3, Nov 29, 1997 - * by Mark Lord (probably), for 2.1.68 - * Updates for use with new IDE block driver. - * - * Version 0.4, Dec 14, 1997 - * by Jan Harkes - * Fixed some errors and cleaned the code. - * - * Version 0.5, Jan 2, 1998 - * by Jaromir Koutek - * Updates for use with (again) new IDE block driver. - * Update of documentation. - * - * Version 0.6, Jan 2, 1999 - * by Jaromir Koutek - * Reversed to version 0.3 of the driver, because - * 0.5 doesn't work. - */ - -#undef REALLY_SLOW_IO /* most systems can safely undef this */ -#define OPTI621_DEBUG /* define for debug messages */ - -#include <linux/types.h> -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/delay.h> -#include <linux/timer.h> -#include <linux/mm.h> -#include <linux/ioport.h> -#include <linux/blkdev.h> -#include <linux/pci.h> -#include <linux/hdreg.h> -#include <linux/ide.h> - -#include <asm/io.h> - -#define OPTI621_MAX_PIO 3 -/* In fact, I do not have any PIO 4 drive - * (address: 25 ns, data: 70 ns, recovery: 35 ns), - * but OPTi 82C621 is programmable and it can do (minimal values): - * on 40MHz PCI bus (pulse 25 ns): - * address: 25 ns, data: 25 ns, recovery: 50 ns; - * on 20MHz PCI bus (pulse 50 ns): - * address: 50 ns, data: 50 ns, recovery: 100 ns. - */ - -/* #define READ_PREFETCH 0 */ -/* Uncomment for disable read prefetch. - * There is some readprefetch capatibility in hdparm, - * but when I type hdparm -P 1 /dev/hda, I got errors - * and till reset drive is inaccessible. - * This (hw) read prefetch is safe on my drive. - */ - -#ifndef READ_PREFETCH -#define READ_PREFETCH 0x40 /* read prefetch is enabled */ -#endif /* else read prefetch is disabled */ - -#define READ_REG 0 /* index of Read cycle timing register */ -#define WRITE_REG 1 /* index of Write cycle timing register */ -#define CNTRL_REG 3 /* index of Control register */ -#define STRAP_REG 5 /* index of Strap register */ -#define MISC_REG 6 /* index of Miscellaneous register */ - -static int reg_base; - -#define PIO_NOT_EXIST 254 -#define PIO_DONT_KNOW 255 - -/* there are stored pio numbers from other calls of opti621_tune_drive */ -static void compute_pios(ide_drive_t *drive, u8 pio) -/* Store values into drive->drive_data - * second_contr - 0 for primary controller, 1 for secondary - * slave_drive - 0 -> pio is for master, 1 -> pio is for slave - * pio - PIO mode for selected drive (for other we don't know) - */ -{ - int d; - ide_hwif_t *hwif = HWIF(drive); - - drive->drive_data = ide_get_best_pio_mode(drive, pio, OPTI621_MAX_PIO, NULL); - for (d = 0; d < 2; ++d) { - drive = &hwif->drives[d]; - if (drive->present) { - if (drive->drive_data == PIO_DONT_KNOW) - drive->drive_data = ide_get_best_pio_mode(drive, 255, OPTI621_MAX_PIO, NULL); -#ifdef OPTI621_DEBUG - printk("%s: Selected PIO mode %d\n", - drive->name, drive->drive_data); -#endif - } else { - drive->drive_data = PIO_NOT_EXIST; - } - } -} - -static int cmpt_clk(int time, int bus_speed) -/* Returns (rounded up) time in clocks for time in ns, - * with bus_speed in MHz. - * Example: bus_speed = 40 MHz, time = 80 ns - * 1000/40 = 25 ns (clk value), - * 80/25 = 3.2, rounded up to 4 (I hope ;-)). - * Use idebus=xx to select right frequency. - */ -{ - return ((time*bus_speed+999)/1000); -} - -static void write_reg(ide_hwif_t *hwif, u8 value, int reg) -/* Write value to register reg, base of register - * is at reg_base (0x1f0 primary, 0x170 secondary, - * if not changed by PCI configuration). - * This is from setupvic.exe program. - */ -{ - hwif->INW(reg_base+1); - hwif->INW(reg_base+1); - hwif->OUTB(3, reg_base+2); - hwif->OUTB(value, reg_base+reg); - hwif->OUTB(0x83, reg_base+2); -} - -static u8 read_reg(ide_hwif_t *hwif, int reg) -/* Read value from register reg, base of register - * is at reg_base (0x1f0 primary, 0x170 secondary, - * if not changed by PCI configuration). - * This is from setupvic.exe program. - */ -{ - u8 ret = 0; - - hwif->INW(reg_base+1); - hwif->INW(reg_base+1); - hwif->OUTB(3, reg_base+2); - ret = hwif->INB(reg_base+reg); - hwif->OUTB(0x83, reg_base+2); - return ret; -} - -typedef struct pio_clocks_s { - int address_time; /* Address setup (clocks) */ - int data_time; /* Active/data pulse (clocks) */ - int recovery_time; /* Recovery time (clocks) */ -} pio_clocks_t; - -static void compute_clocks(int pio, pio_clocks_t *clks) -{ - if (pio != PIO_NOT_EXIST) { - int adr_setup, data_pls; - int bus_speed = system_bus_clock(); - - adr_setup = ide_pio_timings[pio].setup_time; - data_pls = ide_pio_timings[pio].active_time; - clks->address_time = cmpt_clk(adr_setup, bus_speed); - clks->data_time = cmpt_clk(data_pls, bus_speed); - clks->recovery_time = cmpt_clk(ide_pio_timings[pio].cycle_time - - adr_setup-data_pls, bus_speed); - if (clks->address_time<1) clks->address_time = 1; - if (clks->address_time>4) clks->address_time = 4; - if (clks->data_time<1) clks->data_time = 1; - if (clks->data_time>16) clks->data_time = 16; - if (clks->recovery_time<2) clks->recovery_time = 2; - if (clks->recovery_time>17) clks->recovery_time = 17; - } else { - clks->address_time = 1; - clks->data_time = 1; - clks->recovery_time = 2; - /* minimal values */ - } - -} - -/* Main tune procedure, called from tuneproc. */ -static void opti621_tune_drive (ide_drive_t *drive, u8 pio) -{ - /* primary and secondary drives share some registers, - * so we have to program both drives - */ - unsigned long flags; - u8 pio1 = 0, pio2 = 0; - pio_clocks_t first, second; - int ax, drdy; - u8 cycle1, cycle2, misc; - ide_hwif_t *hwif = HWIF(drive); - - /* sets drive->drive_data for both drives */ - compute_pios(drive, pio); - pio1 = hwif->drives[0].drive_data; - pio2 = hwif->drives[1].drive_data; - - compute_clocks(pio1, &first); - compute_clocks(pio2, &second); - - /* ax = max(a1,a2) */ - ax = (first.address_time < second.address_time) ? second.address_time : first.address_time; - - drdy = 2; /* DRDY is default 2 (by OPTi Databook) */ - - cycle1 = ((first.data_time-1)<<4) | (first.recovery_time-2); - cycle2 = ((second.data_time-1)<<4) | (second.recovery_time-2); - misc = READ_PREFETCH | ((ax-1)<<4) | ((drdy-2)<<1); - -#ifdef OPTI621_DEBUG - printk("%s: master: address: %d, data: %d, " - "recovery: %d, drdy: %d [clk]\n", - hwif->name, ax, first.data_time, - first.recovery_time, drdy); - printk("%s: slave: address: %d, data: %d, " - "recovery: %d, drdy: %d [clk]\n", - hwif->name, ax, second.data_time, - second.recovery_time, drdy); -#endif - - spin_lock_irqsave(&ide_lock, flags); - - reg_base = hwif->io_ports[IDE_DATA_OFFSET]; - - /* allow Register-B */ - hwif->OUTB(0xc0, reg_base+CNTRL_REG); - /* hmm, setupvic.exe does this ;-) */ - hwif->OUTB(0xff, reg_base+5); - /* if reads 0xff, adapter not exist? */ - (void) hwif->INB(reg_base+CNTRL_REG); - /* if reads 0xc0, no interface exist? */ - read_reg(hwif, CNTRL_REG); - /* read version, probably 0 */ - read_reg(hwif, STRAP_REG); - - /* program primary drive */ - /* select Index-0 for Register-A */ - write_reg(hwif, 0, MISC_REG); - /* set read cycle timings */ - write_reg(hwif, cycle1, READ_REG); - /* set write cycle timings */ - write_reg(hwif, cycle1, WRITE_REG); - - /* program secondary drive */ - /* select Index-1 for Register-B */ - write_reg(hwif, 1, MISC_REG); - /* set read cycle timings */ - write_reg(hwif, cycle2, READ_REG); - /* set write cycle timings */ - write_reg(hwif, cycle2, WRITE_REG); - - /* use Register-A for drive 0 */ - /* use Register-B for drive 1 */ - write_reg(hwif, 0x85, CNTRL_REG); - - /* set address setup, DRDY timings, */ - /* and read prefetch for both drives */ - write_reg(hwif, misc, MISC_REG); - - spin_unlock_irqrestore(&ide_lock, flags); -} - -/* - * init_hwif_opti621() is called once for each hwif found at boot. - */ -static void __devinit init_hwif_opti621 (ide_hwif_t *hwif) -{ - hwif->autodma = 0; - hwif->drives[0].drive_data = PIO_DONT_KNOW; - hwif->drives[1].drive_data = PIO_DONT_KNOW; - hwif->tuneproc = &opti621_tune_drive; - - if (!(hwif->dma_base)) - return; - - hwif->atapi_dma = 1; - hwif->mwdma_mask = 0x07; - hwif->swdma_mask = 0x07; - - if (!noautodma) - hwif->autodma = 1; - hwif->drives[0].autodma = hwif->autodma; - hwif->drives[1].autodma = hwif->autodma; -} - -static ide_pci_device_t opti621_chipsets[] __devinitdata = { - { /* 0 */ - .name = "OPTI621", - .init_hwif = init_hwif_opti621, - .channels = 2, - .autodma = AUTODMA, - .enablebits = {{0x45,0x80,0x00}, {0x40,0x08,0x00}}, - .bootable = ON_BOARD, - },{ /* 1 */ - .name = "OPTI621X", - .init_hwif = init_hwif_opti621, - .channels = 2, - .autodma = AUTODMA, - .enablebits = {{0x45,0x80,0x00}, {0x40,0x08,0x00}}, - .bootable = ON_BOARD, - } -}; - -static int __devinit opti621_init_one(struct pci_dev *dev, const struct pci_device_id *id) -{ - return ide_setup_pci_device(dev, &opti621_chipsets[id->driver_data]); -} - -static struct pci_device_id opti621_pci_tbl[] = { - { PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C621, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - { PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C825, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1}, - { 0, }, -}; -MODULE_DEVICE_TABLE(pci, opti621_pci_tbl); - -static struct pci_driver driver = { - .name = "Opti621_IDE", - .id_table = opti621_pci_tbl, - .probe = opti621_init_one, -}; - -static int opti621_ide_init(void) -{ - return ide_pci_register_driver(&driver); -} - -module_init(opti621_ide_init); - -MODULE_AUTHOR("Jaromir Koutek, Jan Harkes, Mark Lord"); -MODULE_DESCRIPTION("PCI driver module for Opti621 IDE"); -MODULE_LICENSE("GPL"); diff --git a/drivers/ide/pci/pdc202xx_new.c b/drivers/ide/pci/pdc202xx_new.c deleted file mode 100644 index 6c097e80b4d..00000000000 --- a/drivers/ide/pci/pdc202xx_new.c +++ /dev/null @@ -1,503 +0,0 @@ -/* - * Promise TX2/TX4/TX2000/133 IDE driver - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Split from: - * linux/drivers/ide/pdc202xx.c Version 0.35 Mar. 30, 2002 - * Copyright (C) 1998-2002 Andre Hedrick <andre@linux-ide.org> - * Portions Copyright (C) 1999 Promise Technology, Inc. - * Author: Frank Tiernan (frankt@promise.com) - * Released under terms of General Public License - */ - -#include <linux/module.h> -#include <linux/types.h> -#include <linux/kernel.h> -#include <linux/delay.h> -#include <linux/timer.h> -#include <linux/mm.h> -#include <linux/ioport.h> -#include <linux/blkdev.h> -#include <linux/hdreg.h> -#include <linux/interrupt.h> -#include <linux/pci.h> -#include <linux/init.h> -#include <linux/ide.h> - -#include <asm/io.h> -#include <asm/irq.h> - -#ifdef CONFIG_PPC_PMAC -#include <asm/prom.h> -#include <asm/pci-bridge.h> -#endif - -#define PDC202_DEBUG_CABLE 0 - -static const char *pdc_quirk_drives[] = { - "QUANTUM FIREBALLlct08 08", - "QUANTUM FIREBALLP KA6.4", - "QUANTUM FIREBALLP KA9.1", - "QUANTUM FIREBALLP LM20.4", - "QUANTUM FIREBALLP KX13.6", - "QUANTUM FIREBALLP KX20.5", - "QUANTUM FIREBALLP KX27.3", - "QUANTUM FIREBALLP LM20.5", - NULL -}; - -#define set_2regs(a, b) \ - do { \ - hwif->OUTB((a + adj), indexreg); \ - hwif->OUTB(b, datareg); \ - } while(0) - -#define set_ultra(a, b, c) \ - do { \ - set_2regs(0x10,(a)); \ - set_2regs(0x11,(b)); \ - set_2regs(0x12,(c)); \ - } while(0) - -#define set_ata2(a, b) \ - do { \ - set_2regs(0x0e,(a)); \ - set_2regs(0x0f,(b)); \ - } while(0) - -#define set_pio(a, b, c) \ - do { \ - set_2regs(0x0c,(a)); \ - set_2regs(0x0d,(b)); \ - set_2regs(0x13,(c)); \ - } while(0) - -static u8 pdcnew_ratemask (ide_drive_t *drive) -{ - u8 mode; - - switch(HWIF(drive)->pci_dev->device) { - case PCI_DEVICE_ID_PROMISE_20277: - case PCI_DEVICE_ID_PROMISE_20276: - case PCI_DEVICE_ID_PROMISE_20275: - case PCI_DEVICE_ID_PROMISE_20271: - case PCI_DEVICE_ID_PROMISE_20269: - mode = 4; - break; - case PCI_DEVICE_ID_PROMISE_20270: - case PCI_DEVICE_ID_PROMISE_20268: - mode = 3; - break; - default: - return 0; - } - if (!eighty_ninty_three(drive)) - mode = min(mode, (u8)1); - return mode; -} - -static int check_in_drive_lists (ide_drive_t *drive, const char **list) -{ - struct hd_driveid *id = drive->id; - - if (pdc_quirk_drives == list) { - while (*list) { - if (strstr(id->model, *list++)) { - return 2; - } - } - } else { - while (*list) { - if (!strcmp(*list++,id->model)) { - return 1; - } - } - } - return 0; -} - -static int pdcnew_new_tune_chipset (ide_drive_t *drive, u8 xferspeed) -{ - ide_hwif_t *hwif = HWIF(drive); - unsigned long indexreg = hwif->dma_vendor1; - unsigned long datareg = hwif->dma_vendor3; - u8 thold = 0x10; - u8 adj = (drive->dn%2) ? 0x08 : 0x00; - u8 speed = ide_rate_filter(pdcnew_ratemask(drive), xferspeed); - - if (speed == XFER_UDMA_2) { - hwif->OUTB((thold + adj), indexreg); - hwif->OUTB((hwif->INB(datareg) & 0x7f), datareg); - } - - switch (speed) { - case XFER_UDMA_7: - speed = XFER_UDMA_6; - case XFER_UDMA_6: set_ultra(0x1a, 0x01, 0xcb); break; - case XFER_UDMA_5: set_ultra(0x1a, 0x02, 0xcb); break; - case XFER_UDMA_4: set_ultra(0x1a, 0x03, 0xcd); break; - case XFER_UDMA_3: set_ultra(0x1a, 0x05, 0xcd); break; - case XFER_UDMA_2: set_ultra(0x2a, 0x07, 0xcd); break; - case XFER_UDMA_1: set_ultra(0x3a, 0x0a, 0xd0); break; - case XFER_UDMA_0: set_ultra(0x4a, 0x0f, 0xd5); break; - case XFER_MW_DMA_2: set_ata2(0x69, 0x25); break; - case XFER_MW_DMA_1: set_ata2(0x6b, 0x27); break; - case XFER_MW_DMA_0: set_ata2(0xdf, 0x5f); break; - case XFER_PIO_4: set_pio(0x23, 0x09, 0x25); break; - case XFER_PIO_3: set_pio(0x27, 0x0d, 0x35); break; - case XFER_PIO_2: set_pio(0x23, 0x26, 0x64); break; - case XFER_PIO_1: set_pio(0x46, 0x29, 0xa4); break; - case XFER_PIO_0: set_pio(0xfb, 0x2b, 0xac); break; - default: - ; - } - - return (ide_config_drive_speed(drive, speed)); -} - -/* 0 1 2 3 4 5 6 7 8 - * 960, 480, 390, 300, 240, 180, 120, 90, 60 - * 180, 150, 120, 90, 60 - * DMA_Speed - * 180, 120, 90, 90, 90, 60, 30 - * 11, 5, 4, 3, 2, 1, 0 - */ -static void pdcnew_tune_drive(ide_drive_t *drive, u8 pio) -{ - u8 speed; - - if (pio == 5) pio = 4; - speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, pio, NULL); - - (void)pdcnew_new_tune_chipset(drive, speed); -} - -static u8 pdcnew_new_cable_detect (ide_hwif_t *hwif) -{ - hwif->OUTB(0x0b, hwif->dma_vendor1); - return ((u8)((hwif->INB(hwif->dma_vendor3) & 0x04))); -} -static int config_chipset_for_dma (ide_drive_t *drive) -{ - struct hd_driveid *id = drive->id; - ide_hwif_t *hwif = HWIF(drive); - u8 speed = -1; - u8 cable; - - u8 ultra_66 = ((id->dma_ultra & 0x0010) || - (id->dma_ultra & 0x0008)) ? 1 : 0; - - cable = pdcnew_new_cable_detect(hwif); - - if (ultra_66 && cable) { - printk(KERN_WARNING "Warning: %s channel requires an 80-pin cable for operation.\n", hwif->channel ? "Secondary":"Primary"); - printk(KERN_WARNING "%s reduced to Ultra33 mode.\n", drive->name); - } - - if (drive->media != ide_disk) - return 0; - if (id->capability & 4) { /* IORDY_EN & PREFETCH_EN */ - hwif->OUTB((0x13 + ((drive->dn%2) ? 0x08 : 0x00)), hwif->dma_vendor1); - hwif->OUTB((hwif->INB(hwif->dma_vendor3)|0x03), hwif->dma_vendor3); - } - - speed = ide_dma_speed(drive, pdcnew_ratemask(drive)); - - if (!(speed)) { - hwif->tuneproc(drive, 5); - return 0; - } - - (void) hwif->speedproc(drive, speed); - return ide_dma_enable(drive); -} - -static int pdcnew_config_drive_xfer_rate (ide_drive_t *drive) -{ - ide_hwif_t *hwif = HWIF(drive); - struct hd_driveid *id = drive->id; - - drive->init_speed = 0; - - if (id && (id->capability & 1) && drive->autodma) { - - if (ide_use_dma(drive)) { - if (config_chipset_for_dma(drive)) - return hwif->ide_dma_on(drive); - } - - goto fast_ata_pio; - - } else if ((id->capability & 8) || (id->field_valid & 2)) { -fast_ata_pio: - hwif->tuneproc(drive, 5); - return hwif->ide_dma_off_quietly(drive); - } - /* IORDY not supported */ - return 0; -} - -static int pdcnew_quirkproc (ide_drive_t *drive) -{ - return ((int) check_in_drive_lists(drive, pdc_quirk_drives)); -} - -static int pdcnew_ide_dma_lostirq(ide_drive_t *drive) -{ - if (HWIF(drive)->resetproc != NULL) - HWIF(drive)->resetproc(drive); - return __ide_dma_lostirq(drive); -} - -static int pdcnew_ide_dma_timeout(ide_drive_t *drive) -{ - if (HWIF(drive)->resetproc != NULL) - HWIF(drive)->resetproc(drive); - return __ide_dma_timeout(drive); -} - -static void pdcnew_new_reset (ide_drive_t *drive) -{ - /* - * Deleted this because it is redundant from the caller. - */ - printk(KERN_WARNING "PDC202XX: %s channel reset.\n", - HWIF(drive)->channel ? "Secondary" : "Primary"); -} - -#ifdef CONFIG_PPC_PMAC -static void __devinit apple_kiwi_init(struct pci_dev *pdev) -{ - struct device_node *np = pci_device_to_OF_node(pdev); - unsigned int class_rev = 0; - void __iomem *mmio; - u8 conf; - - if (np == NULL || !device_is_compatible(np, "kiwi-root")) - return; - - pci_read_config_dword(pdev, PCI_CLASS_REVISION, &class_rev); - class_rev &= 0xff; - - if (class_rev >= 0x03) { - /* Setup chip magic config stuff (from darwin) */ - pci_read_config_byte(pdev, 0x40, &conf); - pci_write_config_byte(pdev, 0x40, conf | 0x01); - } - mmio = ioremap(pci_resource_start(pdev, 5), - pci_resource_len(pdev, 5)); - - /* Setup some PLL stuffs */ - switch (pdev->device) { - case PCI_DEVICE_ID_PROMISE_20270: - writew(0x0d2b, mmio + 0x1202); - mdelay(30); - break; - case PCI_DEVICE_ID_PROMISE_20271: - writew(0x0826, mmio + 0x1202); - mdelay(30); - break; - } - - iounmap(mmio); -} -#endif /* CONFIG_PPC_PMAC */ - -static unsigned int __devinit init_chipset_pdcnew(struct pci_dev *dev, const char *name) -{ - if (dev->resource[PCI_ROM_RESOURCE].start) { - pci_write_config_dword(dev, PCI_ROM_ADDRESS, - dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE); - printk(KERN_INFO "%s: ROM enabled at 0x%08lx\n", name, - (unsigned long)dev->resource[PCI_ROM_RESOURCE].start); - } - -#ifdef CONFIG_PPC_PMAC - apple_kiwi_init(dev); -#endif - - return dev->irq; -} - -static void __devinit init_hwif_pdc202new(ide_hwif_t *hwif) -{ - hwif->autodma = 0; - - hwif->tuneproc = &pdcnew_tune_drive; - hwif->quirkproc = &pdcnew_quirkproc; - hwif->speedproc = &pdcnew_new_tune_chipset; - hwif->resetproc = &pdcnew_new_reset; - - hwif->drives[0].autotune = hwif->drives[1].autotune = 1; - - hwif->ultra_mask = 0x7f; - hwif->mwdma_mask = 0x07; - - hwif->err_stops_fifo = 1; - - hwif->ide_dma_check = &pdcnew_config_drive_xfer_rate; - hwif->ide_dma_lostirq = &pdcnew_ide_dma_lostirq; - hwif->ide_dma_timeout = &pdcnew_ide_dma_timeout; - if (!(hwif->udma_four)) - hwif->udma_four = (pdcnew_new_cable_detect(hwif)) ? 0 : 1; - if (!noautodma) - hwif->autodma = 1; - hwif->drives[0].autodma = hwif->drives[1].autodma = hwif->autodma; -#if PDC202_DEBUG_CABLE - printk(KERN_DEBUG "%s: %s-pin cable\n", - hwif->name, hwif->udma_four ? "80" : "40"); -#endif /* PDC202_DEBUG_CABLE */ -} - -static int __devinit init_setup_pdcnew(struct pci_dev *dev, ide_pci_device_t *d) -{ - return ide_setup_pci_device(dev, d); -} - -static int __devinit init_setup_pdc20270(struct pci_dev *dev, - ide_pci_device_t *d) -{ - struct pci_dev *findev = NULL; - - if ((dev->bus->self && - dev->bus->self->vendor == PCI_VENDOR_ID_DEC) && - (dev->bus->self->device == PCI_DEVICE_ID_DEC_21150)) { - if (PCI_SLOT(dev->devfn) & 2) - return -ENODEV; - d->extra = 0; - while ((findev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, findev)) != NULL) { - if ((findev->vendor == dev->vendor) && - (findev->device == dev->device) && - (PCI_SLOT(findev->devfn) & 2)) { - if (findev->irq != dev->irq) { - findev->irq = dev->irq; - } - return ide_setup_pci_devices(dev, findev, d); - } - } - } - return ide_setup_pci_device(dev, d); -} - -static int __devinit init_setup_pdc20276(struct pci_dev *dev, - ide_pci_device_t *d) -{ - if ((dev->bus->self) && - (dev->bus->self->vendor == PCI_VENDOR_ID_INTEL) && - ((dev->bus->self->device == PCI_DEVICE_ID_INTEL_I960) || - (dev->bus->self->device == PCI_DEVICE_ID_INTEL_I960RM))) { - printk(KERN_INFO "ide: Skipping Promise PDC20276 " - "attached to I2O RAID controller.\n"); - return -ENODEV; - } - return ide_setup_pci_device(dev, d); -} - -static ide_pci_device_t pdcnew_chipsets[] __devinitdata = { - { /* 0 */ - .name = "PDC20268", - .init_setup = init_setup_pdcnew, - .init_chipset = init_chipset_pdcnew, - .init_hwif = init_hwif_pdc202new, - .channels = 2, - .autodma = AUTODMA, - .bootable = OFF_BOARD, - },{ /* 1 */ - .name = "PDC20269", - .init_setup = init_setup_pdcnew, - .init_chipset = init_chipset_pdcnew, - .init_hwif = init_hwif_pdc202new, - .channels = 2, - .autodma = AUTODMA, - .bootable = OFF_BOARD, - },{ /* 2 */ - .name = "PDC20270", - .init_setup = init_setup_pdc20270, - .init_chipset = init_chipset_pdcnew, - .init_hwif = init_hwif_pdc202new, - .channels = 2, - .autodma = AUTODMA, - .bootable = OFF_BOARD, - },{ /* 3 */ - .name = "PDC20271", - .init_setup = init_setup_pdcnew, - .init_chipset = init_chipset_pdcnew, - .init_hwif = init_hwif_pdc202new, - .channels = 2, - .autodma = AUTODMA, - .bootable = OFF_BOARD, - },{ /* 4 */ - .name = "PDC20275", - .init_setup = init_setup_pdcnew, - .init_chipset = init_chipset_pdcnew, - .init_hwif = init_hwif_pdc202new, - .channels = 2, - .autodma = AUTODMA, - .bootable = OFF_BOARD, - },{ /* 5 */ - .name = "PDC20276", - .init_setup = init_setup_pdc20276, - .init_chipset = init_chipset_pdcnew, - .init_hwif = init_hwif_pdc202new, - .channels = 2, - .autodma = AUTODMA, - .bootable = OFF_BOARD, - },{ /* 6 */ - .name = "PDC20277", - .init_setup = init_setup_pdcnew, - .init_chipset = init_chipset_pdcnew, - .init_hwif = init_hwif_pdc202new, - .channels = 2, - .autodma = AUTODMA, - .bootable = OFF_BOARD, - } -}; - -/** - * pdc202new_init_one - called when a pdc202xx is found - * @dev: the pdc202new device - * @id: the matching pci id - * - * Called when the PCI registration layer (or the IDE initialization) - * finds a device matching our IDE device tables. - */ - -static int __devinit pdc202new_init_one(struct pci_dev *dev, const struct pci_device_id *id) -{ - ide_pci_device_t *d = &pdcnew_chipsets[id->driver_data]; - - return d->init_setup(dev, d); -} - -static struct pci_device_id pdc202new_pci_tbl[] = { - { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20268, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20269, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1}, - { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20270, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2}, - { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20271, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3}, - { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20275, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4}, - { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20276, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5}, - { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20277, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6}, - { 0, }, -}; -MODULE_DEVICE_TABLE(pci, pdc202new_pci_tbl); - -static struct pci_driver driver = { - .name = "Promise_IDE", - .id_table = pdc202new_pci_tbl, - .probe = pdc202new_init_one, -}; - -static int pdc202new_ide_init(void) -{ - return ide_pci_register_driver(&driver); -} - -module_init(pdc202new_ide_init); - -MODULE_AUTHOR("Andre Hedrick, Frank Tiernan"); -MODULE_DESCRIPTION("PCI driver module for Promise PDC20268 and higher"); -MODULE_LICENSE("GPL"); diff --git a/drivers/ide/pci/pdc202xx_old.c b/drivers/ide/pci/pdc202xx_old.c deleted file mode 100644 index b46022a11be..00000000000 --- a/drivers/ide/pci/pdc202xx_old.c +++ /dev/null @@ -1,731 +0,0 @@ -/* - * linux/drivers/ide/pci/pdc202xx_old.c Version 0.36 Sept 11, 2002 - * - * Copyright (C) 1998-2002 Andre Hedrick <andre@linux-ide.org> - * - * Promise Ultra33 cards with BIOS v1.20 through 1.28 will need this - * compiled into the kernel if you have more than one card installed. - * Note that BIOS v1.29 is reported to fix the problem. Since this is - * safe chipset tuning, including this support is harmless - * - * Promise Ultra66 cards with BIOS v1.11 this - * compiled into the kernel if you have more than one card installed. - * - * Promise Ultra100 cards. - * - * The latest chipset code will support the following :: - * Three Ultra33 controllers and 12 drives. - * 8 are UDMA supported and 4 are limited to DMA mode 2 multi-word. - * The 8/4 ratio is a BIOS code limit by promise. - * - * UNLESS you enable "CONFIG_PDC202XX_BURST" - * - */ - -/* - * Portions Copyright (C) 1999 Promise Technology, Inc. - * Author: Frank Tiernan (frankt@promise.com) - * Released under terms of General Public License - */ - -#include <linux/types.h> -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/delay.h> -#include <linux/timer.h> -#include <linux/mm.h> -#include <linux/ioport.h> -#include <linux/blkdev.h> -#include <linux/hdreg.h> -#include <linux/interrupt.h> -#include <linux/pci.h> -#include <linux/init.h> -#include <linux/ide.h> - -#include <asm/io.h> -#include <asm/irq.h> - -#define PDC202_DEBUG_CABLE 0 -#define PDC202XX_DEBUG_DRIVE_INFO 0 - -static const char *pdc_quirk_drives[] = { - "QUANTUM FIREBALLlct08 08", - "QUANTUM FIREBALLP KA6.4", - "QUANTUM FIREBALLP KA9.1", - "QUANTUM FIREBALLP LM20.4", - "QUANTUM FIREBALLP KX13.6", - "QUANTUM FIREBALLP KX20.5", - "QUANTUM FIREBALLP KX27.3", - "QUANTUM FIREBALLP LM20.5", - NULL -}; - -/* A Register */ -#define SYNC_ERRDY_EN 0xC0 - -#define SYNC_IN 0x80 /* control bit, different for master vs. slave drives */ -#define ERRDY_EN 0x40 /* control bit, different for master vs. slave drives */ -#define IORDY_EN 0x20 /* PIO: IOREADY */ -#define PREFETCH_EN 0x10 /* PIO: PREFETCH */ - -#define PA3 0x08 /* PIO"A" timing */ -#define PA2 0x04 /* PIO"A" timing */ -#define PA1 0x02 /* PIO"A" timing */ -#define PA0 0x01 /* PIO"A" timing */ - -/* B Register */ - -#define MB2 0x80 /* DMA"B" timing */ -#define MB1 0x40 /* DMA"B" timing */ -#define MB0 0x20 /* DMA"B" timing */ - -#define PB4 0x10 /* PIO_FORCE 1:0 */ - -#define PB3 0x08 /* PIO"B" timing */ /* PIO flow Control mode */ -#define PB2 0x04 /* PIO"B" timing */ /* PIO 4 */ -#define PB1 0x02 /* PIO"B" timing */ /* PIO 3 half */ -#define PB0 0x01 /* PIO"B" timing */ /* PIO 3 other half */ - -/* C Register */ -#define IORDYp_NO_SPEED 0x4F -#define SPEED_DIS 0x0F - -#define DMARQp 0x80 -#define IORDYp 0x40 -#define DMAR_EN 0x20 -#define DMAW_EN 0x10 - -#define MC3 0x08 /* DMA"C" timing */ -#define MC2 0x04 /* DMA"C" timing */ -#define MC1 0x02 /* DMA"C" timing */ -#define MC0 0x01 /* DMA"C" timing */ - -static u8 pdc202xx_ratemask (ide_drive_t *drive) -{ - u8 mode; - - switch(HWIF(drive)->pci_dev->device) { - case PCI_DEVICE_ID_PROMISE_20267: - case PCI_DEVICE_ID_PROMISE_20265: - mode = 3; - break; - case PCI_DEVICE_ID_PROMISE_20263: - case PCI_DEVICE_ID_PROMISE_20262: - mode = 2; - break; - case PCI_DEVICE_ID_PROMISE_20246: - return 1; - default: - return 0; - } - if (!eighty_ninty_three(drive)) - mode = min(mode, (u8)1); - return mode; -} - -static int check_in_drive_lists (ide_drive_t *drive, const char **list) -{ - struct hd_driveid *id = drive->id; - - if (pdc_quirk_drives == list) { - while (*list) { - if (strstr(id->model, *list++)) { - return 2; - } - } - } else { - while (*list) { - if (!strcmp(*list++,id->model)) { - return 1; - } - } - } - return 0; -} - -static int pdc202xx_tune_chipset (ide_drive_t *drive, u8 xferspeed) -{ - ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; - u8 drive_pci = 0x60 + (drive->dn << 2); - u8 speed = ide_rate_filter(pdc202xx_ratemask(drive), xferspeed); - - u32 drive_conf; - u8 AP, BP, CP, DP; - u8 TA = 0, TB = 0, TC = 0; - - if ((drive->media != ide_disk) && (speed < XFER_SW_DMA_0)) - return -1; - - pci_read_config_dword(dev, drive_pci, &drive_conf); - pci_read_config_byte(dev, (drive_pci), &AP); - pci_read_config_byte(dev, (drive_pci)|0x01, &BP); - pci_read_config_byte(dev, (drive_pci)|0x02, &CP); - pci_read_config_byte(dev, (drive_pci)|0x03, &DP); - - if (speed < XFER_SW_DMA_0) { - if ((AP & 0x0F) || (BP & 0x07)) { - /* clear PIO modes of lower 8421 bits of A Register */ - pci_write_config_byte(dev, (drive_pci), AP &~0x0F); - pci_read_config_byte(dev, (drive_pci), &AP); - - /* clear PIO modes of lower 421 bits of B Register */ - pci_write_config_byte(dev, (drive_pci)|0x01, BP &~0x07); - pci_read_config_byte(dev, (drive_pci)|0x01, &BP); - - pci_read_config_byte(dev, (drive_pci), &AP); - pci_read_config_byte(dev, (drive_pci)|0x01, &BP); - } - } else { - if ((BP & 0xF0) && (CP & 0x0F)) { - /* clear DMA modes of upper 842 bits of B Register */ - /* clear PIO forced mode upper 1 bit of B Register */ - pci_write_config_byte(dev, (drive_pci)|0x01, BP &~0xF0); - pci_read_config_byte(dev, (drive_pci)|0x01, &BP); - - /* clear DMA modes of lower 8421 bits of C Register */ - pci_write_config_byte(dev, (drive_pci)|0x02, CP &~0x0F); - pci_read_config_byte(dev, (drive_pci)|0x02, &CP); - } - } - - pci_read_config_byte(dev, (drive_pci), &AP); - pci_read_config_byte(dev, (drive_pci)|0x01, &BP); - pci_read_config_byte(dev, (drive_pci)|0x02, &CP); - - switch(speed) { - case XFER_UDMA_6: speed = XFER_UDMA_5; - case XFER_UDMA_5: - case XFER_UDMA_4: TB = 0x20; TC = 0x01; break; - case XFER_UDMA_2: TB = 0x20; TC = 0x01; break; - case XFER_UDMA_3: - case XFER_UDMA_1: TB = 0x40; TC = 0x02; break; - case XFER_UDMA_0: - case XFER_MW_DMA_2: TB = 0x60; TC = 0x03; break; - case XFER_MW_DMA_1: TB = 0x60; TC = 0x04; break; - case XFER_MW_DMA_0: - case XFER_SW_DMA_2: TB = 0x60; TC = 0x05; break; - case XFER_SW_DMA_1: TB = 0x80; TC = 0x06; break; - case XFER_SW_DMA_0: TB = 0xC0; TC = 0x0B; break; - case XFER_PIO_4: TA = 0x01; TB = 0x04; break; - case XFER_PIO_3: TA = 0x02; TB = 0x06; break; - case XFER_PIO_2: TA = 0x03; TB = 0x08; break; - case XFER_PIO_1: TA = 0x05; TB = 0x0C; break; - case XFER_PIO_0: - default: TA = 0x09; TB = 0x13; break; - } - - if (speed < XFER_SW_DMA_0) { - pci_write_config_byte(dev, (drive_pci), AP|TA); - pci_write_config_byte(dev, (drive_pci)|0x01, BP|TB); - } else { - pci_write_config_byte(dev, (drive_pci)|0x01, BP|TB); - pci_write_config_byte(dev, (drive_pci)|0x02, CP|TC); - } - -#if PDC202XX_DEBUG_DRIVE_INFO - printk(KERN_DEBUG "%s: %s drive%d 0x%08x ", - drive->name, ide_xfer_verbose(speed), - drive->dn, drive_conf); - pci_read_config_dword(dev, drive_pci, &drive_conf); - printk("0x%08x\n", drive_conf); -#endif /* PDC202XX_DEBUG_DRIVE_INFO */ - - return (ide_config_drive_speed(drive, speed)); -} - - -/* 0 1 2 3 4 5 6 7 8 - * 960, 480, 390, 300, 240, 180, 120, 90, 60 - * 180, 150, 120, 90, 60 - * DMA_Speed - * 180, 120, 90, 90, 90, 60, 30 - * 11, 5, 4, 3, 2, 1, 0 - */ -static void config_chipset_for_pio (ide_drive_t *drive, u8 pio) -{ - u8 speed = 0; - - if (pio == 5) pio = 4; - speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, pio, NULL); - - pdc202xx_tune_chipset(drive, speed); -} - -static u8 pdc202xx_old_cable_detect (ide_hwif_t *hwif) -{ - u16 CIS = 0, mask = (hwif->channel) ? (1<<11) : (1<<10); - pci_read_config_word(hwif->pci_dev, 0x50, &CIS); - return (CIS & mask) ? 1 : 0; -} - -/* - * Set the control register to use the 66MHz system - * clock for UDMA 3/4/5 mode operation when necessary. - * - * It may also be possible to leave the 66MHz clock on - * and readjust the timing parameters. - */ -static void pdc_old_enable_66MHz_clock(ide_hwif_t *hwif) -{ - unsigned long clock_reg = hwif->dma_master + 0x11; - u8 clock = hwif->INB(clock_reg); - - hwif->OUTB(clock | (hwif->channel ? 0x08 : 0x02), clock_reg); -} - -static void pdc_old_disable_66MHz_clock(ide_hwif_t *hwif) -{ - unsigned long clock_reg = hwif->dma_master + 0x11; - u8 clock = hwif->INB(clock_reg); - - hwif->OUTB(clock & ~(hwif->channel ? 0x08 : 0x02), clock_reg); -} - -static int config_chipset_for_dma (ide_drive_t *drive) -{ - struct hd_driveid *id = drive->id; - ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; - u32 drive_conf = 0; - u8 drive_pci = 0x60 + (drive->dn << 2); - u8 test1 = 0, test2 = 0, speed = -1; - u8 AP = 0, cable = 0; - - u8 ultra_66 = ((id->dma_ultra & 0x0010) || - (id->dma_ultra & 0x0008)) ? 1 : 0; - - if (dev->device != PCI_DEVICE_ID_PROMISE_20246) - cable = pdc202xx_old_cable_detect(hwif); - else - ultra_66 = 0; - - if (ultra_66 && cable) { - printk(KERN_WARNING "Warning: %s channel requires an 80-pin cable for operation.\n", hwif->channel ? "Secondary":"Primary"); - printk(KERN_WARNING "%s reduced to Ultra33 mode.\n", drive->name); - } - - if (dev->device != PCI_DEVICE_ID_PROMISE_20246) - pdc_old_disable_66MHz_clock(drive->hwif); - - drive_pci = 0x60 + (drive->dn << 2); - pci_read_config_dword(dev, drive_pci, &drive_conf); - if ((drive_conf != 0x004ff304) && (drive_conf != 0x004ff3c4)) - goto chipset_is_set; - - pci_read_config_byte(dev, drive_pci, &test1); - if (!(test1 & SYNC_ERRDY_EN)) { - if (drive->select.b.unit & 0x01) { - pci_read_config_byte(dev, drive_pci - 4, &test2); - if ((test2 & SYNC_ERRDY_EN) && - !(test1 & SYNC_ERRDY_EN)) { - pci_write_config_byte(dev, drive_pci, - test1|SYNC_ERRDY_EN); - } - } else { - pci_write_config_byte(dev, drive_pci, - test1|SYNC_ERRDY_EN); - } - } - -chipset_is_set: - - if (drive->media == ide_disk) { - pci_read_config_byte(dev, (drive_pci), &AP); - if (id->capability & 4) /* IORDY_EN */ - pci_write_config_byte(dev, (drive_pci), AP|IORDY_EN); - pci_read_config_byte(dev, (drive_pci), &AP); - if (drive->media == ide_disk) /* PREFETCH_EN */ - pci_write_config_byte(dev, (drive_pci), AP|PREFETCH_EN); - } - - speed = ide_dma_speed(drive, pdc202xx_ratemask(drive)); - - if (!(speed)) { - /* restore original pci-config space */ - pci_write_config_dword(dev, drive_pci, drive_conf); - return 0; - } - - (void) hwif->speedproc(drive, speed); - return ide_dma_enable(drive); -} - -static int pdc202xx_config_drive_xfer_rate (ide_drive_t *drive) -{ - ide_hwif_t *hwif = HWIF(drive); - struct hd_driveid *id = drive->id; - - drive->init_speed = 0; - - if (id && (id->capability & 1) && drive->autodma) { - - if (ide_use_dma(drive)) { - if (config_chipset_for_dma(drive)) - return hwif->ide_dma_on(drive); - } - - goto fast_ata_pio; - - } else if ((id->capability & 8) || (id->field_valid & 2)) { -fast_ata_pio: - hwif->tuneproc(drive, 5); - return hwif->ide_dma_off_quietly(drive); - } - /* IORDY not supported */ - return 0; -} - -static int pdc202xx_quirkproc (ide_drive_t *drive) -{ - return ((int) check_in_drive_lists(drive, pdc_quirk_drives)); -} - -static void pdc202xx_old_ide_dma_start(ide_drive_t *drive) -{ - if (drive->current_speed > XFER_UDMA_2) - pdc_old_enable_66MHz_clock(drive->hwif); - if (drive->addressing == 1) { - struct request *rq = HWGROUP(drive)->rq; - ide_hwif_t *hwif = HWIF(drive); - unsigned long high_16 = hwif->dma_master; - unsigned long atapi_reg = high_16 + (hwif->channel ? 0x24 : 0x20); - u32 word_count = 0; - u8 clock = hwif->INB(high_16 + 0x11); - - hwif->OUTB(clock|(hwif->channel ? 0x08 : 0x02), high_16+0x11); - word_count = (rq->nr_sectors << 8); - word_count = (rq_data_dir(rq) == READ) ? - word_count | 0x05000000 : - word_count | 0x06000000; - hwif->OUTL(word_count, atapi_reg); - } - ide_dma_start(drive); -} - -static int pdc202xx_old_ide_dma_end(ide_drive_t *drive) -{ - if (drive->addressing == 1) { - ide_hwif_t *hwif = HWIF(drive); - unsigned long high_16 = hwif->dma_master; - unsigned long atapi_reg = high_16 + (hwif->channel ? 0x24 : 0x20); - u8 clock = 0; - - hwif->OUTL(0, atapi_reg); /* zero out extra */ - clock = hwif->INB(high_16 + 0x11); - hwif->OUTB(clock & ~(hwif->channel ? 0x08:0x02), high_16+0x11); - } - if (drive->current_speed > XFER_UDMA_2) - pdc_old_disable_66MHz_clock(drive->hwif); - return __ide_dma_end(drive); -} - -static int pdc202xx_old_ide_dma_test_irq(ide_drive_t *drive) -{ - ide_hwif_t *hwif = HWIF(drive); - unsigned long high_16 = hwif->dma_master; - u8 dma_stat = hwif->INB(hwif->dma_status); - u8 sc1d = hwif->INB((high_16 + 0x001d)); - - if (hwif->channel) { - /* bit7: Error, bit6: Interrupting, bit5: FIFO Full, bit4: FIFO Empty */ - if ((sc1d & 0x50) == 0x50) - goto somebody_else; - else if ((sc1d & 0x40) == 0x40) - return (dma_stat & 4) == 4; - } else { - /* bit3: Error, bit2: Interrupting, bit1: FIFO Full, bit0: FIFO Empty */ - if ((sc1d & 0x05) == 0x05) - goto somebody_else; - else if ((sc1d & 0x04) == 0x04) - return (dma_stat & 4) == 4; - } -somebody_else: - return (dma_stat & 4) == 4; /* return 1 if INTR asserted */ -} - -static int pdc202xx_ide_dma_lostirq(ide_drive_t *drive) -{ - if (HWIF(drive)->resetproc != NULL) - HWIF(drive)->resetproc(drive); - return __ide_dma_lostirq(drive); -} - -static int pdc202xx_ide_dma_timeout(ide_drive_t *drive) -{ - if (HWIF(drive)->resetproc != NULL) - HWIF(drive)->resetproc(drive); - return __ide_dma_timeout(drive); -} - -static void pdc202xx_reset_host (ide_hwif_t *hwif) -{ - unsigned long high_16 = hwif->dma_master; - u8 udma_speed_flag = hwif->INB(high_16|0x001f); - - hwif->OUTB((udma_speed_flag | 0x10), (high_16|0x001f)); - mdelay(100); - hwif->OUTB((udma_speed_flag & ~0x10), (high_16|0x001f)); - mdelay(2000); /* 2 seconds ?! */ - - printk(KERN_WARNING "PDC202XX: %s channel reset.\n", - hwif->channel ? "Secondary" : "Primary"); -} - -static void pdc202xx_reset (ide_drive_t *drive) -{ - ide_hwif_t *hwif = HWIF(drive); - ide_hwif_t *mate = hwif->mate; - - pdc202xx_reset_host(hwif); - pdc202xx_reset_host(mate); - hwif->tuneproc(drive, 5); -} - -static unsigned int __devinit init_chipset_pdc202xx(struct pci_dev *dev, - const char *name) -{ - /* This doesn't appear needed */ - if (dev->resource[PCI_ROM_RESOURCE].start) { - pci_write_config_dword(dev, PCI_ROM_ADDRESS, - dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE); - printk(KERN_INFO "%s: ROM enabled at 0x%08lx\n", name, - (unsigned long)dev->resource[PCI_ROM_RESOURCE].start); - } - - return dev->irq; -} - -static void __devinit init_hwif_pdc202xx(ide_hwif_t *hwif) -{ - struct pci_dev *dev = hwif->pci_dev; - - /* PDC20265 has problems with large LBA48 requests */ - if ((dev->device == PCI_DEVICE_ID_PROMISE_20267) || - (dev->device == PCI_DEVICE_ID_PROMISE_20265)) - hwif->rqsize = 256; - - hwif->autodma = 0; - hwif->tuneproc = &config_chipset_for_pio; - hwif->quirkproc = &pdc202xx_quirkproc; - - if (hwif->pci_dev->device != PCI_DEVICE_ID_PROMISE_20246) - hwif->resetproc = &pdc202xx_reset; - - hwif->speedproc = &pdc202xx_tune_chipset; - - hwif->drives[0].autotune = hwif->drives[1].autotune = 1; - - hwif->ultra_mask = 0x3f; - hwif->mwdma_mask = 0x07; - hwif->swdma_mask = 0x07; - - hwif->err_stops_fifo = 1; - - hwif->ide_dma_check = &pdc202xx_config_drive_xfer_rate; - hwif->ide_dma_lostirq = &pdc202xx_ide_dma_lostirq; - hwif->ide_dma_timeout = &pdc202xx_ide_dma_timeout; - - if (hwif->pci_dev->device != PCI_DEVICE_ID_PROMISE_20246) { - if (!(hwif->udma_four)) - hwif->udma_four = (pdc202xx_old_cable_detect(hwif)) ? 0 : 1; - hwif->dma_start = &pdc202xx_old_ide_dma_start; - hwif->ide_dma_end = &pdc202xx_old_ide_dma_end; - } - hwif->ide_dma_test_irq = &pdc202xx_old_ide_dma_test_irq; - - if (!noautodma) - hwif->autodma = 1; - hwif->drives[0].autodma = hwif->drives[1].autodma = hwif->autodma; -#if PDC202_DEBUG_CABLE - printk(KERN_DEBUG "%s: %s-pin cable\n", - hwif->name, hwif->udma_four ? "80" : "40"); -#endif /* PDC202_DEBUG_CABLE */ -} - -static void __devinit init_dma_pdc202xx(ide_hwif_t *hwif, unsigned long dmabase) -{ - u8 udma_speed_flag = 0, primary_mode = 0, secondary_mode = 0; - - if (hwif->channel) { - ide_setup_dma(hwif, dmabase, 8); - return; - } - - udma_speed_flag = hwif->INB((dmabase|0x1f)); - primary_mode = hwif->INB((dmabase|0x1a)); - secondary_mode = hwif->INB((dmabase|0x1b)); - printk(KERN_INFO "%s: (U)DMA Burst Bit %sABLED " \ - "Primary %s Mode " \ - "Secondary %s Mode.\n", hwif->cds->name, - (udma_speed_flag & 1) ? "EN" : "DIS", - (primary_mode & 1) ? "MASTER" : "PCI", - (secondary_mode & 1) ? "MASTER" : "PCI" ); - -#ifdef CONFIG_PDC202XX_BURST - if (!(udma_speed_flag & 1)) { - printk(KERN_INFO "%s: FORCING BURST BIT 0x%02x->0x%02x ", - hwif->cds->name, udma_speed_flag, - (udma_speed_flag|1)); - hwif->OUTB(udma_speed_flag|1,(dmabase|0x1f)); - printk("%sACTIVE\n", - (hwif->INB(dmabase|0x1f)&1) ? "":"IN"); - } -#endif /* CONFIG_PDC202XX_BURST */ -#ifdef CONFIG_PDC202XX_MASTER - if (!(primary_mode & 1)) { - printk(KERN_INFO "%s: FORCING PRIMARY MODE BIT " - "0x%02x -> 0x%02x ", hwif->cds->name, - primary_mode, (primary_mode|1)); - hwif->OUTB(primary_mode|1, (dmabase|0x1a)); - printk("%s\n", - (hwif->INB((dmabase|0x1a)) & 1) ? "MASTER" : "PCI"); - } - - if (!(secondary_mode & 1)) { - printk(KERN_INFO "%s: FORCING SECONDARY MODE BIT " - "0x%02x -> 0x%02x ", hwif->cds->name, - secondary_mode, (secondary_mode|1)); - hwif->OUTB(secondary_mode|1, (dmabase|0x1b)); - printk("%s\n", - (hwif->INB((dmabase|0x1b)) & 1) ? "MASTER" : "PCI"); - } -#endif /* CONFIG_PDC202XX_MASTER */ - - ide_setup_dma(hwif, dmabase, 8); -} - -static int __devinit init_setup_pdc202ata4(struct pci_dev *dev, - ide_pci_device_t *d) -{ - if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE) { - u8 irq = 0, irq2 = 0; - pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq); - /* 0xbc */ - pci_read_config_byte(dev, (PCI_INTERRUPT_LINE)|0x80, &irq2); - if (irq != irq2) { - pci_write_config_byte(dev, - (PCI_INTERRUPT_LINE)|0x80, irq); /* 0xbc */ - printk(KERN_INFO "%s: pci-config space interrupt " - "mirror fixed.\n", d->name); - } - } - return ide_setup_pci_device(dev, d); -} - -static int __devinit init_setup_pdc20265(struct pci_dev *dev, - ide_pci_device_t *d) -{ - if ((dev->bus->self) && - (dev->bus->self->vendor == PCI_VENDOR_ID_INTEL) && - ((dev->bus->self->device == PCI_DEVICE_ID_INTEL_I960) || - (dev->bus->self->device == PCI_DEVICE_ID_INTEL_I960RM))) { - printk(KERN_INFO "ide: Skipping Promise PDC20265 " - "attached to I2O RAID controller.\n"); - return -ENODEV; - } - return ide_setup_pci_device(dev, d); -} - -static int __devinit init_setup_pdc202xx(struct pci_dev *dev, - ide_pci_device_t *d) -{ - return ide_setup_pci_device(dev, d); -} - -static ide_pci_device_t pdc202xx_chipsets[] __devinitdata = { - { /* 0 */ - .name = "PDC20246", - .init_setup = init_setup_pdc202ata4, - .init_chipset = init_chipset_pdc202xx, - .init_hwif = init_hwif_pdc202xx, - .init_dma = init_dma_pdc202xx, - .channels = 2, - .autodma = AUTODMA, - .bootable = OFF_BOARD, - .extra = 16, - },{ /* 1 */ - .name = "PDC20262", - .init_setup = init_setup_pdc202ata4, - .init_chipset = init_chipset_pdc202xx, - .init_hwif = init_hwif_pdc202xx, - .init_dma = init_dma_pdc202xx, - .channels = 2, - .autodma = AUTODMA, - .bootable = OFF_BOARD, - .extra = 48, - },{ /* 2 */ - .name = "PDC20263", - .init_setup = init_setup_pdc202ata4, - .init_chipset = init_chipset_pdc202xx, - .init_hwif = init_hwif_pdc202xx, - .init_dma = init_dma_pdc202xx, - .channels = 2, - .autodma = AUTODMA, - .bootable = OFF_BOARD, - .extra = 48, - },{ /* 3 */ - .name = "PDC20265", - .init_setup = init_setup_pdc20265, - .init_chipset = init_chipset_pdc202xx, - .init_hwif = init_hwif_pdc202xx, - .init_dma = init_dma_pdc202xx, - .channels = 2, - .autodma = AUTODMA, - .bootable = OFF_BOARD, - .extra = 48, - },{ /* 4 */ - .name = "PDC20267", - .init_setup = init_setup_pdc202xx, - .init_chipset = init_chipset_pdc202xx, - .init_hwif = init_hwif_pdc202xx, - .init_dma = init_dma_pdc202xx, - .channels = 2, - .autodma = AUTODMA, - .bootable = OFF_BOARD, - .extra = 48, - } -}; - -/** - * pdc202xx_init_one - called when a PDC202xx is found - * @dev: the pdc202xx device - * @id: the matching pci id - * - * Called when the PCI registration layer (or the IDE initialization) - * finds a device matching our IDE device tables. - */ - -static int __devinit pdc202xx_init_one(struct pci_dev *dev, const struct pci_device_id *id) -{ - ide_pci_device_t *d = &pdc202xx_chipsets[id->driver_data]; - - return d->init_setup(dev, d); -} - -static struct pci_device_id pdc202xx_pci_tbl[] = { - { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20246, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20262, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1}, - { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20263, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2}, - { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20265, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3}, - { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20267, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4}, - { 0, }, -}; -MODULE_DEVICE_TABLE(pci, pdc202xx_pci_tbl); - -static struct pci_driver driver = { - .name = "Promise_Old_IDE", - .id_table = pdc202xx_pci_tbl, - .probe = pdc202xx_init_one, -}; - -static int pdc202xx_ide_init(void) -{ - return ide_pci_register_driver(&driver); -} - -module_init(pdc202xx_ide_init); - -MODULE_AUTHOR("Andre Hedrick, Frank Tiernan"); -MODULE_DESCRIPTION("PCI driver module for older Promise IDE"); -MODULE_LICENSE("GPL"); diff --git a/drivers/ide/pci/piix.c b/drivers/ide/pci/piix.c deleted file mode 100644 index 50332ddd5dd..00000000000 --- a/drivers/ide/pci/piix.c +++ /dev/null @@ -1,685 +0,0 @@ -/* - * linux/drivers/ide/pci/piix.c Version 0.44 March 20, 2003 - * - * Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer - * Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org> - * Copyright (C) 2003 Red Hat Inc <alan@redhat.com> - * - * May be copied or modified under the terms of the GNU General Public License - * - * PIO mode setting function for Intel chipsets. - * For use instead of BIOS settings. - * - * 40-41 - * 42-43 - * - * 41 - * 43 - * - * | PIO 0 | c0 | 80 | 0 | piix_tune_drive(drive, 0); - * | PIO 2 | SW2 | d0 | 90 | 4 | piix_tune_drive(drive, 2); - * | PIO 3 | MW1 | e1 | a1 | 9 | piix_tune_drive(drive, 3); - * | PIO 4 | MW2 | e3 | a3 | b | piix_tune_drive(drive, 4); - * - * sitre = word40 & 0x4000; primary - * sitre = word42 & 0x4000; secondary - * - * 44 8421|8421 hdd|hdb - * - * 48 8421 hdd|hdc|hdb|hda udma enabled - * - * 0001 hda - * 0010 hdb - * 0100 hdc - * 1000 hdd - * - * 4a 84|21 hdb|hda - * 4b 84|21 hdd|hdc - * - * ata-33/82371AB - * ata-33/82371EB - * ata-33/82801AB ata-66/82801AA - * 00|00 udma 0 00|00 reserved - * 01|01 udma 1 01|01 udma 3 - * 10|10 udma 2 10|10 udma 4 - * 11|11 reserved 11|11 reserved - * - * 54 8421|8421 ata66 drive|ata66 enable - * - * pci_read_config_word(HWIF(drive)->pci_dev, 0x40, ®40); - * pci_read_config_word(HWIF(drive)->pci_dev, 0x42, ®42); - * pci_read_config_word(HWIF(drive)->pci_dev, 0x44, ®44); - * pci_read_config_byte(HWIF(drive)->pci_dev, 0x48, ®48); - * pci_read_config_word(HWIF(drive)->pci_dev, 0x4a, ®4a); - * pci_read_config_byte(HWIF(drive)->pci_dev, 0x54, ®54); - * - * Documentation - * Publically available from Intel web site. Errata documentation - * is also publically available. As an aide to anyone hacking on this - * driver the list of errata that are relevant is below.going back to - * PIIX4. Older device documentation is now a bit tricky to find. - * - * Errata of note: - * - * Unfixable - * PIIX4 errata #9 - Only on ultra obscure hw - * ICH3 errata #13 - Not observed to affect real hw - * by Intel - * - * Things we must deal with - * PIIX4 errata #10 - BM IDE hang with non UDMA - * (must stop/start dma to recover) - * 440MX errata #15 - As PIIX4 errata #10 - * PIIX4 errata #15 - Must not read control registers - * during a PIO transfer - * 440MX errata #13 - As PIIX4 errata #15 - * ICH2 errata #21 - DMA mode 0 doesn't work right - * ICH0/1 errata #55 - As ICH2 errata #21 - * ICH2 spec c #9 - Extra operations needed to handle - * drive hotswap [NOT YET SUPPORTED] - * ICH2 spec c #20 - IDE PRD must not cross a 64K boundary - * and must be dword aligned - * ICH2 spec c #24 - UDMA mode 4,5 t85/86 should be 6ns not 3.3 - * - * Should have been BIOS fixed: - * 450NX: errata #19 - DMA hangs on old 450NX - * 450NX: errata #20 - DMA hangs on old 450NX - * 450NX: errata #25 - Corruption with DMA on old 450NX - * ICH3 errata #15 - IDE deadlock under high load - * (BIOS must set dev 31 fn 0 bit 23) - * ICH3 errata #18 - Don't use native mode - */ - -#include <linux/types.h> -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/ioport.h> -#include <linux/pci.h> -#include <linux/hdreg.h> -#include <linux/ide.h> -#include <linux/delay.h> -#include <linux/init.h> - -#include <asm/io.h> - -static int no_piix_dma; - -/** - * piix_ratemask - compute rate mask for PIIX IDE - * @drive: IDE drive to compute for - * - * Returns the available modes for the PIIX IDE controller. - */ - -static u8 piix_ratemask (ide_drive_t *drive) -{ - struct pci_dev *dev = HWIF(drive)->pci_dev; - u8 mode; - - switch(dev->device) { - case PCI_DEVICE_ID_INTEL_82801EB_1: - mode = 3; - break; - /* UDMA 100 capable */ - case PCI_DEVICE_ID_INTEL_82801BA_8: - case PCI_DEVICE_ID_INTEL_82801BA_9: - case PCI_DEVICE_ID_INTEL_82801CA_10: - case PCI_DEVICE_ID_INTEL_82801CA_11: - case PCI_DEVICE_ID_INTEL_82801E_11: - case PCI_DEVICE_ID_INTEL_82801DB_1: - case PCI_DEVICE_ID_INTEL_82801DB_10: - case PCI_DEVICE_ID_INTEL_82801DB_11: - case PCI_DEVICE_ID_INTEL_82801EB_11: - case PCI_DEVICE_ID_INTEL_ESB_2: - case PCI_DEVICE_ID_INTEL_ICH6_19: - case PCI_DEVICE_ID_INTEL_ICH7_21: - case PCI_DEVICE_ID_INTEL_ESB2_18: - case PCI_DEVICE_ID_INTEL_ICH8_6: - mode = 3; - break; - /* UDMA 66 capable */ - case PCI_DEVICE_ID_INTEL_82801AA_1: - case PCI_DEVICE_ID_INTEL_82372FB_1: - mode = 2; - break; - /* UDMA 33 capable */ - case PCI_DEVICE_ID_INTEL_82371AB: - case PCI_DEVICE_ID_INTEL_82443MX_1: - case PCI_DEVICE_ID_INTEL_82451NX: - case PCI_DEVICE_ID_INTEL_82801AB_1: - return 1; - /* Non UDMA capable (MWDMA2) */ - case PCI_DEVICE_ID_INTEL_82371SB_1: - case PCI_DEVICE_ID_INTEL_82371FB_1: - case PCI_DEVICE_ID_INTEL_82371FB_0: - case PCI_DEVICE_ID_INTEL_82371MX: - default: - return 0; - } - - /* - * If we are UDMA66 capable fall back to UDMA33 - * if the drive cannot see an 80pin cable. - */ - if (!eighty_ninty_three(drive)) - mode = min(mode, (u8)1); - return mode; -} - -/** - * piix_dma_2_pio - return the PIO mode matching DMA - * @xfer_rate: transfer speed - * - * Returns the nearest equivalent PIO timing for the PIO or DMA - * mode requested by the controller. - */ - -static u8 piix_dma_2_pio (u8 xfer_rate) { - switch(xfer_rate) { - case XFER_UDMA_6: - case XFER_UDMA_5: - case XFER_UDMA_4: - case XFER_UDMA_3: - case XFER_UDMA_2: - case XFER_UDMA_1: - case XFER_UDMA_0: - case XFER_MW_DMA_2: - case XFER_PIO_4: - return 4; - case XFER_MW_DMA_1: - case XFER_PIO_3: - return 3; - case XFER_SW_DMA_2: - case XFER_PIO_2: - return 2; - case XFER_MW_DMA_0: - case XFER_SW_DMA_1: - case XFER_SW_DMA_0: - case XFER_PIO_1: - case XFER_PIO_0: - case XFER_PIO_SLOW: - default: - return 0; - } -} - -/** - * piix_tune_drive - tune a drive attached to a PIIX - * @drive: drive to tune - * @pio: desired PIO mode - * - * Set the interface PIO mode based upon the settings done by AMI BIOS - * (might be useful if drive is not registered in CMOS for any reason). - */ -static void piix_tune_drive (ide_drive_t *drive, u8 pio) -{ - ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; - int is_slave = (&hwif->drives[1] == drive); - int master_port = hwif->channel ? 0x42 : 0x40; - int slave_port = 0x44; - unsigned long flags; - u16 master_data; - u8 slave_data; - static DEFINE_SPINLOCK(tune_lock); - - /* ISP RTC */ - u8 timings[][2] = { { 0, 0 }, - { 0, 0 }, - { 1, 0 }, - { 2, 1 }, - { 2, 3 }, }; - - pio = ide_get_best_pio_mode(drive, pio, 5, NULL); - - /* - * Master vs slave is synchronized above us but the slave register is - * shared by the two hwifs so the corner case of two slave timeouts in - * parallel must be locked. - */ - spin_lock_irqsave(&tune_lock, flags); - pci_read_config_word(dev, master_port, &master_data); - if (is_slave) { - master_data = master_data | 0x4000; - if (pio > 1) - /* enable PPE, IE and TIME */ - master_data = master_data | 0x0070; - pci_read_config_byte(dev, slave_port, &slave_data); - slave_data = slave_data & (hwif->channel ? 0x0f : 0xf0); - slave_data = slave_data | (((timings[pio][0] << 2) | timings[pio][1]) << (hwif->channel ? 4 : 0)); - } else { - master_data = master_data & 0xccf8; - if (pio > 1) - /* enable PPE, IE and TIME */ - master_data = master_data | 0x0007; - master_data = master_data | (timings[pio][0] << 12) | (timings[pio][1] << 8); - } - pci_write_config_word(dev, master_port, master_data); - if (is_slave) - pci_write_config_byte(dev, slave_port, slave_data); - spin_unlock_irqrestore(&tune_lock, flags); -} - -/** - * piix_tune_chipset - tune a PIIX interface - * @drive: IDE drive to tune - * @xferspeed: speed to configure - * - * Set a PIIX interface channel to the desired speeds. This involves - * requires the right timing data into the PIIX configuration space - * then setting the drive parameters appropriately - */ - -static int piix_tune_chipset (ide_drive_t *drive, u8 xferspeed) -{ - ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; - u8 maslave = hwif->channel ? 0x42 : 0x40; - u8 speed = ide_rate_filter(piix_ratemask(drive), xferspeed); - int a_speed = 3 << (drive->dn * 4); - int u_flag = 1 << drive->dn; - int v_flag = 0x01 << drive->dn; - int w_flag = 0x10 << drive->dn; - int u_speed = 0; - int sitre; - u16 reg4042, reg4a; - u8 reg48, reg54, reg55; - - pci_read_config_word(dev, maslave, ®4042); - sitre = (reg4042 & 0x4000) ? 1 : 0; - pci_read_config_byte(dev, 0x48, ®48); - pci_read_config_word(dev, 0x4a, ®4a); - pci_read_config_byte(dev, 0x54, ®54); - pci_read_config_byte(dev, 0x55, ®55); - - switch(speed) { - case XFER_UDMA_4: - case XFER_UDMA_2: u_speed = 2 << (drive->dn * 4); break; - case XFER_UDMA_5: - case XFER_UDMA_3: - case XFER_UDMA_1: u_speed = 1 << (drive->dn * 4); break; - case XFER_UDMA_0: u_speed = 0 << (drive->dn * 4); break; - case XFER_MW_DMA_2: - case XFER_MW_DMA_1: - case XFER_SW_DMA_2: break; - case XFER_PIO_4: - case XFER_PIO_3: - case XFER_PIO_2: - case XFER_PIO_0: break; - default: return -1; - } - - if (speed >= XFER_UDMA_0) { - if (!(reg48 & u_flag)) - pci_write_config_byte(dev, 0x48, reg48 | u_flag); - if (speed == XFER_UDMA_5) { - pci_write_config_byte(dev, 0x55, (u8) reg55|w_flag); - } else { - pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag); - } - if ((reg4a & a_speed) != u_speed) - pci_write_config_word(dev, 0x4a, (reg4a & ~a_speed) | u_speed); - if (speed > XFER_UDMA_2) { - if (!(reg54 & v_flag)) - pci_write_config_byte(dev, 0x54, reg54 | v_flag); - } else - pci_write_config_byte(dev, 0x54, reg54 & ~v_flag); - } else { - if (reg48 & u_flag) - pci_write_config_byte(dev, 0x48, reg48 & ~u_flag); - if (reg4a & a_speed) - pci_write_config_word(dev, 0x4a, reg4a & ~a_speed); - if (reg54 & v_flag) - pci_write_config_byte(dev, 0x54, reg54 & ~v_flag); - if (reg55 & w_flag) - pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag); - } - - piix_tune_drive(drive, piix_dma_2_pio(speed)); - return (ide_config_drive_speed(drive, speed)); -} - -/** - * piix_faulty_dma0 - check for DMA0 errata - * @hwif: IDE interface to check - * - * If an ICH/ICH0/ICH2 interface is is operating in multi-word - * DMA mode with 600nS cycle time the IDE PIO prefetch buffer will - * inadvertently provide an extra piece of secondary data to the primary - * device resulting in data corruption. - * - * With such a device this test function returns true. This allows - * our tuning code to follow Intel recommendations and use PIO on - * such devices. - */ - -static int piix_faulty_dma0(ide_hwif_t *hwif) -{ - switch(hwif->pci_dev->device) - { - case PCI_DEVICE_ID_INTEL_82801AA_1: /* ICH */ - case PCI_DEVICE_ID_INTEL_82801AB_1: /* ICH0 */ - case PCI_DEVICE_ID_INTEL_82801BA_8: /* ICH2 */ - case PCI_DEVICE_ID_INTEL_82801BA_9: /* ICH2 */ - return 1; - } - return 0; -} - -/** - * piix_config_drive_for_dma - configure drive for DMA - * @drive: IDE drive to configure - * - * Set up a PIIX interface channel for the best available speed. - * We prefer UDMA if it is available and then MWDMA. If DMA is - * not available we switch to PIO and return 0. - */ - -static int piix_config_drive_for_dma (ide_drive_t *drive) -{ - u8 speed = ide_dma_speed(drive, piix_ratemask(drive)); - - /* Some ICH devices cannot support DMA mode 0 */ - if(speed == XFER_MW_DMA_0 && piix_faulty_dma0(HWIF(drive))) - speed = 0; - - /* If no DMA speed was available or the chipset has DMA bugs - then disable DMA and use PIO */ - - if (!speed || no_piix_dma) { - u8 tspeed = ide_get_best_pio_mode(drive, 255, 5, NULL); - speed = piix_dma_2_pio(XFER_PIO_0 + tspeed); - } - - (void) piix_tune_chipset(drive, speed); - return ide_dma_enable(drive); -} - -/** - * piix_config_drive_xfer_rate - set up an IDE device - * @drive: IDE drive to configure - * - * Set up the PIIX interface for the best available speed on this - * interface, preferring DMA to PIO. - */ - -static int piix_config_drive_xfer_rate (ide_drive_t *drive) -{ - ide_hwif_t *hwif = HWIF(drive); - struct hd_driveid *id = drive->id; - - drive->init_speed = 0; - - if ((id->capability & 1) && drive->autodma) { - - if (ide_use_dma(drive)) { - if (piix_config_drive_for_dma(drive)) - return hwif->ide_dma_on(drive); - } - - goto fast_ata_pio; - - } else if ((id->capability & 8) || (id->field_valid & 2)) { -fast_ata_pio: - /* Find best PIO mode. */ - hwif->tuneproc(drive, 255); - return hwif->ide_dma_off_quietly(drive); - } - /* IORDY not supported */ - return 0; -} - -/** - * init_chipset_piix - set up the PIIX chipset - * @dev: PCI device to set up - * @name: Name of the device - * - * Initialize the PCI device as required. For the PIIX this turns - * out to be nice and simple - */ - -static unsigned int __devinit init_chipset_piix (struct pci_dev *dev, const char *name) -{ - switch(dev->device) { - case PCI_DEVICE_ID_INTEL_82801EB_1: - case PCI_DEVICE_ID_INTEL_82801AA_1: - case PCI_DEVICE_ID_INTEL_82801AB_1: - case PCI_DEVICE_ID_INTEL_82801BA_8: - case PCI_DEVICE_ID_INTEL_82801BA_9: - case PCI_DEVICE_ID_INTEL_82801CA_10: - case PCI_DEVICE_ID_INTEL_82801CA_11: - case PCI_DEVICE_ID_INTEL_82801DB_1: - case PCI_DEVICE_ID_INTEL_82801DB_10: - case PCI_DEVICE_ID_INTEL_82801DB_11: - case PCI_DEVICE_ID_INTEL_82801EB_11: - case PCI_DEVICE_ID_INTEL_82801E_11: - case PCI_DEVICE_ID_INTEL_ESB_2: - case PCI_DEVICE_ID_INTEL_ICH6_19: - case PCI_DEVICE_ID_INTEL_ICH7_21: - case PCI_DEVICE_ID_INTEL_ESB2_18: - case PCI_DEVICE_ID_INTEL_ICH8_6: - { - unsigned int extra = 0; - pci_read_config_dword(dev, 0x54, &extra); - pci_write_config_dword(dev, 0x54, extra|0x400); - } - default: - break; - } - - return 0; -} - -/** - * init_hwif_piix - fill in the hwif for the PIIX - * @hwif: IDE interface - * - * Set up the ide_hwif_t for the PIIX interface according to the - * capabilities of the hardware. - */ - -static void __devinit init_hwif_piix(ide_hwif_t *hwif) -{ - u8 reg54h = 0, reg55h = 0, ata66 = 0; - u8 mask = hwif->channel ? 0xc0 : 0x30; - -#ifndef CONFIG_IA64 - if (!hwif->irq) - hwif->irq = hwif->channel ? 15 : 14; -#endif /* CONFIG_IA64 */ - - if (hwif->pci_dev->device == PCI_DEVICE_ID_INTEL_82371MX) { - /* This is a painful system best to let it self tune for now */ - return; - } - - hwif->autodma = 0; - hwif->tuneproc = &piix_tune_drive; - hwif->speedproc = &piix_tune_chipset; - hwif->drives[0].autotune = 1; - hwif->drives[1].autotune = 1; - - if (!hwif->dma_base) - return; - - hwif->atapi_dma = 1; - hwif->ultra_mask = 0x3f; - hwif->mwdma_mask = 0x06; - hwif->swdma_mask = 0x04; - - switch(hwif->pci_dev->device) { - case PCI_DEVICE_ID_INTEL_82371MX: - hwif->mwdma_mask = 0x80; - hwif->swdma_mask = 0x80; - case PCI_DEVICE_ID_INTEL_82371FB_0: - case PCI_DEVICE_ID_INTEL_82371FB_1: - case PCI_DEVICE_ID_INTEL_82371SB_1: - hwif->ultra_mask = 0x80; - break; - case PCI_DEVICE_ID_INTEL_82371AB: - case PCI_DEVICE_ID_INTEL_82443MX_1: - case PCI_DEVICE_ID_INTEL_82451NX: - case PCI_DEVICE_ID_INTEL_82801AB_1: - hwif->ultra_mask = 0x07; - break; - default: - pci_read_config_byte(hwif->pci_dev, 0x54, ®54h); - pci_read_config_byte(hwif->pci_dev, 0x55, ®55h); - ata66 = (reg54h & mask) ? 1 : 0; - break; - } - - if (!(hwif->udma_four)) - hwif->udma_four = ata66; - hwif->ide_dma_check = &piix_config_drive_xfer_rate; - if (!noautodma) - hwif->autodma = 1; - - hwif->drives[1].autodma = hwif->autodma; - hwif->drives[0].autodma = hwif->autodma; -} - -#define DECLARE_PIIX_DEV(name_str) \ - { \ - .name = name_str, \ - .init_chipset = init_chipset_piix, \ - .init_hwif = init_hwif_piix, \ - .channels = 2, \ - .autodma = AUTODMA, \ - .enablebits = {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, \ - .bootable = ON_BOARD, \ - } - -static ide_pci_device_t piix_pci_info[] __devinitdata = { - /* 0 */ DECLARE_PIIX_DEV("PIIXa"), - /* 1 */ DECLARE_PIIX_DEV("PIIXb"), - - { /* 2 */ - .name = "MPIIX", - .init_hwif = init_hwif_piix, - .channels = 2, - .autodma = NODMA, - .enablebits = {{0x6D,0x80,0x80}, {0x6F,0x80,0x80}}, - .bootable = ON_BOARD, - }, - - /* 3 */ DECLARE_PIIX_DEV("PIIX3"), - /* 4 */ DECLARE_PIIX_DEV("PIIX4"), - /* 5 */ DECLARE_PIIX_DEV("ICH0"), - /* 6 */ DECLARE_PIIX_DEV("PIIX4"), - /* 7 */ DECLARE_PIIX_DEV("ICH"), - /* 8 */ DECLARE_PIIX_DEV("PIIX4"), - /* 9 */ DECLARE_PIIX_DEV("PIIX4"), - /* 10 */ DECLARE_PIIX_DEV("ICH2"), - /* 11 */ DECLARE_PIIX_DEV("ICH2M"), - /* 12 */ DECLARE_PIIX_DEV("ICH3M"), - /* 13 */ DECLARE_PIIX_DEV("ICH3"), - /* 14 */ DECLARE_PIIX_DEV("ICH4"), - /* 15 */ DECLARE_PIIX_DEV("ICH5"), - /* 16 */ DECLARE_PIIX_DEV("C-ICH"), - /* 17 */ DECLARE_PIIX_DEV("ICH4"), - /* 18 */ DECLARE_PIIX_DEV("ICH5-SATA"), - /* 19 */ DECLARE_PIIX_DEV("ICH5"), - /* 20 */ DECLARE_PIIX_DEV("ICH6"), - /* 21 */ DECLARE_PIIX_DEV("ICH7"), - /* 22 */ DECLARE_PIIX_DEV("ICH4"), - /* 23 */ DECLARE_PIIX_DEV("ESB2"), - /* 24 */ DECLARE_PIIX_DEV("ICH8M"), -}; - -/** - * piix_init_one - called when a PIIX is found - * @dev: the piix device - * @id: the matching pci id - * - * Called when the PCI registration layer (or the IDE initialization) - * finds a device matching our IDE device tables. - */ - -static int __devinit piix_init_one(struct pci_dev *dev, const struct pci_device_id *id) -{ - ide_pci_device_t *d = &piix_pci_info[id->driver_data]; - - return ide_setup_pci_device(dev, d); -} - -/** - * piix_check_450nx - Check for problem 450NX setup - * - * Check for the present of 450NX errata #19 and errata #25. If - * they are found, disable use of DMA IDE - */ - -static void __devinit piix_check_450nx(void) -{ - struct pci_dev *pdev = NULL; - u16 cfg; - u8 rev; - while((pdev=pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454NX, pdev))!=NULL) - { - /* Look for 450NX PXB. Check for problem configurations - A PCI quirk checks bit 6 already */ - pci_read_config_byte(pdev, PCI_REVISION_ID, &rev); - pci_read_config_word(pdev, 0x41, &cfg); - /* Only on the original revision: IDE DMA can hang */ - if(rev == 0x00) - no_piix_dma = 1; - /* On all revisions below 5 PXB bus lock must be disabled for IDE */ - else if(cfg & (1<<14) && rev < 5) - no_piix_dma = 2; - } - if(no_piix_dma) - printk(KERN_WARNING "piix: 450NX errata present, disabling IDE DMA.\n"); - if(no_piix_dma == 2) - printk(KERN_WARNING "piix: A BIOS update may resolve this.\n"); -} - -static struct pci_device_id piix_pci_tbl[] = { - { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371FB_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371FB_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1}, - { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371MX, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2}, - { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3}, - { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4}, - { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5}, - { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6}, - { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 7}, - { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82372FB_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8}, - { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82451NX, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 9}, - { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 10}, - { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 11}, - { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_10,PCI_ANY_ID, PCI_ANY_ID, 0, 0, 12}, - { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_11,PCI_ANY_ID, PCI_ANY_ID, 0, 0, 13}, - { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_11,PCI_ANY_ID, PCI_ANY_ID, 0, 0, 14}, - { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_11,PCI_ANY_ID, PCI_ANY_ID, 0, 0, 15}, - { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801E_11, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 16}, - { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_10,PCI_ANY_ID, PCI_ANY_ID, 0, 0, 17}, -#ifdef CONFIG_BLK_DEV_IDE_SATA - { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 18}, -#endif - { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 19}, - { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_19, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 20}, - { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_21, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 21}, - { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 22}, - { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB2_18, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 23}, - { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 24}, - { 0, }, -}; -MODULE_DEVICE_TABLE(pci, piix_pci_tbl); - -static struct pci_driver driver = { - .name = "PIIX_IDE", - .id_table = piix_pci_tbl, - .probe = piix_init_one, -}; - -static int __init piix_ide_init(void) -{ - piix_check_450nx(); - return ide_pci_register_driver(&driver); -} - -module_init(piix_ide_init); - -MODULE_AUTHOR("Andre Hedrick, Andrzej Krzysztofowicz"); -MODULE_DESCRIPTION("PCI driver module for Intel PIIX IDE"); -MODULE_LICENSE("GPL"); diff --git a/drivers/ide/pci/rz1000.c b/drivers/ide/pci/rz1000.c deleted file mode 100644 index 608cd760907..00000000000 --- a/drivers/ide/pci/rz1000.c +++ /dev/null @@ -1,91 +0,0 @@ -/* - * linux/drivers/ide/pci/rz1000.c Version 0.06 January 12, 2003 - * - * Copyright (C) 1995-1998 Linus Torvalds & author (see below) - */ - -/* - * Principal Author: mlord@pobox.com (Mark Lord) - * - * See linux/MAINTAINERS for address of current maintainer. - * - * This file provides support for disabling the buggy read-ahead - * mode of the RZ1000 IDE chipset, commonly used on Intel motherboards. - * - * Dunno if this fixes both ports, or only the primary port (?). - */ - -#undef REALLY_SLOW_IO /* most systems can safely undef this */ - -#include <linux/config.h> /* for CONFIG_BLK_DEV_IDEPCI */ -#include <linux/types.h> -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/delay.h> -#include <linux/timer.h> -#include <linux/mm.h> -#include <linux/ioport.h> -#include <linux/blkdev.h> -#include <linux/hdreg.h> -#include <linux/pci.h> -#include <linux/ide.h> -#include <linux/init.h> - -#include <asm/io.h> - -static void __devinit init_hwif_rz1000 (ide_hwif_t *hwif) -{ - u16 reg; - struct pci_dev *dev = hwif->pci_dev; - - hwif->chipset = ide_rz1000; - if (!pci_read_config_word (dev, 0x40, ®) && - !pci_write_config_word(dev, 0x40, reg & 0xdfff)) { - printk(KERN_INFO "%s: disabled chipset read-ahead " - "(buggy RZ1000/RZ1001)\n", hwif->name); - } else { - hwif->serialized = 1; - hwif->drives[0].no_unmask = 1; - hwif->drives[1].no_unmask = 1; - printk(KERN_INFO "%s: serialized, disabled unmasking " - "(buggy RZ1000/RZ1001)\n", hwif->name); - } -} - -static ide_pci_device_t rz1000_chipset __devinitdata = { - .name = "RZ100x", - .init_hwif = init_hwif_rz1000, - .channels = 2, - .autodma = NODMA, - .bootable = ON_BOARD, -}; - -static int __devinit rz1000_init_one(struct pci_dev *dev, const struct pci_device_id *id) -{ - return ide_setup_pci_device(dev, &rz1000_chipset); -} - -static struct pci_device_id rz1000_pci_tbl[] = { - { PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - { PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - { 0, }, -}; -MODULE_DEVICE_TABLE(pci, rz1000_pci_tbl); - -static struct pci_driver driver = { - .name = "RZ1000_IDE", - .id_table = rz1000_pci_tbl, - .probe = rz1000_init_one, -}; - -static int rz1000_ide_init(void) -{ - return ide_pci_register_driver(&driver); -} - -module_init(rz1000_ide_init); - -MODULE_AUTHOR("Andre Hedrick"); -MODULE_DESCRIPTION("PCI driver module for RZ1000 IDE"); -MODULE_LICENSE("GPL"); - diff --git a/drivers/ide/pci/sc1200.c b/drivers/ide/pci/sc1200.c deleted file mode 100644 index fc2b5496b6d..00000000000 --- a/drivers/ide/pci/sc1200.c +++ /dev/null @@ -1,515 +0,0 @@ -/* - * linux/drivers/ide/pci/sc1200.c Version 0.91 28-Jan-2003 - * - * Copyright (C) 2000-2002 Mark Lord <mlord@pobox.com> - * May be copied or modified under the terms of the GNU General Public License - * - * Development of this chipset driver was funded - * by the nice folks at National Semiconductor. - * - * Documentation: - * Available from National Semiconductor - */ - -#include <linux/module.h> -#include <linux/types.h> -#include <linux/kernel.h> -#include <linux/delay.h> -#include <linux/timer.h> -#include <linux/mm.h> -#include <linux/ioport.h> -#include <linux/blkdev.h> -#include <linux/hdreg.h> -#include <linux/interrupt.h> -#include <linux/pci.h> -#include <linux/init.h> -#include <linux/ide.h> -#include <linux/pm.h> -#include <asm/io.h> -#include <asm/irq.h> - -#define SC1200_REV_A 0x00 -#define SC1200_REV_B1 0x01 -#define SC1200_REV_B3 0x02 -#define SC1200_REV_C1 0x03 -#define SC1200_REV_D1 0x04 - -#define PCI_CLK_33 0x00 -#define PCI_CLK_48 0x01 -#define PCI_CLK_66 0x02 -#define PCI_CLK_33A 0x03 - -static unsigned short sc1200_get_pci_clock (void) -{ - unsigned char chip_id, silicon_revision; - unsigned int pci_clock; - /* - * Check the silicon revision, as not all versions of the chip - * have the register with the fast PCI bus timings. - */ - chip_id = inb (0x903c); - silicon_revision = inb (0x903d); - - // Read the fast pci clock frequency - if (chip_id == 0x04 && silicon_revision < SC1200_REV_B1) { - pci_clock = PCI_CLK_33; - } else { - // check clock generator configuration (cfcc) - // the clock is in bits 8 and 9 of this word - - pci_clock = inw (0x901e); - pci_clock >>= 8; - pci_clock &= 0x03; - if (pci_clock == PCI_CLK_33A) - pci_clock = PCI_CLK_33; - } - return pci_clock; -} - -extern char *ide_xfer_verbose (byte xfer_rate); - -/* - * Set a new transfer mode at the drive - */ -static int sc1200_set_xfer_mode (ide_drive_t *drive, byte mode) -{ - printk("%s: sc1200_set_xfer_mode(%s)\n", drive->name, ide_xfer_verbose(mode)); - return ide_config_drive_speed(drive, mode); -} - -/* - * Here are the standard PIO mode 0-4 timings for each "format". - * Format-0 uses fast data reg timings, with slower command reg timings. - * Format-1 uses fast timings for all registers, but won't work with all drives. - */ -static const unsigned int sc1200_pio_timings[4][5] = - {{0x00009172, 0x00012171, 0x00020080, 0x00032010, 0x00040010}, // format0 33Mhz - {0xd1329172, 0x71212171, 0x30200080, 0x20102010, 0x00100010}, // format1, 33Mhz - {0xfaa3f4f3, 0xc23232b2, 0x513101c1, 0x31213121, 0x10211021}, // format1, 48Mhz - {0xfff4fff4, 0xf35353d3, 0x814102f1, 0x42314231, 0x11311131}}; // format1, 66Mhz - -/* - * After chip reset, the PIO timings are set to 0x00009172, which is not valid. - */ -//#define SC1200_BAD_PIO(timings) (((timings)&~0x80000000)==0x00009172) - -static int sc1200_autoselect_dma_mode (ide_drive_t *drive) -{ - int udma_ok = 1, mode = 0; - ide_hwif_t *hwif = HWIF(drive); - int unit = drive->select.b.unit; - ide_drive_t *mate = &hwif->drives[unit^1]; - struct hd_driveid *id = drive->id; - - /* - * The SC1200 specifies that two drives sharing a cable cannot - * mix UDMA/MDMA. It has to be one or the other, for the pair, - * though different timings can still be chosen for each drive. - * We could set the appropriate timing bits on the fly, - * but that might be a bit confusing. So, for now we statically - * handle this requirement by looking at our mate drive to see - * what it is capable of, before choosing a mode for our own drive. - */ - if (mate->present) { - struct hd_driveid *mateid = mate->id; - if (mateid && (mateid->capability & 1) && !__ide_dma_bad_drive(mate)) { - if ((mateid->field_valid & 4) && (mateid->dma_ultra & 7)) - udma_ok = 1; - else if ((mateid->field_valid & 2) && (mateid->dma_mword & 7)) - udma_ok = 0; - else - udma_ok = 1; - } - } - /* - * Now see what the current drive is capable of, - * selecting UDMA only if the mate said it was ok. - */ - if (id && (id->capability & 1) && hwif->autodma && !__ide_dma_bad_drive(drive)) { - if (udma_ok && (id->field_valid & 4) && (id->dma_ultra & 7)) { - if (id->dma_ultra & 4) - mode = XFER_UDMA_2; - else if (id->dma_ultra & 2) - mode = XFER_UDMA_1; - else if (id->dma_ultra & 1) - mode = XFER_UDMA_0; - } - if (!mode && (id->field_valid & 2) && (id->dma_mword & 7)) { - if (id->dma_mword & 4) - mode = XFER_MW_DMA_2; - else if (id->dma_mword & 2) - mode = XFER_MW_DMA_1; - else if (id->dma_mword & 1) - mode = XFER_MW_DMA_0; - } - } - return mode; -} - -/* - * sc1200_config_dma2() handles selection/setting of DMA/UDMA modes - * for both the chipset and drive. - */ -static int sc1200_config_dma2 (ide_drive_t *drive, int mode) -{ - ide_hwif_t *hwif = HWIF(drive); - int unit = drive->select.b.unit; - unsigned int reg, timings; - unsigned short pci_clock; - unsigned int basereg = hwif->channel ? 0x50 : 0x40; - - /* - * Default to DMA-off in case we run into trouble here. - */ - hwif->ide_dma_off_quietly(drive); /* turn off DMA while we fiddle */ - outb(inb(hwif->dma_base+2)&~(unit?0x40:0x20), hwif->dma_base+2); /* clear DMA_capable bit */ - - /* - * Tell the drive to switch to the new mode; abort on failure. - */ - if (!mode || sc1200_set_xfer_mode(drive, mode)) { - printk("SC1200: set xfer mode failure\n"); - return 1; /* failure */ - } - - pci_clock = sc1200_get_pci_clock(); - - /* - * Now tune the chipset to match the drive: - * - * Note that each DMA mode has several timings associated with it. - * The correct timing depends on the fast PCI clock freq. - */ - timings = 0; - switch (mode) { - case XFER_UDMA_0: - switch (pci_clock) { - case PCI_CLK_33: timings = 0x00921250; break; - case PCI_CLK_48: timings = 0x00932470; break; - case PCI_CLK_66: timings = 0x009436a1; break; - } - break; - case XFER_UDMA_1: - switch (pci_clock) { - case PCI_CLK_33: timings = 0x00911140; break; - case PCI_CLK_48: timings = 0x00922260; break; - case PCI_CLK_66: timings = 0x00933481; break; - } - break; - case XFER_UDMA_2: - switch (pci_clock) { - case PCI_CLK_33: timings = 0x00911030; break; - case PCI_CLK_48: timings = 0x00922140; break; - case PCI_CLK_66: timings = 0x00923261; break; - } - break; - case XFER_MW_DMA_0: - switch (pci_clock) { - case PCI_CLK_33: timings = 0x00077771; break; - case PCI_CLK_48: timings = 0x000bbbb2; break; - case PCI_CLK_66: timings = 0x000ffff3; break; - } - break; - case XFER_MW_DMA_1: - switch (pci_clock) { - case PCI_CLK_33: timings = 0x00012121; break; - case PCI_CLK_48: timings = 0x00024241; break; - case PCI_CLK_66: timings = 0x00035352; break; - } - break; - case XFER_MW_DMA_2: - switch (pci_clock) { - case PCI_CLK_33: timings = 0x00002020; break; - case PCI_CLK_48: timings = 0x00013131; break; - case PCI_CLK_66: timings = 0x00015151; break; - } - break; - } - - if (timings == 0) { - printk("%s: sc1200_config_dma: huh? mode=%02x clk=%x \n", drive->name, mode, pci_clock); - return 1; /* failure */ - } - - if (unit == 0) { /* are we configuring drive0? */ - pci_read_config_dword(hwif->pci_dev, basereg+4, ®); - timings |= reg & 0x80000000; /* preserve PIO format bit */ - pci_write_config_dword(hwif->pci_dev, basereg+4, timings); - } else { - pci_write_config_dword(hwif->pci_dev, basereg+12, timings); - } - - outb(inb(hwif->dma_base+2)|(unit?0x40:0x20), hwif->dma_base+2); /* set DMA_capable bit */ - - /* - * Finally, turn DMA on in software, and exit. - */ - return hwif->ide_dma_on(drive); /* success */ -} - -/* - * sc1200_config_dma() handles selection/setting of DMA/UDMA modes - * for both the chipset and drive. - */ -static int sc1200_config_dma (ide_drive_t *drive) -{ - return sc1200_config_dma2(drive, sc1200_autoselect_dma_mode(drive)); -} - - -/* Replacement for the standard ide_dma_end action in - * dma_proc. - * - * returns 1 on error, 0 otherwise - */ -static int sc1200_ide_dma_end (ide_drive_t *drive) -{ - ide_hwif_t *hwif = HWIF(drive); - unsigned long dma_base = hwif->dma_base; - byte dma_stat; - - dma_stat = inb(dma_base+2); /* get DMA status */ - - if (!(dma_stat & 4)) - printk(" ide_dma_end dma_stat=%0x err=%x newerr=%x\n", - dma_stat, ((dma_stat&7)!=4), ((dma_stat&2)==2)); - - outb(dma_stat|0x1b, dma_base+2); /* clear the INTR & ERROR bits */ - outb(inb(dma_base)&~1, dma_base); /* !! DO THIS HERE !! stop DMA */ - - drive->waiting_for_dma = 0; - ide_destroy_dmatable(drive); /* purge DMA mappings */ - - return (dma_stat & 7) != 4; /* verify good DMA status */ -} - -/* - * sc1200_tuneproc() handles selection/setting of PIO modes - * for both the chipset and drive. - * - * All existing BIOSs for this chipset guarantee that all drives - * will have valid default PIO timings set up before we get here. - */ -static void sc1200_tuneproc (ide_drive_t *drive, byte pio) /* mode=255 means "autotune" */ -{ - ide_hwif_t *hwif = HWIF(drive); - unsigned int format; - static byte modes[5] = {XFER_PIO_0, XFER_PIO_1, XFER_PIO_2, XFER_PIO_3, XFER_PIO_4}; - int mode = -1; - - switch (pio) { - case 200: mode = XFER_UDMA_0; break; - case 201: mode = XFER_UDMA_1; break; - case 202: mode = XFER_UDMA_2; break; - case 100: mode = XFER_MW_DMA_0; break; - case 101: mode = XFER_MW_DMA_1; break; - case 102: mode = XFER_MW_DMA_2; break; - } - if (mode != -1) { - printk("SC1200: %s: changing (U)DMA mode\n", drive->name); - (void)sc1200_config_dma2(drive, mode); - return; - } - - pio = ide_get_best_pio_mode(drive, pio, 4, NULL); - printk("SC1200: %s: setting PIO mode%d\n", drive->name, pio); - if (!sc1200_set_xfer_mode(drive, modes[pio])) { - unsigned int basereg = hwif->channel ? 0x50 : 0x40; - pci_read_config_dword (hwif->pci_dev, basereg+4, &format); - format = (format >> 31) & 1; - if (format) - format += sc1200_get_pci_clock(); - pci_write_config_dword(hwif->pci_dev, basereg + (drive->select.b.unit << 3), sc1200_pio_timings[format][pio]); - } -} - -static ide_hwif_t *lookup_pci_dev (ide_hwif_t *prev, struct pci_dev *dev) -{ - int h; - - for (h = 0; h < MAX_HWIFS; h++) { - ide_hwif_t *hwif = &ide_hwifs[h]; - if (prev) { - if (hwif == prev) - prev = NULL; // found previous, now look for next match - } else { - if (hwif && hwif->pci_dev == dev) - return hwif; // found next match - } - } - return NULL; // not found -} - -typedef struct sc1200_saved_state_s { - __u32 regs[4]; -} sc1200_saved_state_t; - - -static int sc1200_suspend (struct pci_dev *dev, pm_message_t state) -{ - ide_hwif_t *hwif = NULL; - - printk("SC1200: suspend(%u)\n", state.event); - - if (state.event == PM_EVENT_ON) { - // we only save state when going from full power to less - - // - // Loop over all interfaces that are part of this PCI device: - // - while ((hwif = lookup_pci_dev(hwif, dev)) != NULL) { - sc1200_saved_state_t *ss; - unsigned int basereg, r; - // - // allocate a permanent save area, if not already allocated - // - ss = (sc1200_saved_state_t *)hwif->config_data; - if (ss == NULL) { - ss = kmalloc(sizeof(sc1200_saved_state_t), GFP_KERNEL); - if (ss == NULL) - return -ENOMEM; - hwif->config_data = (unsigned long)ss; - } - ss = (sc1200_saved_state_t *)hwif->config_data; - // - // Save timing registers: this may be unnecessary if - // BIOS also does it - // - basereg = hwif->channel ? 0x50 : 0x40; - for (r = 0; r < 4; ++r) { - pci_read_config_dword (hwif->pci_dev, basereg + (r<<2), &ss->regs[r]); - } - } - } - - /* You don't need to iterate over disks -- sysfs should have done that for you already */ - - pci_disable_device(dev); - pci_set_power_state(dev, pci_choose_state(dev, state)); - dev->current_state = state.event; - return 0; -} - -static int sc1200_resume (struct pci_dev *dev) -{ - ide_hwif_t *hwif = NULL; - - pci_set_power_state(dev, PCI_D0); // bring chip back from sleep state - dev->current_state = PM_EVENT_ON; - pci_enable_device(dev); - // - // loop over all interfaces that are part of this pci device: - // - while ((hwif = lookup_pci_dev(hwif, dev)) != NULL) { - unsigned int basereg, r, d, format; - sc1200_saved_state_t *ss = (sc1200_saved_state_t *)hwif->config_data; - - // - // Restore timing registers: this may be unnecessary if BIOS also does it - // - basereg = hwif->channel ? 0x50 : 0x40; - if (ss != NULL) { - for (r = 0; r < 4; ++r) { - pci_write_config_dword(hwif->pci_dev, basereg + (r<<2), ss->regs[r]); - } - } - // - // Re-program drive PIO modes - // - pci_read_config_dword(hwif->pci_dev, basereg+4, &format); - format = (format >> 31) & 1; - if (format) - format += sc1200_get_pci_clock(); - for (d = 0; d < 2; ++d) { - ide_drive_t *drive = &(hwif->drives[d]); - if (drive->present) { - unsigned int pio, timings; - pci_read_config_dword(hwif->pci_dev, basereg+(drive->select.b.unit << 3), &timings); - for (pio = 0; pio <= 4; ++pio) { - if (sc1200_pio_timings[format][pio] == timings) - break; - } - if (pio > 4) - pio = 255; /* autotune */ - (void)sc1200_tuneproc(drive, pio); - } - } - // - // Re-program drive DMA modes - // - for (d = 0; d < MAX_DRIVES; ++d) { - ide_drive_t *drive = &(hwif->drives[d]); - if (drive->present && !__ide_dma_bad_drive(drive)) { - int was_using_dma = drive->using_dma; - hwif->ide_dma_off_quietly(drive); - sc1200_config_dma(drive); - if (!was_using_dma && drive->using_dma) { - hwif->ide_dma_off_quietly(drive); - } - } - } - } - return 0; -} - -/* - * This gets invoked by the IDE driver once for each channel, - * and performs channel-specific pre-initialization before drive probing. - */ -static void __devinit init_hwif_sc1200 (ide_hwif_t *hwif) -{ - if (hwif->mate) - hwif->serialized = hwif->mate->serialized = 1; - hwif->autodma = 0; - if (hwif->dma_base) { - hwif->ide_dma_check = &sc1200_config_dma; - hwif->ide_dma_end = &sc1200_ide_dma_end; - if (!noautodma) - hwif->autodma = 1; - hwif->tuneproc = &sc1200_tuneproc; - } - hwif->atapi_dma = 1; - hwif->ultra_mask = 0x07; - hwif->mwdma_mask = 0x07; - - hwif->drives[0].autodma = hwif->autodma; - hwif->drives[1].autodma = hwif->autodma; -} - -static ide_pci_device_t sc1200_chipset __devinitdata = { - .name = "SC1200", - .init_hwif = init_hwif_sc1200, - .channels = 2, - .autodma = AUTODMA, - .bootable = ON_BOARD, -}; - -static int __devinit sc1200_init_one(struct pci_dev *dev, const struct pci_device_id *id) -{ - return ide_setup_pci_device(dev, &sc1200_chipset); -} - -static struct pci_device_id sc1200_pci_tbl[] = { - { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_IDE), 0}, - { 0, }, -}; -MODULE_DEVICE_TABLE(pci, sc1200_pci_tbl); - -static struct pci_driver driver = { - .name = "SC1200_IDE", - .id_table = sc1200_pci_tbl, - .probe = sc1200_init_one, - .suspend = sc1200_suspend, - .resume = sc1200_resume, -}; - -static int sc1200_ide_init(void) -{ - return ide_pci_register_driver(&driver); -} - -module_init(sc1200_ide_init); - -MODULE_AUTHOR("Mark Lord"); -MODULE_DESCRIPTION("PCI driver module for NS SC1200 IDE"); -MODULE_LICENSE("GPL"); diff --git a/drivers/ide/pci/serverworks.c b/drivers/ide/pci/serverworks.c deleted file mode 100644 index f063d954236..00000000000 --- a/drivers/ide/pci/serverworks.c +++ /dev/null @@ -1,676 +0,0 @@ -/* - * linux/drivers/ide/pci/serverworks.c Version 0.8 25 Ebr 2003 - * - * Copyright (C) 1998-2000 Michel Aubry - * Copyright (C) 1998-2000 Andrzej Krzysztofowicz - * Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org> - * Portions copyright (c) 2001 Sun Microsystems - * - * - * RCC/ServerWorks IDE driver for Linux - * - * OSB4: `Open South Bridge' IDE Interface (fn 1) - * supports UDMA mode 2 (33 MB/s) - * - * CSB5: `Champion South Bridge' IDE Interface (fn 1) - * all revisions support UDMA mode 4 (66 MB/s) - * revision A2.0 and up support UDMA mode 5 (100 MB/s) - * - * *** The CSB5 does not provide ANY register *** - * *** to detect 80-conductor cable presence. *** - * - * CSB6: `Champion South Bridge' IDE Interface (optional: third channel) - * - * HT1000: AKA BCM5785 - Hypertransport Southbridge for Opteron systems. IDE - * controller same as the CSB6. Single channel ATA100 only. - * - * Documentation: - * Available under NDA only. Errata info very hard to get. - * - */ - -#include <linux/types.h> -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/ioport.h> -#include <linux/pci.h> -#include <linux/hdreg.h> -#include <linux/ide.h> -#include <linux/init.h> -#include <linux/delay.h> - -#include <asm/io.h> - -#define SVWKS_CSB5_REVISION_NEW 0x92 /* min PCI_REVISION_ID for UDMA5 (A2.0) */ -#define SVWKS_CSB6_REVISION 0xa0 /* min PCI_REVISION_ID for UDMA4 (A1.0) */ - -/* Seagate Barracuda ATA IV Family drives in UDMA mode 5 - * can overrun their FIFOs when used with the CSB5 */ -static const char *svwks_bad_ata100[] = { - "ST320011A", - "ST340016A", - "ST360021A", - "ST380021A", - NULL -}; - -static u8 svwks_revision = 0; -static struct pci_dev *isa_dev; - -static int check_in_drive_lists (ide_drive_t *drive, const char **list) -{ - while (*list) - if (!strcmp(*list++, drive->id->model)) - return 1; - return 0; -} - -static u8 svwks_ratemask (ide_drive_t *drive) -{ - struct pci_dev *dev = HWIF(drive)->pci_dev; - u8 mode = 0; - - if (!svwks_revision) - pci_read_config_byte(dev, PCI_REVISION_ID, &svwks_revision); - - if (dev->device == PCI_DEVICE_ID_SERVERWORKS_HT1000IDE) - return 2; - if (dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) { - u32 reg = 0; - if (isa_dev) - pci_read_config_dword(isa_dev, 0x64, ®); - - /* - * Don't enable UDMA on disk devices for the moment - */ - if(drive->media == ide_disk) - return 0; - /* Check the OSB4 DMA33 enable bit */ - return ((reg & 0x00004000) == 0x00004000) ? 1 : 0; - } else if (svwks_revision < SVWKS_CSB5_REVISION_NEW) { - return 1; - } else if (svwks_revision >= SVWKS_CSB5_REVISION_NEW) { - u8 btr = 0; - pci_read_config_byte(dev, 0x5A, &btr); - mode = btr & 0x3; - if (!eighty_ninty_three(drive)) - mode = min(mode, (u8)1); - /* If someone decides to do UDMA133 on CSB5 the same - issue will bite so be inclusive */ - if (mode > 2 && check_in_drive_lists(drive, svwks_bad_ata100)) - mode = 2; - } - if (((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) || - (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2)) && - (!(PCI_FUNC(dev->devfn) & 1))) - mode = 2; - return mode; -} - -static u8 svwks_csb_check (struct pci_dev *dev) -{ - switch (dev->device) { - case PCI_DEVICE_ID_SERVERWORKS_CSB5IDE: - case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE: - case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2: - case PCI_DEVICE_ID_SERVERWORKS_HT1000IDE: - return 1; - default: - break; - } - return 0; -} -static int svwks_tune_chipset (ide_drive_t *drive, u8 xferspeed) -{ - static const u8 udma_modes[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 }; - static const u8 dma_modes[] = { 0x77, 0x21, 0x20 }; - static const u8 pio_modes[] = { 0x5d, 0x47, 0x34, 0x22, 0x20 }; - static const u8 drive_pci[] = { 0x41, 0x40, 0x43, 0x42 }; - static const u8 drive_pci2[] = { 0x45, 0x44, 0x47, 0x46 }; - - ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; - u8 speed; - u8 pio = ide_get_best_pio_mode(drive, 255, 5, NULL); - u8 unit = (drive->select.b.unit & 0x01); - u8 csb5 = svwks_csb_check(dev); - u8 ultra_enable = 0, ultra_timing = 0; - u8 dma_timing = 0, pio_timing = 0; - u16 csb5_pio = 0; - - if (xferspeed == 255) /* PIO auto-tuning */ - speed = XFER_PIO_0 + pio; - else - speed = ide_rate_filter(svwks_ratemask(drive), xferspeed); - - /* If we are about to put a disk into UDMA mode we screwed up. - Our code assumes we never _ever_ do this on an OSB4 */ - - if(dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4 && - drive->media == ide_disk && speed >= XFER_UDMA_0) - BUG(); - - pci_read_config_byte(dev, drive_pci[drive->dn], &pio_timing); - pci_read_config_byte(dev, drive_pci2[drive->dn], &dma_timing); - pci_read_config_byte(dev, (0x56|hwif->channel), &ultra_timing); - pci_read_config_word(dev, 0x4A, &csb5_pio); - pci_read_config_byte(dev, 0x54, &ultra_enable); - - /* Per Specified Design by OEM, and ASIC Architect */ - if ((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) || - (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2)) { - if (!drive->init_speed) { - u8 dma_stat = hwif->INB(hwif->dma_status); - -dma_pio: - if (((ultra_enable << (7-drive->dn) & 0x80) == 0x80) && - ((dma_stat & (1<<(5+unit))) == (1<<(5+unit)))) { - drive->current_speed = drive->init_speed = XFER_UDMA_0 + udma_modes[(ultra_timing >> (4*unit)) & ~(0xF0)]; - return 0; - } else if ((dma_timing) && - ((dma_stat&(1<<(5+unit)))==(1<<(5+unit)))) { - u8 dmaspeed = dma_timing; - - dma_timing &= ~0xFF; - if ((dmaspeed & 0x20) == 0x20) - dmaspeed = XFER_MW_DMA_2; - else if ((dmaspeed & 0x21) == 0x21) - dmaspeed = XFER_MW_DMA_1; - else if ((dmaspeed & 0x77) == 0x77) - dmaspeed = XFER_MW_DMA_0; - else - goto dma_pio; - drive->current_speed = drive->init_speed = dmaspeed; - return 0; - } else if (pio_timing) { - u8 piospeed = pio_timing; - - pio_timing &= ~0xFF; - if ((piospeed & 0x20) == 0x20) - piospeed = XFER_PIO_4; - else if ((piospeed & 0x22) == 0x22) - piospeed = XFER_PIO_3; - else if ((piospeed & 0x34) == 0x34) - piospeed = XFER_PIO_2; - else if ((piospeed & 0x47) == 0x47) - piospeed = XFER_PIO_1; - else if ((piospeed & 0x5d) == 0x5d) - piospeed = XFER_PIO_0; - else - goto oem_setup_failed; - drive->current_speed = drive->init_speed = piospeed; - return 0; - } - } - } - -oem_setup_failed: - - pio_timing &= ~0xFF; - dma_timing &= ~0xFF; - ultra_timing &= ~(0x0F << (4*unit)); - ultra_enable &= ~(0x01 << drive->dn); - csb5_pio &= ~(0x0F << (4*drive->dn)); - - switch(speed) { - case XFER_PIO_4: - case XFER_PIO_3: - case XFER_PIO_2: - case XFER_PIO_1: - case XFER_PIO_0: - pio_timing |= pio_modes[speed - XFER_PIO_0]; - csb5_pio |= ((speed - XFER_PIO_0) << (4*drive->dn)); - break; - - case XFER_MW_DMA_2: - case XFER_MW_DMA_1: - case XFER_MW_DMA_0: - pio_timing |= pio_modes[pio]; - csb5_pio |= (pio << (4*drive->dn)); - dma_timing |= dma_modes[speed - XFER_MW_DMA_0]; - break; - - case XFER_UDMA_5: - case XFER_UDMA_4: - case XFER_UDMA_3: - case XFER_UDMA_2: - case XFER_UDMA_1: - case XFER_UDMA_0: - pio_timing |= pio_modes[pio]; - csb5_pio |= (pio << (4*drive->dn)); - dma_timing |= dma_modes[2]; - ultra_timing |= ((udma_modes[speed - XFER_UDMA_0]) << (4*unit)); - ultra_enable |= (0x01 << drive->dn); - default: - break; - } - - pci_write_config_byte(dev, drive_pci[drive->dn], pio_timing); - if (csb5) - pci_write_config_word(dev, 0x4A, csb5_pio); - - pci_write_config_byte(dev, drive_pci2[drive->dn], dma_timing); - pci_write_config_byte(dev, (0x56|hwif->channel), ultra_timing); - pci_write_config_byte(dev, 0x54, ultra_enable); - - return (ide_config_drive_speed(drive, speed)); -} - -static void config_chipset_for_pio (ide_drive_t *drive) -{ - u16 eide_pio_timing[6] = {960, 480, 240, 180, 120, 90}; - u16 xfer_pio = drive->id->eide_pio_modes; - u8 timing, speed, pio; - - pio = ide_get_best_pio_mode(drive, 255, 5, NULL); - - if (xfer_pio > 4) - xfer_pio = 0; - - if (drive->id->eide_pio_iordy > 0) - for (xfer_pio = 5; - xfer_pio>0 && - drive->id->eide_pio_iordy>eide_pio_timing[xfer_pio]; - xfer_pio--); - else - xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 : - (drive->id->eide_pio_modes & 2) ? 0x04 : - (drive->id->eide_pio_modes & 1) ? 0x03 : - (drive->id->tPIO & 2) ? 0x02 : - (drive->id->tPIO & 1) ? 0x01 : xfer_pio; - - timing = (xfer_pio >= pio) ? xfer_pio : pio; - - switch(timing) { - case 4: speed = XFER_PIO_4;break; - case 3: speed = XFER_PIO_3;break; - case 2: speed = XFER_PIO_2;break; - case 1: speed = XFER_PIO_1;break; - default: - speed = (!drive->id->tPIO) ? XFER_PIO_0 : XFER_PIO_SLOW; - break; - } - (void) svwks_tune_chipset(drive, speed); - drive->current_speed = speed; -} - -static void svwks_tune_drive (ide_drive_t *drive, u8 pio) -{ - if(pio == 255) - (void) svwks_tune_chipset(drive, 255); - else - (void) svwks_tune_chipset(drive, (XFER_PIO_0 + pio)); -} - -static int config_chipset_for_dma (ide_drive_t *drive) -{ - u8 speed = ide_dma_speed(drive, svwks_ratemask(drive)); - - if (!(speed)) - speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL); - - (void) svwks_tune_chipset(drive, speed); - return ide_dma_enable(drive); -} - -static int svwks_config_drive_xfer_rate (ide_drive_t *drive) -{ - ide_hwif_t *hwif = HWIF(drive); - struct hd_driveid *id = drive->id; - - drive->init_speed = 0; - - if ((id->capability & 1) && drive->autodma) { - - if (ide_use_dma(drive)) { - if (config_chipset_for_dma(drive)) - return hwif->ide_dma_on(drive); - } - - goto fast_ata_pio; - - } else if ((id->capability & 8) || (id->field_valid & 2)) { -fast_ata_pio: - config_chipset_for_pio(drive); - // hwif->tuneproc(drive, 5); - return hwif->ide_dma_off_quietly(drive); - } - /* IORDY not supported */ - return 0; -} - -/* This can go soon */ - -static int svwks_ide_dma_end (ide_drive_t *drive) -{ - return __ide_dma_end(drive); -} - -static unsigned int __devinit init_chipset_svwks (struct pci_dev *dev, const char *name) -{ - unsigned int reg; - u8 btr; - - /* save revision id to determine DMA capability */ - pci_read_config_byte(dev, PCI_REVISION_ID, &svwks_revision); - - /* force Master Latency Timer value to 64 PCICLKs */ - pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x40); - - /* OSB4 : South Bridge and IDE */ - if (dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) { - isa_dev = pci_find_device(PCI_VENDOR_ID_SERVERWORKS, - PCI_DEVICE_ID_SERVERWORKS_OSB4, NULL); - if (isa_dev) { - pci_read_config_dword(isa_dev, 0x64, ®); - reg &= ~0x00002000; /* disable 600ns interrupt mask */ - if(!(reg & 0x00004000)) - printk(KERN_DEBUG "%s: UDMA not BIOS enabled.\n", name); - reg |= 0x00004000; /* enable UDMA/33 support */ - pci_write_config_dword(isa_dev, 0x64, reg); - } - } - - /* setup CSB5/CSB6 : South Bridge and IDE option RAID */ - else if ((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) || - (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) || - (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2)) { - - /* Third Channel Test */ - if (!(PCI_FUNC(dev->devfn) & 1)) { - struct pci_dev * findev = NULL; - u32 reg4c = 0; - findev = pci_find_device(PCI_VENDOR_ID_SERVERWORKS, - PCI_DEVICE_ID_SERVERWORKS_CSB5, NULL); - if (findev) { - pci_read_config_dword(findev, 0x4C, ®4c); - reg4c &= ~0x000007FF; - reg4c |= 0x00000040; - reg4c |= 0x00000020; - pci_write_config_dword(findev, 0x4C, reg4c); - } - outb_p(0x06, 0x0c00); - dev->irq = inb_p(0x0c01); - } else { - struct pci_dev * findev = NULL; - u8 reg41 = 0; - - findev = pci_find_device(PCI_VENDOR_ID_SERVERWORKS, - PCI_DEVICE_ID_SERVERWORKS_CSB6, NULL); - if (findev) { - pci_read_config_byte(findev, 0x41, ®41); - reg41 &= ~0x40; - pci_write_config_byte(findev, 0x41, reg41); - } - /* - * This is a device pin issue on CSB6. - * Since there will be a future raid mode, - * early versions of the chipset require the - * interrupt pin to be set, and it is a compatibility - * mode issue. - */ - if ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE) - dev->irq = 0; - } -// pci_read_config_dword(dev, 0x40, &pioreg) -// pci_write_config_dword(dev, 0x40, 0x99999999); -// pci_read_config_dword(dev, 0x44, &dmareg); -// pci_write_config_dword(dev, 0x44, 0xFFFFFFFF); - /* setup the UDMA Control register - * - * 1. clear bit 6 to enable DMA - * 2. enable DMA modes with bits 0-1 - * 00 : legacy - * 01 : udma2 - * 10 : udma2/udma4 - * 11 : udma2/udma4/udma5 - */ - pci_read_config_byte(dev, 0x5A, &btr); - btr &= ~0x40; - if (!(PCI_FUNC(dev->devfn) & 1)) - btr |= 0x2; - else - btr |= (svwks_revision >= SVWKS_CSB5_REVISION_NEW) ? 0x3 : 0x2; - pci_write_config_byte(dev, 0x5A, btr); - } - /* Setup HT1000 SouthBridge Controller - Single Channel Only */ - else if (dev->device == PCI_DEVICE_ID_SERVERWORKS_HT1000IDE) { - pci_read_config_byte(dev, 0x5A, &btr); - btr &= ~0x40; - btr |= 0x3; - pci_write_config_byte(dev, 0x5A, btr); - } - - return dev->irq; -} - -static unsigned int __devinit ata66_svwks_svwks (ide_hwif_t *hwif) -{ - return 1; -} - -/* On Dell PowerEdge servers with a CSB5/CSB6, the top two bits - * of the subsystem device ID indicate presence of an 80-pin cable. - * Bit 15 clear = secondary IDE channel does not have 80-pin cable. - * Bit 15 set = secondary IDE channel has 80-pin cable. - * Bit 14 clear = primary IDE channel does not have 80-pin cable. - * Bit 14 set = primary IDE channel has 80-pin cable. - */ -static unsigned int __devinit ata66_svwks_dell (ide_hwif_t *hwif) -{ - struct pci_dev *dev = hwif->pci_dev; - if (dev->subsystem_vendor == PCI_VENDOR_ID_DELL && - dev->vendor == PCI_VENDOR_ID_SERVERWORKS && - (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE || - dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE)) - return ((1 << (hwif->channel + 14)) & - dev->subsystem_device) ? 1 : 0; - return 0; -} - -/* Sun Cobalt Alpine hardware avoids the 80-pin cable - * detect issue by attaching the drives directly to the board. - * This check follows the Dell precedent (how scary is that?!) - * - * WARNING: this only works on Alpine hardware! - */ -static unsigned int __devinit ata66_svwks_cobalt (ide_hwif_t *hwif) -{ - struct pci_dev *dev = hwif->pci_dev; - if (dev->subsystem_vendor == PCI_VENDOR_ID_SUN && - dev->vendor == PCI_VENDOR_ID_SERVERWORKS && - dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) - return ((1 << (hwif->channel + 14)) & - dev->subsystem_device) ? 1 : 0; - return 0; -} - -static unsigned int __devinit ata66_svwks (ide_hwif_t *hwif) -{ - struct pci_dev *dev = hwif->pci_dev; - - /* Server Works */ - if (dev->subsystem_vendor == PCI_VENDOR_ID_SERVERWORKS) - return ata66_svwks_svwks (hwif); - - /* Dell PowerEdge */ - if (dev->subsystem_vendor == PCI_VENDOR_ID_DELL) - return ata66_svwks_dell (hwif); - - /* Cobalt Alpine */ - if (dev->subsystem_vendor == PCI_VENDOR_ID_SUN) - return ata66_svwks_cobalt (hwif); - - /* Per Specified Design by OEM, and ASIC Architect */ - if ((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) || - (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2)) - return 1; - - return 0; -} - -static void __devinit init_hwif_svwks (ide_hwif_t *hwif) -{ - u8 dma_stat = 0; - - if (!hwif->irq) - hwif->irq = hwif->channel ? 15 : 14; - - hwif->tuneproc = &svwks_tune_drive; - hwif->speedproc = &svwks_tune_chipset; - - hwif->atapi_dma = 1; - - if (hwif->pci_dev->device != PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) - hwif->ultra_mask = 0x3f; - - hwif->mwdma_mask = 0x07; - - hwif->autodma = 0; - - if (!hwif->dma_base) { - hwif->drives[0].autotune = 1; - hwif->drives[1].autotune = 1; - return; - } - - hwif->ide_dma_check = &svwks_config_drive_xfer_rate; - if (hwif->pci_dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) - hwif->ide_dma_end = &svwks_ide_dma_end; - else if (!(hwif->udma_four)) - hwif->udma_four = ata66_svwks(hwif); - if (!noautodma) - hwif->autodma = 1; - - dma_stat = hwif->INB(hwif->dma_status); - hwif->drives[0].autodma = (dma_stat & 0x20); - hwif->drives[1].autodma = (dma_stat & 0x40); - hwif->drives[0].autotune = (!(dma_stat & 0x20)); - hwif->drives[1].autotune = (!(dma_stat & 0x40)); -} - -/* - * We allow the BM-DMA driver to only work on enabled interfaces. - */ -static void __devinit init_dma_svwks (ide_hwif_t *hwif, unsigned long dmabase) -{ - struct pci_dev *dev = hwif->pci_dev; - - if (((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) || - (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2)) && - (!(PCI_FUNC(dev->devfn) & 1)) && (hwif->channel)) - return; - - ide_setup_dma(hwif, dmabase, 8); -} - -static int __devinit init_setup_svwks (struct pci_dev *dev, ide_pci_device_t *d) -{ - return ide_setup_pci_device(dev, d); -} - -static int __devinit init_setup_csb6 (struct pci_dev *dev, ide_pci_device_t *d) -{ - if (!(PCI_FUNC(dev->devfn) & 1)) { - d->bootable = NEVER_BOARD; - if (dev->resource[0].start == 0x01f1) - d->bootable = ON_BOARD; - } - - d->channels = ((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE || - dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2) && - (!(PCI_FUNC(dev->devfn) & 1))) ? 1 : 2; - - return ide_setup_pci_device(dev, d); -} - -static ide_pci_device_t serverworks_chipsets[] __devinitdata = { - { /* 0 */ - .name = "SvrWks OSB4", - .init_setup = init_setup_svwks, - .init_chipset = init_chipset_svwks, - .init_hwif = init_hwif_svwks, - .channels = 2, - .autodma = AUTODMA, - .bootable = ON_BOARD, - },{ /* 1 */ - .name = "SvrWks CSB5", - .init_setup = init_setup_svwks, - .init_chipset = init_chipset_svwks, - .init_hwif = init_hwif_svwks, - .init_dma = init_dma_svwks, - .channels = 2, - .autodma = AUTODMA, - .bootable = ON_BOARD, - },{ /* 2 */ - .name = "SvrWks CSB6", - .init_setup = init_setup_csb6, - .init_chipset = init_chipset_svwks, - .init_hwif = init_hwif_svwks, - .init_dma = init_dma_svwks, - .channels = 2, - .autodma = AUTODMA, - .bootable = ON_BOARD, - },{ /* 3 */ - .name = "SvrWks CSB6", - .init_setup = init_setup_csb6, - .init_chipset = init_chipset_svwks, - .init_hwif = init_hwif_svwks, - .init_dma = init_dma_svwks, - .channels = 1, /* 2 */ - .autodma = AUTODMA, - .bootable = ON_BOARD, - },{ /* 4 */ - .name = "SvrWks HT1000", - .init_setup = init_setup_svwks, - .init_chipset = init_chipset_svwks, - .init_hwif = init_hwif_svwks, - .init_dma = init_dma_svwks, - .channels = 1, /* 2 */ - .autodma = AUTODMA, - .bootable = ON_BOARD, - } -}; - -/** - * svwks_init_one - called when a OSB/CSB is found - * @dev: the svwks device - * @id: the matching pci id - * - * Called when the PCI registration layer (or the IDE initialization) - * finds a device matching our IDE device tables. - */ - -static int __devinit svwks_init_one(struct pci_dev *dev, const struct pci_device_id *id) -{ - ide_pci_device_t *d = &serverworks_chipsets[id->driver_data]; - - return d->init_setup(dev, d); -} - -static struct pci_device_id svwks_pci_tbl[] = { - { PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - { PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1}, - { PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2}, - { PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3}, - { PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_HT1000IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4}, - { 0, }, -}; -MODULE_DEVICE_TABLE(pci, svwks_pci_tbl); - -static struct pci_driver driver = { - .name = "Serverworks_IDE", - .id_table = svwks_pci_tbl, - .probe = svwks_init_one, -}; - -static int svwks_ide_init(void) -{ - return ide_pci_register_driver(&driver); -} - -module_init(svwks_ide_init); - -MODULE_AUTHOR("Michael Aubry. Andrzej Krzysztofowicz, Andre Hedrick"); -MODULE_DESCRIPTION("PCI driver module for Serverworks OSB4/CSB5/CSB6 IDE"); -MODULE_LICENSE("GPL"); diff --git a/drivers/ide/pci/sgiioc4.c b/drivers/ide/pci/sgiioc4.c deleted file mode 100644 index d8a0d87df73..00000000000 --- a/drivers/ide/pci/sgiioc4.c +++ /dev/null @@ -1,784 +0,0 @@ -/* - * Copyright (c) 2003-2006 Silicon Graphics, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/NoticeExplan - */ - -#include <linux/module.h> -#include <linux/types.h> -#include <linux/pci.h> -#include <linux/delay.h> -#include <linux/hdreg.h> -#include <linux/init.h> -#include <linux/kernel.h> -#include <linux/timer.h> -#include <linux/mm.h> -#include <linux/ioport.h> -#include <linux/blkdev.h> -#include <linux/ioc4.h> -#include <asm/io.h> - -#include <linux/ide.h> - -/* IOC4 Specific Definitions */ -#define IOC4_CMD_OFFSET 0x100 -#define IOC4_CTRL_OFFSET 0x120 -#define IOC4_DMA_OFFSET 0x140 -#define IOC4_INTR_OFFSET 0x0 - -#define IOC4_TIMING 0x00 -#define IOC4_DMA_PTR_L 0x01 -#define IOC4_DMA_PTR_H 0x02 -#define IOC4_DMA_ADDR_L 0x03 -#define IOC4_DMA_ADDR_H 0x04 -#define IOC4_BC_DEV 0x05 -#define IOC4_BC_MEM 0x06 -#define IOC4_DMA_CTRL 0x07 -#define IOC4_DMA_END_ADDR 0x08 - -/* Bits in the IOC4 Control/Status Register */ -#define IOC4_S_DMA_START 0x01 -#define IOC4_S_DMA_STOP 0x02 -#define IOC4_S_DMA_DIR 0x04 -#define IOC4_S_DMA_ACTIVE 0x08 -#define IOC4_S_DMA_ERROR 0x10 -#define IOC4_ATA_MEMERR 0x02 - -/* Read/Write Directions */ -#define IOC4_DMA_WRITE 0x04 -#define IOC4_DMA_READ 0x00 - -/* Interrupt Register Offsets */ -#define IOC4_INTR_REG 0x03 -#define IOC4_INTR_SET 0x05 -#define IOC4_INTR_CLEAR 0x07 - -#define IOC4_IDE_CACHELINE_SIZE 128 -#define IOC4_CMD_CTL_BLK_SIZE 0x20 -#define IOC4_SUPPORTED_FIRMWARE_REV 46 - -typedef struct { - u32 timing_reg0; - u32 timing_reg1; - u32 low_mem_ptr; - u32 high_mem_ptr; - u32 low_mem_addr; - u32 high_mem_addr; - u32 dev_byte_count; - u32 mem_byte_count; - u32 status; -} ioc4_dma_regs_t; - -/* Each Physical Region Descriptor Entry size is 16 bytes (2 * 64 bits) */ -/* IOC4 has only 1 IDE channel */ -#define IOC4_PRD_BYTES 16 -#define IOC4_PRD_ENTRIES (PAGE_SIZE /(4*IOC4_PRD_BYTES)) - - -static void -sgiioc4_init_hwif_ports(hw_regs_t * hw, unsigned long data_port, - unsigned long ctrl_port, unsigned long irq_port) -{ - unsigned long reg = data_port; - int i; - - /* Registers are word (32 bit) aligned */ - for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) - hw->io_ports[i] = reg + i * 4; - - if (ctrl_port) - hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port; - - if (irq_port) - hw->io_ports[IDE_IRQ_OFFSET] = irq_port; -} - -static void -sgiioc4_maskproc(ide_drive_t * drive, int mask) -{ - ide_hwif_t *hwif = HWIF(drive); - hwif->OUTB(mask ? (drive->ctl | 2) : (drive->ctl & ~2), - IDE_CONTROL_REG); -} - - -static int -sgiioc4_checkirq(ide_hwif_t * hwif) -{ - u8 intr_reg = - hwif->INL(hwif->io_ports[IDE_IRQ_OFFSET] + IOC4_INTR_REG * 4); - - if (intr_reg & 0x03) - return 1; - - return 0; -} - - -static int -sgiioc4_clearirq(ide_drive_t * drive) -{ - u32 intr_reg; - ide_hwif_t *hwif = HWIF(drive); - unsigned long other_ir = - hwif->io_ports[IDE_IRQ_OFFSET] + (IOC4_INTR_REG << 2); - - /* Code to check for PCI error conditions */ - intr_reg = hwif->INL(other_ir); - if (intr_reg & 0x03) { /* Valid IOC4-IDE interrupt */ - /* - * Using hwif->INB to read the IDE_STATUS_REG has a side effect - * of clearing the interrupt. The first read should clear it - * if it is set. The second read should return a "clear" status - * if it got cleared. If not, then spin for a bit trying to - * clear it. - */ - u8 stat = hwif->INB(IDE_STATUS_REG); - int count = 0; - stat = hwif->INB(IDE_STATUS_REG); - while ((stat & 0x80) && (count++ < 100)) { - udelay(1); - stat = hwif->INB(IDE_STATUS_REG); - } - - if (intr_reg & 0x02) { - /* Error when transferring DMA data on PCI bus */ - u32 pci_err_addr_low, pci_err_addr_high, - pci_stat_cmd_reg; - - pci_err_addr_low = - hwif->INL(hwif->io_ports[IDE_IRQ_OFFSET]); - pci_err_addr_high = - hwif->INL(hwif->io_ports[IDE_IRQ_OFFSET] + 4); - pci_read_config_dword(hwif->pci_dev, PCI_COMMAND, - &pci_stat_cmd_reg); - printk(KERN_ERR - "%s(%s) : PCI Bus Error when doing DMA:" - " status-cmd reg is 0x%x\n", - __FUNCTION__, drive->name, pci_stat_cmd_reg); - printk(KERN_ERR - "%s(%s) : PCI Error Address is 0x%x%x\n", - __FUNCTION__, drive->name, - pci_err_addr_high, pci_err_addr_low); - /* Clear the PCI Error indicator */ - pci_write_config_dword(hwif->pci_dev, PCI_COMMAND, - 0x00000146); - } - - /* Clear the Interrupt, Error bits on the IOC4 */ - hwif->OUTL(0x03, other_ir); - - intr_reg = hwif->INL(other_ir); - } - - return intr_reg & 3; -} - -static void sgiioc4_ide_dma_start(ide_drive_t * drive) -{ - ide_hwif_t *hwif = HWIF(drive); - unsigned int reg = hwif->INL(hwif->dma_base + IOC4_DMA_CTRL * 4); - unsigned int temp_reg = reg | IOC4_S_DMA_START; - - hwif->OUTL(temp_reg, hwif->dma_base + IOC4_DMA_CTRL * 4); -} - -static u32 -sgiioc4_ide_dma_stop(ide_hwif_t *hwif, u64 dma_base) -{ - u32 ioc4_dma; - int count; - - count = 0; - ioc4_dma = hwif->INL(dma_base + IOC4_DMA_CTRL * 4); - while ((ioc4_dma & IOC4_S_DMA_STOP) && (count++ < 200)) { - udelay(1); - ioc4_dma = hwif->INL(dma_base + IOC4_DMA_CTRL * 4); - } - return ioc4_dma; -} - -/* Stops the IOC4 DMA Engine */ -static int -sgiioc4_ide_dma_end(ide_drive_t * drive) -{ - u32 ioc4_dma, bc_dev, bc_mem, num, valid = 0, cnt = 0; - ide_hwif_t *hwif = HWIF(drive); - u64 dma_base = hwif->dma_base; - int dma_stat = 0; - unsigned long *ending_dma = (unsigned long *) hwif->dma_base2; - - hwif->OUTL(IOC4_S_DMA_STOP, dma_base + IOC4_DMA_CTRL * 4); - - ioc4_dma = sgiioc4_ide_dma_stop(hwif, dma_base); - - if (ioc4_dma & IOC4_S_DMA_STOP) { - printk(KERN_ERR - "%s(%s): IOC4 DMA STOP bit is still 1 :" - "ioc4_dma_reg 0x%x\n", - __FUNCTION__, drive->name, ioc4_dma); - dma_stat = 1; - } - - /* - * The IOC4 will DMA 1's to the ending dma area to indicate that - * previous data DMA is complete. This is necessary because of relaxed - * ordering between register reads and DMA writes on the Altix. - */ - while ((cnt++ < 200) && (!valid)) { - for (num = 0; num < 16; num++) { - if (ending_dma[num]) { - valid = 1; - break; - } - } - udelay(1); - } - if (!valid) { - printk(KERN_ERR "%s(%s) : DMA incomplete\n", __FUNCTION__, - drive->name); - dma_stat = 1; - } - - bc_dev = hwif->INL(dma_base + IOC4_BC_DEV * 4); - bc_mem = hwif->INL(dma_base + IOC4_BC_MEM * 4); - - if ((bc_dev & 0x01FF) || (bc_mem & 0x1FF)) { - if (bc_dev > bc_mem + 8) { - printk(KERN_ERR - "%s(%s): WARNING!! byte_count_dev %d " - "!= byte_count_mem %d\n", - __FUNCTION__, drive->name, bc_dev, bc_mem); - } - } - - drive->waiting_for_dma = 0; - ide_destroy_dmatable(drive); - - return dma_stat; -} - -static int -sgiioc4_ide_dma_check(ide_drive_t * drive) -{ - if (ide_config_drive_speed(drive, XFER_MW_DMA_2) != 0) { - printk(KERN_INFO - "Couldnot set %s in Multimode-2 DMA mode | " - "Drive %s using PIO instead\n", - drive->name, drive->name); - drive->using_dma = 0; - } else - drive->using_dma = 1; - - return 0; -} - -static int -sgiioc4_ide_dma_on(ide_drive_t * drive) -{ - drive->using_dma = 1; - - return HWIF(drive)->ide_dma_host_on(drive); -} - -static int -sgiioc4_ide_dma_off_quietly(ide_drive_t * drive) -{ - drive->using_dma = 0; - - return HWIF(drive)->ide_dma_host_off(drive); -} - -/* returns 1 if dma irq issued, 0 otherwise */ -static int -sgiioc4_ide_dma_test_irq(ide_drive_t * drive) -{ - return sgiioc4_checkirq(HWIF(drive)); -} - -static int -sgiioc4_ide_dma_host_on(ide_drive_t * drive) -{ - if (drive->using_dma) - return 0; - - return 1; -} - -static int -sgiioc4_ide_dma_host_off(ide_drive_t * drive) -{ - sgiioc4_clearirq(drive); - - return 0; -} - -static int -sgiioc4_ide_dma_lostirq(ide_drive_t * drive) -{ - HWIF(drive)->resetproc(drive); - - return __ide_dma_lostirq(drive); -} - -static void -sgiioc4_resetproc(ide_drive_t * drive) -{ - sgiioc4_ide_dma_end(drive); - sgiioc4_clearirq(drive); -} - -static u8 -sgiioc4_INB(unsigned long port) -{ - u8 reg = (u8) readb((void __iomem *) port); - - if ((port & 0xFFF) == 0x11C) { /* Status register of IOC4 */ - if (reg & 0x51) { /* Not busy...check for interrupt */ - unsigned long other_ir = port - 0x110; - unsigned int intr_reg = (u32) readl((void __iomem *) other_ir); - - /* Clear the Interrupt, Error bits on the IOC4 */ - if (intr_reg & 0x03) { - writel(0x03, (void __iomem *) other_ir); - intr_reg = (u32) readl((void __iomem *) other_ir); - } - } - } - - return reg; -} - -/* Creates a dma map for the scatter-gather list entries */ -static void __devinit -ide_dma_sgiioc4(ide_hwif_t * hwif, unsigned long dma_base) -{ - void __iomem *virt_dma_base; - int num_ports = sizeof (ioc4_dma_regs_t); - - printk(KERN_INFO "%s: BM-DMA at 0x%04lx-0x%04lx\n", hwif->name, - dma_base, dma_base + num_ports - 1); - - if (!request_mem_region(dma_base, num_ports, hwif->name)) { - printk(KERN_ERR - "%s(%s) -- ERROR, Addresses 0x%p to 0x%p " - "ALREADY in use\n", - __FUNCTION__, hwif->name, (void *) dma_base, - (void *) dma_base + num_ports - 1); - goto dma_alloc_failure; - } - - virt_dma_base = ioremap(dma_base, num_ports); - if (virt_dma_base == NULL) { - printk(KERN_ERR - "%s(%s) -- ERROR, Unable to map addresses 0x%lx to 0x%lx\n", - __FUNCTION__, hwif->name, dma_base, dma_base + num_ports - 1); - goto dma_remap_failure; - } - hwif->dma_base = (unsigned long) virt_dma_base; - - hwif->dmatable_cpu = pci_alloc_consistent(hwif->pci_dev, - IOC4_PRD_ENTRIES * IOC4_PRD_BYTES, - &hwif->dmatable_dma); - - if (!hwif->dmatable_cpu) - goto dma_pci_alloc_failure; - - hwif->sg_max_nents = IOC4_PRD_ENTRIES; - - hwif->dma_base2 = (unsigned long) - pci_alloc_consistent(hwif->pci_dev, - IOC4_IDE_CACHELINE_SIZE, - (dma_addr_t *) &(hwif->dma_status)); - - if (!hwif->dma_base2) - goto dma_base2alloc_failure; - - return; - -dma_base2alloc_failure: - pci_free_consistent(hwif->pci_dev, - IOC4_PRD_ENTRIES * IOC4_PRD_BYTES, - hwif->dmatable_cpu, hwif->dmatable_dma); - printk(KERN_INFO - "%s() -- Error! Unable to allocate DMA Maps for drive %s\n", - __FUNCTION__, hwif->name); - printk(KERN_INFO - "Changing from DMA to PIO mode for Drive %s\n", hwif->name); - -dma_pci_alloc_failure: - iounmap(virt_dma_base); - -dma_remap_failure: - release_mem_region(dma_base, num_ports); - -dma_alloc_failure: - /* Disable DMA because we couldnot allocate any DMA maps */ - hwif->autodma = 0; - hwif->atapi_dma = 0; -} - -/* Initializes the IOC4 DMA Engine */ -static void -sgiioc4_configure_for_dma(int dma_direction, ide_drive_t * drive) -{ - u32 ioc4_dma; - ide_hwif_t *hwif = HWIF(drive); - u64 dma_base = hwif->dma_base; - u32 dma_addr, ending_dma_addr; - - ioc4_dma = hwif->INL(dma_base + IOC4_DMA_CTRL * 4); - - if (ioc4_dma & IOC4_S_DMA_ACTIVE) { - printk(KERN_WARNING - "%s(%s):Warning!! DMA from previous transfer was still active\n", - __FUNCTION__, drive->name); - hwif->OUTL(IOC4_S_DMA_STOP, dma_base + IOC4_DMA_CTRL * 4); - ioc4_dma = sgiioc4_ide_dma_stop(hwif, dma_base); - - if (ioc4_dma & IOC4_S_DMA_STOP) - printk(KERN_ERR - "%s(%s) : IOC4 Dma STOP bit is still 1\n", - __FUNCTION__, drive->name); - } - - ioc4_dma = hwif->INL(dma_base + IOC4_DMA_CTRL * 4); - if (ioc4_dma & IOC4_S_DMA_ERROR) { - printk(KERN_WARNING - "%s(%s) : Warning!! - DMA Error during Previous" - " transfer | status 0x%x\n", - __FUNCTION__, drive->name, ioc4_dma); - hwif->OUTL(IOC4_S_DMA_STOP, dma_base + IOC4_DMA_CTRL * 4); - ioc4_dma = sgiioc4_ide_dma_stop(hwif, dma_base); - - if (ioc4_dma & IOC4_S_DMA_STOP) - printk(KERN_ERR - "%s(%s) : IOC4 DMA STOP bit is still 1\n", - __FUNCTION__, drive->name); - } - - /* Address of the Scatter Gather List */ - dma_addr = cpu_to_le32(hwif->dmatable_dma); - hwif->OUTL(dma_addr, dma_base + IOC4_DMA_PTR_L * 4); - - /* Address of the Ending DMA */ - memset((unsigned int *) hwif->dma_base2, 0, IOC4_IDE_CACHELINE_SIZE); - ending_dma_addr = cpu_to_le32(hwif->dma_status); - hwif->OUTL(ending_dma_addr, dma_base + IOC4_DMA_END_ADDR * 4); - - hwif->OUTL(dma_direction, dma_base + IOC4_DMA_CTRL * 4); - drive->waiting_for_dma = 1; -} - -/* IOC4 Scatter Gather list Format */ -/* 128 Bit entries to support 64 bit addresses in the future */ -/* The Scatter Gather list Entry should be in the BIG-ENDIAN Format */ -/* --------------------------------------------------------------------- */ -/* | Upper 32 bits - Zero | Lower 32 bits- address | */ -/* --------------------------------------------------------------------- */ -/* | Upper 32 bits - Zero |EOL| 15 unused | 16 Bit Length| */ -/* --------------------------------------------------------------------- */ -/* Creates the scatter gather list, DMA Table */ -static unsigned int -sgiioc4_build_dma_table(ide_drive_t * drive, struct request *rq, int ddir) -{ - ide_hwif_t *hwif = HWIF(drive); - unsigned int *table = hwif->dmatable_cpu; - unsigned int count = 0, i = 1; - struct scatterlist *sg; - - hwif->sg_nents = i = ide_build_sglist(drive, rq); - - if (!i) - return 0; /* sglist of length Zero */ - - sg = hwif->sg_table; - while (i && sg_dma_len(sg)) { - dma_addr_t cur_addr; - int cur_len; - cur_addr = sg_dma_address(sg); - cur_len = sg_dma_len(sg); - - while (cur_len) { - if (count++ >= IOC4_PRD_ENTRIES) { - printk(KERN_WARNING - "%s: DMA table too small\n", - drive->name); - goto use_pio_instead; - } else { - u32 bcount = - 0x10000 - (cur_addr & 0xffff); - - if (bcount > cur_len) - bcount = cur_len; - - /* put the addr, length in - * the IOC4 dma-table format */ - *table = 0x0; - table++; - *table = cpu_to_be32(cur_addr); - table++; - *table = 0x0; - table++; - - *table = cpu_to_be32(bcount); - table++; - - cur_addr += bcount; - cur_len -= bcount; - } - } - - sg++; - i--; - } - - if (count) { - table--; - *table |= cpu_to_be32(0x80000000); - return count; - } - -use_pio_instead: - pci_unmap_sg(hwif->pci_dev, hwif->sg_table, hwif->sg_nents, - hwif->sg_dma_direction); - - return 0; /* revert to PIO for this request */ -} - -static int sgiioc4_ide_dma_setup(ide_drive_t *drive) -{ - struct request *rq = HWGROUP(drive)->rq; - unsigned int count = 0; - int ddir; - - if (rq_data_dir(rq)) - ddir = PCI_DMA_TODEVICE; - else - ddir = PCI_DMA_FROMDEVICE; - - if (!(count = sgiioc4_build_dma_table(drive, rq, ddir))) { - /* try PIO instead of DMA */ - ide_map_sg(drive, rq); - return 1; - } - - if (rq_data_dir(rq)) - /* Writes TO the IOC4 FROM Main Memory */ - ddir = IOC4_DMA_READ; - else - /* Writes FROM the IOC4 TO Main Memory */ - ddir = IOC4_DMA_WRITE; - - sgiioc4_configure_for_dma(ddir, drive); - - return 0; -} - -static void __devinit -ide_init_sgiioc4(ide_hwif_t * hwif) -{ - hwif->mmio = 2; - hwif->autodma = 1; - hwif->atapi_dma = 1; - hwif->ultra_mask = 0x0; /* Disable Ultra DMA */ - hwif->mwdma_mask = 0x2; /* Multimode-2 DMA */ - hwif->swdma_mask = 0x2; - hwif->tuneproc = NULL; /* Sets timing for PIO mode */ - hwif->speedproc = NULL; /* Sets timing for DMA &/or PIO modes */ - hwif->selectproc = NULL;/* Use the default routine to select drive */ - hwif->reset_poll = NULL;/* No HBA specific reset_poll needed */ - hwif->pre_reset = NULL; /* No HBA specific pre_set needed */ - hwif->resetproc = &sgiioc4_resetproc;/* Reset DMA engine, - clear interrupts */ - hwif->intrproc = NULL; /* Enable or Disable interrupt from drive */ - hwif->maskproc = &sgiioc4_maskproc; /* Mask on/off NIEN register */ - hwif->quirkproc = NULL; - hwif->busproc = NULL; - - hwif->dma_setup = &sgiioc4_ide_dma_setup; - hwif->dma_start = &sgiioc4_ide_dma_start; - hwif->ide_dma_end = &sgiioc4_ide_dma_end; - hwif->ide_dma_check = &sgiioc4_ide_dma_check; - hwif->ide_dma_on = &sgiioc4_ide_dma_on; - hwif->ide_dma_off_quietly = &sgiioc4_ide_dma_off_quietly; - hwif->ide_dma_test_irq = &sgiioc4_ide_dma_test_irq; - hwif->ide_dma_host_on = &sgiioc4_ide_dma_host_on; - hwif->ide_dma_host_off = &sgiioc4_ide_dma_host_off; - hwif->ide_dma_lostirq = &sgiioc4_ide_dma_lostirq; - hwif->ide_dma_timeout = &__ide_dma_timeout; - - hwif->INB = &sgiioc4_INB; -} - -static int __devinit -sgiioc4_ide_setup_pci_device(struct pci_dev *dev, ide_pci_device_t * d) -{ - unsigned long cmd_base, dma_base, irqport; - unsigned long bar0, cmd_phys_base, ctl; - void __iomem *virt_base; - ide_hwif_t *hwif; - int h; - - /* - * Find an empty HWIF; if none available, return -ENOMEM. - */ - for (h = 0; h < MAX_HWIFS; ++h) { - hwif = &ide_hwifs[h]; - if (hwif->chipset == ide_unknown) - break; - } - if (h == MAX_HWIFS) { - printk(KERN_ERR "%s: too many IDE interfaces, no room in table\n", d->name); - return -ENOMEM; - } - - /* Get the CmdBlk and CtrlBlk Base Registers */ - bar0 = pci_resource_start(dev, 0); - virt_base = ioremap(bar0, pci_resource_len(dev, 0)); - if (virt_base == NULL) { - printk(KERN_ERR "%s: Unable to remap BAR 0 address: 0x%lx\n", - d->name, bar0); - return -ENOMEM; - } - cmd_base = (unsigned long) virt_base + IOC4_CMD_OFFSET; - ctl = (unsigned long) virt_base + IOC4_CTRL_OFFSET; - irqport = (unsigned long) virt_base + IOC4_INTR_OFFSET; - dma_base = pci_resource_start(dev, 0) + IOC4_DMA_OFFSET; - - cmd_phys_base = bar0 + IOC4_CMD_OFFSET; - if (!request_mem_region(cmd_phys_base, IOC4_CMD_CTL_BLK_SIZE, - hwif->name)) { - printk(KERN_ERR - "%s : %s -- ERROR, Addresses " - "0x%p to 0x%p ALREADY in use\n", - __FUNCTION__, hwif->name, (void *) cmd_phys_base, - (void *) cmd_phys_base + IOC4_CMD_CTL_BLK_SIZE); - return -ENOMEM; - } - - if (hwif->io_ports[IDE_DATA_OFFSET] != cmd_base) { - /* Initialize the IO registers */ - sgiioc4_init_hwif_ports(&hwif->hw, cmd_base, ctl, irqport); - memcpy(hwif->io_ports, hwif->hw.io_ports, - sizeof (hwif->io_ports)); - hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET]; - } - - hwif->irq = dev->irq; - hwif->chipset = ide_pci; - hwif->pci_dev = dev; - hwif->channel = 0; /* Single Channel chip */ - hwif->cds = (struct ide_pci_device_s *) d; - hwif->gendev.parent = &dev->dev;/* setup proper ancestral information */ - - /* The IOC4 uses MMIO rather than Port IO. */ - default_hwif_mmiops(hwif); - - /* Initializing chipset IRQ Registers */ - hwif->OUTL(0x03, irqport + IOC4_INTR_SET * 4); - - ide_init_sgiioc4(hwif); - - if (dma_base) - ide_dma_sgiioc4(hwif, dma_base); - else - printk(KERN_INFO "%s: %s Bus-Master DMA disabled\n", - hwif->name, d->name); - - if (probe_hwif_init(hwif)) - return -EIO; - - /* Create /proc/ide entries */ - create_proc_ide_interfaces(); - - return 0; -} - -static unsigned int __devinit -pci_init_sgiioc4(struct pci_dev *dev, ide_pci_device_t * d) -{ - unsigned int class_rev; - int ret; - - pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev); - class_rev &= 0xff; - printk(KERN_INFO "%s: IDE controller at PCI slot %s, revision %d\n", - d->name, pci_name(dev), class_rev); - if (class_rev < IOC4_SUPPORTED_FIRMWARE_REV) { - printk(KERN_ERR "Skipping %s IDE controller in slot %s: " - "firmware is obsolete - please upgrade to revision" - "46 or higher\n", d->name, pci_name(dev)); - ret = -EAGAIN; - goto out; - } - ret = sgiioc4_ide_setup_pci_device(dev, d); -out: - return ret; -} - -static ide_pci_device_t sgiioc4_chipsets[] __devinitdata = { - { - /* Channel 0 */ - .name = "SGIIOC4", - .init_hwif = ide_init_sgiioc4, - .init_dma = ide_dma_sgiioc4, - .channels = 1, - .autodma = AUTODMA, - /* SGI IOC4 doesn't have enablebits. */ - .bootable = ON_BOARD, - } -}; - -int -ioc4_ide_attach_one(struct ioc4_driver_data *idd) -{ - /* PCI-RT does not bring out IDE connection. - * Do not attach to this particular IOC4. - */ - if (idd->idd_variant == IOC4_VARIANT_PCI_RT) - return 0; - - return pci_init_sgiioc4(idd->idd_pdev, - &sgiioc4_chipsets[idd->idd_pci_id->driver_data]); -} - -static struct ioc4_submodule ioc4_ide_submodule = { - .is_name = "IOC4_ide", - .is_owner = THIS_MODULE, - .is_probe = ioc4_ide_attach_one, -/* .is_remove = ioc4_ide_remove_one, */ -}; - -static int __devinit -ioc4_ide_init(void) -{ - return ioc4_register_submodule(&ioc4_ide_submodule); -} - -static void __devexit -ioc4_ide_exit(void) -{ - ioc4_unregister_submodule(&ioc4_ide_submodule); -} - -module_init(ioc4_ide_init); -module_exit(ioc4_ide_exit); - -MODULE_AUTHOR("Aniket Malatpure/Jeremy Higdon"); -MODULE_DESCRIPTION("IDE PCI driver module for SGI IOC4 Base-IO Card"); -MODULE_LICENSE("GPL"); diff --git a/drivers/ide/pci/siimage.c b/drivers/ide/pci/siimage.c deleted file mode 100644 index 20b392948f3..00000000000 --- a/drivers/ide/pci/siimage.c +++ /dev/null @@ -1,1109 +0,0 @@ -/* - * linux/drivers/ide/pci/siimage.c Version 1.07 Nov 30, 2003 - * - * Copyright (C) 2001-2002 Andre Hedrick <andre@linux-ide.org> - * Copyright (C) 2003 Red Hat <alan@redhat.com> - * - * May be copied or modified under the terms of the GNU General Public License - * - * Documentation for CMD680: - * http://gkernel.sourceforge.net/specs/sii/sii-0680a-v1.31.pdf.bz2 - * - * Documentation for SiI 3112: - * http://gkernel.sourceforge.net/specs/sii/3112A_SiI-DS-0095-B2.pdf.bz2 - * - * Errata and other documentation only available under NDA. - * - * - * FAQ Items: - * If you are using Marvell SATA-IDE adapters with Maxtor drives - * ensure the system is set up for ATA100/UDMA5 not UDMA6. - * - * If you are using WD drives with SATA bridges you must set the - * drive to "Single". "Master" will hang - * - * If you have strange problems with nVidia chipset systems please - * see the SI support documentation and update your system BIOS - * if neccessary - */ - -#include <linux/types.h> -#include <linux/module.h> -#include <linux/pci.h> -#include <linux/delay.h> -#include <linux/hdreg.h> -#include <linux/ide.h> -#include <linux/init.h> - -#include <asm/io.h> - -/** - * pdev_is_sata - check if device is SATA - * @pdev: PCI device to check - * - * Returns true if this is a SATA controller - */ - -static int pdev_is_sata(struct pci_dev *pdev) -{ - switch(pdev->device) - { - case PCI_DEVICE_ID_SII_3112: - case PCI_DEVICE_ID_SII_1210SA: - return 1; - case PCI_DEVICE_ID_SII_680: - return 0; - } - BUG(); - return 0; -} - -/** - * is_sata - check if hwif is SATA - * @hwif: interface to check - * - * Returns true if this is a SATA controller - */ - -static inline int is_sata(ide_hwif_t *hwif) -{ - return pdev_is_sata(hwif->pci_dev); -} - -/** - * siimage_selreg - return register base - * @hwif: interface - * @r: config offset - * - * Turn a config register offset into the right address in either - * PCI space or MMIO space to access the control register in question - * Thankfully this is a configuration operation so isnt performance - * criticial. - */ - -static unsigned long siimage_selreg(ide_hwif_t *hwif, int r) -{ - unsigned long base = (unsigned long)hwif->hwif_data; - base += 0xA0 + r; - if(hwif->mmio) - base += (hwif->channel << 6); - else - base += (hwif->channel << 4); - return base; -} - -/** - * siimage_seldev - return register base - * @hwif: interface - * @r: config offset - * - * Turn a config register offset into the right address in either - * PCI space or MMIO space to access the control register in question - * including accounting for the unit shift. - */ - -static inline unsigned long siimage_seldev(ide_drive_t *drive, int r) -{ - ide_hwif_t *hwif = HWIF(drive); - unsigned long base = (unsigned long)hwif->hwif_data; - base += 0xA0 + r; - if(hwif->mmio) - base += (hwif->channel << 6); - else - base += (hwif->channel << 4); - base |= drive->select.b.unit << drive->select.b.unit; - return base; -} - -/** - * siimage_ratemask - Compute available modes - * @drive: IDE drive - * - * Compute the available speeds for the devices on the interface. - * For the CMD680 this depends on the clocking mode (scsc), for the - * SI3312 SATA controller life is a bit simpler. Enforce UDMA33 - * as a limit if there is no 80pin cable present. - */ - -static byte siimage_ratemask (ide_drive_t *drive) -{ - ide_hwif_t *hwif = HWIF(drive); - u8 mode = 0, scsc = 0; - unsigned long base = (unsigned long) hwif->hwif_data; - - if (hwif->mmio) - scsc = hwif->INB(base + 0x4A); - else - pci_read_config_byte(hwif->pci_dev, 0x8A, &scsc); - - if(is_sata(hwif)) - { - if(strstr(drive->id->model, "Maxtor")) - return 3; - return 4; - } - - if ((scsc & 0x30) == 0x10) /* 133 */ - mode = 4; - else if ((scsc & 0x30) == 0x20) /* 2xPCI */ - mode = 4; - else if ((scsc & 0x30) == 0x00) /* 100 */ - mode = 3; - else /* Disabled ? */ - BUG(); - - if (!eighty_ninty_three(drive)) - mode = min(mode, (u8)1); - return mode; -} - -/** - * siimage_taskfile_timing - turn timing data to a mode - * @hwif: interface to query - * - * Read the timing data for the interface and return the - * mode that is being used. - */ - -static byte siimage_taskfile_timing (ide_hwif_t *hwif) -{ - u16 timing = 0x328a; - unsigned long addr = siimage_selreg(hwif, 2); - - if (hwif->mmio) - timing = hwif->INW(addr); - else - pci_read_config_word(hwif->pci_dev, addr, &timing); - - switch (timing) { - case 0x10c1: return 4; - case 0x10c3: return 3; - case 0x1104: - case 0x1281: return 2; - case 0x2283: return 1; - case 0x328a: - default: return 0; - } -} - -/** - * simmage_tuneproc - tune a drive - * @drive: drive to tune - * @mode_wanted: the target operating mode - * - * Load the timing settings for this device mode into the - * controller. If we are in PIO mode 3 or 4 turn on IORDY - * monitoring (bit 9). The TF timing is bits 31:16 - */ - -static void siimage_tuneproc (ide_drive_t *drive, byte mode_wanted) -{ - ide_hwif_t *hwif = HWIF(drive); - u32 speedt = 0; - u16 speedp = 0; - unsigned long addr = siimage_seldev(drive, 0x04); - unsigned long tfaddr = siimage_selreg(hwif, 0x02); - - /* cheat for now and use the docs */ - switch(mode_wanted) { - case 4: - speedp = 0x10c1; - speedt = 0x10c1; - break; - case 3: - speedp = 0x10C3; - speedt = 0x10C3; - break; - case 2: - speedp = 0x1104; - speedt = 0x1281; - break; - case 1: - speedp = 0x2283; - speedt = 0x1281; - break; - case 0: - default: - speedp = 0x328A; - speedt = 0x328A; - break; - } - if (hwif->mmio) - { - hwif->OUTW(speedt, addr); - hwif->OUTW(speedp, tfaddr); - /* Now set up IORDY */ - if(mode_wanted == 3 || mode_wanted == 4) - hwif->OUTW(hwif->INW(tfaddr-2)|0x200, tfaddr-2); - else - hwif->OUTW(hwif->INW(tfaddr-2)&~0x200, tfaddr-2); - } - else - { - pci_write_config_word(hwif->pci_dev, addr, speedp); - pci_write_config_word(hwif->pci_dev, tfaddr, speedt); - pci_read_config_word(hwif->pci_dev, tfaddr-2, &speedp); - speedp &= ~0x200; - /* Set IORDY for mode 3 or 4 */ - if(mode_wanted == 3 || mode_wanted == 4) - speedp |= 0x200; - pci_write_config_word(hwif->pci_dev, tfaddr-2, speedp); - } -} - -/** - * config_siimage_chipset_for_pio - set drive timings - * @drive: drive to tune - * @speed we want - * - * Compute the best pio mode we can for a given device. Also honour - * the timings for the driver when dealing with mixed devices. Some - * of this is ugly but its all wrapped up here - * - * The SI680 can also do VDMA - we need to start using that - * - * FIXME: we use the BIOS channel timings to avoid driving the task - * files too fast at the disk. We need to compute the master/slave - * drive PIO mode properly so that we can up the speed on a hotplug - * system. - */ - -static void config_siimage_chipset_for_pio (ide_drive_t *drive, byte set_speed) -{ - u8 channel_timings = siimage_taskfile_timing(HWIF(drive)); - u8 speed = 0, set_pio = ide_get_best_pio_mode(drive, 4, 5, NULL); - - /* WARNING PIO timing mess is going to happen b/w devices, argh */ - if ((channel_timings != set_pio) && (set_pio > channel_timings)) - set_pio = channel_timings; - - siimage_tuneproc(drive, set_pio); - speed = XFER_PIO_0 + set_pio; - if (set_speed) - (void) ide_config_drive_speed(drive, speed); -} - -static void config_chipset_for_pio (ide_drive_t *drive, byte set_speed) -{ - config_siimage_chipset_for_pio(drive, set_speed); -} - -/** - * siimage_tune_chipset - set controller timings - * @drive: Drive to set up - * @xferspeed: speed we want to achieve - * - * Tune the SII chipset for the desired mode. If we can't achieve - * the desired mode then tune for a lower one, but ultimately - * make the thing work. - */ - -static int siimage_tune_chipset (ide_drive_t *drive, byte xferspeed) -{ - u8 ultra6[] = { 0x0F, 0x0B, 0x07, 0x05, 0x03, 0x02, 0x01 }; - u8 ultra5[] = { 0x0C, 0x07, 0x05, 0x04, 0x02, 0x01 }; - u16 dma[] = { 0x2208, 0x10C2, 0x10C1 }; - - ide_hwif_t *hwif = HWIF(drive); - u16 ultra = 0, multi = 0; - u8 mode = 0, unit = drive->select.b.unit; - u8 speed = ide_rate_filter(siimage_ratemask(drive), xferspeed); - unsigned long base = (unsigned long)hwif->hwif_data; - u8 scsc = 0, addr_mask = ((hwif->channel) ? - ((hwif->mmio) ? 0xF4 : 0x84) : - ((hwif->mmio) ? 0xB4 : 0x80)); - - unsigned long ma = siimage_seldev(drive, 0x08); - unsigned long ua = siimage_seldev(drive, 0x0C); - - if (hwif->mmio) { - scsc = hwif->INB(base + 0x4A); - mode = hwif->INB(base + addr_mask); - multi = hwif->INW(ma); - ultra = hwif->INW(ua); - } else { - pci_read_config_byte(hwif->pci_dev, 0x8A, &scsc); - pci_read_config_byte(hwif->pci_dev, addr_mask, &mode); - pci_read_config_word(hwif->pci_dev, ma, &multi); - pci_read_config_word(hwif->pci_dev, ua, &ultra); - } - - mode &= ~((unit) ? 0x30 : 0x03); - ultra &= ~0x3F; - scsc = ((scsc & 0x30) == 0x00) ? 0 : 1; - - scsc = is_sata(hwif) ? 1 : scsc; - - switch(speed) { - case XFER_PIO_4: - case XFER_PIO_3: - case XFER_PIO_2: - case XFER_PIO_1: - case XFER_PIO_0: - siimage_tuneproc(drive, (speed - XFER_PIO_0)); - mode |= ((unit) ? 0x10 : 0x01); - break; - case XFER_MW_DMA_2: - case XFER_MW_DMA_1: - case XFER_MW_DMA_0: - multi = dma[speed - XFER_MW_DMA_0]; - mode |= ((unit) ? 0x20 : 0x02); - config_siimage_chipset_for_pio(drive, 0); - break; - case XFER_UDMA_6: - case XFER_UDMA_5: - case XFER_UDMA_4: - case XFER_UDMA_3: - case XFER_UDMA_2: - case XFER_UDMA_1: - case XFER_UDMA_0: - multi = dma[2]; - ultra |= ((scsc) ? (ultra6[speed - XFER_UDMA_0]) : - (ultra5[speed - XFER_UDMA_0])); - mode |= ((unit) ? 0x30 : 0x03); - config_siimage_chipset_for_pio(drive, 0); - break; - default: - return 1; - } - - if (hwif->mmio) { - hwif->OUTB(mode, base + addr_mask); - hwif->OUTW(multi, ma); - hwif->OUTW(ultra, ua); - } else { - pci_write_config_byte(hwif->pci_dev, addr_mask, mode); - pci_write_config_word(hwif->pci_dev, ma, multi); - pci_write_config_word(hwif->pci_dev, ua, ultra); - } - return (ide_config_drive_speed(drive, speed)); -} - -/** - * config_chipset_for_dma - configure for DMA - * @drive: drive to configure - * - * Called by the IDE layer when it wants the timings set up. - * For the CMD680 we also need to set up the PIO timings and - * enable DMA. - */ - -static int config_chipset_for_dma (ide_drive_t *drive) -{ - u8 speed = ide_dma_speed(drive, siimage_ratemask(drive)); - - config_chipset_for_pio(drive, !speed); - - if (!speed) - return 0; - - if (ide_set_xfer_rate(drive, speed)) - return 0; - - if (!drive->init_speed) - drive->init_speed = speed; - - return ide_dma_enable(drive); -} - -/** - * siimage_configure_drive_for_dma - set up for DMA transfers - * @drive: drive we are going to set up - * - * Set up the drive for DMA, tune the controller and drive as - * required. If the drive isn't suitable for DMA or we hit - * other problems then we will drop down to PIO and set up - * PIO appropriately - */ - -static int siimage_config_drive_for_dma (ide_drive_t *drive) -{ - ide_hwif_t *hwif = HWIF(drive); - struct hd_driveid *id = drive->id; - - if ((id->capability & 1) != 0 && drive->autodma) { - - if (ide_use_dma(drive)) { - if (config_chipset_for_dma(drive)) - return hwif->ide_dma_on(drive); - } - - goto fast_ata_pio; - - } else if ((id->capability & 8) || (id->field_valid & 2)) { -fast_ata_pio: - config_chipset_for_pio(drive, 1); - return hwif->ide_dma_off_quietly(drive); - } - /* IORDY not supported */ - return 0; -} - -/* returns 1 if dma irq issued, 0 otherwise */ -static int siimage_io_ide_dma_test_irq (ide_drive_t *drive) -{ - ide_hwif_t *hwif = HWIF(drive); - u8 dma_altstat = 0; - unsigned long addr = siimage_selreg(hwif, 1); - - /* return 1 if INTR asserted */ - if ((hwif->INB(hwif->dma_status) & 4) == 4) - return 1; - - /* return 1 if Device INTR asserted */ - pci_read_config_byte(hwif->pci_dev, addr, &dma_altstat); - if (dma_altstat & 8) - return 0; //return 1; - return 0; -} - -/** - * siimage_mmio_ide_dma_test_irq - check we caused an IRQ - * @drive: drive we are testing - * - * Check if we caused an IDE DMA interrupt. We may also have caused - * SATA status interrupts, if so we clean them up and continue. - */ - -static int siimage_mmio_ide_dma_test_irq (ide_drive_t *drive) -{ - ide_hwif_t *hwif = HWIF(drive); - unsigned long base = (unsigned long)hwif->hwif_data; - unsigned long addr = siimage_selreg(hwif, 0x1); - - if (SATA_ERROR_REG) { - u32 ext_stat = hwif->INL(base + 0x10); - u8 watchdog = 0; - if (ext_stat & ((hwif->channel) ? 0x40 : 0x10)) { - u32 sata_error = hwif->INL(SATA_ERROR_REG); - hwif->OUTL(sata_error, SATA_ERROR_REG); - watchdog = (sata_error & 0x00680000) ? 1 : 0; - printk(KERN_WARNING "%s: sata_error = 0x%08x, " - "watchdog = %d, %s\n", - drive->name, sata_error, watchdog, - __FUNCTION__); - - } else { - watchdog = (ext_stat & 0x8000) ? 1 : 0; - } - ext_stat >>= 16; - - if (!(ext_stat & 0x0404) && !watchdog) - return 0; - } - - /* return 1 if INTR asserted */ - if ((hwif->INB(hwif->dma_status) & 0x04) == 0x04) - return 1; - - /* return 1 if Device INTR asserted */ - if ((hwif->INB(addr) & 8) == 8) - return 0; //return 1; - - return 0; -} - -/** - * siimage_busproc - bus isolation ioctl - * @drive: drive to isolate/restore - * @state: bus state to set - * - * Used by the SII3112 to handle bus isolation. As this is a - * SATA controller the work required is quite limited, we - * just have to clean up the statistics - */ - -static int siimage_busproc (ide_drive_t * drive, int state) -{ - ide_hwif_t *hwif = HWIF(drive); - u32 stat_config = 0; - unsigned long addr = siimage_selreg(hwif, 0); - - if (hwif->mmio) { - stat_config = hwif->INL(addr); - } else - pci_read_config_dword(hwif->pci_dev, addr, &stat_config); - - switch (state) { - case BUSSTATE_ON: - hwif->drives[0].failures = 0; - hwif->drives[1].failures = 0; - break; - case BUSSTATE_OFF: - hwif->drives[0].failures = hwif->drives[0].max_failures + 1; - hwif->drives[1].failures = hwif->drives[1].max_failures + 1; - break; - case BUSSTATE_TRISTATE: - hwif->drives[0].failures = hwif->drives[0].max_failures + 1; - hwif->drives[1].failures = hwif->drives[1].max_failures + 1; - break; - default: - return -EINVAL; - } - hwif->bus_state = state; - return 0; -} - -/** - * siimage_reset_poll - wait for sata reset - * @drive: drive we are resetting - * - * Poll the SATA phy and see whether it has come back from the dead - * yet. - */ - -static int siimage_reset_poll (ide_drive_t *drive) -{ - if (SATA_STATUS_REG) { - ide_hwif_t *hwif = HWIF(drive); - - if ((hwif->INL(SATA_STATUS_REG) & 0x03) != 0x03) { - printk(KERN_WARNING "%s: reset phy dead, status=0x%08x\n", - hwif->name, hwif->INL(SATA_STATUS_REG)); - HWGROUP(drive)->polling = 0; - return ide_started; - } - return 0; - } else { - return 0; - } -} - -/** - * siimage_pre_reset - reset hook - * @drive: IDE device being reset - * - * For the SATA devices we need to handle recalibration/geometry - * differently - */ - -static void siimage_pre_reset (ide_drive_t *drive) -{ - if (drive->media != ide_disk) - return; - - if (is_sata(HWIF(drive))) - { - drive->special.b.set_geometry = 0; - drive->special.b.recalibrate = 0; - } -} - -/** - * siimage_reset - reset a device on an siimage controller - * @drive: drive to reset - * - * Perform a controller level reset fo the device. For - * SATA we must also check the PHY. - */ - -static void siimage_reset (ide_drive_t *drive) -{ - ide_hwif_t *hwif = HWIF(drive); - u8 reset = 0; - unsigned long addr = siimage_selreg(hwif, 0); - - if (hwif->mmio) { - reset = hwif->INB(addr); - hwif->OUTB((reset|0x03), addr); - /* FIXME:posting */ - udelay(25); - hwif->OUTB(reset, addr); - (void) hwif->INB(addr); - } else { - pci_read_config_byte(hwif->pci_dev, addr, &reset); - pci_write_config_byte(hwif->pci_dev, addr, reset|0x03); - udelay(25); - pci_write_config_byte(hwif->pci_dev, addr, reset); - pci_read_config_byte(hwif->pci_dev, addr, &reset); - } - - if (SATA_STATUS_REG) { - u32 sata_stat = hwif->INL(SATA_STATUS_REG); - printk(KERN_WARNING "%s: reset phy, status=0x%08x, %s\n", - hwif->name, sata_stat, __FUNCTION__); - if (!(sata_stat)) { - printk(KERN_WARNING "%s: reset phy dead, status=0x%08x\n", - hwif->name, sata_stat); - drive->failures++; - } - } - -} - -/** - * proc_reports_siimage - add siimage controller to proc - * @dev: PCI device - * @clocking: SCSC value - * @name: controller name - * - * Report the clocking mode of the controller and add it to - * the /proc interface layer - */ - -static void proc_reports_siimage (struct pci_dev *dev, u8 clocking, const char *name) -{ - if (!pdev_is_sata(dev)) { - printk(KERN_INFO "%s: BASE CLOCK ", name); - clocking &= 0x03; - switch (clocking) { - case 0x03: printk("DISABLED!\n"); break; - case 0x02: printk("== 2X PCI\n"); break; - case 0x01: printk("== 133\n"); break; - case 0x00: printk("== 100\n"); break; - } - } -} - -/** - * setup_mmio_siimage - switch an SI controller into MMIO - * @dev: PCI device we are configuring - * @name: device name - * - * Attempt to put the device into mmio mode. There are some slight - * complications here with certain systems where the mmio bar isnt - * mapped so we have to be sure we can fall back to I/O. - */ - -static unsigned int setup_mmio_siimage (struct pci_dev *dev, const char *name) -{ - unsigned long bar5 = pci_resource_start(dev, 5); - unsigned long barsize = pci_resource_len(dev, 5); - u8 tmpbyte = 0; - void __iomem *ioaddr; - u32 tmp, irq_mask; - - /* - * Drop back to PIO if we can't map the mmio. Some - * systems seem to get terminally confused in the PCI - * spaces. - */ - - if(!request_mem_region(bar5, barsize, name)) - { - printk(KERN_WARNING "siimage: IDE controller MMIO ports not available.\n"); - return 0; - } - - ioaddr = ioremap(bar5, barsize); - - if (ioaddr == NULL) - { - release_mem_region(bar5, barsize); - return 0; - } - - pci_set_master(dev); - pci_set_drvdata(dev, (void *) ioaddr); - - if (pdev_is_sata(dev)) { - /* make sure IDE0/1 interrupts are not masked */ - irq_mask = (1 << 22) | (1 << 23); - tmp = readl(ioaddr + 0x48); - if (tmp & irq_mask) { - tmp &= ~irq_mask; - writel(tmp, ioaddr + 0x48); - readl(ioaddr + 0x48); /* flush */ - } - writel(0, ioaddr + 0x148); - writel(0, ioaddr + 0x1C8); - } - - writeb(0, ioaddr + 0xB4); - writeb(0, ioaddr + 0xF4); - tmpbyte = readb(ioaddr + 0x4A); - - switch(tmpbyte & 0x30) { - case 0x00: - /* In 100 MHz clocking, try and switch to 133 */ - writeb(tmpbyte|0x10, ioaddr + 0x4A); - break; - case 0x10: - /* On 133Mhz clocking */ - break; - case 0x20: - /* On PCIx2 clocking */ - break; - case 0x30: - /* Clocking is disabled */ - /* 133 clock attempt to force it on */ - writeb(tmpbyte & ~0x20, ioaddr + 0x4A); - break; - } - - writeb( 0x72, ioaddr + 0xA1); - writew( 0x328A, ioaddr + 0xA2); - writel(0x62DD62DD, ioaddr + 0xA4); - writel(0x43924392, ioaddr + 0xA8); - writel(0x40094009, ioaddr + 0xAC); - writeb( 0x72, ioaddr + 0xE1); - writew( 0x328A, ioaddr + 0xE2); - writel(0x62DD62DD, ioaddr + 0xE4); - writel(0x43924392, ioaddr + 0xE8); - writel(0x40094009, ioaddr + 0xEC); - - if (pdev_is_sata(dev)) { - writel(0xFFFF0000, ioaddr + 0x108); - writel(0xFFFF0000, ioaddr + 0x188); - writel(0x00680000, ioaddr + 0x148); - writel(0x00680000, ioaddr + 0x1C8); - } - - tmpbyte = readb(ioaddr + 0x4A); - - proc_reports_siimage(dev, (tmpbyte>>4), name); - return 1; -} - -/** - * init_chipset_siimage - set up an SI device - * @dev: PCI device - * @name: device name - * - * Perform the initial PCI set up for this device. Attempt to switch - * to 133MHz clocking if the system isn't already set up to do it. - */ - -static unsigned int __devinit init_chipset_siimage(struct pci_dev *dev, const char *name) -{ - u32 class_rev = 0; - u8 tmpbyte = 0; - u8 BA5_EN = 0; - - pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev); - class_rev &= 0xff; - pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, (class_rev) ? 1 : 255); - - pci_read_config_byte(dev, 0x8A, &BA5_EN); - if ((BA5_EN & 0x01) || (pci_resource_start(dev, 5))) { - if (setup_mmio_siimage(dev, name)) { - return 0; - } - } - - pci_write_config_byte(dev, 0x80, 0x00); - pci_write_config_byte(dev, 0x84, 0x00); - pci_read_config_byte(dev, 0x8A, &tmpbyte); - switch(tmpbyte & 0x30) { - case 0x00: - /* 133 clock attempt to force it on */ - pci_write_config_byte(dev, 0x8A, tmpbyte|0x10); - case 0x30: - /* if clocking is disabled */ - /* 133 clock attempt to force it on */ - pci_write_config_byte(dev, 0x8A, tmpbyte & ~0x20); - case 0x10: - /* 133 already */ - break; - case 0x20: - /* BIOS set PCI x2 clocking */ - break; - } - - pci_read_config_byte(dev, 0x8A, &tmpbyte); - - pci_write_config_byte(dev, 0xA1, 0x72); - pci_write_config_word(dev, 0xA2, 0x328A); - pci_write_config_dword(dev, 0xA4, 0x62DD62DD); - pci_write_config_dword(dev, 0xA8, 0x43924392); - pci_write_config_dword(dev, 0xAC, 0x40094009); - pci_write_config_byte(dev, 0xB1, 0x72); - pci_write_config_word(dev, 0xB2, 0x328A); - pci_write_config_dword(dev, 0xB4, 0x62DD62DD); - pci_write_config_dword(dev, 0xB8, 0x43924392); - pci_write_config_dword(dev, 0xBC, 0x40094009); - - proc_reports_siimage(dev, (tmpbyte>>4), name); - return 0; -} - -/** - * init_mmio_iops_siimage - set up the iops for MMIO - * @hwif: interface to set up - * - * The basic setup here is fairly simple, we can use standard MMIO - * operations. However we do have to set the taskfile register offsets - * by hand as there isnt a standard defined layout for them this - * time. - * - * The hardware supports buffered taskfiles and also some rather nice - * extended PRD tables. For better SI3112 support use the libata driver - */ - -static void __devinit init_mmio_iops_siimage(ide_hwif_t *hwif) -{ - struct pci_dev *dev = hwif->pci_dev; - void *addr = pci_get_drvdata(dev); - u8 ch = hwif->channel; - hw_regs_t hw; - unsigned long base; - - /* - * Fill in the basic HWIF bits - */ - - default_hwif_mmiops(hwif); - hwif->hwif_data = addr; - - /* - * Now set up the hw. We have to do this ourselves as - * the MMIO layout isnt the same as the the standard port - * based I/O - */ - - memset(&hw, 0, sizeof(hw_regs_t)); - - base = (unsigned long)addr; - if (ch) - base += 0xC0; - else - base += 0x80; - - /* - * The buffered task file doesn't have status/control - * so we can't currently use it sanely since we want to - * use LBA48 mode. - */ - hw.io_ports[IDE_DATA_OFFSET] = base; - hw.io_ports[IDE_ERROR_OFFSET] = base + 1; - hw.io_ports[IDE_NSECTOR_OFFSET] = base + 2; - hw.io_ports[IDE_SECTOR_OFFSET] = base + 3; - hw.io_ports[IDE_LCYL_OFFSET] = base + 4; - hw.io_ports[IDE_HCYL_OFFSET] = base + 5; - hw.io_ports[IDE_SELECT_OFFSET] = base + 6; - hw.io_ports[IDE_STATUS_OFFSET] = base + 7; - hw.io_ports[IDE_CONTROL_OFFSET] = base + 10; - - hw.io_ports[IDE_IRQ_OFFSET] = 0; - - if (pdev_is_sata(dev)) { - base = (unsigned long)addr; - if (ch) - base += 0x80; - hwif->sata_scr[SATA_STATUS_OFFSET] = base + 0x104; - hwif->sata_scr[SATA_ERROR_OFFSET] = base + 0x108; - hwif->sata_scr[SATA_CONTROL_OFFSET] = base + 0x100; - hwif->sata_misc[SATA_MISC_OFFSET] = base + 0x140; - hwif->sata_misc[SATA_PHY_OFFSET] = base + 0x144; - hwif->sata_misc[SATA_IEN_OFFSET] = base + 0x148; - } - - hw.irq = hwif->pci_dev->irq; - - memcpy(&hwif->hw, &hw, sizeof(hw)); - memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->hw.io_ports)); - - hwif->irq = hw.irq; - - base = (unsigned long) addr; - - hwif->dma_base = base + (ch ? 0x08 : 0x00); - hwif->dma_base2 = base + (ch ? 0x18 : 0x10); - hwif->mmio = 2; -} - -static int is_dev_seagate_sata(ide_drive_t *drive) -{ - const char *s = &drive->id->model[0]; - unsigned len; - - if (!drive->present) - return 0; - - len = strnlen(s, sizeof(drive->id->model)); - - if ((len > 4) && (!memcmp(s, "ST", 2))) { - if ((!memcmp(s + len - 2, "AS", 2)) || - (!memcmp(s + len - 3, "ASL", 3))) { - printk(KERN_INFO "%s: applying pessimistic Seagate " - "errata fix\n", drive->name); - return 1; - } - } - return 0; -} - -/** - * siimage_fixup - post probe fixups - * @hwif: interface to fix up - * - * Called after drive probe we use this to decide whether the - * Seagate fixup must be applied. This used to be in init_iops but - * that can occur before we know what drives are present. - */ - -static void __devinit siimage_fixup(ide_hwif_t *hwif) -{ - /* Try and raise the rqsize */ - if (!is_sata(hwif) || !is_dev_seagate_sata(&hwif->drives[0])) - hwif->rqsize = 128; -} - -/** - * init_iops_siimage - set up iops - * @hwif: interface to set up - * - * Do the basic setup for the SIIMAGE hardware interface - * and then do the MMIO setup if we can. This is the first - * look in we get for setting up the hwif so that we - * can get the iops right before using them. - */ - -static void __devinit init_iops_siimage(ide_hwif_t *hwif) -{ - struct pci_dev *dev = hwif->pci_dev; - u32 class_rev = 0; - - pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev); - class_rev &= 0xff; - - hwif->hwif_data = NULL; - - /* Pessimal until we finish probing */ - hwif->rqsize = 15; - - if (pci_get_drvdata(dev) == NULL) - return; - init_mmio_iops_siimage(hwif); -} - -/** - * ata66_siimage - check for 80 pin cable - * @hwif: interface to check - * - * Check for the presence of an ATA66 capable cable on the - * interface. - */ - -static unsigned int __devinit ata66_siimage(ide_hwif_t *hwif) -{ - unsigned long addr = siimage_selreg(hwif, 0); - if (pci_get_drvdata(hwif->pci_dev) == NULL) { - u8 ata66 = 0; - pci_read_config_byte(hwif->pci_dev, addr, &ata66); - return (ata66 & 0x01) ? 1 : 0; - } - - return (hwif->INB(addr) & 0x01) ? 1 : 0; -} - -/** - * init_hwif_siimage - set up hwif structs - * @hwif: interface to set up - * - * We do the basic set up of the interface structure. The SIIMAGE - * requires several custom handlers so we override the default - * ide DMA handlers appropriately - */ - -static void __devinit init_hwif_siimage(ide_hwif_t *hwif) -{ - hwif->autodma = 0; - - hwif->resetproc = &siimage_reset; - hwif->speedproc = &siimage_tune_chipset; - hwif->tuneproc = &siimage_tuneproc; - hwif->reset_poll = &siimage_reset_poll; - hwif->pre_reset = &siimage_pre_reset; - - if(is_sata(hwif)) { - static int first = 1; - - hwif->busproc = &siimage_busproc; - - if (first) { - printk(KERN_INFO "siimage: For full SATA support you should use the libata sata_sil module.\n"); - first = 0; - } - } - if (!hwif->dma_base) { - hwif->drives[0].autotune = 1; - hwif->drives[1].autotune = 1; - return; - } - - hwif->ultra_mask = 0x7f; - hwif->mwdma_mask = 0x07; - hwif->swdma_mask = 0x07; - - if (!is_sata(hwif)) - hwif->atapi_dma = 1; - - hwif->ide_dma_check = &siimage_config_drive_for_dma; - if (!(hwif->udma_four)) - hwif->udma_four = ata66_siimage(hwif); - - if (hwif->mmio) { - hwif->ide_dma_test_irq = &siimage_mmio_ide_dma_test_irq; - } else { - hwif->ide_dma_test_irq = & siimage_io_ide_dma_test_irq; - } - - /* - * The BIOS often doesn't set up DMA on this controller - * so we always do it. - */ - - hwif->autodma = 1; - hwif->drives[0].autodma = hwif->autodma; - hwif->drives[1].autodma = hwif->autodma; -} - -#define DECLARE_SII_DEV(name_str) \ - { \ - .name = name_str, \ - .init_chipset = init_chipset_siimage, \ - .init_iops = init_iops_siimage, \ - .init_hwif = init_hwif_siimage, \ - .fixup = siimage_fixup, \ - .channels = 2, \ - .autodma = AUTODMA, \ - .bootable = ON_BOARD, \ - } - -static ide_pci_device_t siimage_chipsets[] __devinitdata = { - /* 0 */ DECLARE_SII_DEV("SiI680"), - /* 1 */ DECLARE_SII_DEV("SiI3112 Serial ATA"), - /* 2 */ DECLARE_SII_DEV("Adaptec AAR-1210SA") -}; - -/** - * siimage_init_one - pci layer discovery entry - * @dev: PCI device - * @id: ident table entry - * - * Called by the PCI code when it finds an SI680 or SI3112 controller. - * We then use the IDE PCI generic helper to do most of the work. - */ - -static int __devinit siimage_init_one(struct pci_dev *dev, const struct pci_device_id *id) -{ - return ide_setup_pci_device(dev, &siimage_chipsets[id->driver_data]); -} - -static struct pci_device_id siimage_pci_tbl[] = { - { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_SII_680, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, -#ifdef CONFIG_BLK_DEV_IDE_SATA - { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_SII_3112, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1}, - { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_SII_1210SA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2}, -#endif - { 0, }, -}; -MODULE_DEVICE_TABLE(pci, siimage_pci_tbl); - -static struct pci_driver driver = { - .name = "SiI_IDE", - .id_table = siimage_pci_tbl, - .probe = siimage_init_one, -}; - -static int siimage_ide_init(void) -{ - return ide_pci_register_driver(&driver); -} - -module_init(siimage_ide_init); - -MODULE_AUTHOR("Andre Hedrick, Alan Cox"); -MODULE_DESCRIPTION("PCI driver module for SiI IDE"); -MODULE_LICENSE("GPL"); diff --git a/drivers/ide/pci/sis5513.c b/drivers/ide/pci/sis5513.c deleted file mode 100644 index f03196c5db3..00000000000 --- a/drivers/ide/pci/sis5513.c +++ /dev/null @@ -1,988 +0,0 @@ -/* - * linux/drivers/ide/pci/sis5513.c Version 0.16ac+vp Jun 18, 2003 - * - * Copyright (C) 1999-2000 Andre Hedrick <andre@linux-ide.org> - * Copyright (C) 2002 Lionel Bouton <Lionel.Bouton@inet6.fr>, Maintainer - * Copyright (C) 2003 Vojtech Pavlik <vojtech@suse.cz> - * May be copied or modified under the terms of the GNU General Public License - * - * - * Thanks : - * - * SiS Taiwan : for direct support and hardware. - * Daniela Engert : for initial ATA100 advices and numerous others. - * John Fremlin, Manfred Spraul, Dave Morgan, Peter Kjellerstedt : - * for checking code correctness, providing patches. - * - * - * Original tests and design on the SiS620 chipset. - * ATA100 tests and design on the SiS735 chipset. - * ATA16/33 support from specs - * ATA133 support for SiS961/962 by L.C. Chang <lcchang@sis.com.tw> - * ATA133 961/962/963 fixes by Vojtech Pavlik <vojtech@suse.cz> - * - * Documentation: - * SiS chipset documentation available under NDA to companies only - * (not to individuals). - */ - -/* - * The original SiS5513 comes from a SiS5511/55112/5513 chipset. The original - * SiS5513 was also used in the SiS5596/5513 chipset. Thus if we see a SiS5511 - * or SiS5596, we can assume we see the first MWDMA-16 capable SiS5513 chip. - * - * Later SiS chipsets integrated the 5513 functionality into the NorthBridge, - * starting with SiS5571 and up to SiS745. The PCI ID didn't change, though. We - * can figure out that we have a more modern and more capable 5513 by looking - * for the respective NorthBridge IDs. - * - * Even later (96x family) SiS chipsets use the MuTIOL link and place the 5513 - * into the SouthBrige. Here we cannot rely on looking up the NorthBridge PCI - * ID, while the now ATA-133 capable 5513 still has the same PCI ID. - * Fortunately the 5513 can be 'unmasked' by fiddling with some config space - * bits, changing its device id to the true one - 5517 for 961 and 5518 for - * 962/963. - */ - -#include <linux/types.h> -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/delay.h> -#include <linux/timer.h> -#include <linux/mm.h> -#include <linux/ioport.h> -#include <linux/blkdev.h> -#include <linux/hdreg.h> - -#include <linux/interrupt.h> -#include <linux/pci.h> -#include <linux/init.h> -#include <linux/ide.h> - -#include <asm/irq.h> - -#include "ide-timing.h" - -#define DISPLAY_SIS_TIMINGS - -/* registers layout and init values are chipset family dependant */ - -#define ATA_16 0x01 -#define ATA_33 0x02 -#define ATA_66 0x03 -#define ATA_100a 0x04 // SiS730/SiS550 is ATA100 with ATA66 layout -#define ATA_100 0x05 -#define ATA_133a 0x06 // SiS961b with 133 support -#define ATA_133 0x07 // SiS962/963 - -static u8 chipset_family; - -/* - * Devices supported - */ -static const struct { - const char *name; - u16 host_id; - u8 chipset_family; - u8 flags; -} SiSHostChipInfo[] = { - { "SiS968", PCI_DEVICE_ID_SI_968, ATA_133 }, - { "SiS966", PCI_DEVICE_ID_SI_966, ATA_133 }, - { "SiS965", PCI_DEVICE_ID_SI_965, ATA_133 }, - { "SiS745", PCI_DEVICE_ID_SI_745, ATA_100 }, - { "SiS735", PCI_DEVICE_ID_SI_735, ATA_100 }, - { "SiS733", PCI_DEVICE_ID_SI_733, ATA_100 }, - { "SiS635", PCI_DEVICE_ID_SI_635, ATA_100 }, - { "SiS633", PCI_DEVICE_ID_SI_633, ATA_100 }, - - { "SiS730", PCI_DEVICE_ID_SI_730, ATA_100a }, - { "SiS550", PCI_DEVICE_ID_SI_550, ATA_100a }, - - { "SiS640", PCI_DEVICE_ID_SI_640, ATA_66 }, - { "SiS630", PCI_DEVICE_ID_SI_630, ATA_66 }, - { "SiS620", PCI_DEVICE_ID_SI_620, ATA_66 }, - { "SiS540", PCI_DEVICE_ID_SI_540, ATA_66 }, - { "SiS530", PCI_DEVICE_ID_SI_530, ATA_66 }, - - { "SiS5600", PCI_DEVICE_ID_SI_5600, ATA_33 }, - { "SiS5598", PCI_DEVICE_ID_SI_5598, ATA_33 }, - { "SiS5597", PCI_DEVICE_ID_SI_5597, ATA_33 }, - { "SiS5591/2", PCI_DEVICE_ID_SI_5591, ATA_33 }, - { "SiS5582", PCI_DEVICE_ID_SI_5582, ATA_33 }, - { "SiS5581", PCI_DEVICE_ID_SI_5581, ATA_33 }, - - { "SiS5596", PCI_DEVICE_ID_SI_5596, ATA_16 }, - { "SiS5571", PCI_DEVICE_ID_SI_5571, ATA_16 }, - { "SiS5517", PCI_DEVICE_ID_SI_5517, ATA_16 }, - { "SiS551x", PCI_DEVICE_ID_SI_5511, ATA_16 }, -}; - -/* Cycle time bits and values vary across chip dma capabilities - These three arrays hold the register layout and the values to set. - Indexed by chipset_family and (dma_mode - XFER_UDMA_0) */ - -/* {0, ATA_16, ATA_33, ATA_66, ATA_100a, ATA_100, ATA_133} */ -static u8 cycle_time_offset[] = {0,0,5,4,4,0,0}; -static u8 cycle_time_range[] = {0,0,2,3,3,4,4}; -static u8 cycle_time_value[][XFER_UDMA_6 - XFER_UDMA_0 + 1] = { - {0,0,0,0,0,0,0}, /* no udma */ - {0,0,0,0,0,0,0}, /* no udma */ - {3,2,1,0,0,0,0}, /* ATA_33 */ - {7,5,3,2,1,0,0}, /* ATA_66 */ - {7,5,3,2,1,0,0}, /* ATA_100a (730 specific), differences are on cycle_time range and offset */ - {11,7,5,4,2,1,0}, /* ATA_100 */ - {15,10,7,5,3,2,1}, /* ATA_133a (earliest 691 southbridges) */ - {15,10,7,5,3,2,1}, /* ATA_133 */ -}; -/* CRC Valid Setup Time vary across IDE clock setting 33/66/100/133 - See SiS962 data sheet for more detail */ -static u8 cvs_time_value[][XFER_UDMA_6 - XFER_UDMA_0 + 1] = { - {0,0,0,0,0,0,0}, /* no udma */ - {0,0,0,0,0,0,0}, /* no udma */ - {2,1,1,0,0,0,0}, - {4,3,2,1,0,0,0}, - {4,3,2,1,0,0,0}, - {6,4,3,1,1,1,0}, - {9,6,4,2,2,2,2}, - {9,6,4,2,2,2,2}, -}; -/* Initialize time, Active time, Recovery time vary across - IDE clock settings. These 3 arrays hold the register value - for PIO0/1/2/3/4 and DMA0/1/2 mode in order */ -static u8 ini_time_value[][8] = { - {0,0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0,0}, - {2,1,0,0,0,1,0,0}, - {4,3,1,1,1,3,1,1}, - {4,3,1,1,1,3,1,1}, - {6,4,2,2,2,4,2,2}, - {9,6,3,3,3,6,3,3}, - {9,6,3,3,3,6,3,3}, -}; -static u8 act_time_value[][8] = { - {0,0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0,0}, - {9,9,9,2,2,7,2,2}, - {19,19,19,5,4,14,5,4}, - {19,19,19,5,4,14,5,4}, - {28,28,28,7,6,21,7,6}, - {38,38,38,10,9,28,10,9}, - {38,38,38,10,9,28,10,9}, -}; -static u8 rco_time_value[][8] = { - {0,0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0,0}, - {9,2,0,2,0,7,1,1}, - {19,5,1,5,2,16,3,2}, - {19,5,1,5,2,16,3,2}, - {30,9,3,9,4,25,6,4}, - {40,12,4,12,5,34,12,5}, - {40,12,4,12,5,34,12,5}, -}; - -/* - * Printing configuration - */ -/* Used for chipset type printing at boot time */ -static char* chipset_capability[] = { - "ATA", "ATA 16", - "ATA 33", "ATA 66", - "ATA 100 (1st gen)", "ATA 100 (2nd gen)", - "ATA 133 (1st gen)", "ATA 133 (2nd gen)" -}; - -#if defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS) -#include <linux/stat.h> -#include <linux/proc_fs.h> - -static u8 sis_proc = 0; - -static struct pci_dev *bmide_dev; - -static char* cable_type[] = { - "80 pins", - "40 pins" -}; - -static char* recovery_time[] ={ - "12 PCICLK", "1 PCICLK", - "2 PCICLK", "3 PCICLK", - "4 PCICLK", "5 PCICLCK", - "6 PCICLK", "7 PCICLCK", - "8 PCICLK", "9 PCICLCK", - "10 PCICLK", "11 PCICLK", - "13 PCICLK", "14 PCICLK", - "15 PCICLK", "15 PCICLK" -}; - -static char* active_time[] = { - "8 PCICLK", "1 PCICLCK", - "2 PCICLK", "3 PCICLK", - "4 PCICLK", "5 PCICLK", - "6 PCICLK", "12 PCICLK" -}; - -static char* cycle_time[] = { - "Reserved", "2 CLK", - "3 CLK", "4 CLK", - "5 CLK", "6 CLK", - "7 CLK", "8 CLK", - "9 CLK", "10 CLK", - "11 CLK", "12 CLK", - "13 CLK", "14 CLK", - "15 CLK", "16 CLK" -}; - -/* Generic add master or slave info function */ -static char* get_drives_info (char *buffer, u8 pos) -{ - u8 reg00, reg01, reg10, reg11; /* timing registers */ - u32 regdw0, regdw1; - char* p = buffer; - -/* Postwrite/Prefetch */ - if (chipset_family < ATA_133) { - pci_read_config_byte(bmide_dev, 0x4b, ®00); - p += sprintf(p, "Drive %d: Postwrite %s \t \t Postwrite %s\n", - pos, (reg00 & (0x10 << pos)) ? "Enabled" : "Disabled", - (reg00 & (0x40 << pos)) ? "Enabled" : "Disabled"); - p += sprintf(p, " Prefetch %s \t \t Prefetch %s\n", - (reg00 & (0x01 << pos)) ? "Enabled" : "Disabled", - (reg00 & (0x04 << pos)) ? "Enabled" : "Disabled"); - pci_read_config_byte(bmide_dev, 0x40+2*pos, ®00); - pci_read_config_byte(bmide_dev, 0x41+2*pos, ®01); - pci_read_config_byte(bmide_dev, 0x44+2*pos, ®10); - pci_read_config_byte(bmide_dev, 0x45+2*pos, ®11); - } else { - u32 reg54h; - u8 drive_pci = 0x40; - pci_read_config_dword(bmide_dev, 0x54, ®54h); - if (reg54h & 0x40000000) { - // Configuration space remapped to 0x70 - drive_pci = 0x70; - } - pci_read_config_dword(bmide_dev, (unsigned long)drive_pci+4*pos, ®dw0); - pci_read_config_dword(bmide_dev, (unsigned long)drive_pci+4*pos+8, ®dw1); - - p += sprintf(p, "Drive %d:\n", pos); - } - - -/* UDMA */ - if (chipset_family >= ATA_133) { - p += sprintf(p, " UDMA %s \t \t \t UDMA %s\n", - (regdw0 & 0x04) ? "Enabled" : "Disabled", - (regdw1 & 0x04) ? "Enabled" : "Disabled"); - p += sprintf(p, " UDMA Cycle Time %s \t UDMA Cycle Time %s\n", - cycle_time[(regdw0 & 0xF0) >> 4], - cycle_time[(regdw1 & 0xF0) >> 4]); - } else if (chipset_family >= ATA_33) { - p += sprintf(p, " UDMA %s \t \t \t UDMA %s\n", - (reg01 & 0x80) ? "Enabled" : "Disabled", - (reg11 & 0x80) ? "Enabled" : "Disabled"); - - p += sprintf(p, " UDMA Cycle Time "); - switch(chipset_family) { - case ATA_33: p += sprintf(p, cycle_time[(reg01 & 0x60) >> 5]); break; - case ATA_66: - case ATA_100a: p += sprintf(p, cycle_time[(reg01 & 0x70) >> 4]); break; - case ATA_100: - case ATA_133a: p += sprintf(p, cycle_time[reg01 & 0x0F]); break; - default: p += sprintf(p, "?"); break; - } - p += sprintf(p, " \t UDMA Cycle Time "); - switch(chipset_family) { - case ATA_33: p += sprintf(p, cycle_time[(reg11 & 0x60) >> 5]); break; - case ATA_66: - case ATA_100a: p += sprintf(p, cycle_time[(reg11 & 0x70) >> 4]); break; - case ATA_100: - case ATA_133a: p += sprintf(p, cycle_time[reg11 & 0x0F]); break; - default: p += sprintf(p, "?"); break; - } - p += sprintf(p, "\n"); - } - - - if (chipset_family < ATA_133) { /* else case TODO */ - -/* Data Active */ - p += sprintf(p, " Data Active Time "); - switch(chipset_family) { - case ATA_16: /* confirmed */ - case ATA_33: - case ATA_66: - case ATA_100a: p += sprintf(p, active_time[reg01 & 0x07]); break; - case ATA_100: - case ATA_133a: p += sprintf(p, active_time[(reg00 & 0x70) >> 4]); break; - default: p += sprintf(p, "?"); break; - } - p += sprintf(p, " \t Data Active Time "); - switch(chipset_family) { - case ATA_16: - case ATA_33: - case ATA_66: - case ATA_100a: p += sprintf(p, active_time[reg11 & 0x07]); break; - case ATA_100: - case ATA_133a: p += sprintf(p, active_time[(reg10 & 0x70) >> 4]); break; - default: p += sprintf(p, "?"); break; - } - p += sprintf(p, "\n"); - -/* Data Recovery */ - /* warning: may need (reg&0x07) for pre ATA66 chips */ - p += sprintf(p, " Data Recovery Time %s \t Data Recovery Time %s\n", - recovery_time[reg00 & 0x0f], recovery_time[reg10 & 0x0f]); - } - - return p; -} - -static char* get_masters_info(char* buffer) -{ - return get_drives_info(buffer, 0); -} - -static char* get_slaves_info(char* buffer) -{ - return get_drives_info(buffer, 1); -} - -/* Main get_info, called on /proc/ide/sis reads */ -static int sis_get_info (char *buffer, char **addr, off_t offset, int count) -{ - char *p = buffer; - int len; - u8 reg; - u16 reg2, reg3; - - p += sprintf(p, "\nSiS 5513 "); - switch(chipset_family) { - case ATA_16: p += sprintf(p, "DMA 16"); break; - case ATA_33: p += sprintf(p, "Ultra 33"); break; - case ATA_66: p += sprintf(p, "Ultra 66"); break; - case ATA_100a: - case ATA_100: p += sprintf(p, "Ultra 100"); break; - case ATA_133a: - case ATA_133: p += sprintf(p, "Ultra 133"); break; - default: p+= sprintf(p, "Unknown???"); break; - } - p += sprintf(p, " chipset\n"); - p += sprintf(p, "--------------- Primary Channel " - "---------------- Secondary Channel " - "-------------\n"); - -/* Status */ - pci_read_config_byte(bmide_dev, 0x4a, ®); - if (chipset_family == ATA_133) { - pci_read_config_word(bmide_dev, 0x50, ®2); - pci_read_config_word(bmide_dev, 0x52, ®3); - } - p += sprintf(p, "Channel Status: "); - if (chipset_family < ATA_66) { - p += sprintf(p, "%s \t \t \t \t %s\n", - (reg & 0x04) ? "On" : "Off", - (reg & 0x02) ? "On" : "Off"); - } else if (chipset_family < ATA_133) { - p += sprintf(p, "%s \t \t \t \t %s \n", - (reg & 0x02) ? "On" : "Off", - (reg & 0x04) ? "On" : "Off"); - } else { /* ATA_133 */ - p += sprintf(p, "%s \t \t \t \t %s \n", - (reg2 & 0x02) ? "On" : "Off", - (reg3 & 0x02) ? "On" : "Off"); - } - -/* Operation Mode */ - pci_read_config_byte(bmide_dev, 0x09, ®); - p += sprintf(p, "Operation Mode: %s \t \t \t %s \n", - (reg & 0x01) ? "Native" : "Compatible", - (reg & 0x04) ? "Native" : "Compatible"); - -/* 80-pin cable ? */ - if (chipset_family >= ATA_133) { - p += sprintf(p, "Cable Type: %s \t \t \t %s\n", - (reg2 & 0x01) ? cable_type[1] : cable_type[0], - (reg3 & 0x01) ? cable_type[1] : cable_type[0]); - } else if (chipset_family > ATA_33) { - pci_read_config_byte(bmide_dev, 0x48, ®); - p += sprintf(p, "Cable Type: %s \t \t \t %s\n", - (reg & 0x10) ? cable_type[1] : cable_type[0], - (reg & 0x20) ? cable_type[1] : cable_type[0]); - } - -/* Prefetch Count */ - if (chipset_family < ATA_133) { - pci_read_config_word(bmide_dev, 0x4c, ®2); - pci_read_config_word(bmide_dev, 0x4e, ®3); - p += sprintf(p, "Prefetch Count: %d \t \t \t \t %d\n", - reg2, reg3); - } - - p = get_masters_info(p); - p = get_slaves_info(p); - - len = (p - buffer) - offset; - *addr = buffer + offset; - - return len > count ? count : len; -} -#endif /* defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS) */ - -static u8 sis5513_ratemask (ide_drive_t *drive) -{ - u8 rates[] = { 0, 0, 1, 2, 3, 3, 4, 4 }; - u8 mode = rates[chipset_family]; - - if (!eighty_ninty_three(drive)) - mode = min(mode, (u8)1); - return mode; -} - -/* - * Configuration functions - */ -/* Enables per-drive prefetch and postwrite */ -static void config_drive_art_rwp (ide_drive_t *drive) -{ - ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; - - u8 reg4bh = 0; - u8 rw_prefetch = (0x11 << drive->dn); - - if (drive->media != ide_disk) - return; - pci_read_config_byte(dev, 0x4b, ®4bh); - - if ((reg4bh & rw_prefetch) != rw_prefetch) - pci_write_config_byte(dev, 0x4b, reg4bh|rw_prefetch); -} - - -/* Set per-drive active and recovery time */ -static void config_art_rwp_pio (ide_drive_t *drive, u8 pio) -{ - ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; - - u8 timing, drive_pci, test1, test2; - - u16 eide_pio_timing[6] = {600, 390, 240, 180, 120, 90}; - u16 xfer_pio = drive->id->eide_pio_modes; - - config_drive_art_rwp(drive); - pio = ide_get_best_pio_mode(drive, 255, pio, NULL); - - if (xfer_pio> 4) - xfer_pio = 0; - - if (drive->id->eide_pio_iordy > 0) { - for (xfer_pio = 5; - (xfer_pio > 0) && - (drive->id->eide_pio_iordy > eide_pio_timing[xfer_pio]); - xfer_pio--); - } else { - xfer_pio = (drive->id->eide_pio_modes & 4) ? 0x05 : - (drive->id->eide_pio_modes & 2) ? 0x04 : - (drive->id->eide_pio_modes & 1) ? 0x03 : xfer_pio; - } - - timing = (xfer_pio >= pio) ? xfer_pio : pio; - - /* In pre ATA_133 case, drives sit at 0x40 + 4*drive->dn */ - drive_pci = 0x40; - /* In SiS962 case drives sit at (0x40 or 0x70) + 8*drive->dn) */ - if (chipset_family >= ATA_133) { - u32 reg54h; - pci_read_config_dword(dev, 0x54, ®54h); - if (reg54h & 0x40000000) drive_pci = 0x70; - drive_pci += ((drive->dn)*0x4); - } else { - drive_pci += ((drive->dn)*0x2); - } - - /* register layout changed with newer ATA100 chips */ - if (chipset_family < ATA_100) { - pci_read_config_byte(dev, drive_pci, &test1); - pci_read_config_byte(dev, drive_pci+1, &test2); - - /* Clear active and recovery timings */ - test1 &= ~0x0F; - test2 &= ~0x07; - - switch(timing) { - case 4: test1 |= 0x01; test2 |= 0x03; break; - case 3: test1 |= 0x03; test2 |= 0x03; break; - case 2: test1 |= 0x04; test2 |= 0x04; break; - case 1: test1 |= 0x07; test2 |= 0x06; break; - default: break; - } - pci_write_config_byte(dev, drive_pci, test1); - pci_write_config_byte(dev, drive_pci+1, test2); - } else if (chipset_family < ATA_133) { - switch(timing) { /* active recovery - v v */ - case 4: test1 = 0x30|0x01; break; - case 3: test1 = 0x30|0x03; break; - case 2: test1 = 0x40|0x04; break; - case 1: test1 = 0x60|0x07; break; - case 0: test1 = 0x00; break; - default: break; - } - pci_write_config_byte(dev, drive_pci, test1); - } else { /* ATA_133 */ - u32 test3; - pci_read_config_dword(dev, drive_pci, &test3); - test3 &= 0xc0c00fff; - if (test3 & 0x08) { - test3 |= (unsigned long)ini_time_value[ATA_133][timing] << 12; - test3 |= (unsigned long)act_time_value[ATA_133][timing] << 16; - test3 |= (unsigned long)rco_time_value[ATA_133][timing] << 24; - } else { - test3 |= (unsigned long)ini_time_value[ATA_100][timing] << 12; - test3 |= (unsigned long)act_time_value[ATA_100][timing] << 16; - test3 |= (unsigned long)rco_time_value[ATA_100][timing] << 24; - } - pci_write_config_dword(dev, drive_pci, test3); - } -} - -static int config_chipset_for_pio (ide_drive_t *drive, u8 pio) -{ - if (pio == 255) - pio = ide_find_best_mode(drive, XFER_PIO | XFER_EPIO) - XFER_PIO_0; - config_art_rwp_pio(drive, pio); - return ide_config_drive_speed(drive, XFER_PIO_0 + min_t(u8, pio, 4)); -} - -static int sis5513_tune_chipset (ide_drive_t *drive, u8 xferspeed) -{ - ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; - - u8 drive_pci, reg, speed; - u32 regdw; - - speed = ide_rate_filter(sis5513_ratemask(drive), xferspeed); - - /* See config_art_rwp_pio for drive pci config registers */ - drive_pci = 0x40; - if (chipset_family >= ATA_133) { - u32 reg54h; - pci_read_config_dword(dev, 0x54, ®54h); - if (reg54h & 0x40000000) drive_pci = 0x70; - drive_pci += ((drive->dn)*0x4); - pci_read_config_dword(dev, (unsigned long)drive_pci, ®dw); - /* Disable UDMA bit for non UDMA modes on UDMA chips */ - if (speed < XFER_UDMA_0) { - regdw &= 0xfffffffb; - pci_write_config_dword(dev, (unsigned long)drive_pci, regdw); - } - - } else { - drive_pci += ((drive->dn)*0x2); - pci_read_config_byte(dev, drive_pci+1, ®); - /* Disable UDMA bit for non UDMA modes on UDMA chips */ - if ((speed < XFER_UDMA_0) && (chipset_family > ATA_16)) { - reg &= 0x7F; - pci_write_config_byte(dev, drive_pci+1, reg); - } - } - - /* Config chip for mode */ - switch(speed) { - case XFER_UDMA_6: - case XFER_UDMA_5: - case XFER_UDMA_4: - case XFER_UDMA_3: - case XFER_UDMA_2: - case XFER_UDMA_1: - case XFER_UDMA_0: - if (chipset_family >= ATA_133) { - regdw |= 0x04; - regdw &= 0xfffff00f; - /* check if ATA133 enable */ - if (regdw & 0x08) { - regdw |= (unsigned long)cycle_time_value[ATA_133][speed-XFER_UDMA_0] << 4; - regdw |= (unsigned long)cvs_time_value[ATA_133][speed-XFER_UDMA_0] << 8; - } else { - /* if ATA133 disable, we should not set speed above UDMA5 */ - if (speed > XFER_UDMA_5) - speed = XFER_UDMA_5; - regdw |= (unsigned long)cycle_time_value[ATA_100][speed-XFER_UDMA_0] << 4; - regdw |= (unsigned long)cvs_time_value[ATA_100][speed-XFER_UDMA_0] << 8; - } - pci_write_config_dword(dev, (unsigned long)drive_pci, regdw); - } else { - /* Force the UDMA bit on if we want to use UDMA */ - reg |= 0x80; - /* clean reg cycle time bits */ - reg &= ~((0xFF >> (8 - cycle_time_range[chipset_family])) - << cycle_time_offset[chipset_family]); - /* set reg cycle time bits */ - reg |= cycle_time_value[chipset_family][speed-XFER_UDMA_0] - << cycle_time_offset[chipset_family]; - pci_write_config_byte(dev, drive_pci+1, reg); - } - break; - case XFER_MW_DMA_2: - case XFER_MW_DMA_1: - case XFER_MW_DMA_0: - case XFER_SW_DMA_2: - case XFER_SW_DMA_1: - case XFER_SW_DMA_0: - break; - case XFER_PIO_4: return((int) config_chipset_for_pio(drive, 4)); - case XFER_PIO_3: return((int) config_chipset_for_pio(drive, 3)); - case XFER_PIO_2: return((int) config_chipset_for_pio(drive, 2)); - case XFER_PIO_1: return((int) config_chipset_for_pio(drive, 1)); - case XFER_PIO_0: - default: return((int) config_chipset_for_pio(drive, 0)); - } - - return ((int) ide_config_drive_speed(drive, speed)); -} - -static void sis5513_tune_drive (ide_drive_t *drive, u8 pio) -{ - (void) config_chipset_for_pio(drive, pio); -} - -/* - * ((id->hw_config & 0x4000|0x2000) && (HWIF(drive)->udma_four)) - */ -static int config_chipset_for_dma (ide_drive_t *drive) -{ - u8 speed = ide_dma_speed(drive, sis5513_ratemask(drive)); - -#ifdef DEBUG - printk("SIS5513: config_chipset_for_dma, drive %d, ultra %x\n", - drive->dn, drive->id->dma_ultra); -#endif - - if (!(speed)) - return 0; - - sis5513_tune_chipset(drive, speed); - return ide_dma_enable(drive); -} - -static int sis5513_config_drive_xfer_rate (ide_drive_t *drive) -{ - ide_hwif_t *hwif = HWIF(drive); - struct hd_driveid *id = drive->id; - - drive->init_speed = 0; - - if (id && (id->capability & 1) && drive->autodma) { - - if (ide_use_dma(drive)) { - if (config_chipset_for_dma(drive)) - return hwif->ide_dma_on(drive); - } - - goto fast_ata_pio; - - } else if ((id->capability & 8) || (id->field_valid & 2)) { -fast_ata_pio: - sis5513_tune_drive(drive, 5); - return hwif->ide_dma_off_quietly(drive); - } - /* IORDY not supported */ - return 0; -} - -/* initiates/aborts (U)DMA read/write operations on a drive. */ -static int sis5513_config_xfer_rate (ide_drive_t *drive) -{ - config_drive_art_rwp(drive); - config_art_rwp_pio(drive, 5); - return sis5513_config_drive_xfer_rate(drive); -} - -/* - Future simpler config_xfer_rate : - When ide_find_best_mode is made bad-drive aware - - remove config_drive_xfer_rate and config_chipset_for_dma, - - replace config_xfer_rate with the following - -static int sis5513_config_xfer_rate (ide_drive_t *drive) -{ - u16 w80 = HWIF(drive)->udma_four; - u16 speed; - - config_drive_art_rwp(drive); - config_art_rwp_pio(drive, 5); - - speed = ide_find_best_mode(drive, - XFER_PIO | XFER_EPIO | XFER_SWDMA | XFER_MWDMA | - (chipset_family >= ATA_33 ? XFER_UDMA : 0) | - (w80 && chipset_family >= ATA_66 ? XFER_UDMA_66 : 0) | - (w80 && chipset_family >= ATA_100a ? XFER_UDMA_100 : 0) | - (w80 && chipset_family >= ATA_133a ? XFER_UDMA_133 : 0)); - - sis5513_tune_chipset(drive, speed); - - if (drive->autodma && (speed & XFER_MODE) != XFER_PIO) - return HWIF(drive)->ide_dma_on(drive); - return HWIF(drive)->ide_dma_off_quietly(drive); -} -*/ - -/* Chip detection and general config */ -static unsigned int __devinit init_chipset_sis5513 (struct pci_dev *dev, const char *name) -{ - struct pci_dev *host; - int i = 0; - - chipset_family = 0; - - for (i = 0; i < ARRAY_SIZE(SiSHostChipInfo) && !chipset_family; i++) { - - host = pci_find_device(PCI_VENDOR_ID_SI, SiSHostChipInfo[i].host_id, NULL); - - if (!host) - continue; - - chipset_family = SiSHostChipInfo[i].chipset_family; - - /* Special case for SiS630 : 630S/ET is ATA_100a */ - if (SiSHostChipInfo[i].host_id == PCI_DEVICE_ID_SI_630) { - u8 hostrev; - pci_read_config_byte(host, PCI_REVISION_ID, &hostrev); - if (hostrev >= 0x30) - chipset_family = ATA_100a; - } - - printk(KERN_INFO "SIS5513: %s %s controller\n", - SiSHostChipInfo[i].name, chipset_capability[chipset_family]); - } - - if (!chipset_family) { /* Belongs to pci-quirks */ - - u32 idemisc; - u16 trueid; - - /* Disable ID masking and register remapping */ - pci_read_config_dword(dev, 0x54, &idemisc); - pci_write_config_dword(dev, 0x54, (idemisc & 0x7fffffff)); - pci_read_config_word(dev, PCI_DEVICE_ID, &trueid); - pci_write_config_dword(dev, 0x54, idemisc); - - if (trueid == 0x5518) { - printk(KERN_INFO "SIS5513: SiS 962/963 MuTIOL IDE UDMA133 controller\n"); - chipset_family = ATA_133; - - /* Check for 5513 compability mapping - * We must use this, else the port enabled code will fail, - * as it expects the enablebits at 0x4a. - */ - if ((idemisc & 0x40000000) == 0) { - pci_write_config_dword(dev, 0x54, idemisc | 0x40000000); - printk(KERN_INFO "SIS5513: Switching to 5513 register mapping\n"); - } - } - } - - if (!chipset_family) { /* Belongs to pci-quirks */ - - struct pci_dev *lpc_bridge; - u16 trueid; - u8 prefctl; - u8 idecfg; - u8 sbrev; - - pci_read_config_byte(dev, 0x4a, &idecfg); - pci_write_config_byte(dev, 0x4a, idecfg | 0x10); - pci_read_config_word(dev, PCI_DEVICE_ID, &trueid); - pci_write_config_byte(dev, 0x4a, idecfg); - - if (trueid == 0x5517) { /* SiS 961/961B */ - - lpc_bridge = pci_find_slot(0x00, 0x10); /* Bus 0, Dev 2, Fn 0 */ - pci_read_config_byte(lpc_bridge, PCI_REVISION_ID, &sbrev); - pci_read_config_byte(dev, 0x49, &prefctl); - - if (sbrev == 0x10 && (prefctl & 0x80)) { - printk(KERN_INFO "SIS5513: SiS 961B MuTIOL IDE UDMA133 controller\n"); - chipset_family = ATA_133a; - } else { - printk(KERN_INFO "SIS5513: SiS 961 MuTIOL IDE UDMA100 controller\n"); - chipset_family = ATA_100; - } - } - } - - if (!chipset_family) - return -1; - - /* Make general config ops here - 1/ tell IDE channels to operate in Compatibility mode only - 2/ tell old chips to allow per drive IDE timings */ - - { - u8 reg; - u16 regw; - - switch(chipset_family) { - case ATA_133: - /* SiS962 operation mode */ - pci_read_config_word(dev, 0x50, ®w); - if (regw & 0x08) - pci_write_config_word(dev, 0x50, regw&0xfff7); - pci_read_config_word(dev, 0x52, ®w); - if (regw & 0x08) - pci_write_config_word(dev, 0x52, regw&0xfff7); - break; - case ATA_133a: - case ATA_100: - /* Fixup latency */ - pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x80); - /* Set compatibility bit */ - pci_read_config_byte(dev, 0x49, ®); - if (!(reg & 0x01)) { - pci_write_config_byte(dev, 0x49, reg|0x01); - } - break; - case ATA_100a: - case ATA_66: - /* Fixup latency */ - pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x10); - - /* On ATA_66 chips the bit was elsewhere */ - pci_read_config_byte(dev, 0x52, ®); - if (!(reg & 0x04)) { - pci_write_config_byte(dev, 0x52, reg|0x04); - } - break; - case ATA_33: - /* On ATA_33 we didn't have a single bit to set */ - pci_read_config_byte(dev, 0x09, ®); - if ((reg & 0x0f) != 0x00) { - pci_write_config_byte(dev, 0x09, reg&0xf0); - } - case ATA_16: - /* force per drive recovery and active timings - needed on ATA_33 and below chips */ - pci_read_config_byte(dev, 0x52, ®); - if (!(reg & 0x08)) { - pci_write_config_byte(dev, 0x52, reg|0x08); - } - break; - } - -#if defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_PROC_FS) - if (!sis_proc) { - sis_proc = 1; - bmide_dev = dev; - ide_pci_create_host_proc("sis", sis_get_info); - } -#endif - } - - return 0; -} - -static unsigned int __devinit ata66_sis5513 (ide_hwif_t *hwif) -{ - u8 ata66 = 0; - - if (chipset_family >= ATA_133) { - u16 regw = 0; - u16 reg_addr = hwif->channel ? 0x52: 0x50; - pci_read_config_word(hwif->pci_dev, reg_addr, ®w); - ata66 = (regw & 0x8000) ? 0 : 1; - } else if (chipset_family >= ATA_66) { - u8 reg48h = 0; - u8 mask = hwif->channel ? 0x20 : 0x10; - pci_read_config_byte(hwif->pci_dev, 0x48, ®48h); - ata66 = (reg48h & mask) ? 0 : 1; - } - return ata66; -} - -static void __devinit init_hwif_sis5513 (ide_hwif_t *hwif) -{ - hwif->autodma = 0; - - if (!hwif->irq) - hwif->irq = hwif->channel ? 15 : 14; - - hwif->tuneproc = &sis5513_tune_drive; - hwif->speedproc = &sis5513_tune_chipset; - - if (!(hwif->dma_base)) { - hwif->drives[0].autotune = 1; - hwif->drives[1].autotune = 1; - return; - } - - hwif->atapi_dma = 1; - hwif->ultra_mask = 0x7f; - hwif->mwdma_mask = 0x07; - hwif->swdma_mask = 0x07; - - if (!chipset_family) - return; - - if (!(hwif->udma_four)) - hwif->udma_four = ata66_sis5513(hwif); - - if (chipset_family > ATA_16) { - hwif->ide_dma_check = &sis5513_config_xfer_rate; - if (!noautodma) - hwif->autodma = 1; - } - hwif->drives[0].autodma = hwif->autodma; - hwif->drives[1].autodma = hwif->autodma; - return; -} - -static ide_pci_device_t sis5513_chipset __devinitdata = { - .name = "SIS5513", - .init_chipset = init_chipset_sis5513, - .init_hwif = init_hwif_sis5513, - .channels = 2, - .autodma = NOAUTODMA, - .enablebits = {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}}, - .bootable = ON_BOARD, -}; - -static int __devinit sis5513_init_one(struct pci_dev *dev, const struct pci_device_id *id) -{ - return ide_setup_pci_device(dev, &sis5513_chipset); -} - -static struct pci_device_id sis5513_pci_tbl[] = { - { PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5513, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - { PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5518, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - { 0, }, -}; -MODULE_DEVICE_TABLE(pci, sis5513_pci_tbl); - -static struct pci_driver driver = { - .name = "SIS_IDE", - .id_table = sis5513_pci_tbl, - .probe = sis5513_init_one, -}; - -static int sis5513_ide_init(void) -{ - return ide_pci_register_driver(&driver); -} - -module_init(sis5513_ide_init); - -MODULE_AUTHOR("Lionel Bouton, L C Chang, Andre Hedrick, Vojtech Pavlik"); -MODULE_DESCRIPTION("PCI driver module for SIS IDE"); -MODULE_LICENSE("GPL"); - -/* - * TODO: - * - CLEANUP - * - Use drivers/ide/ide-timing.h ! - * - More checks in the config registers (force values instead of - * relying on the BIOS setting them correctly). - * - Further optimisations ? - * . for example ATA66+ regs 0x48 & 0x4A - */ diff --git a/drivers/ide/pci/sl82c105.c b/drivers/ide/pci/sl82c105.c deleted file mode 100644 index 0b4b6049851..00000000000 --- a/drivers/ide/pci/sl82c105.c +++ /dev/null @@ -1,508 +0,0 @@ -/* - * linux/drivers/ide/pci/sl82c105.c - * - * SL82C105/Winbond 553 IDE driver - * - * Maintainer unknown. - * - * Drive tuning added from Rebel.com's kernel sources - * -- Russell King (15/11/98) linux@arm.linux.org.uk - * - * Merge in Russell's HW workarounds, fix various problems - * with the timing registers setup. - * -- Benjamin Herrenschmidt (01/11/03) benh@kernel.crashing.org - */ - -#include <linux/types.h> -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/timer.h> -#include <linux/mm.h> -#include <linux/ioport.h> -#include <linux/interrupt.h> -#include <linux/blkdev.h> -#include <linux/hdreg.h> -#include <linux/pci.h> -#include <linux/ide.h> - -#include <asm/io.h> -#include <asm/dma.h> - -#undef DEBUG - -#ifdef DEBUG -#define DBG(arg) printk arg -#else -#define DBG(fmt,...) -#endif -/* - * SL82C105 PCI config register 0x40 bits. - */ -#define CTRL_IDE_IRQB (1 << 30) -#define CTRL_IDE_IRQA (1 << 28) -#define CTRL_LEGIRQ (1 << 11) -#define CTRL_P1F16 (1 << 5) -#define CTRL_P1EN (1 << 4) -#define CTRL_P0F16 (1 << 1) -#define CTRL_P0EN (1 << 0) - -/* - * Convert a PIO mode and cycle time to the required on/off - * times for the interface. This has protection against run-away - * timings. - */ -static unsigned int get_timing_sl82c105(ide_pio_data_t *p) -{ - unsigned int cmd_on; - unsigned int cmd_off; - - cmd_on = (ide_pio_timings[p->pio_mode].active_time + 29) / 30; - cmd_off = (p->cycle_time - 30 * cmd_on + 29) / 30; - - if (cmd_on > 32) - cmd_on = 32; - if (cmd_on == 0) - cmd_on = 1; - - if (cmd_off > 32) - cmd_off = 32; - if (cmd_off == 0) - cmd_off = 1; - - return (cmd_on - 1) << 8 | (cmd_off - 1) | (p->use_iordy ? 0x40 : 0x00); -} - -/* - * Configure the drive and chipset for PIO - */ -static void config_for_pio(ide_drive_t *drive, int pio, int report, int chipset_only) -{ - ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; - ide_pio_data_t p; - u16 drv_ctrl = 0x909; - unsigned int xfer_mode, reg; - - DBG(("config_for_pio(drive:%s, pio:%d, report:%d, chipset_only:%d)\n", - drive->name, pio, report, chipset_only)); - - reg = (hwif->channel ? 0x4c : 0x44) + (drive->select.b.unit ? 4 : 0); - - pio = ide_get_best_pio_mode(drive, pio, 5, &p); - - xfer_mode = XFER_PIO_0 + pio; - - if (chipset_only || ide_config_drive_speed(drive, xfer_mode) == 0) { - drv_ctrl = get_timing_sl82c105(&p); - drive->pio_speed = xfer_mode; - } else - drive->pio_speed = XFER_PIO_0; - - if (drive->using_dma == 0) { - /* - * If we are actually using MW DMA, then we can not - * reprogram the interface drive control register. - */ - pci_write_config_word(dev, reg, drv_ctrl); - pci_read_config_word(dev, reg, &drv_ctrl); - - if (report) { - printk("%s: selected %s (%dns) (%04X)\n", drive->name, - ide_xfer_verbose(xfer_mode), p.cycle_time, drv_ctrl); - } - } -} - -/* - * Configure the drive and the chipset for DMA - */ -static int config_for_dma (ide_drive_t *drive) -{ - ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; - unsigned int reg; - - DBG(("config_for_dma(drive:%s)\n", drive->name)); - - reg = (hwif->channel ? 0x4c : 0x44) + (drive->select.b.unit ? 4 : 0); - - if (ide_config_drive_speed(drive, XFER_MW_DMA_2) != 0) - return 1; - - pci_write_config_word(dev, reg, 0x0240); - - return 0; -} - -/* - * Check to see if the drive and - * chipset is capable of DMA mode - */ - -static int sl82c105_check_drive (ide_drive_t *drive) -{ - ide_hwif_t *hwif = HWIF(drive); - - DBG(("sl82c105_check_drive(drive:%s)\n", drive->name)); - - do { - struct hd_driveid *id = drive->id; - - if (!drive->autodma) - break; - - if (!id || !(id->capability & 1)) - break; - - /* Consult the list of known "bad" drives */ - if (__ide_dma_bad_drive(drive)) - break; - - if (id->field_valid & 2) { - if ((id->dma_mword & hwif->mwdma_mask) || - (id->dma_1word & hwif->swdma_mask)) - return hwif->ide_dma_on(drive); - } - - if (__ide_dma_good_drive(drive)) - return hwif->ide_dma_on(drive); - } while (0); - - return hwif->ide_dma_off_quietly(drive); -} - -/* - * The SL82C105 holds off all IDE interrupts while in DMA mode until - * all DMA activity is completed. Sometimes this causes problems (eg, - * when the drive wants to report an error condition). - * - * 0x7e is a "chip testing" register. Bit 2 resets the DMA controller - * state machine. We need to kick this to work around various bugs. - */ -static inline void sl82c105_reset_host(struct pci_dev *dev) -{ - u16 val; - - pci_read_config_word(dev, 0x7e, &val); - pci_write_config_word(dev, 0x7e, val | (1 << 2)); - pci_write_config_word(dev, 0x7e, val & ~(1 << 2)); -} - -/* - * If we get an IRQ timeout, it might be that the DMA state machine - * got confused. Fix from Todd Inglett. Details from Winbond. - * - * This function is called when the IDE timer expires, the drive - * indicates that it is READY, and we were waiting for DMA to complete. - */ -static int sl82c105_ide_dma_lost_irq(ide_drive_t *drive) -{ - ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; - u32 val, mask = hwif->channel ? CTRL_IDE_IRQB : CTRL_IDE_IRQA; - unsigned long dma_base = hwif->dma_base; - - printk("sl82c105: lost IRQ: resetting host\n"); - - /* - * Check the raw interrupt from the drive. - */ - pci_read_config_dword(dev, 0x40, &val); - if (val & mask) - printk("sl82c105: drive was requesting IRQ, but host lost it\n"); - - /* - * Was DMA enabled? If so, disable it - we're resetting the - * host. The IDE layer will be handling the drive for us. - */ - val = hwif->INB(dma_base); - if (val & 1) { - outb(val & ~1, dma_base); - printk("sl82c105: DMA was enabled\n"); - } - - sl82c105_reset_host(dev); - - /* ide_dmaproc would return 1, so we do as well */ - return 1; -} - -/* - * ATAPI devices can cause the SL82C105 DMA state machine to go gaga. - * Winbond recommend that the DMA state machine is reset prior to - * setting the bus master DMA enable bit. - * - * The generic IDE core will have disabled the BMEN bit before this - * function is called. - */ -static void sl82c105_ide_dma_start(ide_drive_t *drive) -{ - ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; - - sl82c105_reset_host(dev); - ide_dma_start(drive); -} - -static int sl82c105_ide_dma_timeout(ide_drive_t *drive) -{ - ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; - - DBG(("sl82c105_ide_dma_timeout(drive:%s)\n", drive->name)); - - sl82c105_reset_host(dev); - return __ide_dma_timeout(drive); -} - -static int sl82c105_ide_dma_on (ide_drive_t *drive) -{ - DBG(("sl82c105_ide_dma_on(drive:%s)\n", drive->name)); - - if (config_for_dma(drive)) { - config_for_pio(drive, 4, 0, 0); - return HWIF(drive)->ide_dma_off_quietly(drive); - } - printk(KERN_INFO "%s: DMA enabled\n", drive->name); - return __ide_dma_on(drive); -} - -static int sl82c105_ide_dma_off_quietly (ide_drive_t *drive) -{ - u8 speed = XFER_PIO_0; - int rc; - - DBG(("sl82c105_ide_dma_off_quietly(drive:%s)\n", drive->name)); - - rc = __ide_dma_off_quietly(drive); - if (drive->pio_speed) - speed = drive->pio_speed - XFER_PIO_0; - config_for_pio(drive, speed, 0, 1); - drive->current_speed = drive->pio_speed; - - return rc; -} - -/* - * Ok, that is nasty, but we must make sure the DMA timings - * won't be used for a PIO access. The solution here is - * to make sure the 16 bits mode is diabled on the channel - * when DMA is enabled, thus causing the chip to use PIO0 - * timings for those operations. - */ -static void sl82c105_selectproc(ide_drive_t *drive) -{ - ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; - u32 val, old, mask; - - //DBG(("sl82c105_selectproc(drive:%s)\n", drive->name)); - - mask = hwif->channel ? CTRL_P1F16 : CTRL_P0F16; - old = val = *((u32 *)&hwif->hwif_data); - if (drive->using_dma) - val &= ~mask; - else - val |= mask; - if (old != val) { - pci_write_config_dword(dev, 0x40, val); - *((u32 *)&hwif->hwif_data) = val; - } -} - -/* - * ATA reset will clear the 16 bits mode in the control - * register, we need to update our cache - */ -static void sl82c105_resetproc(ide_drive_t *drive) -{ - ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; - u32 val; - - DBG(("sl82c105_resetproc(drive:%s)\n", drive->name)); - - pci_read_config_dword(dev, 0x40, &val); - *((u32 *)&hwif->hwif_data) = val; -} - -/* - * We only deal with PIO mode here - DMA mode 'using_dma' is not - * initialised at the point that this function is called. - */ -static void tune_sl82c105(ide_drive_t *drive, u8 pio) -{ - DBG(("tune_sl82c105(drive:%s)\n", drive->name)); - - config_for_pio(drive, pio, 1, 0); - - /* - * We support 32-bit I/O on this interface, and it - * doesn't have problems with interrupts. - */ - drive->io_32bit = 1; - drive->unmask = 1; -} - -/* - * Return the revision of the Winbond bridge - * which this function is part of. - */ -static unsigned int sl82c105_bridge_revision(struct pci_dev *dev) -{ - struct pci_dev *bridge; - u8 rev; - - /* - * The bridge should be part of the same device, but function 0. - */ - bridge = pci_find_slot(dev->bus->number, - PCI_DEVFN(PCI_SLOT(dev->devfn), 0)); - if (!bridge) - return -1; - - /* - * Make sure it is a Winbond 553 and is an ISA bridge. - */ - if (bridge->vendor != PCI_VENDOR_ID_WINBOND || - bridge->device != PCI_DEVICE_ID_WINBOND_83C553 || - bridge->class >> 8 != PCI_CLASS_BRIDGE_ISA) - return -1; - - /* - * We need to find function 0's revision, not function 1 - */ - pci_read_config_byte(bridge, PCI_REVISION_ID, &rev); - - return rev; -} - -/* - * Enable the PCI device - * - * --BenH: It's arch fixup code that should enable channels that - * have not been enabled by firmware. I decided we can still enable - * channel 0 here at least, but channel 1 has to be enabled by - * firmware or arch code. We still set both to 16 bits mode. - */ -static unsigned int __devinit init_chipset_sl82c105(struct pci_dev *dev, const char *msg) -{ - u32 val; - - DBG(("init_chipset_sl82c105()\n")); - - pci_read_config_dword(dev, 0x40, &val); - val |= CTRL_P0EN | CTRL_P0F16 | CTRL_P1F16; - pci_write_config_dword(dev, 0x40, val); - - return dev->irq; -} - -/* - * Initialise the chip - */ - -static void __devinit init_hwif_sl82c105(ide_hwif_t *hwif) -{ - struct pci_dev *dev = hwif->pci_dev; - unsigned int rev; - u8 dma_state; - u32 val; - - DBG(("init_hwif_sl82c105(hwif: ide%d)\n", hwif->index)); - - hwif->tuneproc = tune_sl82c105; - hwif->selectproc = sl82c105_selectproc; - hwif->resetproc = sl82c105_resetproc; - - /* Default to PIO 0 for fallback unless tuned otherwise, - * we always autotune PIO, this is done before DMA is - * checked, so there is no risk of accidentally disabling - * DMA - */ - hwif->drives[0].pio_speed = XFER_PIO_0; - hwif->drives[0].autotune = 1; - hwif->drives[1].pio_speed = XFER_PIO_1; - hwif->drives[1].autotune = 1; - - pci_read_config_dword(dev, 0x40, &val); - *((u32 *)&hwif->hwif_data) = val; - - hwif->atapi_dma = 0; - hwif->mwdma_mask = 0; - hwif->swdma_mask = 0; - hwif->autodma = 0; - - if (!hwif->dma_base) - return; - - dma_state = hwif->INB(hwif->dma_base + 2) & ~0x60; - rev = sl82c105_bridge_revision(hwif->pci_dev); - if (rev <= 5) { - /* - * Never ever EVER under any circumstances enable - * DMA when the bridge is this old. - */ - printk(" %s: Winbond 553 bridge revision %d, BM-DMA disabled\n", - hwif->name, rev); - } else { - dma_state |= 0x60; - - hwif->atapi_dma = 1; - hwif->mwdma_mask = 0x07; - hwif->swdma_mask = 0x07; - - hwif->ide_dma_check = &sl82c105_check_drive; - hwif->ide_dma_on = &sl82c105_ide_dma_on; - hwif->ide_dma_off_quietly = &sl82c105_ide_dma_off_quietly; - hwif->ide_dma_lostirq = &sl82c105_ide_dma_lost_irq; - hwif->dma_start = &sl82c105_ide_dma_start; - hwif->ide_dma_timeout = &sl82c105_ide_dma_timeout; - - if (!noautodma) - hwif->autodma = 1; - hwif->drives[0].autodma = hwif->autodma; - hwif->drives[1].autodma = hwif->autodma; - - if (hwif->mate) - hwif->serialized = hwif->mate->serialized = 1; - } - hwif->OUTB(dma_state, hwif->dma_base + 2); -} - -static ide_pci_device_t sl82c105_chipset __devinitdata = { - .name = "W82C105", - .init_chipset = init_chipset_sl82c105, - .init_hwif = init_hwif_sl82c105, - .channels = 2, - .autodma = NOAUTODMA, - .enablebits = {{0x40,0x01,0x01}, {0x40,0x10,0x10}}, - .bootable = ON_BOARD, -}; - -static int __devinit sl82c105_init_one(struct pci_dev *dev, const struct pci_device_id *id) -{ - return ide_setup_pci_device(dev, &sl82c105_chipset); -} - -static struct pci_device_id sl82c105_pci_tbl[] = { - { PCI_DEVICE(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105), 0}, - { 0, }, -}; -MODULE_DEVICE_TABLE(pci, sl82c105_pci_tbl); - -static struct pci_driver driver = { - .name = "W82C105_IDE", - .id_table = sl82c105_pci_tbl, - .probe = sl82c105_init_one, -}; - -static int sl82c105_ide_init(void) -{ - return ide_pci_register_driver(&driver); -} - -module_init(sl82c105_ide_init); - -MODULE_DESCRIPTION("PCI driver module for W82C105 IDE"); -MODULE_LICENSE("GPL"); diff --git a/drivers/ide/pci/slc90e66.c b/drivers/ide/pci/slc90e66.c deleted file mode 100644 index 4a1853af3bb..00000000000 --- a/drivers/ide/pci/slc90e66.c +++ /dev/null @@ -1,267 +0,0 @@ -/* - * linux/drivers/ide/pci/slc90e66.c Version 0.11 September 11, 2002 - * - * Copyright (C) 2000-2002 Andre Hedrick <andre@linux-ide.org> - * - * This a look-a-like variation of the ICH0 PIIX4 Ultra-66, - * but this keeps the ISA-Bridge and slots alive. - * - */ - -#include <linux/types.h> -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/ioport.h> -#include <linux/pci.h> -#include <linux/hdreg.h> -#include <linux/ide.h> -#include <linux/delay.h> -#include <linux/init.h> - -#include <asm/io.h> - -static u8 slc90e66_ratemask (ide_drive_t *drive) -{ - u8 mode = 2; - - if (!eighty_ninty_three(drive)) - mode = min(mode, (u8)1); - return mode; -} - -static u8 slc90e66_dma_2_pio (u8 xfer_rate) { - switch(xfer_rate) { - case XFER_UDMA_4: - case XFER_UDMA_3: - case XFER_UDMA_2: - case XFER_UDMA_1: - case XFER_UDMA_0: - case XFER_MW_DMA_2: - case XFER_PIO_4: - return 4; - case XFER_MW_DMA_1: - case XFER_PIO_3: - return 3; - case XFER_SW_DMA_2: - case XFER_PIO_2: - return 2; - case XFER_MW_DMA_0: - case XFER_SW_DMA_1: - case XFER_SW_DMA_0: - case XFER_PIO_1: - case XFER_PIO_0: - case XFER_PIO_SLOW: - default: - return 0; - } -} - -/* - * Based on settings done by AMI BIOS - * (might be useful if drive is not registered in CMOS for any reason). - */ -static void slc90e66_tune_drive (ide_drive_t *drive, u8 pio) -{ - ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; - int is_slave = (&hwif->drives[1] == drive); - int master_port = hwif->channel ? 0x42 : 0x40; - int slave_port = 0x44; - unsigned long flags; - u16 master_data; - u8 slave_data; - /* ISP RTC */ - static const u8 timings[][2]= { - { 0, 0 }, - { 0, 0 }, - { 1, 0 }, - { 2, 1 }, - { 2, 3 }, }; - - pio = ide_get_best_pio_mode(drive, pio, 5, NULL); - spin_lock_irqsave(&ide_lock, flags); - pci_read_config_word(dev, master_port, &master_data); - if (is_slave) { - master_data = master_data | 0x4000; - if (pio > 1) - /* enable PPE, IE and TIME */ - master_data = master_data | 0x0070; - pci_read_config_byte(dev, slave_port, &slave_data); - slave_data = slave_data & (hwif->channel ? 0x0f : 0xf0); - slave_data = slave_data | (((timings[pio][0] << 2) | timings[pio][1]) << (hwif->channel ? 4 : 0)); - } else { - master_data = master_data & 0xccf8; - if (pio > 1) - /* enable PPE, IE and TIME */ - master_data = master_data | 0x0007; - master_data = master_data | (timings[pio][0] << 12) | (timings[pio][1] << 8); - } - pci_write_config_word(dev, master_port, master_data); - if (is_slave) - pci_write_config_byte(dev, slave_port, slave_data); - spin_unlock_irqrestore(&ide_lock, flags); -} - -static int slc90e66_tune_chipset (ide_drive_t *drive, u8 xferspeed) -{ - ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; - u8 maslave = hwif->channel ? 0x42 : 0x40; - u8 speed = ide_rate_filter(slc90e66_ratemask(drive), xferspeed); - int sitre = 0, a_speed = 7 << (drive->dn * 4); - int u_speed = 0, u_flag = 1 << drive->dn; - u16 reg4042, reg44, reg48, reg4a; - - pci_read_config_word(dev, maslave, ®4042); - sitre = (reg4042 & 0x4000) ? 1 : 0; - pci_read_config_word(dev, 0x44, ®44); - pci_read_config_word(dev, 0x48, ®48); - pci_read_config_word(dev, 0x4a, ®4a); - - switch(speed) { - case XFER_UDMA_4: u_speed = 4 << (drive->dn * 4); break; - case XFER_UDMA_3: u_speed = 3 << (drive->dn * 4); break; - case XFER_UDMA_2: u_speed = 2 << (drive->dn * 4); break; - case XFER_UDMA_1: u_speed = 1 << (drive->dn * 4); break; - case XFER_UDMA_0: u_speed = 0 << (drive->dn * 4); break; - case XFER_MW_DMA_2: - case XFER_MW_DMA_1: - case XFER_SW_DMA_2: break; - case XFER_PIO_4: - case XFER_PIO_3: - case XFER_PIO_2: - case XFER_PIO_0: break; - default: return -1; - } - - if (speed >= XFER_UDMA_0) { - if (!(reg48 & u_flag)) - pci_write_config_word(dev, 0x48, reg48|u_flag); - /* FIXME: (reg4a & a_speed) ? */ - if ((reg4a & u_speed) != u_speed) { - pci_write_config_word(dev, 0x4a, reg4a & ~a_speed); - pci_read_config_word(dev, 0x4a, ®4a); - pci_write_config_word(dev, 0x4a, reg4a|u_speed); - } - } else { - if (reg48 & u_flag) - pci_write_config_word(dev, 0x48, reg48 & ~u_flag); - if (reg4a & a_speed) - pci_write_config_word(dev, 0x4a, reg4a & ~a_speed); - } - - slc90e66_tune_drive(drive, slc90e66_dma_2_pio(speed)); - return (ide_config_drive_speed(drive, speed)); -} - -static int slc90e66_config_drive_for_dma (ide_drive_t *drive) -{ - u8 speed = ide_dma_speed(drive, slc90e66_ratemask(drive)); - - if (!(speed)) { - u8 tspeed = ide_get_best_pio_mode(drive, 255, 5, NULL); - speed = slc90e66_dma_2_pio(XFER_PIO_0 + tspeed); - } - - (void) slc90e66_tune_chipset(drive, speed); - return ide_dma_enable(drive); -} - -static int slc90e66_config_drive_xfer_rate (ide_drive_t *drive) -{ - ide_hwif_t *hwif = HWIF(drive); - struct hd_driveid *id = drive->id; - - drive->init_speed = 0; - - if (id && (id->capability & 1) && drive->autodma) { - - if (ide_use_dma(drive)) { - if (slc90e66_config_drive_for_dma(drive)) - return hwif->ide_dma_on(drive); - } - - goto fast_ata_pio; - - } else if ((id->capability & 8) || (id->field_valid & 2)) { -fast_ata_pio: - hwif->tuneproc(drive, 5); - return hwif->ide_dma_off_quietly(drive); - } - /* IORDY not supported */ - return 0; -} - -static void __devinit init_hwif_slc90e66 (ide_hwif_t *hwif) -{ - u8 reg47 = 0; - u8 mask = hwif->channel ? 0x01 : 0x02; /* bit0:Primary */ - - hwif->autodma = 0; - - if (!hwif->irq) - hwif->irq = hwif->channel ? 15 : 14; - - hwif->speedproc = &slc90e66_tune_chipset; - hwif->tuneproc = &slc90e66_tune_drive; - - pci_read_config_byte(hwif->pci_dev, 0x47, ®47); - - if (!hwif->dma_base) { - hwif->drives[0].autotune = 1; - hwif->drives[1].autotune = 1; - return; - } - - hwif->atapi_dma = 1; - hwif->ultra_mask = 0x1f; - hwif->mwdma_mask = 0x07; - hwif->swdma_mask = 0x07; - - if (!(hwif->udma_four)) - /* bit[0(1)]: 0:80, 1:40 */ - hwif->udma_four = (reg47 & mask) ? 0 : 1; - - hwif->ide_dma_check = &slc90e66_config_drive_xfer_rate; - if (!noautodma) - hwif->autodma = 1; - hwif->drives[0].autodma = hwif->autodma; - hwif->drives[1].autodma = hwif->autodma; -} - -static ide_pci_device_t slc90e66_chipset __devinitdata = { - .name = "SLC90E66", - .init_hwif = init_hwif_slc90e66, - .channels = 2, - .autodma = AUTODMA, - .enablebits = {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, - .bootable = ON_BOARD, -}; - -static int __devinit slc90e66_init_one(struct pci_dev *dev, const struct pci_device_id *id) -{ - return ide_setup_pci_device(dev, &slc90e66_chipset); -} - -static struct pci_device_id slc90e66_pci_tbl[] = { - { PCI_DEVICE(PCI_VENDOR_ID_EFAR, PCI_DEVICE_ID_EFAR_SLC90E66_1), 0}, - { 0, }, -}; -MODULE_DEVICE_TABLE(pci, slc90e66_pci_tbl); - -static struct pci_driver driver = { - .name = "SLC90e66_IDE", - .id_table = slc90e66_pci_tbl, - .probe = slc90e66_init_one, -}; - -static int slc90e66_ide_init(void) -{ - return ide_pci_register_driver(&driver); -} - -module_init(slc90e66_ide_init); - -MODULE_AUTHOR("Andre Hedrick"); -MODULE_DESCRIPTION("PCI driver module for SLC90E66 IDE"); -MODULE_LICENSE("GPL"); diff --git a/drivers/ide/pci/triflex.c b/drivers/ide/pci/triflex.c deleted file mode 100644 index 56d84931d6d..00000000000 --- a/drivers/ide/pci/triflex.c +++ /dev/null @@ -1,187 +0,0 @@ -/* - * triflex.c - * - * IDE Chipset driver for the Compaq TriFlex IDE controller. - * - * Known to work with the Compaq Workstation 5x00 series. - * - * Copyright (C) 2002 Hewlett-Packard Development Group, L.P. - * Author: Torben Mathiasen <torben.mathiasen@hp.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Loosely based on the piix & svwks drivers. - * - * Documentation: - * Not publically available. - */ - -#include <linux/types.h> -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/delay.h> -#include <linux/timer.h> -#include <linux/mm.h> -#include <linux/ioport.h> -#include <linux/blkdev.h> -#include <linux/hdreg.h> -#include <linux/pci.h> -#include <linux/ide.h> -#include <linux/init.h> - -static int triflex_tune_chipset(ide_drive_t *drive, u8 xferspeed) -{ - ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; - u8 channel_offset = hwif->channel ? 0x74 : 0x70; - u16 timing = 0; - u32 triflex_timings = 0; - u8 unit = (drive->select.b.unit & 0x01); - u8 speed = ide_rate_filter(0, xferspeed); - - pci_read_config_dword(dev, channel_offset, &triflex_timings); - - switch(speed) { - case XFER_MW_DMA_2: - timing = 0x0103; - break; - case XFER_MW_DMA_1: - timing = 0x0203; - break; - case XFER_MW_DMA_0: - timing = 0x0808; - break; - case XFER_SW_DMA_2: - case XFER_SW_DMA_1: - case XFER_SW_DMA_0: - timing = 0x0f0f; - break; - case XFER_PIO_4: - timing = 0x0202; - break; - case XFER_PIO_3: - timing = 0x0204; - break; - case XFER_PIO_2: - timing = 0x0404; - break; - case XFER_PIO_1: - timing = 0x0508; - break; - case XFER_PIO_0: - timing = 0x0808; - break; - default: - return -1; - } - - triflex_timings &= ~(0xFFFF << (16 * unit)); - triflex_timings |= (timing << (16 * unit)); - - pci_write_config_dword(dev, channel_offset, triflex_timings); - - return (ide_config_drive_speed(drive, speed)); -} - -static void triflex_tune_drive(ide_drive_t *drive, u8 pio) -{ - int use_pio = ide_get_best_pio_mode(drive, pio, 4, NULL); - (void) triflex_tune_chipset(drive, (XFER_PIO_0 + use_pio)); -} - -static int triflex_config_drive_for_dma(ide_drive_t *drive) -{ - int speed = ide_dma_speed(drive, 0); /* No ultra speeds */ - - if (!speed) { - u8 pspeed = ide_get_best_pio_mode(drive, 255, 4, NULL); - speed = XFER_PIO_0 + pspeed; - } - - (void) triflex_tune_chipset(drive, speed); - return ide_dma_enable(drive); -} - -static int triflex_config_drive_xfer_rate(ide_drive_t *drive) -{ - ide_hwif_t *hwif = HWIF(drive); - struct hd_driveid *id = drive->id; - - if ((id->capability & 1) && drive->autodma) { - if (ide_use_dma(drive)) { - if (triflex_config_drive_for_dma(drive)) - return hwif->ide_dma_on(drive); - } - } - - hwif->tuneproc(drive, 255); - return hwif->ide_dma_off_quietly(drive); -} - -static void __devinit init_hwif_triflex(ide_hwif_t *hwif) -{ - hwif->tuneproc = &triflex_tune_drive; - hwif->speedproc = &triflex_tune_chipset; - - hwif->atapi_dma = 1; - hwif->mwdma_mask = 0x07; - hwif->swdma_mask = 0x07; - hwif->ide_dma_check = &triflex_config_drive_xfer_rate; - - if (!noautodma) - hwif->autodma = 1; - hwif->drives[0].autodma = hwif->autodma; - hwif->drives[1].autodma = hwif->autodma; -} - -static ide_pci_device_t triflex_device __devinitdata = { - .name = "TRIFLEX", - .init_hwif = init_hwif_triflex, - .channels = 2, - .autodma = AUTODMA, - .enablebits = {{0x80, 0x01, 0x01}, {0x80, 0x02, 0x02}}, - .bootable = ON_BOARD, -}; - -static int __devinit triflex_init_one(struct pci_dev *dev, - const struct pci_device_id *id) -{ - return ide_setup_pci_device(dev, &triflex_device); -} - -static struct pci_device_id triflex_pci_tbl[] = { - { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_TRIFLEX_IDE, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { 0, }, -}; -MODULE_DEVICE_TABLE(pci, triflex_pci_tbl); - -static struct pci_driver driver = { - .name = "TRIFLEX_IDE", - .id_table = triflex_pci_tbl, - .probe = triflex_init_one, -}; - -static int triflex_ide_init(void) -{ - return ide_pci_register_driver(&driver); -} - -module_init(triflex_ide_init); - -MODULE_AUTHOR("Torben Mathiasen"); -MODULE_DESCRIPTION("PCI driver module for Compaq Triflex IDE"); -MODULE_LICENSE("GPL"); - - diff --git a/drivers/ide/pci/via82cxxx.c b/drivers/ide/pci/via82cxxx.c deleted file mode 100644 index 9b7589e8e93..00000000000 --- a/drivers/ide/pci/via82cxxx.c +++ /dev/null @@ -1,520 +0,0 @@ -/* - * - * Version 3.38 - * - * VIA IDE driver for Linux. Supported southbridges: - * - * vt82c576, vt82c586, vt82c586a, vt82c586b, vt82c596a, vt82c596b, - * vt82c686, vt82c686a, vt82c686b, vt8231, vt8233, vt8233c, vt8233a, - * vt8235, vt8237, vt8237a - * - * Copyright (c) 2000-2002 Vojtech Pavlik - * - * Based on the work of: - * Michel Aubry - * Jeff Garzik - * Andre Hedrick - * - * Documentation: - * Obsolete device documentation publically available from via.com.tw - * Current device documentation available under NDA only - */ - -/* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - */ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/ioport.h> -#include <linux/blkdev.h> -#include <linux/pci.h> -#include <linux/init.h> -#include <linux/ide.h> -#include <asm/io.h> - -#ifdef CONFIG_PPC_MULTIPLATFORM -#include <asm/processor.h> -#endif - -#include "ide-timing.h" - -#define DISPLAY_VIA_TIMINGS - -#define VIA_IDE_ENABLE 0x40 -#define VIA_IDE_CONFIG 0x41 -#define VIA_FIFO_CONFIG 0x43 -#define VIA_MISC_1 0x44 -#define VIA_MISC_2 0x45 -#define VIA_MISC_3 0x46 -#define VIA_DRIVE_TIMING 0x48 -#define VIA_8BIT_TIMING 0x4e -#define VIA_ADDRESS_SETUP 0x4c -#define VIA_UDMA_TIMING 0x50 - -#define VIA_UDMA 0x007 -#define VIA_UDMA_NONE 0x000 -#define VIA_UDMA_33 0x001 -#define VIA_UDMA_66 0x002 -#define VIA_UDMA_100 0x003 -#define VIA_UDMA_133 0x004 -#define VIA_BAD_PREQ 0x010 /* Crashes if PREQ# till DDACK# set */ -#define VIA_BAD_CLK66 0x020 /* 66 MHz clock doesn't work correctly */ -#define VIA_SET_FIFO 0x040 /* Needs to have FIFO split set */ -#define VIA_NO_UNMASK 0x080 /* Doesn't work with IRQ unmasking on */ -#define VIA_BAD_ID 0x100 /* Has wrong vendor ID (0x1107) */ -#define VIA_BAD_AST 0x200 /* Don't touch Address Setup Timing */ - -/* - * VIA SouthBridge chips. - */ - -static struct via_isa_bridge { - char *name; - u16 id; - u8 rev_min; - u8 rev_max; - u16 flags; -} via_isa_bridges[] = { - { "vt6410", PCI_DEVICE_ID_VIA_6410, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST }, - { "vt8251", PCI_DEVICE_ID_VIA_8251, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST }, - { "vt8237", PCI_DEVICE_ID_VIA_8237, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST }, - { "vt8237a", PCI_DEVICE_ID_VIA_8237A, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST }, - { "vt8235", PCI_DEVICE_ID_VIA_8235, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST }, - { "vt8233a", PCI_DEVICE_ID_VIA_8233A, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST }, - { "vt8233c", PCI_DEVICE_ID_VIA_8233C_0, 0x00, 0x2f, VIA_UDMA_100 }, - { "vt8233", PCI_DEVICE_ID_VIA_8233_0, 0x00, 0x2f, VIA_UDMA_100 }, - { "vt8231", PCI_DEVICE_ID_VIA_8231, 0x00, 0x2f, VIA_UDMA_100 }, - { "vt82c686b", PCI_DEVICE_ID_VIA_82C686, 0x40, 0x4f, VIA_UDMA_100 }, - { "vt82c686a", PCI_DEVICE_ID_VIA_82C686, 0x10, 0x2f, VIA_UDMA_66 }, - { "vt82c686", PCI_DEVICE_ID_VIA_82C686, 0x00, 0x0f, VIA_UDMA_33 | VIA_BAD_CLK66 }, - { "vt82c596b", PCI_DEVICE_ID_VIA_82C596, 0x10, 0x2f, VIA_UDMA_66 }, - { "vt82c596a", PCI_DEVICE_ID_VIA_82C596, 0x00, 0x0f, VIA_UDMA_33 | VIA_BAD_CLK66 }, - { "vt82c586b", PCI_DEVICE_ID_VIA_82C586_0, 0x47, 0x4f, VIA_UDMA_33 | VIA_SET_FIFO }, - { "vt82c586b", PCI_DEVICE_ID_VIA_82C586_0, 0x40, 0x46, VIA_UDMA_33 | VIA_SET_FIFO | VIA_BAD_PREQ }, - { "vt82c586b", PCI_DEVICE_ID_VIA_82C586_0, 0x30, 0x3f, VIA_UDMA_33 | VIA_SET_FIFO }, - { "vt82c586a", PCI_DEVICE_ID_VIA_82C586_0, 0x20, 0x2f, VIA_UDMA_33 | VIA_SET_FIFO }, - { "vt82c586", PCI_DEVICE_ID_VIA_82C586_0, 0x00, 0x0f, VIA_UDMA_NONE | VIA_SET_FIFO }, - { "vt82c576", PCI_DEVICE_ID_VIA_82C576, 0x00, 0x2f, VIA_UDMA_NONE | VIA_SET_FIFO | VIA_NO_UNMASK }, - { "vt82c576", PCI_DEVICE_ID_VIA_82C576, 0x00, 0x2f, VIA_UDMA_NONE | VIA_SET_FIFO | VIA_NO_UNMASK | VIA_BAD_ID }, - { NULL } -}; - -static unsigned int via_clock; -static char *via_dma[] = { "MWDMA16", "UDMA33", "UDMA66", "UDMA100", "UDMA133" }; - -struct via82cxxx_dev -{ - struct via_isa_bridge *via_config; - unsigned int via_80w; -}; - -/** - * via_set_speed - write timing registers - * @dev: PCI device - * @dn: device - * @timing: IDE timing data to use - * - * via_set_speed writes timing values to the chipset registers - */ - -static void via_set_speed(ide_hwif_t *hwif, u8 dn, struct ide_timing *timing) -{ - struct pci_dev *dev = hwif->pci_dev; - struct via82cxxx_dev *vdev = ide_get_hwifdata(hwif); - u8 t; - - if (~vdev->via_config->flags & VIA_BAD_AST) { - pci_read_config_byte(dev, VIA_ADDRESS_SETUP, &t); - t = (t & ~(3 << ((3 - dn) << 1))) | ((FIT(timing->setup, 1, 4) - 1) << ((3 - dn) << 1)); - pci_write_config_byte(dev, VIA_ADDRESS_SETUP, t); - } - - pci_write_config_byte(dev, VIA_8BIT_TIMING + (1 - (dn >> 1)), - ((FIT(timing->act8b, 1, 16) - 1) << 4) | (FIT(timing->rec8b, 1, 16) - 1)); - - pci_write_config_byte(dev, VIA_DRIVE_TIMING + (3 - dn), - ((FIT(timing->active, 1, 16) - 1) << 4) | (FIT(timing->recover, 1, 16) - 1)); - - switch (vdev->via_config->flags & VIA_UDMA) { - case VIA_UDMA_33: t = timing->udma ? (0xe0 | (FIT(timing->udma, 2, 5) - 2)) : 0x03; break; - case VIA_UDMA_66: t = timing->udma ? (0xe8 | (FIT(timing->udma, 2, 9) - 2)) : 0x0f; break; - case VIA_UDMA_100: t = timing->udma ? (0xe0 | (FIT(timing->udma, 2, 9) - 2)) : 0x07; break; - case VIA_UDMA_133: t = timing->udma ? (0xe0 | (FIT(timing->udma, 2, 9) - 2)) : 0x07; break; - default: return; - } - - pci_write_config_byte(dev, VIA_UDMA_TIMING + (3 - dn), t); -} - -/** - * via_set_drive - configure transfer mode - * @drive: Drive to set up - * @speed: desired speed - * - * via_set_drive() computes timing values configures the drive and - * the chipset to a desired transfer mode. It also can be called - * by upper layers. - */ - -static int via_set_drive(ide_drive_t *drive, u8 speed) -{ - ide_drive_t *peer = HWIF(drive)->drives + (~drive->dn & 1); - struct via82cxxx_dev *vdev = ide_get_hwifdata(drive->hwif); - struct ide_timing t, p; - unsigned int T, UT; - - if (speed != XFER_PIO_SLOW) - ide_config_drive_speed(drive, speed); - - T = 1000000000 / via_clock; - - switch (vdev->via_config->flags & VIA_UDMA) { - case VIA_UDMA_33: UT = T; break; - case VIA_UDMA_66: UT = T/2; break; - case VIA_UDMA_100: UT = T/3; break; - case VIA_UDMA_133: UT = T/4; break; - default: UT = T; - } - - ide_timing_compute(drive, speed, &t, T, UT); - - if (peer->present) { - ide_timing_compute(peer, peer->current_speed, &p, T, UT); - ide_timing_merge(&p, &t, &t, IDE_TIMING_8BIT); - } - - via_set_speed(HWIF(drive), drive->dn, &t); - - if (!drive->init_speed) - drive->init_speed = speed; - drive->current_speed = speed; - - return 0; -} - -/** - * via82cxxx_tune_drive - PIO setup - * @drive: drive to set up - * @pio: mode to use (255 for 'best possible') - * - * A callback from the upper layers for PIO-only tuning. - */ - -static void via82cxxx_tune_drive(ide_drive_t *drive, u8 pio) -{ - if (pio == 255) { - via_set_drive(drive, - ide_find_best_mode(drive, XFER_PIO | XFER_EPIO)); - return; - } - - via_set_drive(drive, XFER_PIO_0 + min_t(u8, pio, 5)); -} - -/** - * via82cxxx_ide_dma_check - set up for DMA if possible - * @drive: IDE drive to set up - * - * Set up the drive for the highest supported speed considering the - * driver, controller and cable - */ - -static int via82cxxx_ide_dma_check (ide_drive_t *drive) -{ - ide_hwif_t *hwif = HWIF(drive); - struct via82cxxx_dev *vdev = ide_get_hwifdata(hwif); - u16 w80 = hwif->udma_four; - - u16 speed = ide_find_best_mode(drive, - XFER_PIO | XFER_EPIO | XFER_SWDMA | XFER_MWDMA | - (vdev->via_config->flags & VIA_UDMA ? XFER_UDMA : 0) | - (w80 && (vdev->via_config->flags & VIA_UDMA) >= VIA_UDMA_66 ? XFER_UDMA_66 : 0) | - (w80 && (vdev->via_config->flags & VIA_UDMA) >= VIA_UDMA_100 ? XFER_UDMA_100 : 0) | - (w80 && (vdev->via_config->flags & VIA_UDMA) >= VIA_UDMA_133 ? XFER_UDMA_133 : 0)); - - via_set_drive(drive, speed); - - if (drive->autodma && (speed & XFER_MODE) != XFER_PIO) - return hwif->ide_dma_on(drive); - return hwif->ide_dma_off_quietly(drive); -} - -static struct via_isa_bridge *via_config_find(struct pci_dev **isa) -{ - struct via_isa_bridge *via_config; - u8 t; - - for (via_config = via_isa_bridges; via_config->id; via_config++) - if ((*isa = pci_find_device(PCI_VENDOR_ID_VIA + - !!(via_config->flags & VIA_BAD_ID), - via_config->id, NULL))) { - - pci_read_config_byte(*isa, PCI_REVISION_ID, &t); - if (t >= via_config->rev_min && - t <= via_config->rev_max) - break; - } - - return via_config; -} - -/** - * init_chipset_via82cxxx - initialization handler - * @dev: PCI device - * @name: Name of interface - * - * The initialization callback. Here we determine the IDE chip type - * and initialize its drive independent registers. - */ - -static unsigned int __devinit init_chipset_via82cxxx(struct pci_dev *dev, const char *name) -{ - struct pci_dev *isa = NULL; - struct via_isa_bridge *via_config; - u8 t, v; - unsigned int u; - - /* - * Find the ISA bridge to see how good the IDE is. - */ - via_config = via_config_find(&isa); - if (!via_config->id) { - printk(KERN_WARNING "VP_IDE: Unknown VIA SouthBridge, disabling DMA.\n"); - return -ENODEV; - } - - /* - * Setup or disable Clk66 if appropriate - */ - - if ((via_config->flags & VIA_UDMA) == VIA_UDMA_66) { - /* Enable Clk66 */ - pci_read_config_dword(dev, VIA_UDMA_TIMING, &u); - pci_write_config_dword(dev, VIA_UDMA_TIMING, u|0x80008); - } else if (via_config->flags & VIA_BAD_CLK66) { - /* Would cause trouble on 596a and 686 */ - pci_read_config_dword(dev, VIA_UDMA_TIMING, &u); - pci_write_config_dword(dev, VIA_UDMA_TIMING, u & ~0x80008); - } - - /* - * Check whether interfaces are enabled. - */ - - pci_read_config_byte(dev, VIA_IDE_ENABLE, &v); - - /* - * Set up FIFO sizes and thresholds. - */ - - pci_read_config_byte(dev, VIA_FIFO_CONFIG, &t); - - /* Disable PREQ# till DDACK# */ - if (via_config->flags & VIA_BAD_PREQ) { - /* Would crash on 586b rev 41 */ - t &= 0x7f; - } - - /* Fix FIFO split between channels */ - if (via_config->flags & VIA_SET_FIFO) { - t &= (t & 0x9f); - switch (v & 3) { - case 2: t |= 0x00; break; /* 16 on primary */ - case 1: t |= 0x60; break; /* 16 on secondary */ - case 3: t |= 0x20; break; /* 8 pri 8 sec */ - } - } - - pci_write_config_byte(dev, VIA_FIFO_CONFIG, t); - - /* - * Determine system bus clock. - */ - - via_clock = system_bus_clock() * 1000; - - switch (via_clock) { - case 33000: via_clock = 33333; break; - case 37000: via_clock = 37500; break; - case 41000: via_clock = 41666; break; - } - - if (via_clock < 20000 || via_clock > 50000) { - printk(KERN_WARNING "VP_IDE: User given PCI clock speed " - "impossible (%d), using 33 MHz instead.\n", via_clock); - printk(KERN_WARNING "VP_IDE: Use ide0=ata66 if you want " - "to assume 80-wire cable.\n"); - via_clock = 33333; - } - - /* - * Print the boot message. - */ - - pci_read_config_byte(isa, PCI_REVISION_ID, &t); - printk(KERN_INFO "VP_IDE: VIA %s (rev %02x) IDE %s " - "controller on pci%s\n", - via_config->name, t, - via_dma[via_config->flags & VIA_UDMA], - pci_name(dev)); - - return 0; -} - -/* - * Check and handle 80-wire cable presence - */ -static void __devinit via_cable_detect(struct pci_dev *dev, struct via82cxxx_dev *vdev) -{ - unsigned int u; - int i; - pci_read_config_dword(dev, VIA_UDMA_TIMING, &u); - - switch (vdev->via_config->flags & VIA_UDMA) { - - case VIA_UDMA_66: - for (i = 24; i >= 0; i -= 8) - if (((u >> (i & 16)) & 8) && - ((u >> i) & 0x20) && - (((u >> i) & 7) < 2)) { - /* - * 2x PCI clock and - * UDMA w/ < 3T/cycle - */ - vdev->via_80w |= (1 << (1 - (i >> 4))); - } - break; - - case VIA_UDMA_100: - for (i = 24; i >= 0; i -= 8) - if (((u >> i) & 0x10) || - (((u >> i) & 0x20) && - (((u >> i) & 7) < 4))) { - /* BIOS 80-wire bit or - * UDMA w/ < 60ns/cycle - */ - vdev->via_80w |= (1 << (1 - (i >> 4))); - } - break; - - case VIA_UDMA_133: - for (i = 24; i >= 0; i -= 8) - if (((u >> i) & 0x10) || - (((u >> i) & 0x20) && - (((u >> i) & 7) < 6))) { - /* BIOS 80-wire bit or - * UDMA w/ < 60ns/cycle - */ - vdev->via_80w |= (1 << (1 - (i >> 4))); - } - break; - - } -} - -static void __devinit init_hwif_via82cxxx(ide_hwif_t *hwif) -{ - struct via82cxxx_dev *vdev = kmalloc(sizeof(struct via82cxxx_dev), - GFP_KERNEL); - struct pci_dev *isa = NULL; - int i; - - if (vdev == NULL) { - printk(KERN_ERR "VP_IDE: out of memory :(\n"); - return; - } - - memset(vdev, 0, sizeof(struct via82cxxx_dev)); - ide_set_hwifdata(hwif, vdev); - - vdev->via_config = via_config_find(&isa); - via_cable_detect(hwif->pci_dev, vdev); - - hwif->autodma = 0; - - hwif->tuneproc = &via82cxxx_tune_drive; - hwif->speedproc = &via_set_drive; - - -#if defined(CONFIG_PPC_CHRP) && defined(CONFIG_PPC32) - if(machine_is(chrp) && _chrp_type == _CHRP_Pegasos) { - hwif->irq = hwif->channel ? 15 : 14; - } -#endif - - for (i = 0; i < 2; i++) { - hwif->drives[i].io_32bit = 1; - hwif->drives[i].unmask = (vdev->via_config->flags & VIA_NO_UNMASK) ? 0 : 1; - hwif->drives[i].autotune = 1; - hwif->drives[i].dn = hwif->channel * 2 + i; - } - - if (!hwif->dma_base) - return; - - hwif->atapi_dma = 1; - hwif->ultra_mask = 0x7f; - hwif->mwdma_mask = 0x07; - hwif->swdma_mask = 0x07; - - if (!hwif->udma_four) - hwif->udma_four = (vdev->via_80w >> hwif->channel) & 1; - hwif->ide_dma_check = &via82cxxx_ide_dma_check; - if (!noautodma) - hwif->autodma = 1; - hwif->drives[0].autodma = hwif->autodma; - hwif->drives[1].autodma = hwif->autodma; -} - -static ide_pci_device_t via82cxxx_chipsets[] __devinitdata = { - { /* 0 */ - .name = "VP_IDE", - .init_chipset = init_chipset_via82cxxx, - .init_hwif = init_hwif_via82cxxx, - .channels = 2, - .autodma = NOAUTODMA, - .enablebits = {{0x40,0x02,0x02}, {0x40,0x01,0x01}}, - .bootable = ON_BOARD - },{ /* 1 */ - .name = "VP_IDE", - .init_chipset = init_chipset_via82cxxx, - .init_hwif = init_hwif_via82cxxx, - .channels = 2, - .autodma = AUTODMA, - .enablebits = {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, - .bootable = ON_BOARD, - } -}; - -static int __devinit via_init_one(struct pci_dev *dev, const struct pci_device_id *id) -{ - return ide_setup_pci_device(dev, &via82cxxx_chipsets[id->driver_data]); -} - -static struct pci_device_id via_pci_tbl[] = { - { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C576_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_6410, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1}, - { 0, }, -}; -MODULE_DEVICE_TABLE(pci, via_pci_tbl); - -static struct pci_driver driver = { - .name = "VIA_IDE", - .id_table = via_pci_tbl, - .probe = via_init_one, -}; - -static int via_ide_init(void) -{ - return ide_pci_register_driver(&driver); -} - -module_init(via_ide_init); - -MODULE_AUTHOR("Vojtech Pavlik, Michel Aubry, Jeff Garzik, Andre Hedrick"); -MODULE_DESCRIPTION("PCI driver module for VIA IDE"); -MODULE_LICENSE("GPL"); diff --git a/drivers/ide/pdc202xx_new.c b/drivers/ide/pdc202xx_new.c new file mode 100644 index 00000000000..df73cbd9387 --- /dev/null +++ b/drivers/ide/pdc202xx_new.c @@ -0,0 +1,562 @@ +/* + * Promise TX2/TX4/TX2000/133 IDE driver + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Split from: + * linux/drivers/ide/pdc202xx.c Version 0.35 Mar. 30, 2002 + * Copyright (C) 1998-2002 Andre Hedrick <andre@linux-ide.org> + * Copyright (C) 2005-2007 MontaVista Software, Inc. + * Portions Copyright (C) 1999 Promise Technology, Inc. + * Author: Frank Tiernan (frankt@promise.com) + * Released under terms of General Public License + */ + +#include <linux/module.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/delay.h> +#include <linux/pci.h> +#include <linux/init.h> +#include <linux/ide.h> + +#include <asm/io.h> + +#ifdef CONFIG_PPC_PMAC +#include <asm/prom.h> +#include <asm/pci-bridge.h> +#endif + +#define DRV_NAME "pdc202xx_new" + +#undef DEBUG + +#ifdef DEBUG +#define DBG(fmt, args...) printk("%s: " fmt, __func__, ## args) +#else +#define DBG(fmt, args...) +#endif + +static u8 max_dma_rate(struct pci_dev *pdev) +{ + u8 mode; + + switch(pdev->device) { + case PCI_DEVICE_ID_PROMISE_20277: + case PCI_DEVICE_ID_PROMISE_20276: + case PCI_DEVICE_ID_PROMISE_20275: + case PCI_DEVICE_ID_PROMISE_20271: + case PCI_DEVICE_ID_PROMISE_20269: + mode = 4; + break; + case PCI_DEVICE_ID_PROMISE_20270: + case PCI_DEVICE_ID_PROMISE_20268: + mode = 3; + break; + default: + return 0; + } + + return mode; +} + +/** + * get_indexed_reg - Get indexed register + * @hwif: for the port address + * @index: index of the indexed register + */ +static u8 get_indexed_reg(ide_hwif_t *hwif, u8 index) +{ + u8 value; + + outb(index, hwif->dma_base + 1); + value = inb(hwif->dma_base + 3); + + DBG("index[%02X] value[%02X]\n", index, value); + return value; +} + +/** + * set_indexed_reg - Set indexed register + * @hwif: for the port address + * @index: index of the indexed register + */ +static void set_indexed_reg(ide_hwif_t *hwif, u8 index, u8 value) +{ + outb(index, hwif->dma_base + 1); + outb(value, hwif->dma_base + 3); + DBG("index[%02X] value[%02X]\n", index, value); +} + +/* + * ATA Timing Tables based on 133 MHz PLL output clock. + * + * If the PLL outputs 100 MHz clock, the ASIC hardware will set + * the timing registers automatically when "set features" command is + * issued to the device. However, if the PLL output clock is 133 MHz, + * the following tables must be used. + */ +static struct pio_timing { + u8 reg0c, reg0d, reg13; +} pio_timings [] = { + { 0xfb, 0x2b, 0xac }, /* PIO mode 0, IORDY off, Prefetch off */ + { 0x46, 0x29, 0xa4 }, /* PIO mode 1, IORDY off, Prefetch off */ + { 0x23, 0x26, 0x64 }, /* PIO mode 2, IORDY off, Prefetch off */ + { 0x27, 0x0d, 0x35 }, /* PIO mode 3, IORDY on, Prefetch off */ + { 0x23, 0x09, 0x25 }, /* PIO mode 4, IORDY on, Prefetch off */ +}; + +static struct mwdma_timing { + u8 reg0e, reg0f; +} mwdma_timings [] = { + { 0xdf, 0x5f }, /* MWDMA mode 0 */ + { 0x6b, 0x27 }, /* MWDMA mode 1 */ + { 0x69, 0x25 }, /* MWDMA mode 2 */ +}; + +static struct udma_timing { + u8 reg10, reg11, reg12; +} udma_timings [] = { + { 0x4a, 0x0f, 0xd5 }, /* UDMA mode 0 */ + { 0x3a, 0x0a, 0xd0 }, /* UDMA mode 1 */ + { 0x2a, 0x07, 0xcd }, /* UDMA mode 2 */ + { 0x1a, 0x05, 0xcd }, /* UDMA mode 3 */ + { 0x1a, 0x03, 0xcd }, /* UDMA mode 4 */ + { 0x1a, 0x02, 0xcb }, /* UDMA mode 5 */ + { 0x1a, 0x01, 0xcb }, /* UDMA mode 6 */ +}; + +static void pdcnew_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive) +{ + struct pci_dev *dev = to_pci_dev(hwif->dev); + u8 adj = (drive->dn & 1) ? 0x08 : 0x00; + const u8 speed = drive->dma_mode; + + /* + * IDE core issues SETFEATURES_XFER to the drive first (thanks to + * IDE_HFLAG_POST_SET_MODE in ->host_flags). PDC202xx hardware will + * automatically set the timing registers based on 100 MHz PLL output. + * + * As we set up the PLL to output 133 MHz for UltraDMA/133 capable + * chips, we must override the default register settings... + */ + if (max_dma_rate(dev) == 4) { + u8 mode = speed & 0x07; + + if (speed >= XFER_UDMA_0) { + set_indexed_reg(hwif, 0x10 + adj, + udma_timings[mode].reg10); + set_indexed_reg(hwif, 0x11 + adj, + udma_timings[mode].reg11); + set_indexed_reg(hwif, 0x12 + adj, + udma_timings[mode].reg12); + } else { + set_indexed_reg(hwif, 0x0e + adj, + mwdma_timings[mode].reg0e); + set_indexed_reg(hwif, 0x0f + adj, + mwdma_timings[mode].reg0f); + } + } else if (speed == XFER_UDMA_2) { + /* Set tHOLD bit to 0 if using UDMA mode 2 */ + u8 tmp = get_indexed_reg(hwif, 0x10 + adj); + + set_indexed_reg(hwif, 0x10 + adj, tmp & 0x7f); + } +} + +static void pdcnew_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) +{ + struct pci_dev *dev = to_pci_dev(hwif->dev); + u8 adj = (drive->dn & 1) ? 0x08 : 0x00; + const u8 pio = drive->pio_mode - XFER_PIO_0; + + if (max_dma_rate(dev) == 4) { + set_indexed_reg(hwif, 0x0c + adj, pio_timings[pio].reg0c); + set_indexed_reg(hwif, 0x0d + adj, pio_timings[pio].reg0d); + set_indexed_reg(hwif, 0x13 + adj, pio_timings[pio].reg13); + } +} + +static u8 pdcnew_cable_detect(ide_hwif_t *hwif) +{ + if (get_indexed_reg(hwif, 0x0b) & 0x04) + return ATA_CBL_PATA40; + else + return ATA_CBL_PATA80; +} + +static void pdcnew_reset(ide_drive_t *drive) +{ + /* + * Deleted this because it is redundant from the caller. + */ + printk(KERN_WARNING "pdc202xx_new: %s channel reset.\n", + drive->hwif->channel ? "Secondary" : "Primary"); +} + +/** + * read_counter - Read the byte count registers + * @dma_base: for the port address + */ +static long read_counter(u32 dma_base) +{ + u32 pri_dma_base = dma_base, sec_dma_base = dma_base + 0x08; + u8 cnt0, cnt1, cnt2, cnt3; + long count = 0, last; + int retry = 3; + + do { + last = count; + + /* Read the current count */ + outb(0x20, pri_dma_base + 0x01); + cnt0 = inb(pri_dma_base + 0x03); + outb(0x21, pri_dma_base + 0x01); + cnt1 = inb(pri_dma_base + 0x03); + outb(0x20, sec_dma_base + 0x01); + cnt2 = inb(sec_dma_base + 0x03); + outb(0x21, sec_dma_base + 0x01); + cnt3 = inb(sec_dma_base + 0x03); + + count = (cnt3 << 23) | (cnt2 << 15) | (cnt1 << 8) | cnt0; + + /* + * The 30-bit decrementing counter is read in 4 pieces. + * Incorrect value may be read when the most significant bytes + * are changing... + */ + } while (retry-- && (((last ^ count) & 0x3fff8000) || last < count)); + + DBG("cnt0[%02X] cnt1[%02X] cnt2[%02X] cnt3[%02X]\n", + cnt0, cnt1, cnt2, cnt3); + + return count; +} + +/** + * detect_pll_input_clock - Detect the PLL input clock in Hz. + * @dma_base: for the port address + * E.g. 16949000 on 33 MHz PCI bus, i.e. half of the PCI clock. + */ +static long detect_pll_input_clock(unsigned long dma_base) +{ + struct timeval start_time, end_time; + long start_count, end_count; + long pll_input, usec_elapsed; + u8 scr1; + + start_count = read_counter(dma_base); + do_gettimeofday(&start_time); + + /* Start the test mode */ + outb(0x01, dma_base + 0x01); + scr1 = inb(dma_base + 0x03); + DBG("scr1[%02X]\n", scr1); + outb(scr1 | 0x40, dma_base + 0x03); + + /* Let the counter run for 10 ms. */ + mdelay(10); + + end_count = read_counter(dma_base); + do_gettimeofday(&end_time); + + /* Stop the test mode */ + outb(0x01, dma_base + 0x01); + scr1 = inb(dma_base + 0x03); + DBG("scr1[%02X]\n", scr1); + outb(scr1 & ~0x40, dma_base + 0x03); + + /* + * Calculate the input clock in Hz + * (the clock counter is 30 bit wide and counts down) + */ + usec_elapsed = (end_time.tv_sec - start_time.tv_sec) * 1000000 + + (end_time.tv_usec - start_time.tv_usec); + pll_input = ((start_count - end_count) & 0x3fffffff) / 10 * + (10000000 / usec_elapsed); + + DBG("start[%ld] end[%ld]\n", start_count, end_count); + + return pll_input; +} + +#ifdef CONFIG_PPC_PMAC +static void apple_kiwi_init(struct pci_dev *pdev) +{ + struct device_node *np = pci_device_to_OF_node(pdev); + u8 conf; + + if (np == NULL || !of_device_is_compatible(np, "kiwi-root")) + return; + + if (pdev->revision >= 0x03) { + /* Setup chip magic config stuff (from darwin) */ + pci_read_config_byte (pdev, 0x40, &conf); + pci_write_config_byte(pdev, 0x40, (conf | 0x01)); + } +} +#endif /* CONFIG_PPC_PMAC */ + +static int init_chipset_pdcnew(struct pci_dev *dev) +{ + const char *name = DRV_NAME; + unsigned long dma_base = pci_resource_start(dev, 4); + unsigned long sec_dma_base = dma_base + 0x08; + long pll_input, pll_output, ratio; + int f, r; + u8 pll_ctl0, pll_ctl1; + + if (dma_base == 0) + return -EFAULT; + +#ifdef CONFIG_PPC_PMAC + apple_kiwi_init(dev); +#endif + + /* Calculate the required PLL output frequency */ + switch(max_dma_rate(dev)) { + case 4: /* it's 133 MHz for Ultra133 chips */ + pll_output = 133333333; + break; + case 3: /* and 100 MHz for Ultra100 chips */ + default: + pll_output = 100000000; + break; + } + + /* + * Detect PLL input clock. + * On some systems, where PCI bus is running at non-standard clock rate + * (e.g. 25 or 40 MHz), we have to adjust the cycle time. + * PDC20268 and newer chips employ PLL circuit to help correct timing + * registers setting. + */ + pll_input = detect_pll_input_clock(dma_base); + printk(KERN_INFO "%s %s: PLL input clock is %ld kHz\n", + name, pci_name(dev), pll_input / 1000); + + /* Sanity check */ + if (unlikely(pll_input < 5000000L || pll_input > 70000000L)) { + printk(KERN_ERR "%s %s: Bad PLL input clock %ld Hz, giving up!" + "\n", name, pci_name(dev), pll_input); + goto out; + } + +#ifdef DEBUG + DBG("pll_output is %ld Hz\n", pll_output); + + /* Show the current clock value of PLL control register + * (maybe already configured by the BIOS) + */ + outb(0x02, sec_dma_base + 0x01); + pll_ctl0 = inb(sec_dma_base + 0x03); + outb(0x03, sec_dma_base + 0x01); + pll_ctl1 = inb(sec_dma_base + 0x03); + + DBG("pll_ctl[%02X][%02X]\n", pll_ctl0, pll_ctl1); +#endif + + /* + * Calculate the ratio of F, R and NO + * POUT = (F + 2) / (( R + 2) * NO) + */ + ratio = pll_output / (pll_input / 1000); + if (ratio < 8600L) { /* 8.6x */ + /* Using NO = 0x01, R = 0x0d */ + r = 0x0d; + } else if (ratio < 12900L) { /* 12.9x */ + /* Using NO = 0x01, R = 0x08 */ + r = 0x08; + } else if (ratio < 16100L) { /* 16.1x */ + /* Using NO = 0x01, R = 0x06 */ + r = 0x06; + } else if (ratio < 64000L) { /* 64x */ + r = 0x00; + } else { + /* Invalid ratio */ + printk(KERN_ERR "%s %s: Bad ratio %ld, giving up!\n", + name, pci_name(dev), ratio); + goto out; + } + + f = (ratio * (r + 2)) / 1000 - 2; + + DBG("F[%d] R[%d] ratio*1000[%ld]\n", f, r, ratio); + + if (unlikely(f < 0 || f > 127)) { + /* Invalid F */ + printk(KERN_ERR "%s %s: F[%d] invalid!\n", + name, pci_name(dev), f); + goto out; + } + + pll_ctl0 = (u8) f; + pll_ctl1 = (u8) r; + + DBG("Writing pll_ctl[%02X][%02X]\n", pll_ctl0, pll_ctl1); + + outb(0x02, sec_dma_base + 0x01); + outb(pll_ctl0, sec_dma_base + 0x03); + outb(0x03, sec_dma_base + 0x01); + outb(pll_ctl1, sec_dma_base + 0x03); + + /* Wait the PLL circuit to be stable */ + mdelay(30); + +#ifdef DEBUG + /* + * Show the current clock value of PLL control register + */ + outb(0x02, sec_dma_base + 0x01); + pll_ctl0 = inb(sec_dma_base + 0x03); + outb(0x03, sec_dma_base + 0x01); + pll_ctl1 = inb(sec_dma_base + 0x03); + + DBG("pll_ctl[%02X][%02X]\n", pll_ctl0, pll_ctl1); +#endif + + out: + return 0; +} + +static struct pci_dev *pdc20270_get_dev2(struct pci_dev *dev) +{ + struct pci_dev *dev2; + + dev2 = pci_get_slot(dev->bus, PCI_DEVFN(PCI_SLOT(dev->devfn) + 1, + PCI_FUNC(dev->devfn))); + + if (dev2 && + dev2->vendor == dev->vendor && + dev2->device == dev->device) { + + if (dev2->irq != dev->irq) { + dev2->irq = dev->irq; + printk(KERN_INFO DRV_NAME " %s: PCI config space " + "interrupt fixed\n", pci_name(dev)); + } + + return dev2; + } + + return NULL; +} + +static const struct ide_port_ops pdcnew_port_ops = { + .set_pio_mode = pdcnew_set_pio_mode, + .set_dma_mode = pdcnew_set_dma_mode, + .resetproc = pdcnew_reset, + .cable_detect = pdcnew_cable_detect, +}; + +#define DECLARE_PDCNEW_DEV(udma) \ + { \ + .name = DRV_NAME, \ + .init_chipset = init_chipset_pdcnew, \ + .port_ops = &pdcnew_port_ops, \ + .host_flags = IDE_HFLAG_POST_SET_MODE | \ + IDE_HFLAG_ERROR_STOPS_FIFO | \ + IDE_HFLAG_OFF_BOARD, \ + .pio_mask = ATA_PIO4, \ + .mwdma_mask = ATA_MWDMA2, \ + .udma_mask = udma, \ + } + +static const struct ide_port_info pdcnew_chipsets[] = { + /* 0: PDC202{68,70} */ DECLARE_PDCNEW_DEV(ATA_UDMA5), + /* 1: PDC202{69,71,75,76,77} */ DECLARE_PDCNEW_DEV(ATA_UDMA6), +}; + +/** + * pdc202new_init_one - called when a pdc202xx is found + * @dev: the pdc202new device + * @id: the matching pci id + * + * Called when the PCI registration layer (or the IDE initialization) + * finds a device matching our IDE device tables. + */ + +static int pdc202new_init_one(struct pci_dev *dev, const struct pci_device_id *id) +{ + const struct ide_port_info *d = &pdcnew_chipsets[id->driver_data]; + struct pci_dev *bridge = dev->bus->self; + + if (dev->device == PCI_DEVICE_ID_PROMISE_20270 && bridge && + bridge->vendor == PCI_VENDOR_ID_DEC && + bridge->device == PCI_DEVICE_ID_DEC_21150) { + struct pci_dev *dev2; + + if (PCI_SLOT(dev->devfn) & 2) + return -ENODEV; + + dev2 = pdc20270_get_dev2(dev); + + if (dev2) { + int ret = ide_pci_init_two(dev, dev2, d, NULL); + if (ret < 0) + pci_dev_put(dev2); + return ret; + } + } + + if (dev->device == PCI_DEVICE_ID_PROMISE_20276 && bridge && + bridge->vendor == PCI_VENDOR_ID_INTEL && + (bridge->device == PCI_DEVICE_ID_INTEL_I960 || + bridge->device == PCI_DEVICE_ID_INTEL_I960RM)) { + printk(KERN_INFO DRV_NAME " %s: attached to I2O RAID controller," + " skipping\n", pci_name(dev)); + return -ENODEV; + } + + return ide_pci_init_one(dev, d, NULL); +} + +static void pdc202new_remove(struct pci_dev *dev) +{ + struct ide_host *host = pci_get_drvdata(dev); + struct pci_dev *dev2 = host->dev[1] ? to_pci_dev(host->dev[1]) : NULL; + + ide_pci_remove(dev); + pci_dev_put(dev2); +} + +static const struct pci_device_id pdc202new_pci_tbl[] = { + { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20268), 0 }, + { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20269), 1 }, + { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20270), 0 }, + { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20271), 1 }, + { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20275), 1 }, + { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20276), 1 }, + { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20277), 1 }, + { 0, }, +}; +MODULE_DEVICE_TABLE(pci, pdc202new_pci_tbl); + +static struct pci_driver pdc202new_pci_driver = { + .name = "Promise_IDE", + .id_table = pdc202new_pci_tbl, + .probe = pdc202new_init_one, + .remove = pdc202new_remove, + .suspend = ide_pci_suspend, + .resume = ide_pci_resume, +}; + +static int __init pdc202new_ide_init(void) +{ + return ide_pci_register_driver(&pdc202new_pci_driver); +} + +static void __exit pdc202new_ide_exit(void) +{ + pci_unregister_driver(&pdc202new_pci_driver); +} + +module_init(pdc202new_ide_init); +module_exit(pdc202new_ide_exit); + +MODULE_AUTHOR("Andre Hedrick, Frank Tiernan"); +MODULE_DESCRIPTION("PCI driver module for Promise PDC20268 and higher"); +MODULE_LICENSE("GPL"); diff --git a/drivers/ide/pdc202xx_old.c b/drivers/ide/pdc202xx_old.c new file mode 100644 index 00000000000..224ad46d6cb --- /dev/null +++ b/drivers/ide/pdc202xx_old.c @@ -0,0 +1,361 @@ +/* + * Copyright (C) 1998-2002 Andre Hedrick <andre@linux-ide.org> + * Copyright (C) 2006-2007, 2009 MontaVista Software, Inc. + * Copyright (C) 2007-2010 Bartlomiej Zolnierkiewicz + * + * Portions Copyright (C) 1999 Promise Technology, Inc. + * Author: Frank Tiernan (frankt@promise.com) + * Released under terms of General Public License + */ + +#include <linux/types.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/delay.h> +#include <linux/blkdev.h> +#include <linux/pci.h> +#include <linux/init.h> +#include <linux/ide.h> + +#include <asm/io.h> + +#define DRV_NAME "pdc202xx_old" + +static void pdc202xx_set_mode(ide_hwif_t *hwif, ide_drive_t *drive) +{ + struct pci_dev *dev = to_pci_dev(hwif->dev); + u8 drive_pci = 0x60 + (drive->dn << 2); + const u8 speed = drive->dma_mode; + + u8 AP = 0, BP = 0, CP = 0; + u8 TA = 0, TB = 0, TC = 0; + + pci_read_config_byte(dev, drive_pci, &AP); + pci_read_config_byte(dev, drive_pci + 1, &BP); + pci_read_config_byte(dev, drive_pci + 2, &CP); + + switch(speed) { + case XFER_UDMA_5: + case XFER_UDMA_4: TB = 0x20; TC = 0x01; break; + case XFER_UDMA_2: TB = 0x20; TC = 0x01; break; + case XFER_UDMA_3: + case XFER_UDMA_1: TB = 0x40; TC = 0x02; break; + case XFER_UDMA_0: + case XFER_MW_DMA_2: TB = 0x60; TC = 0x03; break; + case XFER_MW_DMA_1: TB = 0x60; TC = 0x04; break; + case XFER_MW_DMA_0: TB = 0xE0; TC = 0x0F; break; + case XFER_PIO_4: TA = 0x01; TB = 0x04; break; + case XFER_PIO_3: TA = 0x02; TB = 0x06; break; + case XFER_PIO_2: TA = 0x03; TB = 0x08; break; + case XFER_PIO_1: TA = 0x05; TB = 0x0C; break; + case XFER_PIO_0: + default: TA = 0x09; TB = 0x13; break; + } + + if (speed < XFER_SW_DMA_0) { + /* + * preserve SYNC_INT / ERDDY_EN bits while clearing + * Prefetch_EN / IORDY_EN / PA[3:0] bits of register A + */ + AP &= ~0x3f; + if (ide_pio_need_iordy(drive, speed - XFER_PIO_0)) + AP |= 0x20; /* set IORDY_EN bit */ + if (drive->media == ide_disk) + AP |= 0x10; /* set Prefetch_EN bit */ + /* clear PB[4:0] bits of register B */ + BP &= ~0x1f; + pci_write_config_byte(dev, drive_pci, AP | TA); + pci_write_config_byte(dev, drive_pci + 1, BP | TB); + } else { + /* clear MB[2:0] bits of register B */ + BP &= ~0xe0; + /* clear MC[3:0] bits of register C */ + CP &= ~0x0f; + pci_write_config_byte(dev, drive_pci + 1, BP | TB); + pci_write_config_byte(dev, drive_pci + 2, CP | TC); + } +} + +static void pdc202xx_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) +{ + drive->dma_mode = drive->pio_mode; + pdc202xx_set_mode(hwif, drive); +} + +static int pdc202xx_test_irq(ide_hwif_t *hwif) +{ + struct pci_dev *dev = to_pci_dev(hwif->dev); + unsigned long high_16 = pci_resource_start(dev, 4); + u8 sc1d = inb(high_16 + 0x1d); + + if (hwif->channel) { + /* + * bit 7: error, bit 6: interrupting, + * bit 5: FIFO full, bit 4: FIFO empty + */ + return (sc1d & 0x40) ? 1 : 0; + } else { + /* + * bit 3: error, bit 2: interrupting, + * bit 1: FIFO full, bit 0: FIFO empty + */ + return (sc1d & 0x04) ? 1 : 0; + } +} + +static u8 pdc2026x_cable_detect(ide_hwif_t *hwif) +{ + struct pci_dev *dev = to_pci_dev(hwif->dev); + u16 CIS, mask = hwif->channel ? (1 << 11) : (1 << 10); + + pci_read_config_word(dev, 0x50, &CIS); + + return (CIS & mask) ? ATA_CBL_PATA40 : ATA_CBL_PATA80; +} + +/* + * Set the control register to use the 66MHz system + * clock for UDMA 3/4/5 mode operation when necessary. + * + * FIXME: this register is shared by both channels, some locking is needed + * + * It may also be possible to leave the 66MHz clock on + * and readjust the timing parameters. + */ +static void pdc_old_enable_66MHz_clock(ide_hwif_t *hwif) +{ + unsigned long clock_reg = hwif->extra_base + 0x01; + u8 clock = inb(clock_reg); + + outb(clock | (hwif->channel ? 0x08 : 0x02), clock_reg); +} + +static void pdc_old_disable_66MHz_clock(ide_hwif_t *hwif) +{ + unsigned long clock_reg = hwif->extra_base + 0x01; + u8 clock = inb(clock_reg); + + outb(clock & ~(hwif->channel ? 0x08 : 0x02), clock_reg); +} + +static void pdc2026x_init_hwif(ide_hwif_t *hwif) +{ + pdc_old_disable_66MHz_clock(hwif); +} + +static void pdc202xx_dma_start(ide_drive_t *drive) +{ + if (drive->current_speed > XFER_UDMA_2) + pdc_old_enable_66MHz_clock(drive->hwif); + if (drive->media != ide_disk || (drive->dev_flags & IDE_DFLAG_LBA48)) { + ide_hwif_t *hwif = drive->hwif; + struct request *rq = hwif->rq; + unsigned long high_16 = hwif->extra_base - 16; + unsigned long atapi_reg = high_16 + (hwif->channel ? 0x24 : 0x20); + u32 word_count = 0; + u8 clock = inb(high_16 + 0x11); + + outb(clock | (hwif->channel ? 0x08 : 0x02), high_16 + 0x11); + word_count = (blk_rq_sectors(rq) << 8); + word_count = (rq_data_dir(rq) == READ) ? + word_count | 0x05000000 : + word_count | 0x06000000; + outl(word_count, atapi_reg); + } + ide_dma_start(drive); +} + +static int pdc202xx_dma_end(ide_drive_t *drive) +{ + if (drive->media != ide_disk || (drive->dev_flags & IDE_DFLAG_LBA48)) { + ide_hwif_t *hwif = drive->hwif; + unsigned long high_16 = hwif->extra_base - 16; + unsigned long atapi_reg = high_16 + (hwif->channel ? 0x24 : 0x20); + u8 clock = 0; + + outl(0, atapi_reg); /* zero out extra */ + clock = inb(high_16 + 0x11); + outb(clock & ~(hwif->channel ? 0x08:0x02), high_16 + 0x11); + } + if (drive->current_speed > XFER_UDMA_2) + pdc_old_disable_66MHz_clock(drive->hwif); + return ide_dma_end(drive); +} + +static int init_chipset_pdc202xx(struct pci_dev *dev) +{ + unsigned long dmabase = pci_resource_start(dev, 4); + u8 udma_speed_flag = 0, primary_mode = 0, secondary_mode = 0; + + if (dmabase == 0) + goto out; + + udma_speed_flag = inb(dmabase | 0x1f); + primary_mode = inb(dmabase | 0x1a); + secondary_mode = inb(dmabase | 0x1b); + printk(KERN_INFO "%s: (U)DMA Burst Bit %sABLED " \ + "Primary %s Mode " \ + "Secondary %s Mode.\n", pci_name(dev), + (udma_speed_flag & 1) ? "EN" : "DIS", + (primary_mode & 1) ? "MASTER" : "PCI", + (secondary_mode & 1) ? "MASTER" : "PCI" ); + + if (!(udma_speed_flag & 1)) { + printk(KERN_INFO "%s: FORCING BURST BIT 0x%02x->0x%02x ", + pci_name(dev), udma_speed_flag, + (udma_speed_flag|1)); + outb(udma_speed_flag | 1, dmabase | 0x1f); + printk("%sACTIVE\n", (inb(dmabase | 0x1f) & 1) ? "" : "IN"); + } +out: + return 0; +} + +static void pdc202ata4_fixup_irq(struct pci_dev *dev, const char *name) +{ + if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE) { + u8 irq = 0, irq2 = 0; + pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq); + /* 0xbc */ + pci_read_config_byte(dev, (PCI_INTERRUPT_LINE)|0x80, &irq2); + if (irq != irq2) { + pci_write_config_byte(dev, + (PCI_INTERRUPT_LINE)|0x80, irq); /* 0xbc */ + printk(KERN_INFO "%s %s: PCI config space interrupt " + "mirror fixed\n", name, pci_name(dev)); + } + } +} + +#define IDE_HFLAGS_PDC202XX \ + (IDE_HFLAG_ERROR_STOPS_FIFO | \ + IDE_HFLAG_OFF_BOARD) + +static const struct ide_port_ops pdc20246_port_ops = { + .set_pio_mode = pdc202xx_set_pio_mode, + .set_dma_mode = pdc202xx_set_mode, + .test_irq = pdc202xx_test_irq, +}; + +static const struct ide_port_ops pdc2026x_port_ops = { + .set_pio_mode = pdc202xx_set_pio_mode, + .set_dma_mode = pdc202xx_set_mode, + .test_irq = pdc202xx_test_irq, + .cable_detect = pdc2026x_cable_detect, +}; + +static const struct ide_dma_ops pdc2026x_dma_ops = { + .dma_host_set = ide_dma_host_set, + .dma_setup = ide_dma_setup, + .dma_start = pdc202xx_dma_start, + .dma_end = pdc202xx_dma_end, + .dma_test_irq = ide_dma_test_irq, + .dma_lost_irq = ide_dma_lost_irq, + .dma_timer_expiry = ide_dma_sff_timer_expiry, + .dma_sff_read_status = ide_dma_sff_read_status, +}; + +#define DECLARE_PDC2026X_DEV(udma, sectors) \ + { \ + .name = DRV_NAME, \ + .init_chipset = init_chipset_pdc202xx, \ + .init_hwif = pdc2026x_init_hwif, \ + .port_ops = &pdc2026x_port_ops, \ + .dma_ops = &pdc2026x_dma_ops, \ + .host_flags = IDE_HFLAGS_PDC202XX, \ + .pio_mask = ATA_PIO4, \ + .mwdma_mask = ATA_MWDMA2, \ + .udma_mask = udma, \ + .max_sectors = sectors, \ + } + +static const struct ide_port_info pdc202xx_chipsets[] = { + { /* 0: PDC20246 */ + .name = DRV_NAME, + .init_chipset = init_chipset_pdc202xx, + .port_ops = &pdc20246_port_ops, + .dma_ops = &sff_dma_ops, + .host_flags = IDE_HFLAGS_PDC202XX, + .pio_mask = ATA_PIO4, + .mwdma_mask = ATA_MWDMA2, + .udma_mask = ATA_UDMA2, + }, + + /* 1: PDC2026{2,3} */ + DECLARE_PDC2026X_DEV(ATA_UDMA4, 0), + /* 2: PDC2026{5,7}: UDMA5, limit LBA48 requests to 256 sectors */ + DECLARE_PDC2026X_DEV(ATA_UDMA5, 256), +}; + +/** + * pdc202xx_init_one - called when a PDC202xx is found + * @dev: the pdc202xx device + * @id: the matching pci id + * + * Called when the PCI registration layer (or the IDE initialization) + * finds a device matching our IDE device tables. + */ + +static int pdc202xx_init_one(struct pci_dev *dev, + const struct pci_device_id *id) +{ + const struct ide_port_info *d; + u8 idx = id->driver_data; + + d = &pdc202xx_chipsets[idx]; + + if (idx < 2) + pdc202ata4_fixup_irq(dev, d->name); + + if (dev->vendor == PCI_DEVICE_ID_PROMISE_20265) { + struct pci_dev *bridge = dev->bus->self; + + if (bridge && + bridge->vendor == PCI_VENDOR_ID_INTEL && + (bridge->device == PCI_DEVICE_ID_INTEL_I960 || + bridge->device == PCI_DEVICE_ID_INTEL_I960RM)) { + printk(KERN_INFO DRV_NAME " %s: skipping Promise " + "PDC20265 attached to I2O RAID controller\n", + pci_name(dev)); + return -ENODEV; + } + } + + return ide_pci_init_one(dev, d, NULL); +} + +static const struct pci_device_id pdc202xx_pci_tbl[] = { + { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20246), 0 }, + { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20262), 1 }, + { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20263), 1 }, + { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20265), 2 }, + { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20267), 2 }, + { 0, }, +}; +MODULE_DEVICE_TABLE(pci, pdc202xx_pci_tbl); + +static struct pci_driver pdc202xx_pci_driver = { + .name = "Promise_Old_IDE", + .id_table = pdc202xx_pci_tbl, + .probe = pdc202xx_init_one, + .remove = ide_pci_remove, + .suspend = ide_pci_suspend, + .resume = ide_pci_resume, +}; + +static int __init pdc202xx_ide_init(void) +{ + return ide_pci_register_driver(&pdc202xx_pci_driver); +} + +static void __exit pdc202xx_ide_exit(void) +{ + pci_unregister_driver(&pdc202xx_pci_driver); +} + +module_init(pdc202xx_ide_init); +module_exit(pdc202xx_ide_exit); + +MODULE_AUTHOR("Andre Hedrick, Frank Tiernan, Bartlomiej Zolnierkiewicz"); +MODULE_DESCRIPTION("PCI driver module for older Promise IDE"); +MODULE_LICENSE("GPL"); diff --git a/drivers/ide/piix.c b/drivers/ide/piix.c new file mode 100644 index 00000000000..a671cead6ae --- /dev/null +++ b/drivers/ide/piix.c @@ -0,0 +1,476 @@ +/* + * Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer + * Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org> + * Copyright (C) 2003 Red Hat + * Copyright (C) 2006-2007 MontaVista Software, Inc. <source@mvista.com> + * + * May be copied or modified under the terms of the GNU General Public License + * + * Documentation: + * + * Publicly available from Intel web site. Errata documentation + * is also publicly available. As an aide to anyone hacking on this + * driver the list of errata that are relevant is below.going back to + * PIIX4. Older device documentation is now a bit tricky to find. + * + * Errata of note: + * + * Unfixable + * PIIX4 errata #9 - Only on ultra obscure hw + * ICH3 errata #13 - Not observed to affect real hw + * by Intel + * + * Things we must deal with + * PIIX4 errata #10 - BM IDE hang with non UDMA + * (must stop/start dma to recover) + * 440MX errata #15 - As PIIX4 errata #10 + * PIIX4 errata #15 - Must not read control registers + * during a PIO transfer + * 440MX errata #13 - As PIIX4 errata #15 + * ICH2 errata #21 - DMA mode 0 doesn't work right + * ICH0/1 errata #55 - As ICH2 errata #21 + * ICH2 spec c #9 - Extra operations needed to handle + * drive hotswap [NOT YET SUPPORTED] + * ICH2 spec c #20 - IDE PRD must not cross a 64K boundary + * and must be dword aligned + * ICH2 spec c #24 - UDMA mode 4,5 t85/86 should be 6ns not 3.3 + * + * Should have been BIOS fixed: + * 450NX: errata #19 - DMA hangs on old 450NX + * 450NX: errata #20 - DMA hangs on old 450NX + * 450NX: errata #25 - Corruption with DMA on old 450NX + * ICH3 errata #15 - IDE deadlock under high load + * (BIOS must set dev 31 fn 0 bit 23) + * ICH3 errata #18 - Don't use native mode + */ + +#include <linux/types.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/pci.h> +#include <linux/ide.h> +#include <linux/init.h> + +#include <asm/io.h> + +#define DRV_NAME "piix" + +static int no_piix_dma; + +/** + * piix_set_pio_mode - set host controller for PIO mode + * @port: port + * @drive: drive + * + * Set the interface PIO mode based upon the settings done by AMI BIOS. + */ + +static void piix_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) +{ + struct pci_dev *dev = to_pci_dev(hwif->dev); + int is_slave = drive->dn & 1; + int master_port = hwif->channel ? 0x42 : 0x40; + int slave_port = 0x44; + unsigned long flags; + u16 master_data; + u8 slave_data; + static DEFINE_SPINLOCK(tune_lock); + int control = 0; + const u8 pio = drive->pio_mode - XFER_PIO_0; + + /* ISP RTC */ + static const u8 timings[][2]= { + { 0, 0 }, + { 0, 0 }, + { 1, 0 }, + { 2, 1 }, + { 2, 3 }, }; + + /* + * Master vs slave is synchronized above us but the slave register is + * shared by the two hwifs so the corner case of two slave timeouts in + * parallel must be locked. + */ + spin_lock_irqsave(&tune_lock, flags); + pci_read_config_word(dev, master_port, &master_data); + + if (pio > 1) + control |= 1; /* Programmable timing on */ + if (drive->media == ide_disk) + control |= 4; /* Prefetch, post write */ + if (ide_pio_need_iordy(drive, pio)) + control |= 2; /* IORDY */ + if (is_slave) { + master_data |= 0x4000; + master_data &= ~0x0070; + if (pio > 1) { + /* Set PPE, IE and TIME */ + master_data |= control << 4; + } + pci_read_config_byte(dev, slave_port, &slave_data); + slave_data &= hwif->channel ? 0x0f : 0xf0; + slave_data |= ((timings[pio][0] << 2) | timings[pio][1]) << + (hwif->channel ? 4 : 0); + } else { + master_data &= ~0x3307; + if (pio > 1) { + /* enable PPE, IE and TIME */ + master_data |= control; + } + master_data |= (timings[pio][0] << 12) | (timings[pio][1] << 8); + } + pci_write_config_word(dev, master_port, master_data); + if (is_slave) + pci_write_config_byte(dev, slave_port, slave_data); + spin_unlock_irqrestore(&tune_lock, flags); +} + +/** + * piix_set_dma_mode - set host controller for DMA mode + * @hwif: port + * @drive: drive + * + * Set a PIIX host controller to the desired DMA mode. This involves + * programming the right timing data into the PCI configuration space. + */ + +static void piix_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive) +{ + struct pci_dev *dev = to_pci_dev(hwif->dev); + u8 maslave = hwif->channel ? 0x42 : 0x40; + int a_speed = 3 << (drive->dn * 4); + int u_flag = 1 << drive->dn; + int v_flag = 0x01 << drive->dn; + int w_flag = 0x10 << drive->dn; + int u_speed = 0; + int sitre; + u16 reg4042, reg4a; + u8 reg48, reg54, reg55; + const u8 speed = drive->dma_mode; + + pci_read_config_word(dev, maslave, ®4042); + sitre = (reg4042 & 0x4000) ? 1 : 0; + pci_read_config_byte(dev, 0x48, ®48); + pci_read_config_word(dev, 0x4a, ®4a); + pci_read_config_byte(dev, 0x54, ®54); + pci_read_config_byte(dev, 0x55, ®55); + + if (speed >= XFER_UDMA_0) { + u8 udma = speed - XFER_UDMA_0; + + u_speed = min_t(u8, 2 - (udma & 1), udma) << (drive->dn * 4); + + if (!(reg48 & u_flag)) + pci_write_config_byte(dev, 0x48, reg48 | u_flag); + if (speed == XFER_UDMA_5) { + pci_write_config_byte(dev, 0x55, (u8) reg55|w_flag); + } else { + pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag); + } + if ((reg4a & a_speed) != u_speed) + pci_write_config_word(dev, 0x4a, (reg4a & ~a_speed) | u_speed); + if (speed > XFER_UDMA_2) { + if (!(reg54 & v_flag)) + pci_write_config_byte(dev, 0x54, reg54 | v_flag); + } else + pci_write_config_byte(dev, 0x54, reg54 & ~v_flag); + } else { + const u8 mwdma_to_pio[] = { 0, 3, 4 }; + + if (reg48 & u_flag) + pci_write_config_byte(dev, 0x48, reg48 & ~u_flag); + if (reg4a & a_speed) + pci_write_config_word(dev, 0x4a, reg4a & ~a_speed); + if (reg54 & v_flag) + pci_write_config_byte(dev, 0x54, reg54 & ~v_flag); + if (reg55 & w_flag) + pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag); + + if (speed >= XFER_MW_DMA_0) + drive->pio_mode = + mwdma_to_pio[speed - XFER_MW_DMA_0] + XFER_PIO_0; + else + drive->pio_mode = XFER_PIO_2; /* for SWDMA2 */ + + piix_set_pio_mode(hwif, drive); + } +} + +/** + * init_chipset_ich - set up the ICH chipset + * @dev: PCI device to set up + * + * Initialize the PCI device as required. For the ICH this turns + * out to be nice and simple. + */ + +static int init_chipset_ich(struct pci_dev *dev) +{ + u32 extra = 0; + + pci_read_config_dword(dev, 0x54, &extra); + pci_write_config_dword(dev, 0x54, extra | 0x400); + + return 0; +} + +/** + * ich_clear_irq - clear BMDMA status + * @drive: IDE drive + * + * ICHx contollers set DMA INTR no matter DMA or PIO. + * BMDMA status might need to be cleared even for + * PIO interrupts to prevent spurious/lost IRQ. + */ +static void ich_clear_irq(ide_drive_t *drive) +{ + ide_hwif_t *hwif = drive->hwif; + u8 dma_stat; + + /* + * ide_dma_end() needs BMDMA status for error checking. + * So, skip clearing BMDMA status here and leave it + * to ide_dma_end() if this is DMA interrupt. + */ + if (drive->waiting_for_dma || hwif->dma_base == 0) + return; + + /* clear the INTR & ERROR bits */ + dma_stat = inb(hwif->dma_base + ATA_DMA_STATUS); + /* Should we force the bit as well ? */ + outb(dma_stat, hwif->dma_base + ATA_DMA_STATUS); +} + +struct ich_laptop { + u16 device; + u16 subvendor; + u16 subdevice; +}; + +/* + * List of laptops that use short cables rather than 80 wire + */ + +static const struct ich_laptop ich_laptop[] = { + /* devid, subvendor, subdev */ + { 0x27DF, 0x1025, 0x0102 }, /* ICH7 on Acer 5602aWLMi */ + { 0x27DF, 0x0005, 0x0280 }, /* ICH7 on Acer 5602WLMi */ + { 0x27DF, 0x1025, 0x0110 }, /* ICH7 on Acer 3682WLMi */ + { 0x27DF, 0x1043, 0x1267 }, /* ICH7 on Asus W5F */ + { 0x27DF, 0x103C, 0x30A1 }, /* ICH7 on HP Compaq nc2400 */ + { 0x27DF, 0x1071, 0xD221 }, /* ICH7 on Hercules EC-900 */ + { 0x24CA, 0x1025, 0x0061 }, /* ICH4 on Acer Aspire 2023WLMi */ + { 0x24CA, 0x1025, 0x003d }, /* ICH4 on ACER TM290 */ + { 0x266F, 0x1025, 0x0066 }, /* ICH6 on ACER Aspire 1694WLMi */ + { 0x2653, 0x1043, 0x82D8 }, /* ICH6M on Asus Eee 701 */ + { 0x27df, 0x104d, 0x900e }, /* ICH7 on Sony TZ-90 */ + /* end marker */ + { 0, } +}; + +static u8 piix_cable_detect(ide_hwif_t *hwif) +{ + struct pci_dev *pdev = to_pci_dev(hwif->dev); + const struct ich_laptop *lap = &ich_laptop[0]; + u8 reg54h = 0, mask = hwif->channel ? 0xc0 : 0x30; + + /* check for specials */ + while (lap->device) { + if (lap->device == pdev->device && + lap->subvendor == pdev->subsystem_vendor && + lap->subdevice == pdev->subsystem_device) { + return ATA_CBL_PATA40_SHORT; + } + lap++; + } + + pci_read_config_byte(pdev, 0x54, ®54h); + + return (reg54h & mask) ? ATA_CBL_PATA80 : ATA_CBL_PATA40; +} + +/** + * init_hwif_piix - fill in the hwif for the PIIX + * @hwif: IDE interface + * + * Set up the ide_hwif_t for the PIIX interface according to the + * capabilities of the hardware. + */ + +static void init_hwif_piix(ide_hwif_t *hwif) +{ + if (!hwif->dma_base) + return; + + if (no_piix_dma) + hwif->ultra_mask = hwif->mwdma_mask = hwif->swdma_mask = 0; +} + +static const struct ide_port_ops piix_port_ops = { + .set_pio_mode = piix_set_pio_mode, + .set_dma_mode = piix_set_dma_mode, + .cable_detect = piix_cable_detect, +}; + +static const struct ide_port_ops ich_port_ops = { + .set_pio_mode = piix_set_pio_mode, + .set_dma_mode = piix_set_dma_mode, + .clear_irq = ich_clear_irq, + .cable_detect = piix_cable_detect, +}; + +#define DECLARE_PIIX_DEV(udma) \ + { \ + .name = DRV_NAME, \ + .init_hwif = init_hwif_piix, \ + .enablebits = {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, \ + .port_ops = &piix_port_ops, \ + .pio_mask = ATA_PIO4, \ + .swdma_mask = ATA_SWDMA2_ONLY, \ + .mwdma_mask = ATA_MWDMA12_ONLY, \ + .udma_mask = udma, \ + } + +#define DECLARE_ICH_DEV(mwdma, udma) \ + { \ + .name = DRV_NAME, \ + .init_chipset = init_chipset_ich, \ + .init_hwif = init_hwif_piix, \ + .enablebits = {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, \ + .port_ops = &ich_port_ops, \ + .pio_mask = ATA_PIO4, \ + .swdma_mask = ATA_SWDMA2_ONLY, \ + .mwdma_mask = mwdma, \ + .udma_mask = udma, \ + } + +static const struct ide_port_info piix_pci_info[] = { + /* 0: MPIIX */ + { /* + * MPIIX actually has only a single IDE channel mapped to + * the primary or secondary ports depending on the value + * of the bit 14 of the IDETIM register at offset 0x6c + */ + .name = DRV_NAME, + .enablebits = {{0x6d,0xc0,0x80}, {0x6d,0xc0,0xc0}}, + .host_flags = IDE_HFLAG_ISA_PORTS | IDE_HFLAG_NO_DMA, + .pio_mask = ATA_PIO4, + /* This is a painful system best to let it self tune for now */ + }, + /* 1: PIIXa/PIIXb/PIIX3 */ + DECLARE_PIIX_DEV(0x00), /* no udma */ + /* 2: PIIX4 */ + DECLARE_PIIX_DEV(ATA_UDMA2), + /* 3: ICH0 */ + DECLARE_ICH_DEV(ATA_MWDMA12_ONLY, ATA_UDMA2), + /* 4: ICH */ + DECLARE_ICH_DEV(ATA_MWDMA12_ONLY, ATA_UDMA4), + /* 5: PIIX4 */ + DECLARE_PIIX_DEV(ATA_UDMA4), + /* 6: ICH[2-6]/ICH[2-3]M/C-ICH/ICH5-SATA/ESB2/ICH8M */ + DECLARE_ICH_DEV(ATA_MWDMA12_ONLY, ATA_UDMA5), + /* 7: ICH7/7-R, no MWDMA1 */ + DECLARE_ICH_DEV(ATA_MWDMA2_ONLY, ATA_UDMA5), +}; + +/** + * piix_init_one - called when a PIIX is found + * @dev: the piix device + * @id: the matching pci id + * + * Called when the PCI registration layer (or the IDE initialization) + * finds a device matching our IDE device tables. + */ + +static int piix_init_one(struct pci_dev *dev, const struct pci_device_id *id) +{ + return ide_pci_init_one(dev, &piix_pci_info[id->driver_data], NULL); +} + +/** + * piix_check_450nx - Check for problem 450NX setup + * + * Check for the present of 450NX errata #19 and errata #25. If + * they are found, disable use of DMA IDE + */ + +static void piix_check_450nx(void) +{ + struct pci_dev *pdev = NULL; + u16 cfg; + while((pdev=pci_get_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454NX, pdev))!=NULL) + { + /* Look for 450NX PXB. Check for problem configurations + A PCI quirk checks bit 6 already */ + pci_read_config_word(pdev, 0x41, &cfg); + /* Only on the original revision: IDE DMA can hang */ + if (pdev->revision == 0x00) + no_piix_dma = 1; + /* On all revisions below 5 PXB bus lock must be disabled for IDE */ + else if (cfg & (1<<14) && pdev->revision < 5) + no_piix_dma = 2; + } + if(no_piix_dma) + printk(KERN_WARNING DRV_NAME ": 450NX errata present, disabling IDE DMA.\n"); + if(no_piix_dma == 2) + printk(KERN_WARNING DRV_NAME ": A BIOS update may resolve this.\n"); +} + +static const struct pci_device_id piix_pci_tbl[] = { + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82371FB_0), 1 }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82371FB_1), 1 }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82371MX), 0 }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82371SB_1), 1 }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82371AB), 2 }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801AB_1), 3 }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82443MX_1), 2 }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801AA_1), 4 }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82372FB_1), 5 }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82451NX), 2 }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801BA_9), 6 }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801BA_8), 6 }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801CA_10), 6 }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801CA_11), 6 }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801DB_11), 6 }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801EB_11), 6 }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801E_11), 6 }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801DB_10), 6 }, +#ifdef CONFIG_BLK_DEV_IDE_SATA + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801EB_1), 6 }, +#endif + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ESB_2), 6 }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ICH6_19), 6 }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ICH7_21), 7 }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801DB_1), 6 }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ESB2_18), 7 }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ICH8_6), 6 }, + { 0, }, +}; +MODULE_DEVICE_TABLE(pci, piix_pci_tbl); + +static struct pci_driver piix_pci_driver = { + .name = "PIIX_IDE", + .id_table = piix_pci_tbl, + .probe = piix_init_one, + .remove = ide_pci_remove, + .suspend = ide_pci_suspend, + .resume = ide_pci_resume, +}; + +static int __init piix_ide_init(void) +{ + piix_check_450nx(); + return ide_pci_register_driver(&piix_pci_driver); +} + +static void __exit piix_ide_exit(void) +{ + pci_unregister_driver(&piix_pci_driver); +} + +module_init(piix_ide_init); +module_exit(piix_ide_exit); + +MODULE_AUTHOR("Andre Hedrick, Andrzej Krzysztofowicz"); +MODULE_DESCRIPTION("PCI driver module for Intel PIIX IDE"); +MODULE_LICENSE("GPL"); diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/pmac.c index 31ad79f52df..2db803cd095 100644 --- a/drivers/ide/ppc/pmac.c +++ b/drivers/ide/pmac.c @@ -1,11 +1,11 @@ /* - * linux/drivers/ide/ide-pmac.c - * * Support for IDE interfaces on PowerMacs. + * * These IDE interfaces are memory-mapped and have a DBDMA channel * for doing DMA. * * Copyright (C) 1998-2003 Paul Mackerras & Ben. Herrenschmidt + * Copyright (C) 2007-2008 Bartlomiej Zolnierkiewicz * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -24,16 +24,17 @@ */ #include <linux/types.h> #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/init.h> #include <linux/delay.h> #include <linux/ide.h> #include <linux/notifier.h> +#include <linux/module.h> #include <linux/reboot.h> #include <linux/pci.h> #include <linux/adb.h> #include <linux/pmu.h> #include <linux/scatterlist.h> +#include <linux/slab.h> #include <asm/prom.h> #include <asm/io.h> @@ -44,12 +45,9 @@ #include <asm/pmac_feature.h> #include <asm/sections.h> #include <asm/irq.h> - -#ifndef CONFIG_PPC64 #include <asm/mediabay.h> -#endif -#include "ide-timing.h" +#define DRV_NAME "ide-pmac" #undef IDE_PMAC_DEBUG @@ -60,15 +58,14 @@ typedef struct pmac_ide_hwif { int irq; int kind; int aapl_bus_id; - unsigned cable_80 : 1; - unsigned mediabay : 1; unsigned broken_dma : 1; unsigned broken_dma_warn : 1; struct device_node* node; struct macio_dev *mdev; u32 timings[4]; volatile u32 __iomem * *kauai_fcr; -#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC + ide_hwif_t *hwif; + /* Those fields are duplicating what is in hwif. We currently * can't use the hwif ones because of some assumptions that are * beeing done by the generic code about the kind of dma controller @@ -76,13 +73,8 @@ typedef struct pmac_ide_hwif { */ volatile struct dbdma_regs __iomem * dma_regs; struct dbdma_cmd* dma_table_cpu; -#endif - } pmac_ide_hwif_t; -static pmac_ide_hwif_t pmac_ide[MAX_HWIFS]; -static int pmac_ide_count; - enum { controller_ohare, /* OHare based */ controller_heathrow, /* Heathrow/Paddington */ @@ -227,8 +219,6 @@ static const char* model_name[] = { #define KAUAI_FCR_UATA_RESET_N 0x00000002 #define KAUAI_FCR_UATA_ENABLE 0x00000001 -#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC - /* Rounded Multiword DMA timings * * I gave up finding a generic formula for all controller @@ -312,7 +302,8 @@ static struct kauai_timing kauai_pio_timings[] = { 240 , 0x0800038b }, { 239 , 0x0800030c }, { 180 , 0x05000249 }, - { 120 , 0x04000148 } + { 120 , 0x04000148 }, + { 0 , 0 }, }; static struct kauai_timing kauai_mdma_timings[] = @@ -352,7 +343,8 @@ static struct kauai_timing shasta_pio_timings[] = { 240 , 0x040003cd }, { 239 , 0x040003cd }, { 180 , 0x0400028b }, - { 120 , 0x0400010a } + { 120 , 0x0400010a }, + { 0 , 0 }, }; static struct kauai_timing shasta_mdma_timings[] = @@ -390,6 +382,7 @@ kauai_lookup_timing(struct kauai_timing* table, int cycle_time) for (i=0; table[i].cycle_time; i++) if (cycle_time > table[i+1].cycle_time) return table[i].timing_reg; + BUG(); return 0; } @@ -410,67 +403,22 @@ kauai_lookup_timing(struct kauai_timing* table, int cycle_time) */ #define IDE_WAKEUP_DELAY (1*HZ) -static void pmac_ide_setup_dma(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif); -static int pmac_ide_build_dmatable(ide_drive_t *drive, struct request *rq); -static int pmac_ide_tune_chipset(ide_drive_t *drive, u8 speed); -static void pmac_ide_tuneproc(ide_drive_t *drive, u8 pio); -static void pmac_ide_selectproc(ide_drive_t *drive); -static void pmac_ide_kauai_selectproc(ide_drive_t *drive); +static int pmac_ide_init_dma(ide_hwif_t *, const struct ide_port_info *); -#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */ - -/* - * N.B. this can't be an initfunc, because the media-bay task can - * call ide_[un]register at any time. - */ -void -pmac_ide_init_hwif_ports(hw_regs_t *hw, - unsigned long data_port, unsigned long ctrl_port, - int *irq) -{ - int i, ix; - - if (data_port == 0) - return; - - for (ix = 0; ix < MAX_HWIFS; ++ix) - if (data_port == pmac_ide[ix].regbase) - break; - - if (ix >= MAX_HWIFS) { - /* Probably a PCI interface... */ - for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; ++i) - hw->io_ports[i] = data_port + i - IDE_DATA_OFFSET; - hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port; - return; - } - - for (i = 0; i < 8; ++i) - hw->io_ports[i] = data_port + i * 0x10; - hw->io_ports[8] = data_port + 0x160; - - if (irq != NULL) - *irq = pmac_ide[ix].irq; - - hw->dev = &pmac_ide[ix].mdev->ofdev.dev; -} - -#define PMAC_IDE_REG(x) ((void __iomem *)(IDE_DATA_REG+(x))) +#define PMAC_IDE_REG(x) \ + ((void __iomem *)((drive)->hwif->io_ports.data_addr + (x))) /* * Apply the timings of the proper unit (master/slave) to the shared * timing register when selecting that unit. This version is for * ASICs with a single timing register */ -static void -pmac_ide_selectproc(ide_drive_t *drive) +static void pmac_ide_apply_timings(ide_drive_t *drive) { - pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data; - - if (pmif == NULL) - return; + ide_hwif_t *hwif = drive->hwif; + pmac_ide_hwif_t *pmif = dev_get_drvdata(hwif->gendev.parent); - if (drive->select.b.unit & 0x01) + if (drive->dn & 1) writel(pmif->timings[1], PMAC_IDE_REG(IDE_TIMING_CONFIG)); else writel(pmif->timings[0], PMAC_IDE_REG(IDE_TIMING_CONFIG)); @@ -482,15 +430,12 @@ pmac_ide_selectproc(ide_drive_t *drive) * timing register when selecting that unit. This version is for * ASICs with a dual timing register (Kauai) */ -static void -pmac_ide_kauai_selectproc(ide_drive_t *drive) +static void pmac_ide_kauai_apply_timings(ide_drive_t *drive) { - pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data; - - if (pmif == NULL) - return; + ide_hwif_t *hwif = drive->hwif; + pmac_ide_hwif_t *pmif = dev_get_drvdata(hwif->gendev.parent); - if (drive->select.b.unit & 0x01) { + if (drive->dn & 1) { writel(pmif->timings[1], PMAC_IDE_REG(IDE_KAUAI_PIO_CONFIG)); writel(pmif->timings[3], PMAC_IDE_REG(IDE_KAUAI_ULTRA_CONFIG)); } else { @@ -506,170 +451,100 @@ pmac_ide_kauai_selectproc(ide_drive_t *drive) static void pmac_ide_do_update_timings(ide_drive_t *drive) { - pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data; - - if (pmif == NULL) - return; + ide_hwif_t *hwif = drive->hwif; + pmac_ide_hwif_t *pmif = dev_get_drvdata(hwif->gendev.parent); if (pmif->kind == controller_sh_ata6 || pmif->kind == controller_un_ata6 || pmif->kind == controller_k2_ata6) - pmac_ide_kauai_selectproc(drive); + pmac_ide_kauai_apply_timings(drive); else - pmac_ide_selectproc(drive); + pmac_ide_apply_timings(drive); } -static void -pmac_outbsync(ide_drive_t *drive, u8 value, unsigned long port) +static void pmac_dev_select(ide_drive_t *drive) { - u32 tmp; - - writeb(value, (void __iomem *) port); - tmp = readl(PMAC_IDE_REG(IDE_TIMING_CONFIG)); + pmac_ide_apply_timings(drive); + + writeb(drive->select | ATA_DEVICE_OBS, + (void __iomem *)drive->hwif->io_ports.device_addr); } -/* - * Send the SET_FEATURE IDE command to the drive and update drive->id with - * the new state. We currently don't use the generic routine as it used to - * cause various trouble, especially with older mediabays. - * This code is sometimes triggering a spurrious interrupt though, I need - * to sort that out sooner or later and see if I can finally get the - * common version to work properly in all cases - */ -static int -pmac_ide_do_setfeature(ide_drive_t *drive, u8 command) +static void pmac_kauai_dev_select(ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); - int result = 1; - - disable_irq_nosync(hwif->irq); - udelay(1); - SELECT_DRIVE(drive); - SELECT_MASK(drive, 0); - udelay(1); - /* Get rid of pending error state */ - (void) hwif->INB(IDE_STATUS_REG); - /* Timeout bumped for some powerbooks */ - if (wait_for_ready(drive, 2000)) { - /* Timeout bumped for some powerbooks */ - printk(KERN_ERR "%s: pmac_ide_do_setfeature disk not ready " - "before SET_FEATURE!\n", drive->name); - goto out; - } - udelay(10); - hwif->OUTB(drive->ctl | 2, IDE_CONTROL_REG); - hwif->OUTB(command, IDE_NSECTOR_REG); - hwif->OUTB(SETFEATURES_XFER, IDE_FEATURE_REG); - hwif->OUTBSYNC(drive, WIN_SETFEATURES, IDE_COMMAND_REG); - udelay(1); - /* Timeout bumped for some powerbooks */ - result = wait_for_ready(drive, 2000); - hwif->OUTB(drive->ctl, IDE_CONTROL_REG); - if (result) - printk(KERN_ERR "%s: pmac_ide_do_setfeature disk not ready " - "after SET_FEATURE !\n", drive->name); -out: - SELECT_MASK(drive, 0); - if (result == 0) { - drive->id->dma_ultra &= ~0xFF00; - drive->id->dma_mword &= ~0x0F00; - drive->id->dma_1word &= ~0x0F00; - switch(command) { - case XFER_UDMA_7: - drive->id->dma_ultra |= 0x8080; break; - case XFER_UDMA_6: - drive->id->dma_ultra |= 0x4040; break; - case XFER_UDMA_5: - drive->id->dma_ultra |= 0x2020; break; - case XFER_UDMA_4: - drive->id->dma_ultra |= 0x1010; break; - case XFER_UDMA_3: - drive->id->dma_ultra |= 0x0808; break; - case XFER_UDMA_2: - drive->id->dma_ultra |= 0x0404; break; - case XFER_UDMA_1: - drive->id->dma_ultra |= 0x0202; break; - case XFER_UDMA_0: - drive->id->dma_ultra |= 0x0101; break; - case XFER_MW_DMA_2: - drive->id->dma_mword |= 0x0404; break; - case XFER_MW_DMA_1: - drive->id->dma_mword |= 0x0202; break; - case XFER_MW_DMA_0: - drive->id->dma_mword |= 0x0101; break; - case XFER_SW_DMA_2: - drive->id->dma_1word |= 0x0404; break; - case XFER_SW_DMA_1: - drive->id->dma_1word |= 0x0202; break; - case XFER_SW_DMA_0: - drive->id->dma_1word |= 0x0101; break; - default: break; - } - } - enable_irq(hwif->irq); - return result; + pmac_ide_kauai_apply_timings(drive); + + writeb(drive->select | ATA_DEVICE_OBS, + (void __iomem *)drive->hwif->io_ports.device_addr); +} + +static void pmac_exec_command(ide_hwif_t *hwif, u8 cmd) +{ + writeb(cmd, (void __iomem *)hwif->io_ports.command_addr); + (void)readl((void __iomem *)(hwif->io_ports.data_addr + + IDE_TIMING_CONFIG)); +} + +static void pmac_write_devctl(ide_hwif_t *hwif, u8 ctl) +{ + writeb(ctl, (void __iomem *)hwif->io_ports.ctl_addr); + (void)readl((void __iomem *)(hwif->io_ports.data_addr + + IDE_TIMING_CONFIG)); } /* * Old tuning functions (called on hdparm -p), sets up drive PIO timings */ -static void -pmac_ide_tuneproc(ide_drive_t *drive, u8 pio) +static void pmac_ide_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) { - ide_pio_data_t d; - u32 *timings; + pmac_ide_hwif_t *pmif = dev_get_drvdata(hwif->gendev.parent); + const u8 pio = drive->pio_mode - XFER_PIO_0; + struct ide_timing *tim = ide_timing_find_mode(XFER_PIO_0 + pio); + u32 *timings, t; unsigned accessTicks, recTicks; unsigned accessTime, recTime; - pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data; - - if (pmif == NULL) - return; - + unsigned int cycle_time; + /* which drive is it ? */ - timings = &pmif->timings[drive->select.b.unit & 0x01]; + timings = &pmif->timings[drive->dn & 1]; + t = *timings; - pio = ide_get_best_pio_mode(drive, pio, 4, &d); + cycle_time = ide_pio_cycle_time(drive, pio); switch (pmif->kind) { case controller_sh_ata6: { /* 133Mhz cell */ - u32 tr = kauai_lookup_timing(shasta_pio_timings, d.cycle_time); - if (tr == 0) - return; - *timings = ((*timings) & ~TR_133_PIOREG_PIO_MASK) | tr; + u32 tr = kauai_lookup_timing(shasta_pio_timings, cycle_time); + t = (t & ~TR_133_PIOREG_PIO_MASK) | tr; break; } case controller_un_ata6: case controller_k2_ata6: { /* 100Mhz cell */ - u32 tr = kauai_lookup_timing(kauai_pio_timings, d.cycle_time); - if (tr == 0) - return; - *timings = ((*timings) & ~TR_100_PIOREG_PIO_MASK) | tr; + u32 tr = kauai_lookup_timing(kauai_pio_timings, cycle_time); + t = (t & ~TR_100_PIOREG_PIO_MASK) | tr; break; } case controller_kl_ata4: /* 66Mhz cell */ - recTime = d.cycle_time - ide_pio_timings[pio].active_time - - ide_pio_timings[pio].setup_time; + recTime = cycle_time - tim->active - tim->setup; recTime = max(recTime, 150U); - accessTime = ide_pio_timings[pio].active_time; + accessTime = tim->active; accessTime = max(accessTime, 150U); accessTicks = SYSCLK_TICKS_66(accessTime); accessTicks = min(accessTicks, 0x1fU); recTicks = SYSCLK_TICKS_66(recTime); recTicks = min(recTicks, 0x1fU); - *timings = ((*timings) & ~TR_66_PIO_MASK) | - (accessTicks << TR_66_PIO_ACCESS_SHIFT) | - (recTicks << TR_66_PIO_RECOVERY_SHIFT); + t = (t & ~TR_66_PIO_MASK) | + (accessTicks << TR_66_PIO_ACCESS_SHIFT) | + (recTicks << TR_66_PIO_RECOVERY_SHIFT); break; default: { /* 33Mhz cell */ int ebit = 0; - recTime = d.cycle_time - ide_pio_timings[pio].active_time - - ide_pio_timings[pio].setup_time; + recTime = cycle_time - tim->active - tim->setup; recTime = max(recTime, 150U); - accessTime = ide_pio_timings[pio].active_time; + accessTime = tim->active; accessTime = max(accessTime, 150U); accessTicks = SYSCLK_TICKS(accessTime); accessTicks = min(accessTicks, 0x1fU); @@ -681,11 +556,11 @@ pmac_ide_tuneproc(ide_drive_t *drive, u8 pio) recTicks--; /* guess, but it's only for PIO0, so... */ ebit = 1; } - *timings = ((*timings) & ~TR_33_PIO_MASK) | + t = (t & ~TR_33_PIO_MASK) | (accessTicks << TR_33_PIO_ACCESS_SHIFT) | (recTicks << TR_33_PIO_RECOVERY_SHIFT); if (ebit) - *timings |= TR_33_PIO_E; + t |= TR_33_PIO_E; break; } } @@ -695,12 +570,10 @@ pmac_ide_tuneproc(ide_drive_t *drive, u8 pio) drive->name, pio, *timings); #endif - if (drive->select.all == HWIF(drive)->INB(IDE_SELECT_REG)) - pmac_ide_do_update_timings(drive); + *timings = t; + pmac_ide_do_update_timings(drive); } -#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC - /* * Calculate KeyLargo ATA/66 UDMA timings */ @@ -741,8 +614,6 @@ set_timings_udma_ata6(u32 *pio_timings, u32 *ultra_timings, u8 speed) if (speed > XFER_UDMA_5 || t == NULL) return 1; tr = kauai_lookup_timing(kauai_udma_timings, (int)t->udma); - if (tr == 0) - return 1; *ultra_timings = ((*ultra_timings) & ~TR_100_UDMAREG_UDMA_MASK) | tr; *ultra_timings = (*ultra_timings) | TR_100_UDMAREG_UDMA_EN; @@ -761,8 +632,6 @@ set_timings_udma_shasta(u32 *pio_timings, u32 *ultra_timings, u8 speed) if (speed > XFER_UDMA_6 || t == NULL) return 1; tr = kauai_lookup_timing(shasta_udma133_timings, (int)t->udma); - if (tr == 0) - return 1; *ultra_timings = ((*ultra_timings) & ~TR_133_UDMAREG_UDMA_MASK) | tr; *ultra_timings = (*ultra_timings) | TR_133_UDMAREG_UDMA_EN; @@ -772,10 +641,11 @@ set_timings_udma_shasta(u32 *pio_timings, u32 *ultra_timings, u8 speed) /* * Calculate MDMA timings for all cells */ -static int +static void set_timings_mdma(ide_drive_t *drive, int intf_type, u32 *timings, u32 *timings2, - u8 speed, int drive_cycle_time) + u8 speed) { + u16 *id = drive->id; int cycleTime, accessTime = 0, recTime = 0; unsigned accessTicks, recTicks; struct mdma_timings_t* tm = NULL; @@ -787,11 +657,14 @@ set_timings_mdma(ide_drive_t *drive, int intf_type, u32 *timings, u32 *timings2, case 1: cycleTime = 150; break; case 2: cycleTime = 120; break; default: - return 1; + BUG(); + break; } - /* Adjust for drive */ - if (drive_cycle_time && drive_cycle_time > cycleTime) - cycleTime = drive_cycle_time; + + /* Check if drive provides explicit DMA cycle time */ + if ((id[ATA_ID_FIELD_VALID] & 2) && id[ATA_ID_EIDE_DMA_TIME]) + cycleTime = max_t(int, id[ATA_ID_EIDE_DMA_TIME], cycleTime); + /* OHare limits according to some old Apple sources */ if ((intf_type == controller_ohare) && (cycleTime < 150)) cycleTime = 150; @@ -819,8 +692,6 @@ set_timings_mdma(ide_drive_t *drive, int intf_type, u32 *timings, u32 *timings2, break; i++; } - if (i < 0) - return 1; cycleTime = tm[i].cycleTime; accessTime = tm[i].accessTime; recTime = tm[i].recoveryTime; @@ -834,8 +705,6 @@ set_timings_mdma(ide_drive_t *drive, int intf_type, u32 *timings, u32 *timings2, case controller_sh_ata6: { /* 133Mhz cell */ u32 tr = kauai_lookup_timing(shasta_mdma_timings, cycleTime); - if (tr == 0) - return 1; *timings = ((*timings) & ~TR_133_PIOREG_MDMA_MASK) | tr; *timings2 = (*timings2) & ~TR_133_UDMAREG_UDMA_EN; } @@ -843,8 +712,6 @@ set_timings_mdma(ide_drive_t *drive, int intf_type, u32 *timings, u32 *timings2, case controller_k2_ata6: { /* 100Mhz cell */ u32 tr = kauai_lookup_timing(kauai_mdma_timings, cycleTime); - if (tr == 0) - return 1; *timings = ((*timings) & ~TR_100_PIOREG_MDMA_MASK) | tr; *timings2 = (*timings2) & ~TR_100_UDMAREG_UDMA_EN; } @@ -906,89 +773,44 @@ set_timings_mdma(ide_drive_t *drive, int intf_type, u32 *timings, u32 *timings2, printk(KERN_ERR "%s: Set MDMA timing for mode %d, reg: 0x%08x\n", drive->name, speed & 0xf, *timings); #endif - return 0; } -#endif /* #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC */ -/* - * Speedproc. This function is called by the core to set any of the standard - * timing (PIO, MDMA or UDMA) to both the drive and the controller. - * You may notice we don't use this function on normal "dma check" operation, - * our dedicated function is more precise as it uses the drive provided - * cycle time value. We should probably fix this one to deal with that too... - */ -static int -pmac_ide_tune_chipset (ide_drive_t *drive, byte speed) +static void pmac_ide_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive) { - int unit = (drive->select.b.unit & 0x01); + pmac_ide_hwif_t *pmif = dev_get_drvdata(hwif->gendev.parent); int ret = 0; - pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data; - u32 *timings, *timings2; + u32 *timings, *timings2, tl[2]; + u8 unit = drive->dn & 1; + const u8 speed = drive->dma_mode; - if (pmif == NULL) - return 1; - timings = &pmif->timings[unit]; timings2 = &pmif->timings[unit+2]; - - switch(speed) { -#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC - case XFER_UDMA_6: - if (pmif->kind != controller_sh_ata6) - return 1; - case XFER_UDMA_5: - if (pmif->kind != controller_un_ata6 && - pmif->kind != controller_k2_ata6 && - pmif->kind != controller_sh_ata6) - return 1; - case XFER_UDMA_4: - case XFER_UDMA_3: - if (HWIF(drive)->udma_four == 0) - return 1; - case XFER_UDMA_2: - case XFER_UDMA_1: - case XFER_UDMA_0: - if (pmif->kind == controller_kl_ata4) - ret = set_timings_udma_ata4(timings, speed); - else if (pmif->kind == controller_un_ata6 - || pmif->kind == controller_k2_ata6) - ret = set_timings_udma_ata6(timings, timings2, speed); - else if (pmif->kind == controller_sh_ata6) - ret = set_timings_udma_shasta(timings, timings2, speed); - else - ret = 1; - break; - case XFER_MW_DMA_2: - case XFER_MW_DMA_1: - case XFER_MW_DMA_0: - ret = set_timings_mdma(drive, pmif->kind, timings, timings2, speed, 0); - break; - case XFER_SW_DMA_2: - case XFER_SW_DMA_1: - case XFER_SW_DMA_0: - return 1; -#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */ - case XFER_PIO_4: - case XFER_PIO_3: - case XFER_PIO_2: - case XFER_PIO_1: - case XFER_PIO_0: - pmac_ide_tuneproc(drive, speed & 0x07); - break; - default: - ret = 1; - } - if (ret) - return ret; - ret = pmac_ide_do_setfeature(drive, speed); + /* Copy timings to local image */ + tl[0] = *timings; + tl[1] = *timings2; + + if (speed >= XFER_UDMA_0) { + if (pmif->kind == controller_kl_ata4) + ret = set_timings_udma_ata4(&tl[0], speed); + else if (pmif->kind == controller_un_ata6 + || pmif->kind == controller_k2_ata6) + ret = set_timings_udma_ata6(&tl[0], &tl[1], speed); + else if (pmif->kind == controller_sh_ata6) + ret = set_timings_udma_shasta(&tl[0], &tl[1], speed); + else + ret = -1; + } else + set_timings_mdma(drive, pmif->kind, &tl[0], &tl[1], speed); + if (ret) - return ret; - - pmac_ide_do_update_timings(drive); - drive->current_speed = speed; + return; - return 0; + /* Apply timings to controller */ + *timings = tl[0]; + *timings2 = tl[1]; + + pmac_ide_do_update_timings(drive); } /* @@ -1026,66 +848,16 @@ sanitize_timings(pmac_ide_hwif_t *pmif) pmif->timings[2] = pmif->timings[3] = value2; } -unsigned long -pmac_ide_get_base(int index) -{ - return pmac_ide[index].regbase; -} - -int -pmac_ide_check_base(unsigned long base) -{ - int ix; - - for (ix = 0; ix < MAX_HWIFS; ++ix) - if (base == pmac_ide[ix].regbase) - return ix; - return -1; -} - -int -pmac_ide_get_irq(unsigned long base) +static int on_media_bay(pmac_ide_hwif_t *pmif) { - int ix; - - for (ix = 0; ix < MAX_HWIFS; ++ix) - if (base == pmac_ide[ix].regbase) - return pmac_ide[ix].irq; - return 0; -} - -static int ide_majors[] = { 3, 22, 33, 34, 56, 57 }; - -dev_t __init -pmac_find_ide_boot(char *bootdevice, int n) -{ - int i; - - /* - * Look through the list of IDE interfaces for this one. - */ - for (i = 0; i < pmac_ide_count; ++i) { - char *name; - if (!pmac_ide[i].node || !pmac_ide[i].node->full_name) - continue; - name = pmac_ide[i].node->full_name; - if (memcmp(name, bootdevice, n) == 0 && name[n] == 0) { - /* XXX should cope with the 2nd drive as well... */ - return MKDEV(ide_majors[i], 0); - } - } - - return 0; + return pmif->mdev && pmif->mdev->media_bay != NULL; } /* Suspend call back, should be called after the child devices * have actually been suspended */ -static int -pmac_ide_do_suspend(ide_hwif_t *hwif) +static int pmac_ide_do_suspend(pmac_ide_hwif_t *pmif) { - pmac_ide_hwif_t *pmif = (pmac_ide_hwif_t *)hwif->hwif_data; - /* We clear the timings */ pmif->timings[0] = 0; pmif->timings[1] = 0; @@ -1093,7 +865,7 @@ pmac_ide_do_suspend(ide_hwif_t *hwif) disable_irq(pmif->irq); /* The media bay will handle itself just fine */ - if (pmif->mediabay) + if (on_media_bay(pmif)) return 0; /* Kauai has bus control FCRs directly here */ @@ -1113,13 +885,10 @@ pmac_ide_do_suspend(ide_hwif_t *hwif) /* Resume call back, should be called before the child devices * are resumed */ -static int -pmac_ide_do_resume(ide_hwif_t *hwif) +static int pmac_ide_do_resume(pmac_ide_hwif_t *pmif) { - pmac_ide_hwif_t *pmif = (pmac_ide_hwif_t *)hwif->hwif_data; - /* Hard reset & re-enable controller (do we really need to reset ? -BenH) */ - if (!pmif->mediabay) { + if (!on_media_bay(pmif)) { ppc_md.feature_call(PMAC_FTR_IDE_RESET, pmif->node, pmif->aapl_bus_id, 1); ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, pmif->node, pmif->aapl_bus_id, 1); msleep(10); @@ -1143,77 +912,177 @@ pmac_ide_do_resume(ide_hwif_t *hwif) return 0; } +static u8 pmac_ide_cable_detect(ide_hwif_t *hwif) +{ + pmac_ide_hwif_t *pmif = dev_get_drvdata(hwif->gendev.parent); + struct device_node *np = pmif->node; + const char *cable = of_get_property(np, "cable-type", NULL); + struct device_node *root = of_find_node_by_path("/"); + const char *model = of_get_property(root, "model", NULL); + + /* Get cable type from device-tree. */ + if (cable && !strncmp(cable, "80-", 3)) { + /* Some drives fail to detect 80c cable in PowerBook */ + /* These machine use proprietary short IDE cable anyway */ + if (!strncmp(model, "PowerBook", 9)) + return ATA_CBL_PATA40_SHORT; + else + return ATA_CBL_PATA80; + } + + /* + * G5's seem to have incorrect cable type in device-tree. + * Let's assume they have a 80 conductor cable, this seem + * to be always the case unless the user mucked around. + */ + if (of_device_is_compatible(np, "K2-UATA") || + of_device_is_compatible(np, "shasta-ata")) + return ATA_CBL_PATA80; + + return ATA_CBL_PATA40; +} + +static void pmac_ide_init_dev(ide_drive_t *drive) +{ + ide_hwif_t *hwif = drive->hwif; + pmac_ide_hwif_t *pmif = dev_get_drvdata(hwif->gendev.parent); + + if (on_media_bay(pmif)) { + if (check_media_bay(pmif->mdev->media_bay) == MB_CD) { + drive->dev_flags &= ~IDE_DFLAG_NOPROBE; + return; + } + drive->dev_flags |= IDE_DFLAG_NOPROBE; + } +} + +static const struct ide_tp_ops pmac_tp_ops = { + .exec_command = pmac_exec_command, + .read_status = ide_read_status, + .read_altstatus = ide_read_altstatus, + .write_devctl = pmac_write_devctl, + + .dev_select = pmac_dev_select, + .tf_load = ide_tf_load, + .tf_read = ide_tf_read, + + .input_data = ide_input_data, + .output_data = ide_output_data, +}; + +static const struct ide_tp_ops pmac_ata6_tp_ops = { + .exec_command = pmac_exec_command, + .read_status = ide_read_status, + .read_altstatus = ide_read_altstatus, + .write_devctl = pmac_write_devctl, + + .dev_select = pmac_kauai_dev_select, + .tf_load = ide_tf_load, + .tf_read = ide_tf_read, + + .input_data = ide_input_data, + .output_data = ide_output_data, +}; + +static const struct ide_port_ops pmac_ide_ata4_port_ops = { + .init_dev = pmac_ide_init_dev, + .set_pio_mode = pmac_ide_set_pio_mode, + .set_dma_mode = pmac_ide_set_dma_mode, + .cable_detect = pmac_ide_cable_detect, +}; + +static const struct ide_port_ops pmac_ide_port_ops = { + .init_dev = pmac_ide_init_dev, + .set_pio_mode = pmac_ide_set_pio_mode, + .set_dma_mode = pmac_ide_set_dma_mode, +}; + +static const struct ide_dma_ops pmac_dma_ops; + +static const struct ide_port_info pmac_port_info = { + .name = DRV_NAME, + .init_dma = pmac_ide_init_dma, + .chipset = ide_pmac, + .tp_ops = &pmac_tp_ops, + .port_ops = &pmac_ide_port_ops, + .dma_ops = &pmac_dma_ops, + .host_flags = IDE_HFLAG_SET_PIO_MODE_KEEP_DMA | + IDE_HFLAG_POST_SET_MODE | + IDE_HFLAG_MMIO | + IDE_HFLAG_UNMASK_IRQS, + .pio_mask = ATA_PIO4, + .mwdma_mask = ATA_MWDMA2, +}; + /* * Setup, register & probe an IDE channel driven by this driver, this is - * called by one of the 2 probe functions (macio or PCI). Note that a channel - * that ends up beeing free of any device is not kept around by this driver - * (it is kept in 2.4). This introduce an interface numbering change on some - * rare machines unfortunately, but it's better this way. + * called by one of the 2 probe functions (macio or PCI). */ -static int -pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif) +static int pmac_ide_setup_device(pmac_ide_hwif_t *pmif, struct ide_hw *hw) { struct device_node *np = pmif->node; const int *bidp; + struct ide_host *host; + ide_hwif_t *hwif; + struct ide_hw *hws[] = { hw }; + struct ide_port_info d = pmac_port_info; + int rc; - pmif->cable_80 = 0; pmif->broken_dma = pmif->broken_dma_warn = 0; - if (device_is_compatible(np, "shasta-ata")) + if (of_device_is_compatible(np, "shasta-ata")) { pmif->kind = controller_sh_ata6; - else if (device_is_compatible(np, "kauai-ata")) + d.tp_ops = &pmac_ata6_tp_ops; + d.port_ops = &pmac_ide_ata4_port_ops; + d.udma_mask = ATA_UDMA6; + } else if (of_device_is_compatible(np, "kauai-ata")) { pmif->kind = controller_un_ata6; - else if (device_is_compatible(np, "K2-UATA")) + d.tp_ops = &pmac_ata6_tp_ops; + d.port_ops = &pmac_ide_ata4_port_ops; + d.udma_mask = ATA_UDMA5; + } else if (of_device_is_compatible(np, "K2-UATA")) { pmif->kind = controller_k2_ata6; - else if (device_is_compatible(np, "keylargo-ata")) { - if (strcmp(np->name, "ata-4") == 0) + d.tp_ops = &pmac_ata6_tp_ops; + d.port_ops = &pmac_ide_ata4_port_ops; + d.udma_mask = ATA_UDMA5; + } else if (of_device_is_compatible(np, "keylargo-ata")) { + if (strcmp(np->name, "ata-4") == 0) { pmif->kind = controller_kl_ata4; - else + d.port_ops = &pmac_ide_ata4_port_ops; + d.udma_mask = ATA_UDMA4; + } else pmif->kind = controller_kl_ata3; - } else if (device_is_compatible(np, "heathrow-ata")) + } else if (of_device_is_compatible(np, "heathrow-ata")) { pmif->kind = controller_heathrow; - else { + } else { pmif->kind = controller_ohare; pmif->broken_dma = 1; } - bidp = get_property(np, "AAPL,bus-id", NULL); + bidp = of_get_property(np, "AAPL,bus-id", NULL); pmif->aapl_bus_id = bidp ? *bidp : 0; - /* Get cable type from device-tree */ - if (pmif->kind == controller_kl_ata4 || pmif->kind == controller_un_ata6 - || pmif->kind == controller_k2_ata6 - || pmif->kind == controller_sh_ata6) { - const char* cable = get_property(np, "cable-type", NULL); - if (cable && !strncmp(cable, "80-", 3)) - pmif->cable_80 = 1; - } - /* G5's seem to have incorrect cable type in device-tree. Let's assume - * they have a 80 conductor cable, this seem to be always the case unless - * the user mucked around - */ - if (device_is_compatible(np, "K2-UATA") || - device_is_compatible(np, "shasta-ata")) - pmif->cable_80 = 1; - /* On Kauai-type controllers, we make sure the FCR is correct */ if (pmif->kauai_fcr) writel(KAUAI_FCR_UATA_MAGIC | KAUAI_FCR_UATA_RESET_N | KAUAI_FCR_UATA_ENABLE, pmif->kauai_fcr); - - pmif->mediabay = 0; /* Make sure we have sane timings */ sanitize_timings(pmif); -#ifndef CONFIG_PPC64 - /* XXX FIXME: Media bay stuff need re-organizing */ - if (np->parent && np->parent->name - && strcasecmp(np->parent->name, "media-bay") == 0) { -#ifdef CONFIG_PMAC_MEDIABAY - media_bay_set_ide_infos(np->parent, pmif->regbase, pmif->irq, hwif->index); -#endif /* CONFIG_PMAC_MEDIABAY */ - pmif->mediabay = 1; + /* If we are on a media bay, wait for it to settle and lock it */ + if (pmif->mdev) + lock_media_bay(pmif->mdev->media_bay); + + host = ide_host_alloc(&d, hws, 1); + if (host == NULL) { + rc = -ENOMEM; + goto bail; + } + hwif = pmif->hwif = host->ports[0]; + + if (on_media_bay(pmif)) { + /* Fixup bus ID for media bay */ if (!bidp) pmif->aapl_bus_id = 1; } else if (pmif->kind == controller_ohare) { @@ -1222,9 +1091,7 @@ pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif) * units, I keep the old way */ ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, 0, 1); - } else -#endif - { + } else { /* This is necessary to enable IDE when net-booting */ ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmif->aapl_bus_id, 1); ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, pmif->aapl_bus_id, 1); @@ -1233,89 +1100,63 @@ pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif) msleep(jiffies_to_msecs(IDE_WAKEUP_DELAY)); } - /* Setup MMIO ops */ - default_hwif_mmiops(hwif); - hwif->OUTBSYNC = pmac_outbsync; - - /* Tell common code _not_ to mess with resources */ - hwif->mmio = 2; - hwif->hwif_data = pmif; - pmac_ide_init_hwif_ports(&hwif->hw, pmif->regbase, 0, &hwif->irq); - memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports)); - hwif->chipset = ide_pmac; - hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET] || pmif->mediabay; - hwif->hold = pmif->mediabay; - hwif->udma_four = pmif->cable_80; - hwif->drives[0].unmask = 1; - hwif->drives[1].unmask = 1; - hwif->tuneproc = pmac_ide_tuneproc; - if (pmif->kind == controller_un_ata6 - || pmif->kind == controller_k2_ata6 - || pmif->kind == controller_sh_ata6) - hwif->selectproc = pmac_ide_kauai_selectproc; - else - hwif->selectproc = pmac_ide_selectproc; - hwif->speedproc = pmac_ide_tune_chipset; + printk(KERN_INFO DRV_NAME ": Found Apple %s controller (%s), " + "bus ID %d%s, irq %d\n", model_name[pmif->kind], + pmif->mdev ? "macio" : "PCI", pmif->aapl_bus_id, + on_media_bay(pmif) ? " (mediabay)" : "", hw->irq); - printk(KERN_INFO "ide%d: Found Apple %s controller, bus ID %d%s, irq %d\n", - hwif->index, model_name[pmif->kind], pmif->aapl_bus_id, - pmif->mediabay ? " (mediabay)" : "", hwif->irq); - -#ifdef CONFIG_PMAC_MEDIABAY - if (pmif->mediabay && check_media_bay_by_base(pmif->regbase, MB_CD) == 0) - hwif->noprobe = 0; -#endif /* CONFIG_PMAC_MEDIABAY */ + rc = ide_host_register(host, &d, hws); + if (rc) + pmif->hwif = NULL; - hwif->sg_max_nents = MAX_DCMDS; + if (pmif->mdev) + unlock_media_bay(pmif->mdev->media_bay); -#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC - /* has a DBDMA controller channel */ - if (pmif->dma_regs) - pmac_ide_setup_dma(pmif, hwif); -#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */ + bail: + if (rc && host) + ide_host_free(host); + return rc; +} - /* We probe the hwif now */ - probe_hwif_init(hwif); +static void pmac_ide_init_ports(struct ide_hw *hw, unsigned long base) +{ + int i; - return 0; + for (i = 0; i < 8; ++i) + hw->io_ports_array[i] = base + i * 0x10; + + hw->io_ports.ctl_addr = base + 0x160; } /* * Attach to a macio probed interface */ -static int __devinit -pmac_ide_macio_attach(struct macio_dev *mdev, const struct of_device_id *match) +static int pmac_ide_macio_attach(struct macio_dev *mdev, + const struct of_device_id *match) { void __iomem *base; unsigned long regbase; - int irq; - ide_hwif_t *hwif; pmac_ide_hwif_t *pmif; - int i, rc; - - i = 0; - while (i < MAX_HWIFS && (ide_hwifs[i].io_ports[IDE_DATA_OFFSET] != 0 - || pmac_ide[i].node != NULL)) - ++i; - if (i >= MAX_HWIFS) { - printk(KERN_ERR "ide-pmac: MacIO interface attach with no slot\n"); - printk(KERN_ERR " %s\n", mdev->ofdev.node->full_name); - return -ENODEV; - } + int irq, rc; + struct ide_hw hw; - pmif = &pmac_ide[i]; - hwif = &ide_hwifs[i]; + pmif = kzalloc(sizeof(*pmif), GFP_KERNEL); + if (pmif == NULL) + return -ENOMEM; if (macio_resource_count(mdev) == 0) { - printk(KERN_WARNING "ide%d: no address for %s\n", - i, mdev->ofdev.node->full_name); - return -ENXIO; + printk(KERN_WARNING "ide-pmac: no address for %s\n", + mdev->ofdev.dev.of_node->full_name); + rc = -ENXIO; + goto out_free_pmif; } /* Request memory resource for IO ports */ if (macio_request_resource(mdev, 0, "ide-pmac (ports)")) { - printk(KERN_ERR "ide%d: can't request mmio resource !\n", i); - return -EBUSY; + printk(KERN_ERR "ide-pmac: can't request MMIO resource for " + "%s!\n", mdev->ofdev.dev.of_node->full_name); + rc = -EBUSY; + goto out_free_pmif; } /* XXX This is bogus. Should be fixed in the registry by checking @@ -1324,8 +1165,8 @@ pmac_ide_macio_attach(struct macio_dev *mdev, const struct of_device_id *match) * where that happens though... */ if (macio_irq_count(mdev) == 0) { - printk(KERN_WARNING "ide%d: no intrs for device %s, using 13\n", - i, mdev->ofdev.node->full_name); + printk(KERN_WARNING "ide-pmac: no intrs for device %s, using " + "13\n", mdev->ofdev.dev.of_node->full_name); irq = irq_create_mapping(NULL, 13); } else irq = macio_irq(mdev, 0); @@ -1333,50 +1174,59 @@ pmac_ide_macio_attach(struct macio_dev *mdev, const struct of_device_id *match) base = ioremap(macio_resource_start(mdev, 0), 0x400); regbase = (unsigned long) base; - hwif->pci_dev = mdev->bus->pdev; - hwif->gendev.parent = &mdev->ofdev.dev; - pmif->mdev = mdev; - pmif->node = mdev->ofdev.node; + pmif->node = mdev->ofdev.dev.of_node; pmif->regbase = regbase; pmif->irq = irq; pmif->kauai_fcr = NULL; -#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC + if (macio_resource_count(mdev) >= 2) { if (macio_request_resource(mdev, 1, "ide-pmac (dma)")) - printk(KERN_WARNING "ide%d: can't request DMA resource !\n", i); + printk(KERN_WARNING "ide-pmac: can't request DMA " + "resource for %s!\n", + mdev->ofdev.dev.of_node->full_name); else pmif->dma_regs = ioremap(macio_resource_start(mdev, 1), 0x1000); } else pmif->dma_regs = NULL; -#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */ - dev_set_drvdata(&mdev->ofdev.dev, hwif); - rc = pmac_ide_setup_device(pmif, hwif); + dev_set_drvdata(&mdev->ofdev.dev, pmif); + + memset(&hw, 0, sizeof(hw)); + pmac_ide_init_ports(&hw, pmif->regbase); + hw.irq = irq; + hw.dev = &mdev->bus->pdev->dev; + hw.parent = &mdev->ofdev.dev; + + rc = pmac_ide_setup_device(pmif, &hw); if (rc != 0) { /* The inteface is released to the common IDE layer */ dev_set_drvdata(&mdev->ofdev.dev, NULL); iounmap(base); - if (pmif->dma_regs) + if (pmif->dma_regs) { iounmap(pmif->dma_regs); - memset(pmif, 0, sizeof(*pmif)); - macio_release_resource(mdev, 0); - if (pmif->dma_regs) macio_release_resource(mdev, 1); + } + macio_release_resource(mdev, 0); + kfree(pmif); } return rc; + +out_free_pmif: + kfree(pmif); + return rc; } static int pmac_ide_macio_suspend(struct macio_dev *mdev, pm_message_t mesg) { - ide_hwif_t *hwif = (ide_hwif_t *)dev_get_drvdata(&mdev->ofdev.dev); - int rc = 0; + pmac_ide_hwif_t *pmif = dev_get_drvdata(&mdev->ofdev.dev); + int rc = 0; if (mesg.event != mdev->ofdev.dev.power.power_state.event - && mesg.event == PM_EVENT_SUSPEND) { - rc = pmac_ide_do_suspend(hwif); + && (mesg.event & PM_EVENT_SLEEP)) { + rc = pmac_ide_do_suspend(pmif); if (rc == 0) mdev->ofdev.dev.power.power_state = mesg; } @@ -1387,11 +1237,11 @@ pmac_ide_macio_suspend(struct macio_dev *mdev, pm_message_t mesg) static int pmac_ide_macio_resume(struct macio_dev *mdev) { - ide_hwif_t *hwif = (ide_hwif_t *)dev_get_drvdata(&mdev->ofdev.dev); - int rc = 0; - + pmac_ide_hwif_t *pmif = dev_get_drvdata(&mdev->ofdev.dev); + int rc = 0; + if (mdev->ofdev.dev.power.power_state.event != PM_EVENT_ON) { - rc = pmac_ide_do_resume(hwif); + rc = pmac_ide_do_resume(pmif); if (rc == 0) mdev->ofdev.dev.power.power_state = PMSG_ON; } @@ -1402,49 +1252,41 @@ pmac_ide_macio_resume(struct macio_dev *mdev) /* * Attach to a PCI probed interface */ -static int __devinit -pmac_ide_pci_attach(struct pci_dev *pdev, const struct pci_device_id *id) +static int pmac_ide_pci_attach(struct pci_dev *pdev, + const struct pci_device_id *id) { - ide_hwif_t *hwif; struct device_node *np; pmac_ide_hwif_t *pmif; void __iomem *base; unsigned long rbase, rlen; - int i, rc; + int rc; + struct ide_hw hw; np = pci_device_to_OF_node(pdev); if (np == NULL) { printk(KERN_ERR "ide-pmac: cannot find MacIO node for Kauai ATA interface\n"); return -ENODEV; } - i = 0; - while (i < MAX_HWIFS && (ide_hwifs[i].io_ports[IDE_DATA_OFFSET] != 0 - || pmac_ide[i].node != NULL)) - ++i; - if (i >= MAX_HWIFS) { - printk(KERN_ERR "ide-pmac: PCI interface attach with no slot\n"); - printk(KERN_ERR " %s\n", np->full_name); - return -ENODEV; - } - pmif = &pmac_ide[i]; - hwif = &ide_hwifs[i]; + pmif = kzalloc(sizeof(*pmif), GFP_KERNEL); + if (pmif == NULL) + return -ENOMEM; if (pci_enable_device(pdev)) { - printk(KERN_WARNING "ide%i: Can't enable PCI device for %s\n", - i, np->full_name); - return -ENXIO; + printk(KERN_WARNING "ide-pmac: Can't enable PCI device for " + "%s\n", np->full_name); + rc = -ENXIO; + goto out_free_pmif; } pci_set_master(pdev); if (pci_request_regions(pdev, "Kauai ATA")) { - printk(KERN_ERR "ide%d: Cannot obtain PCI resources for %s\n", - i, np->full_name); - return -ENXIO; + printk(KERN_ERR "ide-pmac: Cannot obtain PCI resources for " + "%s\n", np->full_name); + rc = -ENXIO; + goto out_free_pmif; } - hwif->pci_dev = pdev; - hwif->gendev.parent = &pdev->dev; pmif->mdev = NULL; pmif->node = np; @@ -1453,35 +1295,41 @@ pmac_ide_pci_attach(struct pci_dev *pdev, const struct pci_device_id *id) base = ioremap(rbase, rlen); pmif->regbase = (unsigned long) base + 0x2000; -#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC pmif->dma_regs = base + 0x1000; -#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */ pmif->kauai_fcr = base; pmif->irq = pdev->irq; - pci_set_drvdata(pdev, hwif); + pci_set_drvdata(pdev, pmif); + + memset(&hw, 0, sizeof(hw)); + pmac_ide_init_ports(&hw, pmif->regbase); + hw.irq = pdev->irq; + hw.dev = &pdev->dev; - rc = pmac_ide_setup_device(pmif, hwif); + rc = pmac_ide_setup_device(pmif, &hw); if (rc != 0) { /* The inteface is released to the common IDE layer */ - pci_set_drvdata(pdev, NULL); iounmap(base); - memset(pmif, 0, sizeof(*pmif)); pci_release_regions(pdev); + kfree(pmif); } return rc; + +out_free_pmif: + kfree(pmif); + return rc; } static int pmac_ide_pci_suspend(struct pci_dev *pdev, pm_message_t mesg) { - ide_hwif_t *hwif = (ide_hwif_t *)pci_get_drvdata(pdev); - int rc = 0; - + pmac_ide_hwif_t *pmif = pci_get_drvdata(pdev); + int rc = 0; + if (mesg.event != pdev->dev.power.power_state.event - && mesg.event == PM_EVENT_SUSPEND) { - rc = pmac_ide_do_suspend(hwif); + && (mesg.event & PM_EVENT_SLEEP)) { + rc = pmac_ide_do_suspend(pmif); if (rc == 0) pdev->dev.power.power_state = mesg; } @@ -1492,11 +1340,11 @@ pmac_ide_pci_suspend(struct pci_dev *pdev, pm_message_t mesg) static int pmac_ide_pci_resume(struct pci_dev *pdev) { - ide_hwif_t *hwif = (ide_hwif_t *)pci_get_drvdata(pdev); - int rc = 0; - + pmac_ide_hwif_t *pmif = pci_get_drvdata(pdev); + int rc = 0; + if (pdev->dev.power.power_state.event != PM_EVENT_ON) { - rc = pmac_ide_do_resume(hwif); + rc = pmac_ide_do_resume(pmif); if (rc == 0) pdev->dev.power.power_state = PMSG_ON; } @@ -1504,6 +1352,24 @@ pmac_ide_pci_resume(struct pci_dev *pdev) return rc; } +#ifdef CONFIG_PMAC_MEDIABAY +static void pmac_ide_macio_mb_event(struct macio_dev* mdev, int mb_state) +{ + pmac_ide_hwif_t *pmif = dev_get_drvdata(&mdev->ofdev.dev); + + switch(mb_state) { + case MB_CD: + if (!pmif->hwif->present) + ide_port_scan(pmif->hwif); + break; + default: + if (pmif->hwif->present) + ide_port_unregister_devices(pmif->hwif); + } +} +#endif /* CONFIG_PMAC_MEDIABAY */ + + static struct of_device_id pmac_ide_macio_match[] = { { @@ -1523,24 +1389,26 @@ static struct of_device_id pmac_ide_macio_match[] = static struct macio_driver pmac_ide_macio_driver = { - .name = "ide-pmac", - .match_table = pmac_ide_macio_match, + .driver = { + .name = "ide-pmac", + .owner = THIS_MODULE, + .of_match_table = pmac_ide_macio_match, + }, .probe = pmac_ide_macio_attach, .suspend = pmac_ide_macio_suspend, .resume = pmac_ide_macio_resume, +#ifdef CONFIG_PMAC_MEDIABAY + .mediabay_event = pmac_ide_macio_mb_event, +#endif }; -static struct pci_device_id pmac_ide_pci_match[] = { - { PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_UNI_N_ATA, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - { PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_IPID_ATA100, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - { PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_K2_ATA100, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - { PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_SH_ATA, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - { PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_IPID2_ATA, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, +static const struct pci_device_id pmac_ide_pci_match[] = { + { PCI_VDEVICE(APPLE, PCI_DEVICE_ID_APPLE_UNI_N_ATA), 0 }, + { PCI_VDEVICE(APPLE, PCI_DEVICE_ID_APPLE_IPID_ATA100), 0 }, + { PCI_VDEVICE(APPLE, PCI_DEVICE_ID_APPLE_K2_ATA100), 0 }, + { PCI_VDEVICE(APPLE, PCI_DEVICE_ID_APPLE_SH_ATA), 0 }, + { PCI_VDEVICE(APPLE, PCI_DEVICE_ID_APPLE_IPID2_ATA), 0 }, + {}, }; static struct pci_driver pmac_ide_pci_driver = { @@ -1552,37 +1420,49 @@ static struct pci_driver pmac_ide_pci_driver = { }; MODULE_DEVICE_TABLE(pci, pmac_ide_pci_match); -void __init -pmac_ide_probe(void) +int __init pmac_ide_probe(void) { + int error; + if (!machine_is(powermac)) - return; + return -ENODEV; #ifdef CONFIG_BLK_DEV_IDE_PMAC_ATA100FIRST - pci_register_driver(&pmac_ide_pci_driver); - macio_register_driver(&pmac_ide_macio_driver); + error = pci_register_driver(&pmac_ide_pci_driver); + if (error) + goto out; + error = macio_register_driver(&pmac_ide_macio_driver); + if (error) { + pci_unregister_driver(&pmac_ide_pci_driver); + goto out; + } #else - macio_register_driver(&pmac_ide_macio_driver); - pci_register_driver(&pmac_ide_pci_driver); + error = macio_register_driver(&pmac_ide_macio_driver); + if (error) + goto out; + error = pci_register_driver(&pmac_ide_pci_driver); + if (error) { + macio_unregister_driver(&pmac_ide_macio_driver); + goto out; + } #endif +out: + return error; } -#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC - /* * pmac_ide_build_dmatable builds the DBDMA command list * for a transfer and sets the DBDMA channel to point to it. */ -static int -pmac_ide_build_dmatable(ide_drive_t *drive, struct request *rq) +static int pmac_ide_build_dmatable(ide_drive_t *drive, struct ide_cmd *cmd) { + ide_hwif_t *hwif = drive->hwif; + pmac_ide_hwif_t *pmif = dev_get_drvdata(hwif->gendev.parent); struct dbdma_cmd *table; - int i, count = 0; - ide_hwif_t *hwif = HWIF(drive); - pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)hwif->hwif_data; volatile struct dbdma_regs __iomem *dma = pmif->dma_regs; struct scatterlist *sg; - int wr = (rq_data_dir(rq) == WRITE); + int wr = !!(cmd->tf_flags & IDE_TFLAG_WRITE); + int i = cmd->sg_nents, count = 0; /* DMA table is already aligned */ table = (struct dbdma_cmd *) pmif->dma_table_cpu; @@ -1592,11 +1472,6 @@ pmac_ide_build_dmatable(ide_drive_t *drive, struct request *rq) while (readl(&dma->status) & RUN) udelay(1); - hwif->sg_nents = i = ide_build_sglist(drive, rq); - - if (!i) - return 0; - /* Build DBDMA commands list */ sg = hwif->sg_table; while (i && sg_dma_len(sg)) { @@ -1608,11 +1483,11 @@ pmac_ide_build_dmatable(ide_drive_t *drive, struct request *rq) if (pmif->broken_dma && cur_addr & (L1_CACHE_BYTES - 1)) { if (pmif->broken_dma_warn == 0) { - printk(KERN_WARNING "%s: DMA on non aligned address," + printk(KERN_WARNING "%s: DMA on non aligned address, " "switching to PIO on Ohare chipset\n", drive->name); pmif->broken_dma_warn = 1; } - goto use_pio_instead; + return 0; } while (cur_len) { unsigned int tc = (cur_len < 0xfe00)? cur_len: 0xfe00; @@ -1620,7 +1495,7 @@ pmac_ide_build_dmatable(ide_drive_t *drive, struct request *rq) if (count++ >= MAX_DCMDS) { printk(KERN_WARNING "%s: DMA table too small\n", drive->name); - goto use_pio_instead; + return 0; } st_le16(&table->command, wr? OUTPUT_MORE: INPUT_MORE); st_le16(&table->req_count, tc); @@ -1632,7 +1507,7 @@ pmac_ide_build_dmatable(ide_drive_t *drive, struct request *rq) cur_len -= tc; ++table; } - sg++; + sg = sg_next(sg); i--; } @@ -1648,234 +1523,34 @@ pmac_ide_build_dmatable(ide_drive_t *drive, struct request *rq) } printk(KERN_DEBUG "%s: empty DMA table?\n", drive->name); - use_pio_instead: - pci_unmap_sg(hwif->pci_dev, - hwif->sg_table, - hwif->sg_nents, - hwif->sg_dma_direction); - return 0; /* revert to PIO for this request */ -} - -/* Teardown mappings after DMA has completed. */ -static void -pmac_ide_destroy_dmatable (ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - struct pci_dev *dev = HWIF(drive)->pci_dev; - struct scatterlist *sg = hwif->sg_table; - int nents = hwif->sg_nents; - - if (nents) { - pci_unmap_sg(dev, sg, nents, hwif->sg_dma_direction); - hwif->sg_nents = 0; - } -} -/* - * Pick up best MDMA timing for the drive and apply it - */ -static int -pmac_ide_mdma_enable(ide_drive_t *drive, u16 mode) -{ - ide_hwif_t *hwif = HWIF(drive); - pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)hwif->hwif_data; - int drive_cycle_time; - struct hd_driveid *id = drive->id; - u32 *timings, *timings2; - u32 timing_local[2]; - int ret; - - /* which drive is it ? */ - timings = &pmif->timings[drive->select.b.unit & 0x01]; - timings2 = &pmif->timings[(drive->select.b.unit & 0x01) + 2]; - - /* Check if drive provide explicit cycle time */ - if ((id->field_valid & 2) && (id->eide_dma_time)) - drive_cycle_time = id->eide_dma_time; - else - drive_cycle_time = 0; - - /* Copy timings to local image */ - timing_local[0] = *timings; - timing_local[1] = *timings2; - - /* Calculate controller timings */ - ret = set_timings_mdma( drive, pmif->kind, - &timing_local[0], - &timing_local[1], - mode, - drive_cycle_time); - if (ret) - return 0; - - /* Set feature on drive */ - printk(KERN_INFO "%s: Enabling MultiWord DMA %d\n", drive->name, mode & 0xf); - ret = pmac_ide_do_setfeature(drive, mode); - if (ret) { - printk(KERN_WARNING "%s: Failed !\n", drive->name); - return 0; - } - - /* Apply timings to controller */ - *timings = timing_local[0]; - *timings2 = timing_local[1]; - - /* Set speed info in drive */ - drive->current_speed = mode; - if (!drive->init_speed) - drive->init_speed = mode; - - return 1; -} - -/* - * Pick up best UDMA timing for the drive and apply it - */ -static int -pmac_ide_udma_enable(ide_drive_t *drive, u16 mode) -{ - ide_hwif_t *hwif = HWIF(drive); - pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)hwif->hwif_data; - u32 *timings, *timings2; - u32 timing_local[2]; - int ret; - - /* which drive is it ? */ - timings = &pmif->timings[drive->select.b.unit & 0x01]; - timings2 = &pmif->timings[(drive->select.b.unit & 0x01) + 2]; - - /* Copy timings to local image */ - timing_local[0] = *timings; - timing_local[1] = *timings2; - - /* Calculate timings for interface */ - if (pmif->kind == controller_un_ata6 - || pmif->kind == controller_k2_ata6) - ret = set_timings_udma_ata6( &timing_local[0], - &timing_local[1], - mode); - else if (pmif->kind == controller_sh_ata6) - ret = set_timings_udma_shasta( &timing_local[0], - &timing_local[1], - mode); - else - ret = set_timings_udma_ata4(&timing_local[0], mode); - if (ret) - return 0; - - /* Set feature on drive */ - printk(KERN_INFO "%s: Enabling Ultra DMA %d\n", drive->name, mode & 0x0f); - ret = pmac_ide_do_setfeature(drive, mode); - if (ret) { - printk(KERN_WARNING "%s: Failed !\n", drive->name); - return 0; - } - - /* Apply timings to controller */ - *timings = timing_local[0]; - *timings2 = timing_local[1]; - - /* Set speed info in drive */ - drive->current_speed = mode; - if (!drive->init_speed) - drive->init_speed = mode; - - return 1; -} - -/* - * Check what is the best DMA timing setting for the drive and - * call appropriate functions to apply it. - */ -static int -pmac_ide_dma_check(ide_drive_t *drive) -{ - struct hd_driveid *id = drive->id; - ide_hwif_t *hwif = HWIF(drive); - pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)hwif->hwif_data; - int enable = 1; - int map; - drive->using_dma = 0; - - if (drive->media == ide_floppy) - enable = 0; - if (((id->capability & 1) == 0) && !__ide_dma_good_drive(drive)) - enable = 0; - if (__ide_dma_bad_drive(drive)) - enable = 0; - - if (enable) { - short mode; - - map = XFER_MWDMA; - if (pmif->kind == controller_kl_ata4 - || pmif->kind == controller_un_ata6 - || pmif->kind == controller_k2_ata6 - || pmif->kind == controller_sh_ata6) { - map |= XFER_UDMA; - if (pmif->cable_80) { - map |= XFER_UDMA_66; - if (pmif->kind == controller_un_ata6 || - pmif->kind == controller_k2_ata6 || - pmif->kind == controller_sh_ata6) - map |= XFER_UDMA_100; - if (pmif->kind == controller_sh_ata6) - map |= XFER_UDMA_133; - } - } - mode = ide_find_best_mode(drive, map); - if (mode & XFER_UDMA) - drive->using_dma = pmac_ide_udma_enable(drive, mode); - else if (mode & XFER_MWDMA) - drive->using_dma = pmac_ide_mdma_enable(drive, mode); - hwif->OUTB(0, IDE_CONTROL_REG); - /* Apply settings to controller */ - pmac_ide_do_update_timings(drive); - } - return 0; + return 0; /* revert to PIO for this request */ } /* * Prepare a DMA transfer. We build the DMA table, adjust the timings for * a read on KeyLargo ATA/66 and mark us as waiting for DMA completion */ -static int -pmac_ide_dma_setup(ide_drive_t *drive) +static int pmac_ide_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd) { - ide_hwif_t *hwif = HWIF(drive); - pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)hwif->hwif_data; - struct request *rq = HWGROUP(drive)->rq; - u8 unit = (drive->select.b.unit & 0x01); - u8 ata4; - - if (pmif == NULL) - return 1; - ata4 = (pmif->kind == controller_kl_ata4); + ide_hwif_t *hwif = drive->hwif; + pmac_ide_hwif_t *pmif = dev_get_drvdata(hwif->gendev.parent); + u8 unit = drive->dn & 1, ata4 = (pmif->kind == controller_kl_ata4); + u8 write = !!(cmd->tf_flags & IDE_TFLAG_WRITE); - if (!pmac_ide_build_dmatable(drive, rq)) { - ide_map_sg(drive, rq); + if (pmac_ide_build_dmatable(drive, cmd) == 0) return 1; - } /* Apple adds 60ns to wrDataSetup on reads */ if (ata4 && (pmif->timings[unit] & TR_66_UDMA_EN)) { - writel(pmif->timings[unit] + (!rq_data_dir(rq) ? 0x00800000UL : 0), + writel(pmif->timings[unit] + (write ? 0 : 0x00800000UL), PMAC_IDE_REG(IDE_TIMING_CONFIG)); (void)readl(PMAC_IDE_REG(IDE_TIMING_CONFIG)); } - drive->waiting_for_dma = 1; - return 0; } -static void -pmac_ide_dma_exec_cmd(ide_drive_t *drive, u8 command) -{ - /* issue cmd to drive */ - ide_execute_command(drive, command, &ide_dma_intr, 2*WAIT_CMD, NULL); -} - /* * Kick the DMA controller into life after the DMA command has been issued * to the drive. @@ -1883,7 +1558,8 @@ pmac_ide_dma_exec_cmd(ide_drive_t *drive, u8 command) static void pmac_ide_dma_start(ide_drive_t *drive) { - pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data; + ide_hwif_t *hwif = drive->hwif; + pmac_ide_hwif_t *pmif = dev_get_drvdata(hwif->gendev.parent); volatile struct dbdma_regs __iomem *dma; dma = pmif->dma_regs; @@ -1899,18 +1575,14 @@ pmac_ide_dma_start(ide_drive_t *drive) static int pmac_ide_dma_end (ide_drive_t *drive) { - pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data; - volatile struct dbdma_regs __iomem *dma; + ide_hwif_t *hwif = drive->hwif; + pmac_ide_hwif_t *pmif = dev_get_drvdata(hwif->gendev.parent); + volatile struct dbdma_regs __iomem *dma = pmif->dma_regs; u32 dstat; - - if (pmif == NULL) - return 0; - dma = pmif->dma_regs; - drive->waiting_for_dma = 0; dstat = readl(&dma->status); writel(((RUN|WAKE|DEAD) << 16), &dma->control); - pmac_ide_destroy_dmatable(drive); + /* verify good dma status. we don't check for ACTIVE beeing 0. We should... * in theory, but with ATAPI decices doing buffer underruns, that would * cause us to disable DMA, which isn't what we want @@ -1927,14 +1599,11 @@ pmac_ide_dma_end (ide_drive_t *drive) static int pmac_ide_dma_test_irq (ide_drive_t *drive) { - pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data; - volatile struct dbdma_regs __iomem *dma; + ide_hwif_t *hwif = drive->hwif; + pmac_ide_hwif_t *pmif = dev_get_drvdata(hwif->gendev.parent); + volatile struct dbdma_regs __iomem *dma = pmif->dma_regs; unsigned long status, timeout; - if (pmif == NULL) - return 0; - dma = pmif->dma_regs; - /* We have to things to deal with here: * * - The dbdma won't stop if the command was started @@ -1953,9 +1622,6 @@ pmac_ide_dma_test_irq (ide_drive_t *drive) status = readl(&dma->status); if (!(status & ACTIVE)) return 1; - if (!drive->waiting_for_dma) - printk(KERN_WARNING "ide%d, ide_dma_test_irq \ - called while not waiting\n", HWIF(drive)->index); /* If dbdma didn't execute the STOP command yet, the * active bit is still set. We consider that we aren't @@ -1972,106 +1638,72 @@ pmac_ide_dma_test_irq (ide_drive_t *drive) if ((status & FLUSH) == 0) break; if (++timeout > 100) { - printk(KERN_WARNING "ide%d, ide_dma_test_irq \ - timeout flushing channel\n", HWIF(drive)->index); + printk(KERN_WARNING "ide%d, ide_dma_test_irq timeout flushing channel\n", + hwif->index); break; } } return 1; } -static int -pmac_ide_dma_host_off (ide_drive_t *drive) +static void pmac_ide_dma_host_set(ide_drive_t *drive, int on) { - return 0; } -static int -pmac_ide_dma_host_on (ide_drive_t *drive) -{ - return 0; -} - -static int -pmac_ide_dma_lostirq (ide_drive_t *drive) +static void +pmac_ide_dma_lost_irq (ide_drive_t *drive) { - pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data; - volatile struct dbdma_regs __iomem *dma; - unsigned long status; - - if (pmif == NULL) - return 0; - dma = pmif->dma_regs; + ide_hwif_t *hwif = drive->hwif; + pmac_ide_hwif_t *pmif = dev_get_drvdata(hwif->gendev.parent); + volatile struct dbdma_regs __iomem *dma = pmif->dma_regs; + unsigned long status = readl(&dma->status); - status = readl(&dma->status); printk(KERN_ERR "ide-pmac lost interrupt, dma status: %lx\n", status); - return 0; } +static const struct ide_dma_ops pmac_dma_ops = { + .dma_host_set = pmac_ide_dma_host_set, + .dma_setup = pmac_ide_dma_setup, + .dma_start = pmac_ide_dma_start, + .dma_end = pmac_ide_dma_end, + .dma_test_irq = pmac_ide_dma_test_irq, + .dma_lost_irq = pmac_ide_dma_lost_irq, +}; + /* * Allocate the data structures needed for using DMA with an interface * and fill the proper list of functions pointers */ -static void __init -pmac_ide_setup_dma(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif) +static int pmac_ide_init_dma(ide_hwif_t *hwif, const struct ide_port_info *d) { + pmac_ide_hwif_t *pmif = dev_get_drvdata(hwif->gendev.parent); + struct pci_dev *dev = to_pci_dev(hwif->dev); + /* We won't need pci_dev if we switch to generic consistent * DMA routines ... */ - if (hwif->pci_dev == NULL) - return; + if (dev == NULL || pmif->dma_regs == 0) + return -ENODEV; /* * Allocate space for the DBDMA commands. * The +2 is +1 for the stop command and +1 to allow for * aligning the start address to a multiple of 16 bytes. */ - pmif->dma_table_cpu = (struct dbdma_cmd*)pci_alloc_consistent( - hwif->pci_dev, + pmif->dma_table_cpu = pci_alloc_consistent( + dev, (MAX_DCMDS + 2) * sizeof(struct dbdma_cmd), &hwif->dmatable_dma); if (pmif->dma_table_cpu == NULL) { printk(KERN_ERR "%s: unable to allocate DMA command list\n", hwif->name); - return; + return -ENOMEM; } - hwif->ide_dma_off_quietly = &__ide_dma_off_quietly; - hwif->ide_dma_on = &__ide_dma_on; - hwif->ide_dma_check = &pmac_ide_dma_check; - hwif->dma_setup = &pmac_ide_dma_setup; - hwif->dma_exec_cmd = &pmac_ide_dma_exec_cmd; - hwif->dma_start = &pmac_ide_dma_start; - hwif->ide_dma_end = &pmac_ide_dma_end; - hwif->ide_dma_test_irq = &pmac_ide_dma_test_irq; - hwif->ide_dma_host_off = &pmac_ide_dma_host_off; - hwif->ide_dma_host_on = &pmac_ide_dma_host_on; - hwif->ide_dma_timeout = &__ide_dma_timeout; - hwif->ide_dma_lostirq = &pmac_ide_dma_lostirq; - - hwif->atapi_dma = 1; - switch(pmif->kind) { - case controller_sh_ata6: - hwif->ultra_mask = pmif->cable_80 ? 0x7f : 0x07; - hwif->mwdma_mask = 0x07; - hwif->swdma_mask = 0x00; - break; - case controller_un_ata6: - case controller_k2_ata6: - hwif->ultra_mask = pmif->cable_80 ? 0x3f : 0x07; - hwif->mwdma_mask = 0x07; - hwif->swdma_mask = 0x00; - break; - case controller_kl_ata4: - hwif->ultra_mask = pmif->cable_80 ? 0x1f : 0x07; - hwif->mwdma_mask = 0x07; - hwif->swdma_mask = 0x00; - break; - default: - hwif->ultra_mask = 0x00; - hwif->mwdma_mask = 0x07; - hwif->swdma_mask = 0x00; - break; - } + hwif->sg_max_nents = MAX_DCMDS; + + return 0; } -#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */ +module_init(pmac_ide_probe); + +MODULE_LICENSE("GPL"); diff --git a/drivers/ide/ppc/mpc8xx.c b/drivers/ide/ppc/mpc8xx.c deleted file mode 100644 index 0ac9da3a737..00000000000 --- a/drivers/ide/ppc/mpc8xx.c +++ /dev/null @@ -1,854 +0,0 @@ -/* - * linux/drivers/ide/ppc/ide-m8xx.c - * - * Copyright (C) 2000, 2001 Wolfgang Denk, wd@denx.de - * Modified for direct IDE interface - * by Thomas Lange, thomas@corelatus.com - * Modified for direct IDE interface on 8xx without using the PCMCIA - * controller - * by Steven.Scholz@imc-berlin.de - * Moved out of arch/ppc/kernel/m8xx_setup.c, other minor cleanups - * by Mathew Locke <mattl@mvista.com> - */ - -#include <linux/errno.h> -#include <linux/sched.h> -#include <linux/kernel.h> -#include <linux/mm.h> -#include <linux/stddef.h> -#include <linux/unistd.h> -#include <linux/ptrace.h> -#include <linux/slab.h> -#include <linux/user.h> -#include <linux/a.out.h> -#include <linux/tty.h> -#include <linux/major.h> -#include <linux/interrupt.h> -#include <linux/reboot.h> -#include <linux/init.h> -#include <linux/ioport.h> -#include <linux/ide.h> -#include <linux/bootmem.h> - -#include <asm/mpc8xx.h> -#include <asm/mmu.h> -#include <asm/processor.h> -#include <asm/residual.h> -#include <asm/io.h> -#include <asm/pgtable.h> -#include <asm/ide.h> -#include <asm/8xx_immap.h> -#include <asm/machdep.h> -#include <asm/irq.h> - -static int identify (volatile u8 *p); -static void print_fixed (volatile u8 *p); -static void print_funcid (int func); -static int check_ide_device (unsigned long base); - -static void ide_interrupt_ack (void *dev); -static void m8xx_ide_tuneproc(ide_drive_t *drive, u8 pio); - -typedef struct ide_ioport_desc { - unsigned long base_off; /* Offset to PCMCIA memory */ - unsigned long reg_off[IDE_NR_PORTS]; /* controller register offsets */ - int irq; /* IRQ */ -} ide_ioport_desc_t; - -ide_ioport_desc_t ioport_dsc[MAX_HWIFS] = { -#ifdef IDE0_BASE_OFFSET - { IDE0_BASE_OFFSET, - { - IDE0_DATA_REG_OFFSET, - IDE0_ERROR_REG_OFFSET, - IDE0_NSECTOR_REG_OFFSET, - IDE0_SECTOR_REG_OFFSET, - IDE0_LCYL_REG_OFFSET, - IDE0_HCYL_REG_OFFSET, - IDE0_SELECT_REG_OFFSET, - IDE0_STATUS_REG_OFFSET, - IDE0_CONTROL_REG_OFFSET, - IDE0_IRQ_REG_OFFSET, - }, - IDE0_INTERRUPT, - }, -#ifdef IDE1_BASE_OFFSET - { IDE1_BASE_OFFSET, - { - IDE1_DATA_REG_OFFSET, - IDE1_ERROR_REG_OFFSET, - IDE1_NSECTOR_REG_OFFSET, - IDE1_SECTOR_REG_OFFSET, - IDE1_LCYL_REG_OFFSET, - IDE1_HCYL_REG_OFFSET, - IDE1_SELECT_REG_OFFSET, - IDE1_STATUS_REG_OFFSET, - IDE1_CONTROL_REG_OFFSET, - IDE1_IRQ_REG_OFFSET, - }, - IDE1_INTERRUPT, - }, -#endif /* IDE1_BASE_OFFSET */ -#endif /* IDE0_BASE_OFFSET */ -}; - -ide_pio_timings_t ide_pio_clocks[6]; -int hold_time[6] = {30, 20, 15, 10, 10, 10 }; /* PIO Mode 5 with IORDY (nonstandard) */ - -/* - * Warning: only 1 (ONE) PCMCIA slot supported here, - * which must be correctly initialized by the firmware (PPCBoot). - */ -static int _slot_ = -1; /* will be read from PCMCIA registers */ - -/* Make clock cycles and always round up */ -#define PCMCIA_MK_CLKS( t, T ) (( (t) * ((T)/1000000) + 999U ) / 1000U ) - - - -/* - * IDE stuff. - */ -static int -m8xx_ide_default_irq(unsigned long base) -{ -#ifdef CONFIG_BLK_DEV_MPC8xx_IDE - if (base >= MAX_HWIFS) - return 0; - - printk("[%d] m8xx_ide_default_irq %d\n",__LINE__,ioport_dsc[base].irq); - - return (ioport_dsc[base].irq); -#else - return 9; -#endif -} - -static unsigned long -m8xx_ide_default_io_base(int index) -{ - return index; -} - -#define M8XX_PCMCIA_CD2(slot) (0x10000000 >> (slot << 4)) -#define M8XX_PCMCIA_CD1(slot) (0x08000000 >> (slot << 4)) - -/* - * The TQM850L hardware has two pins swapped! Grrrrgh! - */ -#ifdef CONFIG_TQM850L -#define __MY_PCMCIA_GCRX_CXRESET PCMCIA_GCRX_CXOE -#define __MY_PCMCIA_GCRX_CXOE PCMCIA_GCRX_CXRESET -#else -#define __MY_PCMCIA_GCRX_CXRESET PCMCIA_GCRX_CXRESET -#define __MY_PCMCIA_GCRX_CXOE PCMCIA_GCRX_CXOE -#endif - -#if defined(CONFIG_BLK_DEV_MPC8xx_IDE) && defined(CONFIG_IDE_8xx_PCCARD) -#define PCMCIA_SCHLVL IDE0_INTERRUPT /* Status Change Interrupt Level */ -static int pcmcia_schlvl = PCMCIA_SCHLVL; -#endif - -/* - * See include/linux/ide.h for definition of hw_regs_t (p, base) - */ - -/* - * m8xx_ide_init_hwif_ports for a direct IDE interface _using_ - */ -#if defined(CONFIG_IDE_8xx_PCCARD) || defined(CONFIG_IDE_8xx_DIRECT) -static void -m8xx_ide_init_hwif_ports(hw_regs_t *hw, unsigned long data_port, - unsigned long ctrl_port, int *irq) -{ - unsigned long *p = hw->io_ports; - int i; - - typedef struct { - ulong br; - ulong or; - } pcmcia_win_t; - volatile pcmcia_win_t *win; - volatile pcmconf8xx_t *pcmp; - - uint *pgcrx; - u32 pcmcia_phy_base; - u32 pcmcia_phy_end; - static unsigned long pcmcia_base = 0; - unsigned long base; - - *p = 0; - if (irq) - *irq = 0; - - pcmp = (pcmconf8xx_t *)(&(((immap_t *)IMAP_ADDR)->im_pcmcia)); - - if (!pcmcia_base) { - /* - * Read out PCMCIA registers. Since the reset values - * are undefined, we sure hope that they have been - * set up by firmware - */ - - /* Scan all registers for valid settings */ - pcmcia_phy_base = 0xFFFFFFFF; - pcmcia_phy_end = 0; - /* br0 is start of brX and orX regs */ - win = (pcmcia_win_t *) \ - (&(((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pbr0)); - for (i = 0; i < 8; i++) { - if (win->or & 1) { /* This bank is marked as valid */ - if (win->br < pcmcia_phy_base) { - pcmcia_phy_base = win->br; - } - if ((win->br + PCMCIA_MEM_SIZE) > pcmcia_phy_end) { - pcmcia_phy_end = win->br + PCMCIA_MEM_SIZE; - } - /* Check which slot that has been defined */ - _slot_ = (win->or >> 2) & 1; - - } /* Valid bank */ - win++; - } /* for */ - - printk ("PCMCIA slot %c: phys mem %08x...%08x (size %08x)\n", - 'A' + _slot_, - pcmcia_phy_base, pcmcia_phy_end, - pcmcia_phy_end - pcmcia_phy_base); - - pcmcia_base=(unsigned long)ioremap(pcmcia_phy_base, - pcmcia_phy_end-pcmcia_phy_base); - -#ifdef DEBUG - printk ("PCMCIA virt base: %08lx\n", pcmcia_base); -#endif - /* Compute clock cycles for PIO timings */ - for (i=0; i<6; ++i) { - bd_t *binfo = (bd_t *)__res; - - hold_time[i] = - PCMCIA_MK_CLKS (hold_time[i], - binfo->bi_busfreq); - ide_pio_clocks[i].setup_time = - PCMCIA_MK_CLKS (ide_pio_timings[i].setup_time, - binfo->bi_busfreq); - ide_pio_clocks[i].active_time = - PCMCIA_MK_CLKS (ide_pio_timings[i].active_time, - binfo->bi_busfreq); - ide_pio_clocks[i].cycle_time = - PCMCIA_MK_CLKS (ide_pio_timings[i].cycle_time, - binfo->bi_busfreq); -#if 0 - printk ("PIO mode %d timings: %d/%d/%d => %d/%d/%d\n", - i, - ide_pio_clocks[i].setup_time, - ide_pio_clocks[i].active_time, - ide_pio_clocks[i].hold_time, - ide_pio_clocks[i].cycle_time, - ide_pio_timings[i].setup_time, - ide_pio_timings[i].active_time, - ide_pio_timings[i].hold_time, - ide_pio_timings[i].cycle_time); -#endif - } - } - - if (data_port >= MAX_HWIFS) - return; - - if (_slot_ == -1) { - printk ("PCMCIA slot has not been defined! Using A as default\n"); - _slot_ = 0; - } - -#ifdef CONFIG_IDE_8xx_PCCARD - -#ifdef DEBUG - printk ("PIPR = 0x%08X slot %c ==> mask = 0x%X\n", - pcmp->pcmc_pipr, - 'A' + _slot_, - M8XX_PCMCIA_CD1(_slot_) | M8XX_PCMCIA_CD2(_slot_) ); -#endif /* DEBUG */ - - if (pcmp->pcmc_pipr & (M8XX_PCMCIA_CD1(_slot_)|M8XX_PCMCIA_CD2(_slot_))) { - printk ("No card in slot %c: PIPR=%08x\n", - 'A' + _slot_, (u32) pcmp->pcmc_pipr); - return; /* No card in slot */ - } - - check_ide_device (pcmcia_base); - -#endif /* CONFIG_IDE_8xx_PCCARD */ - - base = pcmcia_base + ioport_dsc[data_port].base_off; -#ifdef DEBUG - printk ("base: %08x + %08x = %08x\n", - pcmcia_base, ioport_dsc[data_port].base_off, base); -#endif - - for (i = 0; i < IDE_NR_PORTS; ++i) { -#ifdef DEBUG - printk ("port[%d]: %08x + %08x = %08x\n", - i, - base, - ioport_dsc[data_port].reg_off[i], - i, base + ioport_dsc[data_port].reg_off[i]); -#endif - *p++ = base + ioport_dsc[data_port].reg_off[i]; - } - - if (irq) { -#ifdef CONFIG_IDE_8xx_PCCARD - unsigned int reg; - - *irq = ioport_dsc[data_port].irq; - if (_slot_) - pgcrx = &((immap_t *) IMAP_ADDR)->im_pcmcia.pcmc_pgcrb; - else - pgcrx = &((immap_t *) IMAP_ADDR)->im_pcmcia.pcmc_pgcra; - - reg = *pgcrx; - reg |= mk_int_int_mask (pcmcia_schlvl) << 24; - reg |= mk_int_int_mask (pcmcia_schlvl) << 16; - *pgcrx = reg; -#else /* direct connected IDE drive, i.e. external IRQ, not the PCMCIA irq */ - *irq = ioport_dsc[data_port].irq; -#endif /* CONFIG_IDE_8xx_PCCARD */ - } - - /* register routine to tune PIO mode */ - ide_hwifs[data_port].tuneproc = m8xx_ide_tuneproc; - - hw->ack_intr = (ide_ack_intr_t *) ide_interrupt_ack; - /* Enable Harddisk Interrupt, - * and make it edge sensitive - */ - /* (11-18) Set edge detect for irq, no wakeup from low power mode */ - ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_siel |= - (0x80000000 >> ioport_dsc[data_port].irq); - -#ifdef CONFIG_IDE_8xx_PCCARD - /* Make sure we don't get garbage irq */ - ((immap_t *) IMAP_ADDR)->im_pcmcia.pcmc_pscr = 0xFFFF; - - /* Enable falling edge irq */ - pcmp->pcmc_per = 0x100000 >> (16 * _slot_); -#endif /* CONFIG_IDE_8xx_PCCARD */ -} /* m8xx_ide_init_hwif_ports() using 8xx internal PCMCIA interface */ -#endif /* CONFIG_IDE_8xx_PCCARD || CONFIG_IDE_8xx_DIRECT */ - -/* - * m8xx_ide_init_hwif_ports for a direct IDE interface _not_ using - * MPC8xx's internal PCMCIA interface - */ -#if defined(CONFIG_IDE_EXT_DIRECT) -void m8xx_ide_init_hwif_ports (hw_regs_t *hw, - unsigned long data_port, unsigned long ctrl_port, int *irq) -{ - unsigned long *p = hw->io_ports; - int i; - - u32 ide_phy_base; - u32 ide_phy_end; - static unsigned long ide_base = 0; - unsigned long base; - - *p = 0; - if (irq) - *irq = 0; - - if (!ide_base) { - - /* TODO: - * - add code to read ORx, BRx - */ - ide_phy_base = CFG_ATA_BASE_ADDR; - ide_phy_end = CFG_ATA_BASE_ADDR + 0x200; - - printk ("IDE phys mem : %08x...%08x (size %08x)\n", - ide_phy_base, ide_phy_end, - ide_phy_end - ide_phy_base); - - ide_base=(unsigned long)ioremap(ide_phy_base, - ide_phy_end-ide_phy_base); - -#ifdef DEBUG - printk ("IDE virt base: %08lx\n", ide_base); -#endif - } - - if (data_port >= MAX_HWIFS) - return; - - base = ide_base + ioport_dsc[data_port].base_off; -#ifdef DEBUG - printk ("base: %08x + %08x = %08x\n", - ide_base, ioport_dsc[data_port].base_off, base); -#endif - - for (i = 0; i < IDE_NR_PORTS; ++i) { -#ifdef DEBUG - printk ("port[%d]: %08x + %08x = %08x\n", - i, - base, - ioport_dsc[data_port].reg_off[i], - i, base + ioport_dsc[data_port].reg_off[i]); -#endif - *p++ = base + ioport_dsc[data_port].reg_off[i]; - } - - if (irq) { - /* direct connected IDE drive, i.e. external IRQ */ - *irq = ioport_dsc[data_port].irq; - } - - /* register routine to tune PIO mode */ - ide_hwifs[data_port].tuneproc = m8xx_ide_tuneproc; - - hw->ack_intr = (ide_ack_intr_t *) ide_interrupt_ack; - /* Enable Harddisk Interrupt, - * and make it edge sensitive - */ - /* (11-18) Set edge detect for irq, no wakeup from low power mode */ - ((immap_t *) IMAP_ADDR)->im_siu_conf.sc_siel |= - (0x80000000 >> ioport_dsc[data_port].irq); -} /* m8xx_ide_init_hwif_ports() for CONFIG_IDE_8xx_DIRECT */ - -#endif /* CONFIG_IDE_8xx_DIRECT */ - - -/* -------------------------------------------------------------------- */ - - -/* PCMCIA Timing */ -#ifndef PCMCIA_SHT -#define PCMCIA_SHT(t) ((t & 0x0F)<<16) /* Strobe Hold Time */ -#define PCMCIA_SST(t) ((t & 0x0F)<<12) /* Strobe Setup Time */ -#define PCMCIA_SL(t) ((t==32) ? 0 : ((t & 0x1F)<<7)) /* Strobe Length */ -#endif - - -/* Calculate PIO timings */ -static void -m8xx_ide_tuneproc(ide_drive_t *drive, u8 pio) -{ - ide_pio_data_t d; -#if defined(CONFIG_IDE_8xx_PCCARD) || defined(CONFIG_IDE_8xx_DIRECT) - volatile pcmconf8xx_t *pcmp; - ulong timing, mask, reg; -#endif - - pio = ide_get_best_pio_mode(drive, pio, 4, &d); - -#if 1 - printk("%s[%d] %s: best PIO mode: %d\n", - __FILE__,__LINE__,__FUNCTION__, pio); -#endif - -#if defined(CONFIG_IDE_8xx_PCCARD) || defined(CONFIG_IDE_8xx_DIRECT) - pcmp = (pcmconf8xx_t *)(&(((immap_t *)IMAP_ADDR)->im_pcmcia)); - - mask = ~(PCMCIA_SHT(0xFF) | PCMCIA_SST(0xFF) | PCMCIA_SL(0xFF)); - - timing = PCMCIA_SHT(hold_time[pio] ) - | PCMCIA_SST(ide_pio_clocks[pio].setup_time ) - | PCMCIA_SL (ide_pio_clocks[pio].active_time) - ; - -#if 1 - printk ("Setting timing bits 0x%08lx in PCMCIA controller\n", timing); -#endif - if ((reg = pcmp->pcmc_por0 & mask) != 0) - pcmp->pcmc_por0 = reg | timing; - - if ((reg = pcmp->pcmc_por1 & mask) != 0) - pcmp->pcmc_por1 = reg | timing; - - if ((reg = pcmp->pcmc_por2 & mask) != 0) - pcmp->pcmc_por2 = reg | timing; - - if ((reg = pcmp->pcmc_por3 & mask) != 0) - pcmp->pcmc_por3 = reg | timing; - - if ((reg = pcmp->pcmc_por4 & mask) != 0) - pcmp->pcmc_por4 = reg | timing; - - if ((reg = pcmp->pcmc_por5 & mask) != 0) - pcmp->pcmc_por5 = reg | timing; - - if ((reg = pcmp->pcmc_por6 & mask) != 0) - pcmp->pcmc_por6 = reg | timing; - - if ((reg = pcmp->pcmc_por7 & mask) != 0) - pcmp->pcmc_por7 = reg | timing; - -#elif defined(CONFIG_IDE_EXT_DIRECT) - - printk("%s[%d] %s: not implemented yet!\n", - __FILE__,__LINE__,__FUNCTION__); -#endif /* defined(CONFIG_IDE_8xx_PCCARD) || defined(CONFIG_IDE_8xx_PCMCIA */ -} - -static void -ide_interrupt_ack (void *dev) -{ -#ifdef CONFIG_IDE_8xx_PCCARD - u_int pscr, pipr; - -#if (PCMCIA_SOCKETS_NO == 2) - u_int _slot_; -#endif - - /* get interrupt sources */ - - pscr = ((volatile immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pscr; - pipr = ((volatile immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pipr; - - /* - * report only if both card detect signals are the same - * not too nice done, - * we depend on that CD2 is the bit to the left of CD1... - */ - - if(_slot_==-1){ - printk("PCMCIA slot has not been defined! Using A as default\n"); - _slot_=0; - } - - if(((pipr & M8XX_PCMCIA_CD2(_slot_)) >> 1) ^ - (pipr & M8XX_PCMCIA_CD1(_slot_)) ) { - printk ("card detect interrupt\n"); - } - /* clear the interrupt sources */ - ((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pscr = pscr; - -#else /* ! CONFIG_IDE_8xx_PCCARD */ - /* - * Only CONFIG_IDE_8xx_PCCARD is using the interrupt of the - * MPC8xx's PCMCIA controller, so there is nothing to be done here - * for CONFIG_IDE_8xx_DIRECT and CONFIG_IDE_EXT_DIRECT. - * The interrupt is handled somewhere else. -- Steven - */ -#endif /* CONFIG_IDE_8xx_PCCARD */ -} - - - -/* - * CIS Tupel codes - */ -#define CISTPL_NULL 0x00 -#define CISTPL_DEVICE 0x01 -#define CISTPL_LONGLINK_CB 0x02 -#define CISTPL_INDIRECT 0x03 -#define CISTPL_CONFIG_CB 0x04 -#define CISTPL_CFTABLE_ENTRY_CB 0x05 -#define CISTPL_LONGLINK_MFC 0x06 -#define CISTPL_BAR 0x07 -#define CISTPL_PWR_MGMNT 0x08 -#define CISTPL_EXTDEVICE 0x09 -#define CISTPL_CHECKSUM 0x10 -#define CISTPL_LONGLINK_A 0x11 -#define CISTPL_LONGLINK_C 0x12 -#define CISTPL_LINKTARGET 0x13 -#define CISTPL_NO_LINK 0x14 -#define CISTPL_VERS_1 0x15 -#define CISTPL_ALTSTR 0x16 -#define CISTPL_DEVICE_A 0x17 -#define CISTPL_JEDEC_C 0x18 -#define CISTPL_JEDEC_A 0x19 -#define CISTPL_CONFIG 0x1a -#define CISTPL_CFTABLE_ENTRY 0x1b -#define CISTPL_DEVICE_OC 0x1c -#define CISTPL_DEVICE_OA 0x1d -#define CISTPL_DEVICE_GEO 0x1e -#define CISTPL_DEVICE_GEO_A 0x1f -#define CISTPL_MANFID 0x20 -#define CISTPL_FUNCID 0x21 -#define CISTPL_FUNCE 0x22 -#define CISTPL_SWIL 0x23 -#define CISTPL_END 0xff - -/* - * CIS Function ID codes - */ -#define CISTPL_FUNCID_MULTI 0x00 -#define CISTPL_FUNCID_MEMORY 0x01 -#define CISTPL_FUNCID_SERIAL 0x02 -#define CISTPL_FUNCID_PARALLEL 0x03 -#define CISTPL_FUNCID_FIXED 0x04 -#define CISTPL_FUNCID_VIDEO 0x05 -#define CISTPL_FUNCID_NETWORK 0x06 -#define CISTPL_FUNCID_AIMS 0x07 -#define CISTPL_FUNCID_SCSI 0x08 - -/* - * Fixed Disk FUNCE codes - */ -#define CISTPL_IDE_INTERFACE 0x01 - -#define CISTPL_FUNCE_IDE_IFACE 0x01 -#define CISTPL_FUNCE_IDE_MASTER 0x02 -#define CISTPL_FUNCE_IDE_SLAVE 0x03 - -/* First feature byte */ -#define CISTPL_IDE_SILICON 0x04 -#define CISTPL_IDE_UNIQUE 0x08 -#define CISTPL_IDE_DUAL 0x10 - -/* Second feature byte */ -#define CISTPL_IDE_HAS_SLEEP 0x01 -#define CISTPL_IDE_HAS_STANDBY 0x02 -#define CISTPL_IDE_HAS_IDLE 0x04 -#define CISTPL_IDE_LOW_POWER 0x08 -#define CISTPL_IDE_REG_INHIBIT 0x10 -#define CISTPL_IDE_HAS_INDEX 0x20 -#define CISTPL_IDE_IOIS16 0x40 - - -/* -------------------------------------------------------------------- */ - - -#define MAX_TUPEL_SZ 512 -#define MAX_FEATURES 4 - -static int check_ide_device (unsigned long base) -{ - volatile u8 *ident = NULL; - volatile u8 *feature_p[MAX_FEATURES]; - volatile u8 *p, *start; - int n_features = 0; - u8 func_id = ~0; - u8 code, len; - unsigned short config_base = 0; - int found = 0; - int i; - -#ifdef DEBUG - printk ("PCMCIA MEM: %08lX\n", base); -#endif - start = p = (volatile u8 *) base; - - while ((p - start) < MAX_TUPEL_SZ) { - - code = *p; p += 2; - - if (code == 0xFF) { /* End of chain */ - break; - } - - len = *p; p += 2; -#ifdef DEBUG_PCMCIA - { volatile u8 *q = p; - printk ("\nTuple code %02x length %d\n\tData:", - code, len); - - for (i = 0; i < len; ++i) { - printk (" %02x", *q); - q+= 2; - } - } -#endif /* DEBUG_PCMCIA */ - switch (code) { - case CISTPL_VERS_1: - ident = p + 4; - break; - case CISTPL_FUNCID: - func_id = *p; - break; - case CISTPL_FUNCE: - if (n_features < MAX_FEATURES) - feature_p[n_features++] = p; - break; - case CISTPL_CONFIG: - config_base = (*(p+6) << 8) + (*(p+4)); - default: - break; - } - p += 2 * len; - } - - found = identify (ident); - - if (func_id != ((u8)~0)) { - print_funcid (func_id); - - if (func_id == CISTPL_FUNCID_FIXED) - found = 1; - else - return (1); /* no disk drive */ - } - - for (i=0; i<n_features; ++i) { - print_fixed (feature_p[i]); - } - - if (!found) { - printk ("unknown card type\n"); - return (1); - } - - /* set level mode irq and I/O mapped device in config reg*/ - *((u8 *)(base + config_base)) = 0x41; - - return (0); -} - -/* ------------------------------------------------------------------------- */ - -static void print_funcid (int func) -{ - switch (func) { - case CISTPL_FUNCID_MULTI: - printk (" Multi-Function"); - break; - case CISTPL_FUNCID_MEMORY: - printk (" Memory"); - break; - case CISTPL_FUNCID_SERIAL: - printk (" Serial Port"); - break; - case CISTPL_FUNCID_PARALLEL: - printk (" Parallel Port"); - break; - case CISTPL_FUNCID_FIXED: - printk (" Fixed Disk"); - break; - case CISTPL_FUNCID_VIDEO: - printk (" Video Adapter"); - break; - case CISTPL_FUNCID_NETWORK: - printk (" Network Adapter"); - break; - case CISTPL_FUNCID_AIMS: - printk (" AIMS Card"); - break; - case CISTPL_FUNCID_SCSI: - printk (" SCSI Adapter"); - break; - default: - printk (" Unknown"); - break; - } - printk (" Card\n"); -} - -/* ------------------------------------------------------------------------- */ - -static void print_fixed (volatile u8 *p) -{ - if (p == NULL) - return; - - switch (*p) { - case CISTPL_FUNCE_IDE_IFACE: - { u8 iface = *(p+2); - - printk ((iface == CISTPL_IDE_INTERFACE) ? " IDE" : " unknown"); - printk (" interface "); - break; - } - case CISTPL_FUNCE_IDE_MASTER: - case CISTPL_FUNCE_IDE_SLAVE: - { u8 f1 = *(p+2); - u8 f2 = *(p+4); - - printk ((f1 & CISTPL_IDE_SILICON) ? " [silicon]" : " [rotating]"); - - if (f1 & CISTPL_IDE_UNIQUE) - printk (" [unique]"); - - printk ((f1 & CISTPL_IDE_DUAL) ? " [dual]" : " [single]"); - - if (f2 & CISTPL_IDE_HAS_SLEEP) - printk (" [sleep]"); - - if (f2 & CISTPL_IDE_HAS_STANDBY) - printk (" [standby]"); - - if (f2 & CISTPL_IDE_HAS_IDLE) - printk (" [idle]"); - - if (f2 & CISTPL_IDE_LOW_POWER) - printk (" [low power]"); - - if (f2 & CISTPL_IDE_REG_INHIBIT) - printk (" [reg inhibit]"); - - if (f2 & CISTPL_IDE_HAS_INDEX) - printk (" [index]"); - - if (f2 & CISTPL_IDE_IOIS16) - printk (" [IOis16]"); - - break; - } - } - printk ("\n"); -} - -/* ------------------------------------------------------------------------- */ - - -#define MAX_IDENT_CHARS 64 -#define MAX_IDENT_FIELDS 4 - -static u8 *known_cards[] = { - "ARGOSY PnPIDE D5", - NULL -}; - -static int identify (volatile u8 *p) -{ - u8 id_str[MAX_IDENT_CHARS]; - u8 data; - u8 *t; - u8 **card; - int i, done; - - if (p == NULL) - return (0); /* Don't know */ - - t = id_str; - done =0; - - for (i=0; i<=4 && !done; ++i, p+=2) { - while ((data = *p) != '\0') { - if (data == 0xFF) { - done = 1; - break; - } - *t++ = data; - if (t == &id_str[MAX_IDENT_CHARS-1]) { - done = 1; - break; - } - p += 2; - } - if (!done) - *t++ = ' '; - } - *t = '\0'; - while (--t > id_str) { - if (*t == ' ') - *t = '\0'; - else - break; - } - printk ("Card ID: %s\n", id_str); - - for (card=known_cards; *card; ++card) { - if (strcmp(*card, id_str) == 0) { /* found! */ - return (1); - } - } - - return (0); /* don't know */ -} - -void m8xx_ide_init(void) -{ - ppc_ide_md.default_irq = m8xx_ide_default_irq; - ppc_ide_md.default_io_base = m8xx_ide_default_io_base; - ppc_ide_md.ide_init_hwif = m8xx_ide_init_hwif_ports; -} diff --git a/drivers/ide/q40ide.c b/drivers/ide/q40ide.c new file mode 100644 index 00000000000..ecd0a69245f --- /dev/null +++ b/drivers/ide/q40ide.c @@ -0,0 +1,168 @@ +/* + * Q40 I/O port IDE Driver + * + * (c) Richard Zidlicky + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + * + * + */ + +#include <linux/types.h> +#include <linux/mm.h> +#include <linux/interrupt.h> +#include <linux/blkdev.h> +#include <linux/ide.h> +#include <linux/module.h> + +#include <asm/ide.h> + + /* + * Bases of the IDE interfaces + */ + +#define Q40IDE_NUM_HWIFS 2 + +#define PCIDE_BASE1 0x1f0 +#define PCIDE_BASE2 0x170 +#define PCIDE_BASE3 0x1e8 +#define PCIDE_BASE4 0x168 +#define PCIDE_BASE5 0x1e0 +#define PCIDE_BASE6 0x160 + +static const unsigned long pcide_bases[Q40IDE_NUM_HWIFS] = { + PCIDE_BASE1, PCIDE_BASE2, /* PCIDE_BASE3, PCIDE_BASE4 , PCIDE_BASE5, + PCIDE_BASE6 */ +}; + +static int q40ide_default_irq(unsigned long base) +{ + switch (base) { + case 0x1f0: return 14; + case 0x170: return 15; + case 0x1e8: return 11; + default: + return 0; + } +} + + +/* + * Addresses are pretranslated for Q40 ISA access. + */ +static void q40_ide_setup_ports(struct ide_hw *hw, unsigned long base, int irq) +{ + memset(hw, 0, sizeof(*hw)); + /* BIG FAT WARNING: + assumption: only DATA port is ever used in 16 bit mode */ + hw->io_ports.data_addr = Q40_ISA_IO_W(base); + hw->io_ports.error_addr = Q40_ISA_IO_B(base + 1); + hw->io_ports.nsect_addr = Q40_ISA_IO_B(base + 2); + hw->io_ports.lbal_addr = Q40_ISA_IO_B(base + 3); + hw->io_ports.lbam_addr = Q40_ISA_IO_B(base + 4); + hw->io_ports.lbah_addr = Q40_ISA_IO_B(base + 5); + hw->io_ports.device_addr = Q40_ISA_IO_B(base + 6); + hw->io_ports.status_addr = Q40_ISA_IO_B(base + 7); + hw->io_ports.ctl_addr = Q40_ISA_IO_B(base + 0x206); + + hw->irq = irq; +} + +static void q40ide_input_data(ide_drive_t *drive, struct ide_cmd *cmd, + void *buf, unsigned int len) +{ + unsigned long data_addr = drive->hwif->io_ports.data_addr; + + if (drive->media == ide_disk && cmd && (cmd->tf_flags & IDE_TFLAG_FS)) { + __ide_mm_insw(data_addr, buf, (len + 1) / 2); + return; + } + + raw_insw_swapw((u16 *)data_addr, buf, (len + 1) / 2); +} + +static void q40ide_output_data(ide_drive_t *drive, struct ide_cmd *cmd, + void *buf, unsigned int len) +{ + unsigned long data_addr = drive->hwif->io_ports.data_addr; + + if (drive->media == ide_disk && cmd && (cmd->tf_flags & IDE_TFLAG_FS)) { + __ide_mm_outsw(data_addr, buf, (len + 1) / 2); + return; + } + + raw_outsw_swapw((u16 *)data_addr, buf, (len + 1) / 2); +} + +/* Q40 has a byte-swapped IDE interface */ +static const struct ide_tp_ops q40ide_tp_ops = { + .exec_command = ide_exec_command, + .read_status = ide_read_status, + .read_altstatus = ide_read_altstatus, + .write_devctl = ide_write_devctl, + + .dev_select = ide_dev_select, + .tf_load = ide_tf_load, + .tf_read = ide_tf_read, + + .input_data = q40ide_input_data, + .output_data = q40ide_output_data, +}; + +static const struct ide_port_info q40ide_port_info = { + .tp_ops = &q40ide_tp_ops, + .host_flags = IDE_HFLAG_MMIO | IDE_HFLAG_NO_DMA, + .irq_flags = IRQF_SHARED, + .chipset = ide_generic, +}; + +/* + * the static array is needed to have the name reported in /proc/ioports, + * hwif->name unfortunately isn't available yet + */ +static const char *q40_ide_names[Q40IDE_NUM_HWIFS]={ + "ide0", "ide1" +}; + +/* + * Probe for Q40 IDE interfaces + */ + +static int __init q40ide_init(void) +{ + int i; + struct ide_hw hw[Q40IDE_NUM_HWIFS], *hws[] = { NULL, NULL }; + + if (!MACH_IS_Q40) + return -ENODEV; + + printk(KERN_INFO "ide: Q40 IDE controller\n"); + + for (i = 0; i < Q40IDE_NUM_HWIFS; i++) { + const char *name = q40_ide_names[i]; + + if (!request_region(pcide_bases[i], 8, name)) { + printk("could not reserve ports %lx-%lx for %s\n", + pcide_bases[i],pcide_bases[i]+8,name); + continue; + } + if (!request_region(pcide_bases[i]+0x206, 1, name)) { + printk("could not reserve port %lx for %s\n", + pcide_bases[i]+0x206,name); + release_region(pcide_bases[i], 8); + continue; + } + q40_ide_setup_ports(&hw[i], pcide_bases[i], + q40ide_default_irq(pcide_bases[i])); + + hws[i] = &hw[i]; + } + + return ide_host_add(&q40ide_port_info, hws, Q40IDE_NUM_HWIFS, NULL); +} + +module_init(q40ide_init); + +MODULE_LICENSE("GPL"); diff --git a/drivers/ide/qd65xx.c b/drivers/ide/qd65xx.c new file mode 100644 index 00000000000..a6fb6a894c7 --- /dev/null +++ b/drivers/ide/qd65xx.c @@ -0,0 +1,445 @@ +/* + * Copyright (C) 1996-2001 Linus Torvalds & author (see below) + */ + +/* + * Version 0.03 Cleaned auto-tune, added probe + * Version 0.04 Added second channel tuning + * Version 0.05 Enhanced tuning ; added qd6500 support + * Version 0.06 Added dos driver's list + * Version 0.07 Second channel bug fix + * + * QDI QD6500/QD6580 EIDE controller fast support + * + * To activate controller support, use "ide0=qd65xx" + */ + +/* + * Rewritten from the work of Colten Edwards <pje120@cs.usask.ca> by + * Samuel Thibault <samuel.thibault@ens-lyon.org> + */ + +#include <linux/module.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/delay.h> +#include <linux/timer.h> +#include <linux/mm.h> +#include <linux/ioport.h> +#include <linux/blkdev.h> +#include <linux/ide.h> +#include <linux/init.h> +#include <asm/io.h> + +#define DRV_NAME "qd65xx" + +#include "qd65xx.h" + +/* + * I/O ports are 0x30-0x31 (and 0x32-0x33 for qd6580) + * or 0xb0-0xb1 (and 0xb2-0xb3 for qd6580) + * -- qd6500 is a single IDE interface + * -- qd6580 is a dual IDE interface + * + * More research on qd6580 being done by willmore@cig.mot.com (David) + * More Information given by Petr Soucek (petr@ryston.cz) + * http://www.ryston.cz/petr/vlb + */ + +/* + * base: Timer1 + * + * + * base+0x01: Config (R/O) + * + * bit 0: ide baseport: 1 = 0x1f0 ; 0 = 0x170 (only useful for qd6500) + * bit 1: qd65xx baseport: 1 = 0xb0 ; 0 = 0x30 + * bit 2: ID3: bus speed: 1 = <=33MHz ; 0 = >33MHz + * bit 3: qd6500: 1 = disabled, 0 = enabled + * qd6580: 1 + * upper nibble: + * qd6500: 1100 + * qd6580: either 1010 or 0101 + * + * + * base+0x02: Timer2 (qd6580 only) + * + * + * base+0x03: Control (qd6580 only) + * + * bits 0-3 must always be set 1 + * bit 4 must be set 1, but is set 0 by dos driver while measuring vlb clock + * bit 0 : 1 = Only primary port enabled : channel 0 for hda, channel 1 for hdb + * 0 = Primary and Secondary ports enabled : channel 0 for hda & hdb + * channel 1 for hdc & hdd + * bit 1 : 1 = only disks on primary port + * 0 = disks & ATAPI devices on primary port + * bit 2-4 : always 0 + * bit 5 : status, but of what ? + * bit 6 : always set 1 by dos driver + * bit 7 : set 1 for non-ATAPI devices on primary port + * (maybe read-ahead and post-write buffer ?) + */ + +static int timings[4]={-1,-1,-1,-1}; /* stores current timing for each timer */ + +/* + * qd65xx_select: + * + * This routine is invoked to prepare for access to a given drive. + */ + +static void qd65xx_dev_select(ide_drive_t *drive) +{ + u8 index = (( (QD_TIMREG(drive)) & 0x80 ) >> 7) | + (QD_TIMREG(drive) & 0x02); + + if (timings[index] != QD_TIMING(drive)) + outb(timings[index] = QD_TIMING(drive), QD_TIMREG(drive)); + + outb(drive->select | ATA_DEVICE_OBS, drive->hwif->io_ports.device_addr); +} + +/* + * qd6500_compute_timing + * + * computes the timing value where + * lower nibble represents active time, in count of VLB clocks + * upper nibble represents recovery time, in count of VLB clocks + */ + +static u8 qd6500_compute_timing (ide_hwif_t *hwif, int active_time, int recovery_time) +{ + int clk = ide_vlb_clk ? ide_vlb_clk : 50; + u8 act_cyc, rec_cyc; + + if (clk <= 33) { + act_cyc = 9 - IDE_IN(active_time * clk / 1000 + 1, 2, 9); + rec_cyc = 15 - IDE_IN(recovery_time * clk / 1000 + 1, 0, 15); + } else { + act_cyc = 8 - IDE_IN(active_time * clk / 1000 + 1, 1, 8); + rec_cyc = 18 - IDE_IN(recovery_time * clk / 1000 + 1, 3, 18); + } + + return (rec_cyc << 4) | 0x08 | act_cyc; +} + +/* + * qd6580_compute_timing + * + * idem for qd6580 + */ + +static u8 qd6580_compute_timing (int active_time, int recovery_time) +{ + int clk = ide_vlb_clk ? ide_vlb_clk : 50; + u8 act_cyc, rec_cyc; + + act_cyc = 17 - IDE_IN(active_time * clk / 1000 + 1, 2, 17); + rec_cyc = 15 - IDE_IN(recovery_time * clk / 1000 + 1, 2, 15); + + return (rec_cyc << 4) | act_cyc; +} + +/* + * qd_find_disk_type + * + * tries to find timing from dos driver's table + */ + +static int qd_find_disk_type (ide_drive_t *drive, + int *active_time, int *recovery_time) +{ + struct qd65xx_timing_s *p; + char *m = (char *)&drive->id[ATA_ID_PROD]; + char model[ATA_ID_PROD_LEN]; + + if (*m == 0) + return 0; + + strncpy(model, m, ATA_ID_PROD_LEN); + ide_fixstring(model, ATA_ID_PROD_LEN, 1); /* byte-swap */ + + for (p = qd65xx_timing ; p->offset != -1 ; p++) { + if (!strncmp(p->model, model+p->offset, 4)) { + printk(KERN_DEBUG "%s: listed !\n", drive->name); + *active_time = p->active; + *recovery_time = p->recovery; + return 1; + } + } + return 0; +} + +/* + * qd_set_timing: + * + * records the timing + */ + +static void qd_set_timing (ide_drive_t *drive, u8 timing) +{ + unsigned long data = (unsigned long)ide_get_drivedata(drive); + + data &= 0xff00; + data |= timing; + ide_set_drivedata(drive, (void *)data); + + printk(KERN_DEBUG "%s: %#x\n", drive->name, timing); +} + +static void qd6500_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) +{ + u16 *id = drive->id; + int active_time = 175; + int recovery_time = 415; /* worst case values from the dos driver */ + + /* FIXME: use drive->pio_mode value */ + if (!qd_find_disk_type(drive, &active_time, &recovery_time) && + (id[ATA_ID_OLD_PIO_MODES] & 0xff) && (id[ATA_ID_FIELD_VALID] & 2) && + id[ATA_ID_EIDE_PIO] >= 240) { + printk(KERN_INFO "%s: PIO mode%d\n", drive->name, + id[ATA_ID_OLD_PIO_MODES] & 0xff); + active_time = 110; + recovery_time = drive->id[ATA_ID_EIDE_PIO] - 120; + } + + qd_set_timing(drive, qd6500_compute_timing(drive->hwif, + active_time, recovery_time)); +} + +static void qd6580_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) +{ + const u8 pio = drive->pio_mode - XFER_PIO_0; + struct ide_timing *t = ide_timing_find_mode(XFER_PIO_0 + pio); + unsigned int cycle_time; + int active_time = 175; + int recovery_time = 415; /* worst case values from the dos driver */ + u8 base = (hwif->config_data & 0xff00) >> 8; + + if (drive->id && !qd_find_disk_type(drive, &active_time, &recovery_time)) { + cycle_time = ide_pio_cycle_time(drive, pio); + + switch (pio) { + case 0: break; + case 3: + if (cycle_time >= 110) { + active_time = 86; + recovery_time = cycle_time - 102; + } else + printk(KERN_WARNING "%s: Strange recovery time !\n",drive->name); + break; + case 4: + if (cycle_time >= 69) { + active_time = 70; + recovery_time = cycle_time - 61; + } else + printk(KERN_WARNING "%s: Strange recovery time !\n",drive->name); + break; + default: + if (cycle_time >= 180) { + active_time = 110; + recovery_time = cycle_time - 120; + } else { + active_time = t->active; + recovery_time = cycle_time - active_time; + } + } + printk(KERN_INFO "%s: PIO mode%d\n", drive->name,pio); + } + + if (!hwif->channel && drive->media != ide_disk) { + outb(0x5f, QD_CONTROL_PORT); + printk(KERN_WARNING "%s: ATAPI: disabled read-ahead FIFO " + "and post-write buffer on %s.\n", + drive->name, hwif->name); + } + + qd_set_timing(drive, qd6580_compute_timing(active_time, recovery_time)); +} + +/* + * qd_testreg + * + * tests if the given port is a register + */ + +static int __init qd_testreg(int port) +{ + unsigned long flags; + u8 savereg, readreg; + + local_irq_save(flags); + savereg = inb_p(port); + outb_p(QD_TESTVAL, port); /* safe value */ + readreg = inb_p(port); + outb(savereg, port); + local_irq_restore(flags); + + if (savereg == QD_TESTVAL) { + printk(KERN_ERR "Outch ! the probe for qd65xx isn't reliable !\n"); + printk(KERN_ERR "Please contact maintainers to tell about your hardware\n"); + printk(KERN_ERR "Assuming qd65xx is not present.\n"); + return 1; + } + + return (readreg != QD_TESTVAL); +} + +static void __init qd6500_init_dev(ide_drive_t *drive) +{ + ide_hwif_t *hwif = drive->hwif; + u8 base = (hwif->config_data & 0xff00) >> 8; + u8 config = QD_CONFIG(hwif); + + ide_set_drivedata(drive, (void *)QD6500_DEF_DATA); +} + +static void __init qd6580_init_dev(ide_drive_t *drive) +{ + ide_hwif_t *hwif = drive->hwif; + u16 t1, t2; + u8 base = (hwif->config_data & 0xff00) >> 8; + u8 config = QD_CONFIG(hwif); + + if (hwif->host_flags & IDE_HFLAG_SINGLE) { + t1 = QD6580_DEF_DATA; + t2 = QD6580_DEF_DATA2; + } else + t2 = t1 = hwif->channel ? QD6580_DEF_DATA2 : QD6580_DEF_DATA; + + ide_set_drivedata(drive, (void *)((drive->dn & 1) ? t2 : t1)); +} + +static const struct ide_tp_ops qd65xx_tp_ops = { + .exec_command = ide_exec_command, + .read_status = ide_read_status, + .read_altstatus = ide_read_altstatus, + .write_devctl = ide_write_devctl, + + .dev_select = qd65xx_dev_select, + .tf_load = ide_tf_load, + .tf_read = ide_tf_read, + + .input_data = ide_input_data, + .output_data = ide_output_data, +}; + +static const struct ide_port_ops qd6500_port_ops = { + .init_dev = qd6500_init_dev, + .set_pio_mode = qd6500_set_pio_mode, +}; + +static const struct ide_port_ops qd6580_port_ops = { + .init_dev = qd6580_init_dev, + .set_pio_mode = qd6580_set_pio_mode, +}; + +static const struct ide_port_info qd65xx_port_info __initconst = { + .name = DRV_NAME, + .tp_ops = &qd65xx_tp_ops, + .chipset = ide_qd65xx, + .host_flags = IDE_HFLAG_IO_32BIT | + IDE_HFLAG_NO_DMA, + .pio_mask = ATA_PIO4, +}; + +/* + * qd_probe: + * + * looks at the specified baseport, and if qd found, registers & initialises it + * return 1 if another qd may be probed + */ + +static int __init qd_probe(int base) +{ + int rc; + u8 config, unit, control; + struct ide_port_info d = qd65xx_port_info; + + config = inb(QD_CONFIG_PORT); + + if (! ((config & QD_CONFIG_BASEPORT) >> 1 == (base == 0xb0)) ) + return -ENODEV; + + unit = ! (config & QD_CONFIG_IDE_BASEPORT); + + if (unit) + d.host_flags |= IDE_HFLAG_QD_2ND_PORT; + + switch (config & 0xf0) { + case QD_CONFIG_QD6500: + if (qd_testreg(base)) + return -ENODEV; /* bad register */ + + if (config & QD_CONFIG_DISABLED) { + printk(KERN_WARNING "qd6500 is disabled !\n"); + return -ENODEV; + } + + printk(KERN_NOTICE "qd6500 at %#x\n", base); + printk(KERN_DEBUG "qd6500: config=%#x, ID3=%u\n", + config, QD_ID3); + + d.port_ops = &qd6500_port_ops; + d.host_flags |= IDE_HFLAG_SINGLE; + break; + case QD_CONFIG_QD6580_A: + case QD_CONFIG_QD6580_B: + if (qd_testreg(base) || qd_testreg(base + 0x02)) + return -ENODEV; /* bad registers */ + + control = inb(QD_CONTROL_PORT); + + printk(KERN_NOTICE "qd6580 at %#x\n", base); + printk(KERN_DEBUG "qd6580: config=%#x, control=%#x, ID3=%u\n", + config, control, QD_ID3); + + outb(QD_DEF_CONTR, QD_CONTROL_PORT); + + d.port_ops = &qd6580_port_ops; + if (control & QD_CONTR_SEC_DISABLED) + d.host_flags |= IDE_HFLAG_SINGLE; + + printk(KERN_INFO "qd6580: %s IDE board\n", + (control & QD_CONTR_SEC_DISABLED) ? "single" : "dual"); + break; + default: + return -ENODEV; + } + + rc = ide_legacy_device_add(&d, (base << 8) | config); + + if (d.host_flags & IDE_HFLAG_SINGLE) + return (rc == 0) ? 1 : rc; + + return rc; +} + +static bool probe_qd65xx; + +module_param_named(probe, probe_qd65xx, bool, 0); +MODULE_PARM_DESC(probe, "probe for QD65xx chipsets"); + +static int __init qd65xx_init(void) +{ + int rc1, rc2 = -ENODEV; + + if (probe_qd65xx == 0) + return -ENODEV; + + rc1 = qd_probe(0x30); + if (rc1) + rc2 = qd_probe(0xb0); + + if (rc1 < 0 && rc2 < 0) + return -ENODEV; + + return 0; +} + +module_init(qd65xx_init); + +MODULE_AUTHOR("Samuel Thibault"); +MODULE_DESCRIPTION("support of qd65xx vlb ide chipset"); +MODULE_LICENSE("GPL"); diff --git a/drivers/ide/legacy/qd65xx.h b/drivers/ide/qd65xx.h index 633a42456ef..1fba2a5f281 100644 --- a/drivers/ide/legacy/qd65xx.h +++ b/drivers/ide/qd65xx.h @@ -1,12 +1,10 @@ /* - * linux/drivers/ide/legacy/qd65xx.h - * * Copyright (c) 2000 Linus Torvalds & authors */ /* * Authors: Petr Soucek <petr@ryston.cz> - * Samuel Thibault <samuel.thibault@fnac.net> + * Samuel Thibault <samuel.thibault@ens-lyon.org> */ /* truncates a in [b,c] */ @@ -32,10 +30,16 @@ #define QD_ID3 ((config & QD_CONFIG_ID3)!=0) #define QD_CONFIG(hwif) ((hwif)->config_data & 0x00ff) -#define QD_CONTROL(hwif) (((hwif)->config_data & 0xff00) >> 8) -#define QD_TIMING(drive) (byte)(((drive)->drive_data) & 0x00ff) -#define QD_TIMREG(drive) (byte)((((drive)->drive_data) & 0xff00) >> 8) +static inline u8 QD_TIMING(ide_drive_t *drive) +{ + return (unsigned long)ide_get_drivedata(drive) & 0x00ff; +} + +static inline u8 QD_TIMREG(ide_drive_t *drive) +{ + return ((unsigned long)ide_get_drivedata(drive) & 0xff00) >> 8; +} #define QD6500_DEF_DATA ((QD_TIM1_PORT<<8) | (QD_ID3 ? 0x0c : 0x08)) #define QD6580_DEF_DATA ((QD_TIM1_PORT<<8) | (QD_ID3 ? 0x0a : 0x00)) diff --git a/drivers/ide/rapide.c b/drivers/ide/rapide.c new file mode 100644 index 00000000000..d73c3d10087 --- /dev/null +++ b/drivers/ide/rapide.c @@ -0,0 +1,105 @@ +/* + * Copyright (c) 1996-2002 Russell King. + */ + +#include <linux/module.h> +#include <linux/blkdev.h> +#include <linux/errno.h> +#include <linux/ide.h> +#include <linux/init.h> + +#include <asm/ecard.h> + +static const struct ide_port_info rapide_port_info = { + .host_flags = IDE_HFLAG_MMIO | IDE_HFLAG_NO_DMA, + .chipset = ide_generic, +}; + +static void rapide_setup_ports(struct ide_hw *hw, void __iomem *base, + void __iomem *ctrl, unsigned int sz, int irq) +{ + unsigned long port = (unsigned long)base; + int i; + + for (i = 0; i <= 7; i++) { + hw->io_ports_array[i] = port; + port += sz; + } + hw->io_ports.ctl_addr = (unsigned long)ctrl; + hw->irq = irq; +} + +static int rapide_probe(struct expansion_card *ec, const struct ecard_id *id) +{ + void __iomem *base; + struct ide_host *host; + int ret; + struct ide_hw hw, *hws[] = { &hw }; + + ret = ecard_request_resources(ec); + if (ret) + goto out; + + base = ecardm_iomap(ec, ECARD_RES_MEMC, 0, 0); + if (!base) { + ret = -ENOMEM; + goto release; + } + + memset(&hw, 0, sizeof(hw)); + rapide_setup_ports(&hw, base, base + 0x818, 1 << 6, ec->irq); + hw.dev = &ec->dev; + + ret = ide_host_add(&rapide_port_info, hws, 1, &host); + if (ret) + goto release; + + ecard_set_drvdata(ec, host); + goto out; + + release: + ecard_release_resources(ec); + out: + return ret; +} + +static void rapide_remove(struct expansion_card *ec) +{ + struct ide_host *host = ecard_get_drvdata(ec); + + ecard_set_drvdata(ec, NULL); + + ide_host_remove(host); + + ecard_release_resources(ec); +} + +static struct ecard_id rapide_ids[] = { + { MANU_YELLOWSTONE, PROD_YELLOWSTONE_RAPIDE32 }, + { 0xffff, 0xffff } +}; + +static struct ecard_driver rapide_driver = { + .probe = rapide_probe, + .remove = rapide_remove, + .id_table = rapide_ids, + .drv = { + .name = "rapide", + }, +}; + +static int __init rapide_init(void) +{ + return ecard_register_driver(&rapide_driver); +} + +static void __exit rapide_exit(void) +{ + ecard_remove_driver(&rapide_driver); +} + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Yellowstone RAPIDE driver"); + +module_init(rapide_init); +module_exit(rapide_exit); diff --git a/drivers/ide/rz1000.c b/drivers/ide/rz1000.c new file mode 100644 index 00000000000..f4b66f7ec9f --- /dev/null +++ b/drivers/ide/rz1000.c @@ -0,0 +1,99 @@ +/* + * Copyright (C) 1995-1998 Linus Torvalds & author (see below) + */ + +/* + * Principal Author: mlord@pobox.com (Mark Lord) + * + * See linux/MAINTAINERS for address of current maintainer. + * + * This file provides support for disabling the buggy read-ahead + * mode of the RZ1000 IDE chipset, commonly used on Intel motherboards. + * + * Dunno if this fixes both ports, or only the primary port (?). + */ + +#include <linux/types.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/pci.h> +#include <linux/ide.h> +#include <linux/init.h> + +#define DRV_NAME "rz1000" + +static int rz1000_disable_readahead(struct pci_dev *dev) +{ + u16 reg; + + if (!pci_read_config_word (dev, 0x40, ®) && + !pci_write_config_word(dev, 0x40, reg & 0xdfff)) { + printk(KERN_INFO "%s: disabled chipset read-ahead " + "(buggy RZ1000/RZ1001)\n", pci_name(dev)); + return 0; + } else { + printk(KERN_INFO "%s: serialized, disabled unmasking " + "(buggy RZ1000/RZ1001)\n", pci_name(dev)); + return 1; + } +} + +static const struct ide_port_info rz1000_chipset = { + .name = DRV_NAME, + .host_flags = IDE_HFLAG_NO_DMA, +}; + +static int rz1000_init_one(struct pci_dev *dev, const struct pci_device_id *id) +{ + struct ide_port_info d = rz1000_chipset; + int rc; + + rc = pci_enable_device(dev); + if (rc) + return rc; + + if (rz1000_disable_readahead(dev)) { + d.host_flags |= IDE_HFLAG_SERIALIZE; + d.host_flags |= IDE_HFLAG_NO_UNMASK_IRQS; + } + + return ide_pci_init_one(dev, &d, NULL); +} + +static void rz1000_remove(struct pci_dev *dev) +{ + ide_pci_remove(dev); + pci_disable_device(dev); +} + +static const struct pci_device_id rz1000_pci_tbl[] = { + { PCI_VDEVICE(PCTECH, PCI_DEVICE_ID_PCTECH_RZ1000), 0 }, + { PCI_VDEVICE(PCTECH, PCI_DEVICE_ID_PCTECH_RZ1001), 0 }, + { 0, }, +}; +MODULE_DEVICE_TABLE(pci, rz1000_pci_tbl); + +static struct pci_driver rz1000_pci_driver = { + .name = "RZ1000_IDE", + .id_table = rz1000_pci_tbl, + .probe = rz1000_init_one, + .remove = rz1000_remove, +}; + +static int __init rz1000_ide_init(void) +{ + return ide_pci_register_driver(&rz1000_pci_driver); +} + +static void __exit rz1000_ide_exit(void) +{ + pci_unregister_driver(&rz1000_pci_driver); +} + +module_init(rz1000_ide_init); +module_exit(rz1000_ide_exit); + +MODULE_AUTHOR("Andre Hedrick"); +MODULE_DESCRIPTION("PCI driver module for RZ1000 IDE"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/ide/sc1200.c b/drivers/ide/sc1200.c new file mode 100644 index 00000000000..a5b70181840 --- /dev/null +++ b/drivers/ide/sc1200.c @@ -0,0 +1,355 @@ +/* + * Copyright (C) 2000-2002 Mark Lord <mlord@pobox.com> + * Copyright (C) 2007 Bartlomiej Zolnierkiewicz + * + * May be copied or modified under the terms of the GNU General Public License + * + * Development of this chipset driver was funded + * by the nice folks at National Semiconductor. + * + * Documentation: + * Available from National Semiconductor + */ + +#include <linux/module.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/pci.h> +#include <linux/init.h> +#include <linux/ide.h> +#include <linux/pm.h> + +#include <asm/io.h> + +#define DRV_NAME "sc1200" + +#define SC1200_REV_A 0x00 +#define SC1200_REV_B1 0x01 +#define SC1200_REV_B3 0x02 +#define SC1200_REV_C1 0x03 +#define SC1200_REV_D1 0x04 + +#define PCI_CLK_33 0x00 +#define PCI_CLK_48 0x01 +#define PCI_CLK_66 0x02 +#define PCI_CLK_33A 0x03 + +static unsigned short sc1200_get_pci_clock (void) +{ + unsigned char chip_id, silicon_revision; + unsigned int pci_clock; + /* + * Check the silicon revision, as not all versions of the chip + * have the register with the fast PCI bus timings. + */ + chip_id = inb (0x903c); + silicon_revision = inb (0x903d); + + // Read the fast pci clock frequency + if (chip_id == 0x04 && silicon_revision < SC1200_REV_B1) { + pci_clock = PCI_CLK_33; + } else { + // check clock generator configuration (cfcc) + // the clock is in bits 8 and 9 of this word + + pci_clock = inw (0x901e); + pci_clock >>= 8; + pci_clock &= 0x03; + if (pci_clock == PCI_CLK_33A) + pci_clock = PCI_CLK_33; + } + return pci_clock; +} + +/* + * Here are the standard PIO mode 0-4 timings for each "format". + * Format-0 uses fast data reg timings, with slower command reg timings. + * Format-1 uses fast timings for all registers, but won't work with all drives. + */ +static const unsigned int sc1200_pio_timings[4][5] = + {{0x00009172, 0x00012171, 0x00020080, 0x00032010, 0x00040010}, // format0 33Mhz + {0xd1329172, 0x71212171, 0x30200080, 0x20102010, 0x00100010}, // format1, 33Mhz + {0xfaa3f4f3, 0xc23232b2, 0x513101c1, 0x31213121, 0x10211021}, // format1, 48Mhz + {0xfff4fff4, 0xf35353d3, 0x814102f1, 0x42314231, 0x11311131}}; // format1, 66Mhz + +/* + * After chip reset, the PIO timings are set to 0x00009172, which is not valid. + */ +//#define SC1200_BAD_PIO(timings) (((timings)&~0x80000000)==0x00009172) + +static void sc1200_tunepio(ide_drive_t *drive, u8 pio) +{ + ide_hwif_t *hwif = drive->hwif; + struct pci_dev *pdev = to_pci_dev(hwif->dev); + unsigned int basereg = hwif->channel ? 0x50 : 0x40, format = 0; + + pci_read_config_dword(pdev, basereg + 4, &format); + format = (format >> 31) & 1; + if (format) + format += sc1200_get_pci_clock(); + pci_write_config_dword(pdev, basereg + ((drive->dn & 1) << 3), + sc1200_pio_timings[format][pio]); +} + +/* + * The SC1200 specifies that two drives sharing a cable cannot mix + * UDMA/MDMA. It has to be one or the other, for the pair, though + * different timings can still be chosen for each drive. We could + * set the appropriate timing bits on the fly, but that might be + * a bit confusing. So, for now we statically handle this requirement + * by looking at our mate drive to see what it is capable of, before + * choosing a mode for our own drive. + */ +static u8 sc1200_udma_filter(ide_drive_t *drive) +{ + ide_hwif_t *hwif = drive->hwif; + ide_drive_t *mate = ide_get_pair_dev(drive); + u16 *mateid; + u8 mask = hwif->ultra_mask; + + if (mate == NULL) + goto out; + mateid = mate->id; + + if (ata_id_has_dma(mateid) && __ide_dma_bad_drive(mate) == 0) { + if ((mateid[ATA_ID_FIELD_VALID] & 4) && + (mateid[ATA_ID_UDMA_MODES] & 7)) + goto out; + if (mateid[ATA_ID_MWDMA_MODES] & 7) + mask = 0; + } +out: + return mask; +} + +static void sc1200_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive) +{ + struct pci_dev *dev = to_pci_dev(hwif->dev); + unsigned int reg, timings; + unsigned short pci_clock; + unsigned int basereg = hwif->channel ? 0x50 : 0x40; + const u8 mode = drive->dma_mode; + + static const u32 udma_timing[3][3] = { + { 0x00921250, 0x00911140, 0x00911030 }, + { 0x00932470, 0x00922260, 0x00922140 }, + { 0x009436a1, 0x00933481, 0x00923261 }, + }; + + static const u32 mwdma_timing[3][3] = { + { 0x00077771, 0x00012121, 0x00002020 }, + { 0x000bbbb2, 0x00024241, 0x00013131 }, + { 0x000ffff3, 0x00035352, 0x00015151 }, + }; + + pci_clock = sc1200_get_pci_clock(); + + /* + * Note that each DMA mode has several timings associated with it. + * The correct timing depends on the fast PCI clock freq. + */ + + if (mode >= XFER_UDMA_0) + timings = udma_timing[pci_clock][mode - XFER_UDMA_0]; + else + timings = mwdma_timing[pci_clock][mode - XFER_MW_DMA_0]; + + if ((drive->dn & 1) == 0) { + pci_read_config_dword(dev, basereg + 4, ®); + timings |= reg & 0x80000000; /* preserve PIO format bit */ + pci_write_config_dword(dev, basereg + 4, timings); + } else + pci_write_config_dword(dev, basereg + 12, timings); +} + +/* Replacement for the standard ide_dma_end action in + * dma_proc. + * + * returns 1 on error, 0 otherwise + */ +static int sc1200_dma_end(ide_drive_t *drive) +{ + ide_hwif_t *hwif = drive->hwif; + unsigned long dma_base = hwif->dma_base; + u8 dma_stat; + + dma_stat = inb(dma_base+2); /* get DMA status */ + + if (!(dma_stat & 4)) + printk(" ide_dma_end dma_stat=%0x err=%x newerr=%x\n", + dma_stat, ((dma_stat&7)!=4), ((dma_stat&2)==2)); + + outb(dma_stat|0x1b, dma_base+2); /* clear the INTR & ERROR bits */ + outb(inb(dma_base)&~1, dma_base); /* !! DO THIS HERE !! stop DMA */ + + return (dma_stat & 7) != 4; /* verify good DMA status */ +} + +/* + * sc1200_set_pio_mode() handles setting of PIO modes + * for both the chipset and drive. + * + * All existing BIOSs for this chipset guarantee that all drives + * will have valid default PIO timings set up before we get here. + */ + +static void sc1200_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) +{ + int mode = -1; + const u8 pio = drive->pio_mode - XFER_PIO_0; + + /* + * bad abuse of ->set_pio_mode interface + */ + switch (pio) { + case 200: mode = XFER_UDMA_0; break; + case 201: mode = XFER_UDMA_1; break; + case 202: mode = XFER_UDMA_2; break; + case 100: mode = XFER_MW_DMA_0; break; + case 101: mode = XFER_MW_DMA_1; break; + case 102: mode = XFER_MW_DMA_2; break; + } + if (mode != -1) { + printk("SC1200: %s: changing (U)DMA mode\n", drive->name); + ide_dma_off_quietly(drive); + if (ide_set_dma_mode(drive, mode) == 0 && + (drive->dev_flags & IDE_DFLAG_USING_DMA)) + hwif->dma_ops->dma_host_set(drive, 1); + return; + } + + sc1200_tunepio(drive, pio); +} + +#ifdef CONFIG_PM +struct sc1200_saved_state { + u32 regs[8]; +}; + +static int sc1200_suspend (struct pci_dev *dev, pm_message_t state) +{ + printk("SC1200: suspend(%u)\n", state.event); + + /* + * we only save state when going from full power to less + */ + if (state.event == PM_EVENT_ON) { + struct ide_host *host = pci_get_drvdata(dev); + struct sc1200_saved_state *ss = host->host_priv; + unsigned int r; + + /* + * save timing registers + * (this may be unnecessary if BIOS also does it) + */ + for (r = 0; r < 8; r++) + pci_read_config_dword(dev, 0x40 + r * 4, &ss->regs[r]); + } + + pci_disable_device(dev); + pci_set_power_state(dev, pci_choose_state(dev, state)); + return 0; +} + +static int sc1200_resume (struct pci_dev *dev) +{ + struct ide_host *host = pci_get_drvdata(dev); + struct sc1200_saved_state *ss = host->host_priv; + unsigned int r; + int i; + + i = pci_enable_device(dev); + if (i) + return i; + + /* + * restore timing registers + * (this may be unnecessary if BIOS also does it) + */ + for (r = 0; r < 8; r++) + pci_write_config_dword(dev, 0x40 + r * 4, ss->regs[r]); + + return 0; +} +#endif + +static const struct ide_port_ops sc1200_port_ops = { + .set_pio_mode = sc1200_set_pio_mode, + .set_dma_mode = sc1200_set_dma_mode, + .udma_filter = sc1200_udma_filter, +}; + +static const struct ide_dma_ops sc1200_dma_ops = { + .dma_host_set = ide_dma_host_set, + .dma_setup = ide_dma_setup, + .dma_start = ide_dma_start, + .dma_end = sc1200_dma_end, + .dma_test_irq = ide_dma_test_irq, + .dma_lost_irq = ide_dma_lost_irq, + .dma_timer_expiry = ide_dma_sff_timer_expiry, + .dma_sff_read_status = ide_dma_sff_read_status, +}; + +static const struct ide_port_info sc1200_chipset = { + .name = DRV_NAME, + .port_ops = &sc1200_port_ops, + .dma_ops = &sc1200_dma_ops, + .host_flags = IDE_HFLAG_SERIALIZE | + IDE_HFLAG_POST_SET_MODE | + IDE_HFLAG_ABUSE_DMA_MODES, + .pio_mask = ATA_PIO4, + .mwdma_mask = ATA_MWDMA2, + .udma_mask = ATA_UDMA2, +}; + +static int sc1200_init_one(struct pci_dev *dev, const struct pci_device_id *id) +{ + struct sc1200_saved_state *ss = NULL; + int rc; + +#ifdef CONFIG_PM + ss = kmalloc(sizeof(*ss), GFP_KERNEL); + if (ss == NULL) + return -ENOMEM; +#endif + rc = ide_pci_init_one(dev, &sc1200_chipset, ss); + if (rc) + kfree(ss); + + return rc; +} + +static const struct pci_device_id sc1200_pci_tbl[] = { + { PCI_VDEVICE(NS, PCI_DEVICE_ID_NS_SCx200_IDE), 0}, + { 0, }, +}; +MODULE_DEVICE_TABLE(pci, sc1200_pci_tbl); + +static struct pci_driver sc1200_pci_driver = { + .name = "SC1200_IDE", + .id_table = sc1200_pci_tbl, + .probe = sc1200_init_one, + .remove = ide_pci_remove, +#ifdef CONFIG_PM + .suspend = sc1200_suspend, + .resume = sc1200_resume, +#endif +}; + +static int __init sc1200_ide_init(void) +{ + return ide_pci_register_driver(&sc1200_pci_driver); +} + +static void __exit sc1200_ide_exit(void) +{ + pci_unregister_driver(&sc1200_pci_driver); +} + +module_init(sc1200_ide_init); +module_exit(sc1200_ide_exit); + +MODULE_AUTHOR("Mark Lord"); +MODULE_DESCRIPTION("PCI driver module for NS SC1200 IDE"); +MODULE_LICENSE("GPL"); diff --git a/drivers/ide/scc_pata.c b/drivers/ide/scc_pata.c new file mode 100644 index 00000000000..2a2d188b5d5 --- /dev/null +++ b/drivers/ide/scc_pata.c @@ -0,0 +1,887 @@ +/* + * Support for IDE interfaces on Celleb platform + * + * (C) Copyright 2006 TOSHIBA CORPORATION + * + * This code is based on drivers/ide/pci/siimage.c: + * Copyright (C) 2001-2002 Andre Hedrick <andre@linux-ide.org> + * Copyright (C) 2003 Red Hat + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <linux/types.h> +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/delay.h> +#include <linux/ide.h> +#include <linux/init.h> + +#define PCI_DEVICE_ID_TOSHIBA_SCC_ATA 0x01b4 + +#define SCC_PATA_NAME "scc IDE" + +#define TDVHSEL_MASTER 0x00000001 +#define TDVHSEL_SLAVE 0x00000004 + +#define MODE_JCUSFEN 0x00000080 + +#define CCKCTRL_ATARESET 0x00040000 +#define CCKCTRL_BUFCNT 0x00020000 +#define CCKCTRL_CRST 0x00010000 +#define CCKCTRL_OCLKEN 0x00000100 +#define CCKCTRL_ATACLKOEN 0x00000002 +#define CCKCTRL_LCLKEN 0x00000001 + +#define QCHCD_IOS_SS 0x00000001 + +#define QCHSD_STPDIAG 0x00020000 + +#define INTMASK_MSK 0xD1000012 +#define INTSTS_SERROR 0x80000000 +#define INTSTS_PRERR 0x40000000 +#define INTSTS_RERR 0x10000000 +#define INTSTS_ICERR 0x01000000 +#define INTSTS_BMSINT 0x00000010 +#define INTSTS_BMHE 0x00000008 +#define INTSTS_IOIRQS 0x00000004 +#define INTSTS_INTRQ 0x00000002 +#define INTSTS_ACTEINT 0x00000001 + +#define ECMODE_VALUE 0x01 + +static struct scc_ports { + unsigned long ctl, dma; + struct ide_host *host; /* for removing port from system */ +} scc_ports[MAX_HWIFS]; + +/* PIO transfer mode table */ +/* JCHST */ +static unsigned long JCHSTtbl[2][7] = { + {0x0E, 0x05, 0x02, 0x03, 0x02, 0x00, 0x00}, /* 100MHz */ + {0x13, 0x07, 0x04, 0x04, 0x03, 0x00, 0x00} /* 133MHz */ +}; + +/* JCHHT */ +static unsigned long JCHHTtbl[2][7] = { + {0x0E, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00}, /* 100MHz */ + {0x13, 0x03, 0x03, 0x03, 0x03, 0x00, 0x00} /* 133MHz */ +}; + +/* JCHCT */ +static unsigned long JCHCTtbl[2][7] = { + {0x1D, 0x1D, 0x1C, 0x0B, 0x06, 0x00, 0x00}, /* 100MHz */ + {0x27, 0x26, 0x26, 0x0E, 0x09, 0x00, 0x00} /* 133MHz */ +}; + + +/* DMA transfer mode table */ +/* JCHDCTM/JCHDCTS */ +static unsigned long JCHDCTxtbl[2][7] = { + {0x0A, 0x06, 0x04, 0x03, 0x01, 0x00, 0x00}, /* 100MHz */ + {0x0E, 0x09, 0x06, 0x04, 0x02, 0x01, 0x00} /* 133MHz */ +}; + +/* JCSTWTM/JCSTWTS */ +static unsigned long JCSTWTxtbl[2][7] = { + {0x06, 0x04, 0x03, 0x02, 0x02, 0x02, 0x00}, /* 100MHz */ + {0x09, 0x06, 0x04, 0x02, 0x02, 0x02, 0x02} /* 133MHz */ +}; + +/* JCTSS */ +static unsigned long JCTSStbl[2][7] = { + {0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x00}, /* 100MHz */ + {0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05} /* 133MHz */ +}; + +/* JCENVT */ +static unsigned long JCENVTtbl[2][7] = { + {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00}, /* 100MHz */ + {0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02} /* 133MHz */ +}; + +/* JCACTSELS/JCACTSELM */ +static unsigned long JCACTSELtbl[2][7] = { + {0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00}, /* 100MHz */ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01} /* 133MHz */ +}; + + +static u8 scc_ide_inb(unsigned long port) +{ + u32 data = in_be32((void*)port); + return (u8)data; +} + +static void scc_exec_command(ide_hwif_t *hwif, u8 cmd) +{ + out_be32((void *)hwif->io_ports.command_addr, cmd); + eieio(); + in_be32((void *)(hwif->dma_base + 0x01c)); + eieio(); +} + +static u8 scc_read_status(ide_hwif_t *hwif) +{ + return (u8)in_be32((void *)hwif->io_ports.status_addr); +} + +static u8 scc_read_altstatus(ide_hwif_t *hwif) +{ + return (u8)in_be32((void *)hwif->io_ports.ctl_addr); +} + +static u8 scc_dma_sff_read_status(ide_hwif_t *hwif) +{ + return (u8)in_be32((void *)(hwif->dma_base + 4)); +} + +static void scc_write_devctl(ide_hwif_t *hwif, u8 ctl) +{ + out_be32((void *)hwif->io_ports.ctl_addr, ctl); + eieio(); + in_be32((void *)(hwif->dma_base + 0x01c)); + eieio(); +} + +static void scc_ide_insw(unsigned long port, void *addr, u32 count) +{ + u16 *ptr = (u16 *)addr; + while (count--) { + *ptr++ = le16_to_cpu(in_be32((void*)port)); + } +} + +static void scc_ide_insl(unsigned long port, void *addr, u32 count) +{ + u16 *ptr = (u16 *)addr; + while (count--) { + *ptr++ = le16_to_cpu(in_be32((void*)port)); + *ptr++ = le16_to_cpu(in_be32((void*)port)); + } +} + +static void scc_ide_outb(u8 addr, unsigned long port) +{ + out_be32((void*)port, addr); +} + +static void +scc_ide_outsw(unsigned long port, void *addr, u32 count) +{ + u16 *ptr = (u16 *)addr; + while (count--) { + out_be32((void*)port, cpu_to_le16(*ptr++)); + } +} + +static void +scc_ide_outsl(unsigned long port, void *addr, u32 count) +{ + u16 *ptr = (u16 *)addr; + while (count--) { + out_be32((void*)port, cpu_to_le16(*ptr++)); + out_be32((void*)port, cpu_to_le16(*ptr++)); + } +} + +/** + * scc_set_pio_mode - set host controller for PIO mode + * @hwif: port + * @drive: drive + * + * Load the timing settings for this device mode into the + * controller. + */ + +static void scc_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) +{ + struct scc_ports *ports = ide_get_hwifdata(hwif); + unsigned long ctl_base = ports->ctl; + unsigned long cckctrl_port = ctl_base + 0xff0; + unsigned long piosht_port = ctl_base + 0x000; + unsigned long pioct_port = ctl_base + 0x004; + unsigned long reg; + int offset; + const u8 pio = drive->pio_mode - XFER_PIO_0; + + reg = in_be32((void __iomem *)cckctrl_port); + if (reg & CCKCTRL_ATACLKOEN) { + offset = 1; /* 133MHz */ + } else { + offset = 0; /* 100MHz */ + } + reg = JCHSTtbl[offset][pio] << 16 | JCHHTtbl[offset][pio]; + out_be32((void __iomem *)piosht_port, reg); + reg = JCHCTtbl[offset][pio]; + out_be32((void __iomem *)pioct_port, reg); +} + +/** + * scc_set_dma_mode - set host controller for DMA mode + * @hwif: port + * @drive: drive + * + * Load the timing settings for this device mode into the + * controller. + */ + +static void scc_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive) +{ + struct scc_ports *ports = ide_get_hwifdata(hwif); + unsigned long ctl_base = ports->ctl; + unsigned long cckctrl_port = ctl_base + 0xff0; + unsigned long mdmact_port = ctl_base + 0x008; + unsigned long mcrcst_port = ctl_base + 0x00c; + unsigned long sdmact_port = ctl_base + 0x010; + unsigned long scrcst_port = ctl_base + 0x014; + unsigned long udenvt_port = ctl_base + 0x018; + unsigned long tdvhsel_port = ctl_base + 0x020; + int is_slave = drive->dn & 1; + int offset, idx; + unsigned long reg; + unsigned long jcactsel; + const u8 speed = drive->dma_mode; + + reg = in_be32((void __iomem *)cckctrl_port); + if (reg & CCKCTRL_ATACLKOEN) { + offset = 1; /* 133MHz */ + } else { + offset = 0; /* 100MHz */ + } + + idx = speed - XFER_UDMA_0; + + jcactsel = JCACTSELtbl[offset][idx]; + if (is_slave) { + out_be32((void __iomem *)sdmact_port, JCHDCTxtbl[offset][idx]); + out_be32((void __iomem *)scrcst_port, JCSTWTxtbl[offset][idx]); + jcactsel = jcactsel << 2; + out_be32((void __iomem *)tdvhsel_port, (in_be32((void __iomem *)tdvhsel_port) & ~TDVHSEL_SLAVE) | jcactsel); + } else { + out_be32((void __iomem *)mdmact_port, JCHDCTxtbl[offset][idx]); + out_be32((void __iomem *)mcrcst_port, JCSTWTxtbl[offset][idx]); + out_be32((void __iomem *)tdvhsel_port, (in_be32((void __iomem *)tdvhsel_port) & ~TDVHSEL_MASTER) | jcactsel); + } + reg = JCTSStbl[offset][idx] << 16 | JCENVTtbl[offset][idx]; + out_be32((void __iomem *)udenvt_port, reg); +} + +static void scc_dma_host_set(ide_drive_t *drive, int on) +{ + ide_hwif_t *hwif = drive->hwif; + u8 unit = drive->dn & 1; + u8 dma_stat = scc_dma_sff_read_status(hwif); + + if (on) + dma_stat |= (1 << (5 + unit)); + else + dma_stat &= ~(1 << (5 + unit)); + + scc_ide_outb(dma_stat, hwif->dma_base + 4); +} + +/** + * scc_dma_setup - begin a DMA phase + * @drive: target device + * @cmd: command + * + * Build an IDE DMA PRD (IDE speak for scatter gather table) + * and then set up the DMA transfer registers. + * + * Returns 0 on success. If a PIO fallback is required then 1 + * is returned. + */ + +static int scc_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd) +{ + ide_hwif_t *hwif = drive->hwif; + u32 rw = (cmd->tf_flags & IDE_TFLAG_WRITE) ? 0 : ATA_DMA_WR; + u8 dma_stat; + + /* fall back to pio! */ + if (ide_build_dmatable(drive, cmd) == 0) + return 1; + + /* PRD table */ + out_be32((void __iomem *)(hwif->dma_base + 8), hwif->dmatable_dma); + + /* specify r/w */ + out_be32((void __iomem *)hwif->dma_base, rw); + + /* read DMA status for INTR & ERROR flags */ + dma_stat = scc_dma_sff_read_status(hwif); + + /* clear INTR & ERROR flags */ + out_be32((void __iomem *)(hwif->dma_base + 4), dma_stat | 6); + + return 0; +} + +static void scc_dma_start(ide_drive_t *drive) +{ + ide_hwif_t *hwif = drive->hwif; + u8 dma_cmd = scc_ide_inb(hwif->dma_base); + + /* start DMA */ + scc_ide_outb(dma_cmd | 1, hwif->dma_base); +} + +static int __scc_dma_end(ide_drive_t *drive) +{ + ide_hwif_t *hwif = drive->hwif; + u8 dma_stat, dma_cmd; + + /* get DMA command mode */ + dma_cmd = scc_ide_inb(hwif->dma_base); + /* stop DMA */ + scc_ide_outb(dma_cmd & ~1, hwif->dma_base); + /* get DMA status */ + dma_stat = scc_dma_sff_read_status(hwif); + /* clear the INTR & ERROR bits */ + scc_ide_outb(dma_stat | 6, hwif->dma_base + 4); + /* verify good DMA status */ + return (dma_stat & 7) != 4 ? (0x10 | dma_stat) : 0; +} + +/** + * scc_dma_end - Stop DMA + * @drive: IDE drive + * + * Check and clear INT Status register. + * Then call __scc_dma_end(). + */ + +static int scc_dma_end(ide_drive_t *drive) +{ + ide_hwif_t *hwif = drive->hwif; + void __iomem *dma_base = (void __iomem *)hwif->dma_base; + unsigned long intsts_port = hwif->dma_base + 0x014; + u32 reg; + int dma_stat, data_loss = 0; + static int retry = 0; + + /* errata A308 workaround: Step5 (check data loss) */ + /* We don't check non ide_disk because it is limited to UDMA4 */ + if (!(in_be32((void __iomem *)hwif->io_ports.ctl_addr) + & ATA_ERR) && + drive->media == ide_disk && drive->current_speed > XFER_UDMA_4) { + reg = in_be32((void __iomem *)intsts_port); + if (!(reg & INTSTS_ACTEINT)) { + printk(KERN_WARNING "%s: operation failed (transfer data loss)\n", + drive->name); + data_loss = 1; + if (retry++) { + struct request *rq = hwif->rq; + ide_drive_t *drive; + int i; + + /* ERROR_RESET and drive->crc_count are needed + * to reduce DMA transfer mode in retry process. + */ + if (rq) + rq->errors |= ERROR_RESET; + + ide_port_for_each_dev(i, drive, hwif) + drive->crc_count++; + } + } + } + + while (1) { + reg = in_be32((void __iomem *)intsts_port); + + if (reg & INTSTS_SERROR) { + printk(KERN_WARNING "%s: SERROR\n", SCC_PATA_NAME); + out_be32((void __iomem *)intsts_port, INTSTS_SERROR|INTSTS_BMSINT); + + out_be32(dma_base, in_be32(dma_base) & ~QCHCD_IOS_SS); + continue; + } + + if (reg & INTSTS_PRERR) { + u32 maea0, maec0; + unsigned long ctl_base = hwif->config_data; + + maea0 = in_be32((void __iomem *)(ctl_base + 0xF50)); + maec0 = in_be32((void __iomem *)(ctl_base + 0xF54)); + + printk(KERN_WARNING "%s: PRERR [addr:%x cmd:%x]\n", SCC_PATA_NAME, maea0, maec0); + + out_be32((void __iomem *)intsts_port, INTSTS_PRERR|INTSTS_BMSINT); + + out_be32(dma_base, in_be32(dma_base) & ~QCHCD_IOS_SS); + continue; + } + + if (reg & INTSTS_RERR) { + printk(KERN_WARNING "%s: Response Error\n", SCC_PATA_NAME); + out_be32((void __iomem *)intsts_port, INTSTS_RERR|INTSTS_BMSINT); + + out_be32(dma_base, in_be32(dma_base) & ~QCHCD_IOS_SS); + continue; + } + + if (reg & INTSTS_ICERR) { + out_be32(dma_base, in_be32(dma_base) & ~QCHCD_IOS_SS); + + printk(KERN_WARNING "%s: Illegal Configuration\n", SCC_PATA_NAME); + out_be32((void __iomem *)intsts_port, INTSTS_ICERR|INTSTS_BMSINT); + continue; + } + + if (reg & INTSTS_BMSINT) { + printk(KERN_WARNING "%s: Internal Bus Error\n", SCC_PATA_NAME); + out_be32((void __iomem *)intsts_port, INTSTS_BMSINT); + + ide_do_reset(drive); + continue; + } + + if (reg & INTSTS_BMHE) { + out_be32((void __iomem *)intsts_port, INTSTS_BMHE); + continue; + } + + if (reg & INTSTS_ACTEINT) { + out_be32((void __iomem *)intsts_port, INTSTS_ACTEINT); + continue; + } + + if (reg & INTSTS_IOIRQS) { + out_be32((void __iomem *)intsts_port, INTSTS_IOIRQS); + continue; + } + break; + } + + dma_stat = __scc_dma_end(drive); + if (data_loss) + dma_stat |= 2; /* emulate DMA error (to retry command) */ + return dma_stat; +} + +/* returns 1 if dma irq issued, 0 otherwise */ +static int scc_dma_test_irq(ide_drive_t *drive) +{ + ide_hwif_t *hwif = drive->hwif; + u32 int_stat = in_be32((void __iomem *)hwif->dma_base + 0x014); + + /* SCC errata A252,A308 workaround: Step4 */ + if ((in_be32((void __iomem *)hwif->io_ports.ctl_addr) + & ATA_ERR) && + (int_stat & INTSTS_INTRQ)) + return 1; + + /* SCC errata A308 workaround: Step5 (polling IOIRQS) */ + if (int_stat & INTSTS_IOIRQS) + return 1; + + return 0; +} + +static u8 scc_udma_filter(ide_drive_t *drive) +{ + ide_hwif_t *hwif = drive->hwif; + u8 mask = hwif->ultra_mask; + + /* errata A308 workaround: limit non ide_disk drive to UDMA4 */ + if ((drive->media != ide_disk) && (mask & 0xE0)) { + printk(KERN_INFO "%s: limit %s to UDMA4\n", + SCC_PATA_NAME, drive->name); + mask = ATA_UDMA4; + } + + return mask; +} + +/** + * setup_mmio_scc - map CTRL/BMID region + * @dev: PCI device we are configuring + * @name: device name + * + */ + +static int setup_mmio_scc (struct pci_dev *dev, const char *name) +{ + void __iomem *ctl_addr; + void __iomem *dma_addr; + int i, ret; + + for (i = 0; i < MAX_HWIFS; i++) { + if (scc_ports[i].ctl == 0) + break; + } + if (i >= MAX_HWIFS) + return -ENOMEM; + + ret = pci_request_selected_regions(dev, (1 << 2) - 1, name); + if (ret < 0) { + printk(KERN_ERR "%s: can't reserve resources\n", name); + return ret; + } + + ctl_addr = pci_ioremap_bar(dev, 0); + if (!ctl_addr) + goto fail_0; + + dma_addr = pci_ioremap_bar(dev, 1); + if (!dma_addr) + goto fail_1; + + pci_set_master(dev); + scc_ports[i].ctl = (unsigned long)ctl_addr; + scc_ports[i].dma = (unsigned long)dma_addr; + pci_set_drvdata(dev, (void *) &scc_ports[i]); + + return 1; + + fail_1: + iounmap(ctl_addr); + fail_0: + return -ENOMEM; +} + +static int scc_ide_setup_pci_device(struct pci_dev *dev, + const struct ide_port_info *d) +{ + struct scc_ports *ports = pci_get_drvdata(dev); + struct ide_host *host; + struct ide_hw hw, *hws[] = { &hw }; + int i, rc; + + memset(&hw, 0, sizeof(hw)); + for (i = 0; i <= 8; i++) + hw.io_ports_array[i] = ports->dma + 0x20 + i * 4; + hw.irq = dev->irq; + hw.dev = &dev->dev; + + rc = ide_host_add(d, hws, 1, &host); + if (rc) + return rc; + + ports->host = host; + + return 0; +} + +/** + * init_setup_scc - set up an SCC PATA Controller + * @dev: PCI device + * @d: IDE port info + * + * Perform the initial set up for this device. + */ + +static int init_setup_scc(struct pci_dev *dev, const struct ide_port_info *d) +{ + unsigned long ctl_base; + unsigned long dma_base; + unsigned long cckctrl_port; + unsigned long intmask_port; + unsigned long mode_port; + unsigned long ecmode_port; + u32 reg = 0; + struct scc_ports *ports; + int rc; + + rc = pci_enable_device(dev); + if (rc) + goto end; + + rc = setup_mmio_scc(dev, d->name); + if (rc < 0) + goto end; + + ports = pci_get_drvdata(dev); + ctl_base = ports->ctl; + dma_base = ports->dma; + cckctrl_port = ctl_base + 0xff0; + intmask_port = dma_base + 0x010; + mode_port = ctl_base + 0x024; + ecmode_port = ctl_base + 0xf00; + + /* controller initialization */ + reg = 0; + out_be32((void*)cckctrl_port, reg); + reg |= CCKCTRL_ATACLKOEN; + out_be32((void*)cckctrl_port, reg); + reg |= CCKCTRL_LCLKEN | CCKCTRL_OCLKEN; + out_be32((void*)cckctrl_port, reg); + reg |= CCKCTRL_CRST; + out_be32((void*)cckctrl_port, reg); + + for (;;) { + reg = in_be32((void*)cckctrl_port); + if (reg & CCKCTRL_CRST) + break; + udelay(5000); + } + + reg |= CCKCTRL_ATARESET; + out_be32((void*)cckctrl_port, reg); + + out_be32((void*)ecmode_port, ECMODE_VALUE); + out_be32((void*)mode_port, MODE_JCUSFEN); + out_be32((void*)intmask_port, INTMASK_MSK); + + rc = scc_ide_setup_pci_device(dev, d); + + end: + return rc; +} + +static void scc_tf_load(ide_drive_t *drive, struct ide_taskfile *tf, u8 valid) +{ + struct ide_io_ports *io_ports = &drive->hwif->io_ports; + + if (valid & IDE_VALID_FEATURE) + scc_ide_outb(tf->feature, io_ports->feature_addr); + if (valid & IDE_VALID_NSECT) + scc_ide_outb(tf->nsect, io_ports->nsect_addr); + if (valid & IDE_VALID_LBAL) + scc_ide_outb(tf->lbal, io_ports->lbal_addr); + if (valid & IDE_VALID_LBAM) + scc_ide_outb(tf->lbam, io_ports->lbam_addr); + if (valid & IDE_VALID_LBAH) + scc_ide_outb(tf->lbah, io_ports->lbah_addr); + if (valid & IDE_VALID_DEVICE) + scc_ide_outb(tf->device, io_ports->device_addr); +} + +static void scc_tf_read(ide_drive_t *drive, struct ide_taskfile *tf, u8 valid) +{ + struct ide_io_ports *io_ports = &drive->hwif->io_ports; + + if (valid & IDE_VALID_ERROR) + tf->error = scc_ide_inb(io_ports->feature_addr); + if (valid & IDE_VALID_NSECT) + tf->nsect = scc_ide_inb(io_ports->nsect_addr); + if (valid & IDE_VALID_LBAL) + tf->lbal = scc_ide_inb(io_ports->lbal_addr); + if (valid & IDE_VALID_LBAM) + tf->lbam = scc_ide_inb(io_ports->lbam_addr); + if (valid & IDE_VALID_LBAH) + tf->lbah = scc_ide_inb(io_ports->lbah_addr); + if (valid & IDE_VALID_DEVICE) + tf->device = scc_ide_inb(io_ports->device_addr); +} + +static void scc_input_data(ide_drive_t *drive, struct ide_cmd *cmd, + void *buf, unsigned int len) +{ + unsigned long data_addr = drive->hwif->io_ports.data_addr; + + len++; + + if (drive->io_32bit) { + scc_ide_insl(data_addr, buf, len / 4); + + if ((len & 3) >= 2) + scc_ide_insw(data_addr, (u8 *)buf + (len & ~3), 1); + } else + scc_ide_insw(data_addr, buf, len / 2); +} + +static void scc_output_data(ide_drive_t *drive, struct ide_cmd *cmd, + void *buf, unsigned int len) +{ + unsigned long data_addr = drive->hwif->io_ports.data_addr; + + len++; + + if (drive->io_32bit) { + scc_ide_outsl(data_addr, buf, len / 4); + + if ((len & 3) >= 2) + scc_ide_outsw(data_addr, (u8 *)buf + (len & ~3), 1); + } else + scc_ide_outsw(data_addr, buf, len / 2); +} + +/** + * init_mmio_iops_scc - set up the iops for MMIO + * @hwif: interface to set up + * + */ + +static void init_mmio_iops_scc(ide_hwif_t *hwif) +{ + struct pci_dev *dev = to_pci_dev(hwif->dev); + struct scc_ports *ports = pci_get_drvdata(dev); + unsigned long dma_base = ports->dma; + + ide_set_hwifdata(hwif, ports); + + hwif->dma_base = dma_base; + hwif->config_data = ports->ctl; +} + +/** + * init_iops_scc - set up iops + * @hwif: interface to set up + * + * Do the basic setup for the SCC hardware interface + * and then do the MMIO setup. + */ + +static void init_iops_scc(ide_hwif_t *hwif) +{ + struct pci_dev *dev = to_pci_dev(hwif->dev); + + hwif->hwif_data = NULL; + if (pci_get_drvdata(dev) == NULL) + return; + init_mmio_iops_scc(hwif); +} + +static int scc_init_dma(ide_hwif_t *hwif, const struct ide_port_info *d) +{ + return ide_allocate_dma_engine(hwif); +} + +static u8 scc_cable_detect(ide_hwif_t *hwif) +{ + return ATA_CBL_PATA80; +} + +/** + * init_hwif_scc - set up hwif + * @hwif: interface to set up + * + * We do the basic set up of the interface structure. The SCC + * requires several custom handlers so we override the default + * ide DMA handlers appropriately. + */ + +static void init_hwif_scc(ide_hwif_t *hwif) +{ + /* PTERADD */ + out_be32((void __iomem *)(hwif->dma_base + 0x018), hwif->dmatable_dma); + + if (in_be32((void __iomem *)(hwif->config_data + 0xff0)) & CCKCTRL_ATACLKOEN) + hwif->ultra_mask = ATA_UDMA6; /* 133MHz */ + else + hwif->ultra_mask = ATA_UDMA5; /* 100MHz */ +} + +static const struct ide_tp_ops scc_tp_ops = { + .exec_command = scc_exec_command, + .read_status = scc_read_status, + .read_altstatus = scc_read_altstatus, + .write_devctl = scc_write_devctl, + + .dev_select = ide_dev_select, + .tf_load = scc_tf_load, + .tf_read = scc_tf_read, + + .input_data = scc_input_data, + .output_data = scc_output_data, +}; + +static const struct ide_port_ops scc_port_ops = { + .set_pio_mode = scc_set_pio_mode, + .set_dma_mode = scc_set_dma_mode, + .udma_filter = scc_udma_filter, + .cable_detect = scc_cable_detect, +}; + +static const struct ide_dma_ops scc_dma_ops = { + .dma_host_set = scc_dma_host_set, + .dma_setup = scc_dma_setup, + .dma_start = scc_dma_start, + .dma_end = scc_dma_end, + .dma_test_irq = scc_dma_test_irq, + .dma_lost_irq = ide_dma_lost_irq, + .dma_timer_expiry = ide_dma_sff_timer_expiry, + .dma_sff_read_status = scc_dma_sff_read_status, +}; + +static const struct ide_port_info scc_chipset = { + .name = "sccIDE", + .init_iops = init_iops_scc, + .init_dma = scc_init_dma, + .init_hwif = init_hwif_scc, + .tp_ops = &scc_tp_ops, + .port_ops = &scc_port_ops, + .dma_ops = &scc_dma_ops, + .host_flags = IDE_HFLAG_SINGLE, + .irq_flags = IRQF_SHARED, + .pio_mask = ATA_PIO4, + .chipset = ide_pci, +}; + +/** + * scc_init_one - pci layer discovery entry + * @dev: PCI device + * @id: ident table entry + * + * Called by the PCI code when it finds an SCC PATA controller. + * We then use the IDE PCI generic helper to do most of the work. + */ + +static int scc_init_one(struct pci_dev *dev, const struct pci_device_id *id) +{ + return init_setup_scc(dev, &scc_chipset); +} + +/** + * scc_remove - pci layer remove entry + * @dev: PCI device + * + * Called by the PCI code when it removes an SCC PATA controller. + */ + +static void scc_remove(struct pci_dev *dev) +{ + struct scc_ports *ports = pci_get_drvdata(dev); + struct ide_host *host = ports->host; + + ide_host_remove(host); + + iounmap((void*)ports->dma); + iounmap((void*)ports->ctl); + pci_release_selected_regions(dev, (1 << 2) - 1); + memset(ports, 0, sizeof(*ports)); +} + +static const struct pci_device_id scc_pci_tbl[] = { + { PCI_VDEVICE(TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_SCC_ATA), 0 }, + { 0, }, +}; +MODULE_DEVICE_TABLE(pci, scc_pci_tbl); + +static struct pci_driver scc_pci_driver = { + .name = "SCC IDE", + .id_table = scc_pci_tbl, + .probe = scc_init_one, + .remove = scc_remove, +}; + +static int __init scc_ide_init(void) +{ + return ide_pci_register_driver(&scc_pci_driver); +} + +static void __exit scc_ide_exit(void) +{ + pci_unregister_driver(&scc_pci_driver); +} + +module_init(scc_ide_init); +module_exit(scc_ide_exit); + +MODULE_DESCRIPTION("PCI driver module for Toshiba SCC IDE"); +MODULE_LICENSE("GPL"); diff --git a/drivers/ide/serverworks.c b/drivers/ide/serverworks.c new file mode 100644 index 00000000000..a97affca18a --- /dev/null +++ b/drivers/ide/serverworks.c @@ -0,0 +1,449 @@ +/* + * Copyright (C) 1998-2000 Michel Aubry + * Copyright (C) 1998-2000 Andrzej Krzysztofowicz + * Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org> + * Copyright (C) 2007-2010 Bartlomiej Zolnierkiewicz + * Portions copyright (c) 2001 Sun Microsystems + * + * + * RCC/ServerWorks IDE driver for Linux + * + * OSB4: `Open South Bridge' IDE Interface (fn 1) + * supports UDMA mode 2 (33 MB/s) + * + * CSB5: `Champion South Bridge' IDE Interface (fn 1) + * all revisions support UDMA mode 4 (66 MB/s) + * revision A2.0 and up support UDMA mode 5 (100 MB/s) + * + * *** The CSB5 does not provide ANY register *** + * *** to detect 80-conductor cable presence. *** + * + * CSB6: `Champion South Bridge' IDE Interface (optional: third channel) + * + * HT1000: AKA BCM5785 - Hypertransport Southbridge for Opteron systems. IDE + * controller same as the CSB6. Single channel ATA100 only. + * + * Documentation: + * Available under NDA only. Errata info very hard to get. + * + */ + +#include <linux/types.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/pci.h> +#include <linux/ide.h> +#include <linux/init.h> + +#include <asm/io.h> + +#define DRV_NAME "serverworks" + +#define SVWKS_CSB5_REVISION_NEW 0x92 /* min PCI_REVISION_ID for UDMA5 (A2.0) */ +#define SVWKS_CSB6_REVISION 0xa0 /* min PCI_REVISION_ID for UDMA4 (A1.0) */ + +/* Seagate Barracuda ATA IV Family drives in UDMA mode 5 + * can overrun their FIFOs when used with the CSB5 */ +static const char *svwks_bad_ata100[] = { + "ST320011A", + "ST340016A", + "ST360021A", + "ST380021A", + NULL +}; + +static int check_in_drive_lists (ide_drive_t *drive, const char **list) +{ + char *m = (char *)&drive->id[ATA_ID_PROD]; + + while (*list) + if (!strcmp(*list++, m)) + return 1; + return 0; +} + +static u8 svwks_udma_filter(ide_drive_t *drive) +{ + struct pci_dev *dev = to_pci_dev(drive->hwif->dev); + + if (dev->device == PCI_DEVICE_ID_SERVERWORKS_HT1000IDE) { + return 0x1f; + } else if (dev->revision < SVWKS_CSB5_REVISION_NEW) { + return 0x07; + } else { + u8 btr = 0, mode, mask; + + pci_read_config_byte(dev, 0x5A, &btr); + mode = btr & 0x3; + + /* If someone decides to do UDMA133 on CSB5 the same + issue will bite so be inclusive */ + if (mode > 2 && check_in_drive_lists(drive, svwks_bad_ata100)) + mode = 2; + + switch(mode) { + case 3: mask = 0x3f; break; + case 2: mask = 0x1f; break; + case 1: mask = 0x07; break; + default: mask = 0x00; break; + } + + return mask; + } +} + +static u8 svwks_csb_check (struct pci_dev *dev) +{ + switch (dev->device) { + case PCI_DEVICE_ID_SERVERWORKS_CSB5IDE: + case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE: + case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2: + case PCI_DEVICE_ID_SERVERWORKS_HT1000IDE: + return 1; + default: + break; + } + return 0; +} + +static void svwks_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) +{ + static const u8 pio_modes[] = { 0x5d, 0x47, 0x34, 0x22, 0x20 }; + static const u8 drive_pci[] = { 0x41, 0x40, 0x43, 0x42 }; + + struct pci_dev *dev = to_pci_dev(hwif->dev); + const u8 pio = drive->pio_mode - XFER_PIO_0; + + pci_write_config_byte(dev, drive_pci[drive->dn], pio_modes[pio]); + + if (svwks_csb_check(dev)) { + u16 csb_pio = 0; + + pci_read_config_word(dev, 0x4a, &csb_pio); + + csb_pio &= ~(0x0f << (4 * drive->dn)); + csb_pio |= (pio << (4 * drive->dn)); + + pci_write_config_word(dev, 0x4a, csb_pio); + } +} + +static void svwks_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive) +{ + static const u8 udma_modes[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 }; + static const u8 dma_modes[] = { 0x77, 0x21, 0x20 }; + static const u8 drive_pci2[] = { 0x45, 0x44, 0x47, 0x46 }; + + struct pci_dev *dev = to_pci_dev(hwif->dev); + const u8 speed = drive->dma_mode; + u8 unit = drive->dn & 1; + + u8 ultra_enable = 0, ultra_timing = 0, dma_timing = 0; + + pci_read_config_byte(dev, (0x56|hwif->channel), &ultra_timing); + pci_read_config_byte(dev, 0x54, &ultra_enable); + + ultra_timing &= ~(0x0F << (4*unit)); + ultra_enable &= ~(0x01 << drive->dn); + + if (speed >= XFER_UDMA_0) { + dma_timing |= dma_modes[2]; + ultra_timing |= (udma_modes[speed - XFER_UDMA_0] << (4 * unit)); + ultra_enable |= (0x01 << drive->dn); + } else if (speed >= XFER_MW_DMA_0) + dma_timing |= dma_modes[speed - XFER_MW_DMA_0]; + + pci_write_config_byte(dev, drive_pci2[drive->dn], dma_timing); + pci_write_config_byte(dev, (0x56|hwif->channel), ultra_timing); + pci_write_config_byte(dev, 0x54, ultra_enable); +} + +static int init_chipset_svwks(struct pci_dev *dev) +{ + unsigned int reg; + u8 btr; + + /* force Master Latency Timer value to 64 PCICLKs */ + pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x40); + + /* OSB4 : South Bridge and IDE */ + if (dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) { + struct pci_dev *isa_dev = + pci_get_device(PCI_VENDOR_ID_SERVERWORKS, + PCI_DEVICE_ID_SERVERWORKS_OSB4, NULL); + if (isa_dev) { + pci_read_config_dword(isa_dev, 0x64, ®); + reg &= ~0x00002000; /* disable 600ns interrupt mask */ + if(!(reg & 0x00004000)) + printk(KERN_DEBUG DRV_NAME " %s: UDMA not BIOS " + "enabled.\n", pci_name(dev)); + reg |= 0x00004000; /* enable UDMA/33 support */ + pci_write_config_dword(isa_dev, 0x64, reg); + pci_dev_put(isa_dev); + } + } + + /* setup CSB5/CSB6 : South Bridge and IDE option RAID */ + else if ((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) || + (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) || + (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2)) { + + /* Third Channel Test */ + if (!(PCI_FUNC(dev->devfn) & 1)) { + struct pci_dev * findev = NULL; + u32 reg4c = 0; + findev = pci_get_device(PCI_VENDOR_ID_SERVERWORKS, + PCI_DEVICE_ID_SERVERWORKS_CSB5, NULL); + if (findev) { + pci_read_config_dword(findev, 0x4C, ®4c); + reg4c &= ~0x000007FF; + reg4c |= 0x00000040; + reg4c |= 0x00000020; + pci_write_config_dword(findev, 0x4C, reg4c); + pci_dev_put(findev); + } + outb_p(0x06, 0x0c00); + dev->irq = inb_p(0x0c01); + } else { + struct pci_dev * findev = NULL; + u8 reg41 = 0; + + findev = pci_get_device(PCI_VENDOR_ID_SERVERWORKS, + PCI_DEVICE_ID_SERVERWORKS_CSB6, NULL); + if (findev) { + pci_read_config_byte(findev, 0x41, ®41); + reg41 &= ~0x40; + pci_write_config_byte(findev, 0x41, reg41); + pci_dev_put(findev); + } + /* + * This is a device pin issue on CSB6. + * Since there will be a future raid mode, + * early versions of the chipset require the + * interrupt pin to be set, and it is a compatibility + * mode issue. + */ + if ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE) + dev->irq = 0; + } +// pci_read_config_dword(dev, 0x40, &pioreg) +// pci_write_config_dword(dev, 0x40, 0x99999999); +// pci_read_config_dword(dev, 0x44, &dmareg); +// pci_write_config_dword(dev, 0x44, 0xFFFFFFFF); + /* setup the UDMA Control register + * + * 1. clear bit 6 to enable DMA + * 2. enable DMA modes with bits 0-1 + * 00 : legacy + * 01 : udma2 + * 10 : udma2/udma4 + * 11 : udma2/udma4/udma5 + */ + pci_read_config_byte(dev, 0x5A, &btr); + btr &= ~0x40; + if (!(PCI_FUNC(dev->devfn) & 1)) + btr |= 0x2; + else + btr |= (dev->revision >= SVWKS_CSB5_REVISION_NEW) ? 0x3 : 0x2; + pci_write_config_byte(dev, 0x5A, btr); + } + /* Setup HT1000 SouthBridge Controller - Single Channel Only */ + else if (dev->device == PCI_DEVICE_ID_SERVERWORKS_HT1000IDE) { + pci_read_config_byte(dev, 0x5A, &btr); + btr &= ~0x40; + btr |= 0x3; + pci_write_config_byte(dev, 0x5A, btr); + } + + return 0; +} + +static u8 ata66_svwks_svwks(ide_hwif_t *hwif) +{ + return ATA_CBL_PATA80; +} + +/* On Dell PowerEdge servers with a CSB5/CSB6, the top two bits + * of the subsystem device ID indicate presence of an 80-pin cable. + * Bit 15 clear = secondary IDE channel does not have 80-pin cable. + * Bit 15 set = secondary IDE channel has 80-pin cable. + * Bit 14 clear = primary IDE channel does not have 80-pin cable. + * Bit 14 set = primary IDE channel has 80-pin cable. + */ +static u8 ata66_svwks_dell(ide_hwif_t *hwif) +{ + struct pci_dev *dev = to_pci_dev(hwif->dev); + + if (dev->subsystem_vendor == PCI_VENDOR_ID_DELL && + dev->vendor == PCI_VENDOR_ID_SERVERWORKS && + (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE || + dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE)) + return ((1 << (hwif->channel + 14)) & + dev->subsystem_device) ? ATA_CBL_PATA80 : ATA_CBL_PATA40; + return ATA_CBL_PATA40; +} + +/* Sun Cobalt Alpine hardware avoids the 80-pin cable + * detect issue by attaching the drives directly to the board. + * This check follows the Dell precedent (how scary is that?!) + * + * WARNING: this only works on Alpine hardware! + */ +static u8 ata66_svwks_cobalt(ide_hwif_t *hwif) +{ + struct pci_dev *dev = to_pci_dev(hwif->dev); + + if (dev->subsystem_vendor == PCI_VENDOR_ID_SUN && + dev->vendor == PCI_VENDOR_ID_SERVERWORKS && + dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) + return ((1 << (hwif->channel + 14)) & + dev->subsystem_device) ? ATA_CBL_PATA80 : ATA_CBL_PATA40; + return ATA_CBL_PATA40; +} + +static u8 svwks_cable_detect(ide_hwif_t *hwif) +{ + struct pci_dev *dev = to_pci_dev(hwif->dev); + + /* Server Works */ + if (dev->subsystem_vendor == PCI_VENDOR_ID_SERVERWORKS) + return ata66_svwks_svwks (hwif); + + /* Dell PowerEdge */ + if (dev->subsystem_vendor == PCI_VENDOR_ID_DELL) + return ata66_svwks_dell (hwif); + + /* Cobalt Alpine */ + if (dev->subsystem_vendor == PCI_VENDOR_ID_SUN) + return ata66_svwks_cobalt (hwif); + + /* Per Specified Design by OEM, and ASIC Architect */ + if ((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) || + (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2)) + return ATA_CBL_PATA80; + + return ATA_CBL_PATA40; +} + +static const struct ide_port_ops osb4_port_ops = { + .set_pio_mode = svwks_set_pio_mode, + .set_dma_mode = svwks_set_dma_mode, +}; + +static const struct ide_port_ops svwks_port_ops = { + .set_pio_mode = svwks_set_pio_mode, + .set_dma_mode = svwks_set_dma_mode, + .udma_filter = svwks_udma_filter, + .cable_detect = svwks_cable_detect, +}; + +static const struct ide_port_info serverworks_chipsets[] = { + { /* 0: OSB4 */ + .name = DRV_NAME, + .init_chipset = init_chipset_svwks, + .port_ops = &osb4_port_ops, + .pio_mask = ATA_PIO4, + .mwdma_mask = ATA_MWDMA2, + .udma_mask = 0x00, /* UDMA is problematic on OSB4 */ + }, + { /* 1: CSB5 */ + .name = DRV_NAME, + .init_chipset = init_chipset_svwks, + .port_ops = &svwks_port_ops, + .pio_mask = ATA_PIO4, + .mwdma_mask = ATA_MWDMA2, + .udma_mask = ATA_UDMA5, + }, + { /* 2: CSB6 */ + .name = DRV_NAME, + .init_chipset = init_chipset_svwks, + .port_ops = &svwks_port_ops, + .pio_mask = ATA_PIO4, + .mwdma_mask = ATA_MWDMA2, + .udma_mask = ATA_UDMA5, + }, + { /* 3: CSB6-2 */ + .name = DRV_NAME, + .init_chipset = init_chipset_svwks, + .port_ops = &svwks_port_ops, + .host_flags = IDE_HFLAG_SINGLE, + .pio_mask = ATA_PIO4, + .mwdma_mask = ATA_MWDMA2, + .udma_mask = ATA_UDMA5, + }, + { /* 4: HT1000 */ + .name = DRV_NAME, + .init_chipset = init_chipset_svwks, + .port_ops = &svwks_port_ops, + .host_flags = IDE_HFLAG_SINGLE, + .pio_mask = ATA_PIO4, + .mwdma_mask = ATA_MWDMA2, + .udma_mask = ATA_UDMA5, + } +}; + +/** + * svwks_init_one - called when a OSB/CSB is found + * @dev: the svwks device + * @id: the matching pci id + * + * Called when the PCI registration layer (or the IDE initialization) + * finds a device matching our IDE device tables. + */ + +static int svwks_init_one(struct pci_dev *dev, const struct pci_device_id *id) +{ + struct ide_port_info d; + u8 idx = id->driver_data; + + d = serverworks_chipsets[idx]; + + if (idx == 1) + d.host_flags |= IDE_HFLAG_CLEAR_SIMPLEX; + else if (idx == 2 || idx == 3) { + if ((PCI_FUNC(dev->devfn) & 1) == 0) { + if (pci_resource_start(dev, 0) != 0x01f1) + d.host_flags |= IDE_HFLAG_NON_BOOTABLE; + d.host_flags |= IDE_HFLAG_SINGLE; + } else + d.host_flags &= ~IDE_HFLAG_SINGLE; + } + + return ide_pci_init_one(dev, &d, NULL); +} + +static const struct pci_device_id svwks_pci_tbl[] = { + { PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4IDE), 0 }, + { PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5IDE), 1 }, + { PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6IDE), 2 }, + { PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2), 3 }, + { PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_HT1000IDE), 4 }, + { 0, }, +}; +MODULE_DEVICE_TABLE(pci, svwks_pci_tbl); + +static struct pci_driver svwks_pci_driver = { + .name = "Serverworks_IDE", + .id_table = svwks_pci_tbl, + .probe = svwks_init_one, + .remove = ide_pci_remove, + .suspend = ide_pci_suspend, + .resume = ide_pci_resume, +}; + +static int __init svwks_ide_init(void) +{ + return ide_pci_register_driver(&svwks_pci_driver); +} + +static void __exit svwks_ide_exit(void) +{ + pci_unregister_driver(&svwks_pci_driver); +} + +module_init(svwks_ide_init); +module_exit(svwks_ide_exit); + +MODULE_AUTHOR("Michael Aubry. Andrzej Krzysztofowicz, Andre Hedrick, Bartlomiej Zolnierkiewicz"); +MODULE_DESCRIPTION("PCI driver module for Serverworks OSB4/CSB5/CSB6 IDE"); +MODULE_LICENSE("GPL"); diff --git a/drivers/ide/setup-pci.c b/drivers/ide/setup-pci.c index eb0945284ac..34a5e5223d5 100644 --- a/drivers/ide/setup-pci.c +++ b/drivers/ide/setup-pci.c @@ -1,114 +1,21 @@ /* - * linux/drivers/ide/setup-pci.c Version 1.10 2002/08/19 + * Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org> + * Copyright (C) 1995-1998 Mark Lord + * Copyright (C) 2007-2009 Bartlomiej Zolnierkiewicz * - * Copyright (c) 1998-2000 Andre Hedrick <andre@linux-ide.org> - * - * Copyright (c) 1995-1998 Mark Lord * May be copied or modified under the terms of the GNU General Public License - * - * Recent Changes - * Split the set up function into multiple functions - * Use pci_set_master - * Fix misreporting of I/O v MMIO problems - * Initial fixups for simplex devices */ -/* - * This module provides support for automatic detection and - * configuration of all PCI IDE interfaces present in a system. - */ - -#include <linux/module.h> #include <linux/types.h> #include <linux/kernel.h> +#include <linux/export.h> #include <linux/pci.h> #include <linux/init.h> -#include <linux/timer.h> -#include <linux/mm.h> #include <linux/interrupt.h> #include <linux/ide.h> #include <linux/dma-mapping.h> #include <asm/io.h> -#include <asm/irq.h> - - -/** - * ide_match_hwif - match a PCI IDE against an ide_hwif - * @io_base: I/O base of device - * @bootable: set if its bootable - * @name: name of device - * - * Match a PCI IDE port against an entry in ide_hwifs[], - * based on io_base port if possible. Return the matching hwif, - * or a new hwif. If we find an error (clashing, out of devices, etc) - * return NULL - * - * FIXME: we need to handle mmio matches here too - */ - -static ide_hwif_t *ide_match_hwif(unsigned long io_base, u8 bootable, const char *name) -{ - int h; - ide_hwif_t *hwif; - - /* - * Look for a hwif with matching io_base specified using - * parameters to ide_setup(). - */ - for (h = 0; h < MAX_HWIFS; ++h) { - hwif = &ide_hwifs[h]; - if (hwif->io_ports[IDE_DATA_OFFSET] == io_base) { - if (hwif->chipset == ide_forced) - return hwif; /* a perfect match */ - } - } - /* - * Look for a hwif with matching io_base default value. - * If chipset is "ide_unknown", then claim that hwif slot. - * Otherwise, some other chipset has already claimed it.. :( - */ - for (h = 0; h < MAX_HWIFS; ++h) { - hwif = &ide_hwifs[h]; - if (hwif->io_ports[IDE_DATA_OFFSET] == io_base) { - if (hwif->chipset == ide_unknown) - return hwif; /* match */ - printk(KERN_ERR "%s: port 0x%04lx already claimed by %s\n", - name, io_base, hwif->name); - return NULL; /* already claimed */ - } - } - /* - * Okay, there is no hwif matching our io_base, - * so we'll just claim an unassigned slot. - * Give preference to claiming other slots before claiming ide0/ide1, - * just in case there's another interface yet-to-be-scanned - * which uses ports 1f0/170 (the ide0/ide1 defaults). - * - * Unless there is a bootable card that does not use the standard - * ports 1f0/170 (the ide0/ide1 defaults). The (bootable) flag. - */ - if (bootable) { - for (h = 0; h < MAX_HWIFS; ++h) { - hwif = &ide_hwifs[h]; - if (hwif->chipset == ide_unknown) - return hwif; /* pick an unused entry */ - } - } else { - for (h = 2; h < MAX_HWIFS; ++h) { - hwif = ide_hwifs + h; - if (hwif->chipset == ide_unknown) - return hwif; /* pick an unused entry */ - } - } - for (h = 0; h < 2; ++h) { - hwif = ide_hwifs + h; - if (hwif->chipset == ide_unknown) - return hwif; /* pick an unused entry */ - } - printk(KERN_ERR "%s: too many IDE interfaces, no room in table\n", name); - return NULL; -} /** * ide_setup_pci_baseregs - place a PCI IDE controller native @@ -117,13 +24,13 @@ static ide_hwif_t *ide_match_hwif(unsigned long io_base, u8 bootable, const char * * We attempt to place the PCI interface into PCI native mode. If * we succeed the BARs are ok and the controller is in PCI mode. - * Returns 0 on success or an errno code. + * Returns 0 on success or an errno code. * * FIXME: if we program the interface and then fail to set the BARS * we don't switch it back to legacy mode. Do we actually care ?? */ - -static int ide_setup_pci_baseregs (struct pci_dev *dev, const char *name) + +static int ide_setup_pci_baseregs(struct pci_dev *dev, const char *name) { u8 progif = 0; @@ -133,17 +40,18 @@ static int ide_setup_pci_baseregs (struct pci_dev *dev, const char *name) if (pci_read_config_byte(dev, PCI_CLASS_PROG, &progif) || (progif & 5) != 5) { if ((progif & 0xa) != 0xa) { - printk(KERN_INFO "%s: device not capable of full " - "native PCI mode\n", name); + printk(KERN_INFO "%s %s: device not capable of full " + "native PCI mode\n", name, pci_name(dev)); return -EOPNOTSUPP; } - printk("%s: placing both ports into native PCI mode\n", name); + printk(KERN_INFO "%s %s: placing both ports into native PCI " + "mode\n", name, pci_name(dev)); (void) pci_write_config_byte(dev, PCI_CLASS_PROG, progif|5); if (pci_read_config_byte(dev, PCI_CLASS_PROG, &progif) || (progif & 5) != 5) { - printk(KERN_ERR "%s: rewrite of PROGIF failed, wanted " - "0x%04x, got 0x%04x\n", - name, progif|5, progif); + printk(KERN_ERR "%s %s: rewrite of PROGIF failed, " + "wanted 0x%04x, got 0x%04x\n", + name, pci_name(dev), progif | 5, progif); return -EOPNOTSUPP; } } @@ -151,176 +59,179 @@ static int ide_setup_pci_baseregs (struct pci_dev *dev, const char *name) } #ifdef CONFIG_BLK_DEV_IDEDMA_PCI +static int ide_pci_clear_simplex(unsigned long dma_base, const char *name) +{ + u8 dma_stat = inb(dma_base + 2); -#ifdef CONFIG_BLK_DEV_IDEDMA_FORCED -/* - * Long lost data from 2.0.34 that is now in 2.0.39 - * - * This was used in ./drivers/block/triton.c to do DMA Base address setup - * when PnP failed. Oh the things we forget. I believe this was part - * of SFF-8038i that has been withdrawn from public access... :-(( - */ -#define DEFAULT_BMIBA 0xe800 /* in case BIOS did not init it */ -#define DEFAULT_BMCRBA 0xcc00 /* VIA's default value */ -#define DEFAULT_BMALIBA 0xd400 /* ALI's default value */ -#endif /* CONFIG_BLK_DEV_IDEDMA_FORCED */ + outb(dma_stat & 0x60, dma_base + 2); + dma_stat = inb(dma_base + 2); + + return (dma_stat & 0x80) ? 1 : 0; +} /** - * ide_get_or_set_dma_base - setup BMIBA - * @hwif: Interface + * ide_pci_dma_base - setup BMIBA + * @hwif: IDE interface + * @d: IDE port info * - * Fetch the DMA Bus-Master-I/O-Base-Address (BMIBA) from PCI space: - * If need be we set up the DMA base. Where a device has a partner that - * is already in DMA mode we check and enforce IDE simplex rules. + * Fetch the DMA Bus-Master-I/O-Base-Address (BMIBA) from PCI space. */ -static unsigned long ide_get_or_set_dma_base (ide_hwif_t *hwif) +unsigned long ide_pci_dma_base(ide_hwif_t *hwif, const struct ide_port_info *d) { - unsigned long dma_base = 0; - struct pci_dev *dev = hwif->pci_dev; - -#ifdef CONFIG_BLK_DEV_IDEDMA_FORCED - int second_chance = 0; + struct pci_dev *dev = to_pci_dev(hwif->dev); + unsigned long dma_base = 0; -second_chance_to_dma: -#endif /* CONFIG_BLK_DEV_IDEDMA_FORCED */ - - if (hwif->mmio) + if (hwif->host_flags & IDE_HFLAG_MMIO) return hwif->dma_base; if (hwif->mate && hwif->mate->dma_base) { dma_base = hwif->mate->dma_base - (hwif->channel ? 0 : 8); } else { - dma_base = pci_resource_start(dev, 4); - if (!dma_base) { - printk(KERN_ERR "%s: dma_base is invalid\n", - hwif->cds->name); + u8 baridx = (d->host_flags & IDE_HFLAG_CS5520) ? 2 : 4; + + dma_base = pci_resource_start(dev, baridx); + + if (dma_base == 0) { + printk(KERN_ERR "%s %s: DMA base is invalid\n", + d->name, pci_name(dev)); + return 0; } } -#ifdef CONFIG_BLK_DEV_IDEDMA_FORCED - /* FIXME - should use pci_assign_resource surely */ - if ((!dma_base) && (!second_chance)) { - unsigned long set_bmiba = 0; - second_chance++; - switch(dev->vendor) { - case PCI_VENDOR_ID_AL: - set_bmiba = DEFAULT_BMALIBA; break; - case PCI_VENDOR_ID_VIA: - set_bmiba = DEFAULT_BMCRBA; break; - case PCI_VENDOR_ID_INTEL: - set_bmiba = DEFAULT_BMIBA; break; - default: - return dma_base; - } - pci_write_config_dword(dev, 0x20, set_bmiba|1); - goto second_chance_to_dma; + if (hwif->channel) + dma_base += 8; + + return dma_base; +} +EXPORT_SYMBOL_GPL(ide_pci_dma_base); + +int ide_pci_check_simplex(ide_hwif_t *hwif, const struct ide_port_info *d) +{ + struct pci_dev *dev = to_pci_dev(hwif->dev); + u8 dma_stat; + + if (d->host_flags & (IDE_HFLAG_MMIO | IDE_HFLAG_CS5520)) + goto out; + + if (d->host_flags & IDE_HFLAG_CLEAR_SIMPLEX) { + if (ide_pci_clear_simplex(hwif->dma_base, d->name)) + printk(KERN_INFO "%s %s: simplex device: DMA forced\n", + d->name, pci_name(dev)); + goto out; } -#endif /* CONFIG_BLK_DEV_IDEDMA_FORCED */ - - if (dma_base) { - u8 simplex_stat = 0; - dma_base += hwif->channel ? 8 : 0; - - switch(dev->device) { - case PCI_DEVICE_ID_AL_M5219: - case PCI_DEVICE_ID_AL_M5229: - case PCI_DEVICE_ID_AMD_VIPER_7409: - case PCI_DEVICE_ID_CMD_643: - case PCI_DEVICE_ID_SERVERWORKS_CSB5IDE: - case PCI_DEVICE_ID_REVOLUTION: - simplex_stat = hwif->INB(dma_base + 2); - hwif->OUTB((simplex_stat&0x60),(dma_base + 2)); - simplex_stat = hwif->INB(dma_base + 2); - if (simplex_stat & 0x80) { - printk(KERN_INFO "%s: simplex device: " - "DMA forced\n", - hwif->cds->name); - } - break; - default: - /* - * If the device claims "simplex" DMA, - * this means only one of the two interfaces - * can be trusted with DMA at any point in time. - * So we should enable DMA only on one of the - * two interfaces. - */ - simplex_stat = hwif->INB(dma_base + 2); - if (simplex_stat & 0x80) { - /* simplex device? */ + + /* + * If the device claims "simplex" DMA, this means that only one of + * the two interfaces can be trusted with DMA at any point in time + * (so we should enable DMA only on one of the two interfaces). + * + * FIXME: At this point we haven't probed the drives so we can't make + * the appropriate decision. Really we should defer this problem until + * we tune the drive then try to grab DMA ownership if we want to be + * the DMA end. This has to be become dynamic to handle hot-plug. + */ + dma_stat = hwif->dma_ops->dma_sff_read_status(hwif); + if ((dma_stat & 0x80) && hwif->mate && hwif->mate->dma_base) { + printk(KERN_INFO "%s %s: simplex device: DMA disabled\n", + d->name, pci_name(dev)); + return -1; + } +out: + return 0; +} +EXPORT_SYMBOL_GPL(ide_pci_check_simplex); + /* - * At this point we haven't probed the drives so we can't make the - * appropriate decision. Really we should defer this problem - * until we tune the drive then try to grab DMA ownership if we want - * to be the DMA end. This has to be become dynamic to handle hot - * plug. + * Set up BM-DMA capability (PnP BIOS should have done this) */ - if (hwif->mate && hwif->mate->dma_base) { - printk(KERN_INFO "%s: simplex device: " - "DMA disabled\n", - hwif->cds->name); - dma_base = 0; - } - } +int ide_pci_set_master(struct pci_dev *dev, const char *name) +{ + u16 pcicmd; + + pci_read_config_word(dev, PCI_COMMAND, &pcicmd); + + if ((pcicmd & PCI_COMMAND_MASTER) == 0) { + pci_set_master(dev); + + if (pci_read_config_word(dev, PCI_COMMAND, &pcicmd) || + (pcicmd & PCI_COMMAND_MASTER) == 0) { + printk(KERN_ERR "%s %s: error updating PCICMD\n", + name, pci_name(dev)); + return -EIO; } } - return dma_base; + + return 0; } +EXPORT_SYMBOL_GPL(ide_pci_set_master); #endif /* CONFIG_BLK_DEV_IDEDMA_PCI */ -void ide_setup_pci_noise (struct pci_dev *dev, ide_pci_device_t *d) +void ide_setup_pci_noise(struct pci_dev *dev, const struct ide_port_info *d) { - printk(KERN_INFO "%s: IDE controller at PCI slot %s\n", - d->name, pci_name(dev)); + printk(KERN_INFO "%s %s: IDE controller (0x%04x:0x%04x rev 0x%02x)\n", + d->name, pci_name(dev), + dev->vendor, dev->device, dev->revision); } - EXPORT_SYMBOL_GPL(ide_setup_pci_noise); /** * ide_pci_enable - do PCI enables * @dev: PCI device - * @d: IDE pci device data + * @d: IDE port info * * Enable the IDE PCI device. We attempt to enable the device in full - * but if that fails then we only need BAR4 so we will enable that. - * + * but if that fails then we only need IO space. The PCI code should + * have setup the proper resources for us already for controllers in + * legacy mode. + * * Returns zero on success or an error code */ - -static int ide_pci_enable(struct pci_dev *dev, ide_pci_device_t *d) + +static int ide_pci_enable(struct pci_dev *dev, const struct ide_port_info *d) { - int ret; + int ret, bars; if (pci_enable_device(dev)) { - ret = pci_enable_device_bars(dev, 1 << 4); + ret = pci_enable_device_io(dev); if (ret < 0) { - printk(KERN_WARNING "%s: (ide_setup_pci_device:) " - "Could not enable device.\n", d->name); + printk(KERN_WARNING "%s %s: couldn't enable device\n", + d->name, pci_name(dev)); goto out; } - printk(KERN_WARNING "%s: BIOS configuration fixed.\n", d->name); + printk(KERN_WARNING "%s %s: BIOS configuration fixed\n", + d->name, pci_name(dev)); } /* - * assume all devices can do 32-bit dma for now. we can add a - * dma mask field to the ide_pci_device_t if we need it (or let - * lower level driver set the dma mask) + * assume all devices can do 32-bit DMA for now, we can add + * a DMA mask field to the struct ide_port_info if we need it + * (or let lower level driver set the DMA mask) */ - ret = pci_set_dma_mask(dev, DMA_32BIT_MASK); + ret = pci_set_dma_mask(dev, DMA_BIT_MASK(32)); if (ret < 0) { - printk(KERN_ERR "%s: can't set dma mask\n", d->name); + printk(KERN_ERR "%s %s: can't set DMA mask\n", + d->name, pci_name(dev)); goto out; } - /* FIXME: Temporary - until we put in the hotplug interface logic - Check that the bits we want are not in use by someone else. */ - ret = pci_request_region(dev, 4, "ide_tmp"); - if (ret < 0) - goto out; + if (d->host_flags & IDE_HFLAG_SINGLE) + bars = (1 << 2) - 1; + else + bars = (1 << 4) - 1; + + if ((d->host_flags & IDE_HFLAG_NO_DMA) == 0) { + if (d->host_flags & IDE_HFLAG_CS5520) + bars |= (1 << 2); + else + bars |= (1 << 4); + } - pci_release_region(dev, 4); + ret = pci_request_selected_regions(dev, bars, d->name); + if (ret < 0) + printk(KERN_ERR "%s %s: can't reserve resources\n", + d->name, pci_name(dev)); out: return ret; } @@ -328,13 +239,13 @@ out: /** * ide_pci_configure - configure an unconfigured device * @dev: PCI device - * @d: IDE pci device data + * @d: IDE port info * * Enable and configure the PCI device we have been passed. * Returns zero on success or an error code. */ - -static int ide_pci_configure(struct pci_dev *dev, ide_pci_device_t *d) + +static int ide_pci_configure(struct pci_dev *dev, const struct ide_port_info *d) { u16 pcicmd = 0; /* @@ -344,17 +255,20 @@ static int ide_pci_configure(struct pci_dev *dev, ide_pci_device_t *d) * Maybe the user deliberately *disabled* the device, * but we'll eventually ignore it again if no drives respond. */ - if (ide_setup_pci_baseregs(dev, d->name) || pci_write_config_word(dev, PCI_COMMAND, pcicmd|PCI_COMMAND_IO)) - { - printk(KERN_INFO "%s: device disabled (BIOS)\n", d->name); + if (ide_setup_pci_baseregs(dev, d->name) || + pci_write_config_word(dev, PCI_COMMAND, pcicmd | PCI_COMMAND_IO)) { + printk(KERN_INFO "%s %s: device disabled (BIOS)\n", + d->name, pci_name(dev)); return -ENODEV; } if (pci_read_config_word(dev, PCI_COMMAND, &pcicmd)) { - printk(KERN_ERR "%s: error accessing PCI regs\n", d->name); + printk(KERN_ERR "%s %s: error accessing PCI regs\n", + d->name, pci_name(dev)); return -EIO; } if (!(pcicmd & PCI_COMMAND_IO)) { - printk(KERN_ERR "%s: unable to enable IDE controller\n", d->name); + printk(KERN_ERR "%s %s: unable to enable IDE controller\n", + d->name, pci_name(dev)); return -ENXIO; } return 0; @@ -362,172 +276,145 @@ static int ide_pci_configure(struct pci_dev *dev, ide_pci_device_t *d) /** * ide_pci_check_iomem - check a register is I/O - * @dev: pci device - * @d: ide_pci_device - * @bar: bar number + * @dev: PCI device + * @d: IDE port info + * @bar: BAR number * - * Checks if a BAR is configured and points to MMIO space. If so - * print an error and return an error code. Otherwise return 0 + * Checks if a BAR is configured and points to MMIO space. If so, + * return an error code. Otherwise return 0 */ - -static int ide_pci_check_iomem(struct pci_dev *dev, ide_pci_device_t *d, int bar) + +static int ide_pci_check_iomem(struct pci_dev *dev, const struct ide_port_info *d, + int bar) { ulong flags = pci_resource_flags(dev, bar); - + /* Unconfigured ? */ if (!flags || pci_resource_len(dev, bar) == 0) return 0; - /* I/O space */ - if(flags & PCI_BASE_ADDRESS_IO_MASK) + /* I/O space */ + if (flags & IORESOURCE_IO) return 0; - + /* Bad */ - printk(KERN_ERR "%s: IO baseregs (BIOS) are reported " - "as MEM, report to " - "<andre@linux-ide.org>.\n", d->name); return -EINVAL; } /** - * ide_hwif_configure - configure an IDE interface + * ide_hw_configure - configure a struct ide_hw instance * @dev: PCI device holding interface - * @d: IDE pci data - * @mate: Paired interface if any + * @d: IDE port info + * @port: port number + * @hw: struct ide_hw instance corresponding to this port * * Perform the initial set up for the hardware interface structure. This * is done per interface port rather than per PCI device. There may be * more than one port per device. * - * Returns the new hardware interface structure, or NULL on a failure + * Returns zero on success or an error code. */ - -static ide_hwif_t *ide_hwif_configure(struct pci_dev *dev, ide_pci_device_t *d, ide_hwif_t *mate, int port, int irq) + +static int ide_hw_configure(struct pci_dev *dev, const struct ide_port_info *d, + unsigned int port, struct ide_hw *hw) { unsigned long ctl = 0, base = 0; - ide_hwif_t *hwif; - if ((d->flags & IDEPCI_FLAG_ISA_PORTS) == 0) { - /* Possibly we should fail if these checks report true */ - ide_pci_check_iomem(dev, d, 2*port); - ide_pci_check_iomem(dev, d, 2*port+1); - + if ((d->host_flags & IDE_HFLAG_ISA_PORTS) == 0) { + if (ide_pci_check_iomem(dev, d, 2 * port) || + ide_pci_check_iomem(dev, d, 2 * port + 1)) { + printk(KERN_ERR "%s %s: I/O baseregs (BIOS) are " + "reported as MEM for port %d!\n", + d->name, pci_name(dev), port); + return -EINVAL; + } + ctl = pci_resource_start(dev, 2*port+1); base = pci_resource_start(dev, 2*port); - if ((ctl && !base) || (base && !ctl)) { - printk(KERN_ERR "%s: inconsistent baseregs (BIOS) " - "for port %d, skipping\n", d->name, port); - return NULL; - } - } - if (!ctl) - { + } else { /* Use default values */ ctl = port ? 0x374 : 0x3f4; base = port ? 0x170 : 0x1f0; } - if ((hwif = ide_match_hwif(base, d->bootable, d->name)) == NULL) - return NULL; /* no room in ide_hwifs[] */ - if (hwif->io_ports[IDE_DATA_OFFSET] != base || - hwif->io_ports[IDE_CONTROL_OFFSET] != (ctl | 2)) { - memset(&hwif->hw, 0, sizeof(hwif->hw)); -#ifndef IDE_ARCH_OBSOLETE_INIT - ide_std_init_ports(&hwif->hw, base, (ctl | 2)); - hwif->hw.io_ports[IDE_IRQ_OFFSET] = 0; -#else - ide_init_hwif_ports(&hwif->hw, base, (ctl | 2), NULL); -#endif - memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports)); - hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET]; - } - hwif->chipset = ide_pci; - hwif->pci_dev = dev; - hwif->cds = (struct ide_pci_device_s *) d; - hwif->channel = port; - - if (!hwif->irq) - hwif->irq = irq; - if (mate) { - hwif->mate = mate; - mate->mate = hwif; + + if (!base || !ctl) { + printk(KERN_ERR "%s %s: bad PCI BARs for port %d, skipping\n", + d->name, pci_name(dev), port); + return -EINVAL; } - return hwif; + + memset(hw, 0, sizeof(*hw)); + hw->dev = &dev->dev; + ide_std_init_ports(hw, base, ctl | 2); + + return 0; } +#ifdef CONFIG_BLK_DEV_IDEDMA_PCI /** * ide_hwif_setup_dma - configure DMA interface - * @dev: PCI device - * @d: IDE pci data - * @hwif: Hardware interface we are configuring + * @hwif: IDE interface + * @d: IDE port info * * Set up the DMA base for the interface. Enable the master bits as * necessary and attempt to bring the device DMA into a ready to use * state */ - -#ifndef CONFIG_BLK_DEV_IDEDMA_PCI -static void ide_hwif_setup_dma(struct pci_dev *dev, ide_pci_device_t *d, ide_hwif_t *hwif) -{ -} -#else -static void ide_hwif_setup_dma(struct pci_dev *dev, ide_pci_device_t *d, ide_hwif_t *hwif) + +int ide_hwif_setup_dma(ide_hwif_t *hwif, const struct ide_port_info *d) { - u16 pcicmd; - pci_read_config_word(dev, PCI_COMMAND, &pcicmd); + struct pci_dev *dev = to_pci_dev(hwif->dev); - if ((d->autodma == AUTODMA) || + if ((d->host_flags & IDE_HFLAG_NO_AUTODMA) == 0 || ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE && (dev->class & 0x80))) { - unsigned long dma_base = ide_get_or_set_dma_base(hwif); - if (dma_base && !(pcicmd & PCI_COMMAND_MASTER)) { - /* - * Set up BM-DMA capability - * (PnP BIOS should have done this) - */ - /* default DMA off if we had to configure it here */ - hwif->autodma = 0; - pci_set_master(dev); - if (pci_read_config_word(dev, PCI_COMMAND, &pcicmd) || !(pcicmd & PCI_COMMAND_MASTER)) { - printk(KERN_ERR "%s: %s error updating PCICMD\n", - hwif->name, d->name); - dma_base = 0; - } - } - if (dma_base) { - if (d->init_dma) { - d->init_dma(hwif, dma_base); - } else { - ide_setup_dma(hwif, dma_base, 8); - } - } else { - printk(KERN_INFO "%s: %s Bus-Master DMA disabled " - "(BIOS)\n", hwif->name, d->name); - } - } -} + unsigned long base = ide_pci_dma_base(hwif, d); -#ifndef CONFIG_IDEDMA_PCI_AUTO -#warning CONFIG_IDEDMA_PCI_AUTO=n support is obsolete, and will be removed soon. -#endif + if (base == 0) + return -1; + + hwif->dma_base = base; + + if (hwif->dma_ops == NULL) + hwif->dma_ops = &sff_dma_ops; + + if (ide_pci_check_simplex(hwif, d) < 0) + return -1; + + if (ide_pci_set_master(dev, d->name) < 0) + return -1; + + if (hwif->host_flags & IDE_HFLAG_MMIO) + printk(KERN_INFO " %s: MMIO-DMA\n", hwif->name); + else + printk(KERN_INFO " %s: BM-DMA at 0x%04lx-0x%04lx\n", + hwif->name, base, base + 7); + + hwif->extra_base = base + (hwif->channel ? 8 : 16); + + if (ide_allocate_dma_engine(hwif)) + return -1; + } -#endif /* CONFIG_BLK_DEV_IDEDMA_PCI*/ + return 0; +} +#endif /* CONFIG_BLK_DEV_IDEDMA_PCI */ /** * ide_setup_pci_controller - set up IDE PCI * @dev: PCI device - * @d: IDE PCI data + * @d: IDE port info * @noisy: verbose flag - * @config: returned as 1 if we configured the hardware * * Set up the PCI and controller side of the IDE interface. This brings * up the PCI side of the device, checks that the device is enabled * and enables it if need be */ - -static int ide_setup_pci_controller(struct pci_dev *dev, ide_pci_device_t *d, int noisy, int *config) + +static int ide_setup_pci_controller(struct pci_dev *dev, + const struct ide_port_info *d, int noisy) { int ret; - u32 class_rev; u16 pcicmd; if (noisy) @@ -539,21 +426,18 @@ static int ide_setup_pci_controller(struct pci_dev *dev, ide_pci_device_t *d, in ret = pci_read_config_word(dev, PCI_COMMAND, &pcicmd); if (ret < 0) { - printk(KERN_ERR "%s: error accessing PCI regs\n", d->name); + printk(KERN_ERR "%s %s: error accessing PCI regs\n", + d->name, pci_name(dev)); goto out; } if (!(pcicmd & PCI_COMMAND_IO)) { /* is device disabled? */ ret = ide_pci_configure(dev, d); if (ret < 0) goto out; - *config = 1; - printk(KERN_INFO "%s: device enabled (Linux)\n", d->name); + printk(KERN_INFO "%s %s: device enabled (Linux)\n", + d->name, pci_name(dev)); } - pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev); - class_rev &= 0xff; - if (noisy) - printk(KERN_INFO "%s: chipset revision %d\n", d->name, class_rev); out: return ret; } @@ -561,9 +445,9 @@ out: /** * ide_pci_setup_ports - configure ports/devices on PCI IDE * @dev: PCI device - * @d: IDE pci device info - * @pciirq: IRQ line - * @index: ata index to update + * @d: IDE port info + * @hw: struct ide_hw instances corresponding to this PCI IDE device + * @hws: struct ide_hw pointers table to update * * Scan the interfaces attached to this device and do any * necessary per port setup. Attach the devices and ask the @@ -573,67 +457,33 @@ out: * but is also used directly as a helper function by some controllers * where the chipset setup is not the default PCI IDE one. */ - -void ide_pci_setup_ports(struct pci_dev *dev, ide_pci_device_t *d, int pciirq, ata_index_t *index) + +void ide_pci_setup_ports(struct pci_dev *dev, const struct ide_port_info *d, + struct ide_hw *hw, struct ide_hw **hws) { - int port; - int at_least_one_hwif_enabled = 0; - ide_hwif_t *hwif, *mate = NULL; + int channels = (d->host_flags & IDE_HFLAG_SINGLE) ? 1 : 2, port; u8 tmp; - index->all = 0xf0f0; - /* * Set up the IDE ports */ - - for (port = 0; port <= 1; ++port) { - ide_pci_enablebit_t *e = &(d->enablebits[port]); - - if (e->reg && (pci_read_config_byte(dev, e->reg, &tmp) || - (tmp & e->mask) != e->val)) - continue; /* port not enabled */ - - if (d->channels <= port) - break; - - if ((hwif = ide_hwif_configure(dev, d, mate, port, pciirq)) == NULL) - continue; - /* setup proper ancestral information */ - hwif->gendev.parent = &dev->dev; + for (port = 0; port < channels; ++port) { + const struct ide_pci_enablebit *e = &d->enablebits[port]; - if (hwif->channel) { - index->b.high = hwif->index; - } else { - index->b.low = hwif->index; + if (e->reg && (pci_read_config_byte(dev, e->reg, &tmp) || + (tmp & e->mask) != e->val)) { + printk(KERN_INFO "%s %s: IDE port disabled\n", + d->name, pci_name(dev)); + continue; /* port not enabled */ } - - if (d->init_iops) - d->init_iops(hwif); - - if (d->autodma == NODMA) - goto bypass_legacy_dma; + if (ide_hw_configure(dev, d, port, hw + port)) + continue; - if(d->init_setup_dma) - d->init_setup_dma(dev, d, hwif); - else - ide_hwif_setup_dma(dev, d, hwif); -bypass_legacy_dma: - if (d->init_hwif) - /* Call chipset-specific routine - * for each enabled hwif - */ - d->init_hwif(hwif); - - mate = hwif; - at_least_one_hwif_enabled = 1; + *(hws + port) = hw + port; } - if (!at_least_one_hwif_enabled) - printk(KERN_INFO "%s: neither IDE port enabled (BIOS)\n", d->name); } - EXPORT_SYMBOL_GPL(ide_pci_setup_ports); /* @@ -643,243 +493,173 @@ EXPORT_SYMBOL_GPL(ide_pci_setup_ports); * * One thing that is not standardized is the location of the * primary/secondary interface "enable/disable" bits. For chipsets that - * we "know" about, this information is in the ide_pci_device_t struct; + * we "know" about, this information is in the struct ide_port_info; * for all other chipsets, we just assume both interfaces are enabled. */ -static int do_ide_setup_pci_device(struct pci_dev *dev, ide_pci_device_t *d, - ata_index_t *index, u8 noisy) +static int do_ide_setup_pci_device(struct pci_dev *dev, + const struct ide_port_info *d, + u8 noisy) { - static ata_index_t ata_index = { .b = { .low = 0xff, .high = 0xff } }; - int tried_config = 0; int pciirq, ret; - ret = ide_setup_pci_controller(dev, d, noisy, &tried_config); - if (ret < 0) - goto out; - /* * Can we trust the reported IRQ? */ pciirq = dev->irq; - /* Is it an "IDE storage" device in non-PCI mode? */ - if ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE && (dev->class & 5) != 5) { - if (noisy) - printk(KERN_INFO "%s: not 100%% native mode: " - "will probe irqs later\n", d->name); - /* - * This allows offboard ide-pci cards the enable a BIOS, - * verify interrupt settings of split-mirror pci-config - * space, place chipset into init-mode, and/or preserve - * an interrupt if the card is not native ide support. - */ - ret = d->init_chipset ? d->init_chipset(dev, d->name) : 0; - if (ret < 0) - goto out; - pciirq = ret; - } else if (tried_config) { - if (noisy) - printk(KERN_INFO "%s: will probe irqs later\n", d->name); - pciirq = 0; - } else if (!pciirq) { + /* + * This allows offboard ide-pci cards the enable a BIOS, + * verify interrupt settings of split-mirror pci-config + * space, place chipset into init-mode, and/or preserve + * an interrupt if the card is not native ide support. + */ + ret = d->init_chipset ? d->init_chipset(dev) : 0; + if (ret < 0) + goto out; + + if (ide_pci_is_in_compatibility_mode(dev)) { if (noisy) - printk(KERN_WARNING "%s: bad irq (%d): will probe later\n", - d->name, pciirq); + printk(KERN_INFO "%s %s: not 100%% native mode: will " + "probe irqs later\n", d->name, pci_name(dev)); pciirq = 0; - } else { - if (d->init_chipset) { - ret = d->init_chipset(dev, d->name); - if (ret < 0) - goto out; - } - if (noisy) - printk(KERN_INFO "%s: 100%% native mode on irq %d\n", - d->name, pciirq); + } else if (!pciirq && noisy) { + printk(KERN_WARNING "%s %s: bad irq (%d): will probe later\n", + d->name, pci_name(dev), pciirq); + } else if (noisy) { + printk(KERN_INFO "%s %s: 100%% native mode on irq %d\n", + d->name, pci_name(dev), pciirq); } - /* FIXME: silent failure can happen */ - - *index = ata_index; - ide_pci_setup_ports(dev, d, pciirq, index); + ret = pciirq; out: return ret; } -int ide_setup_pci_device(struct pci_dev *dev, ide_pci_device_t *d) +int ide_pci_init_two(struct pci_dev *dev1, struct pci_dev *dev2, + const struct ide_port_info *d, void *priv) { - ata_index_t index_list; - int ret; + struct pci_dev *pdev[] = { dev1, dev2 }; + struct ide_host *host; + int ret, i, n_ports = dev2 ? 4 : 2; + struct ide_hw hw[4], *hws[] = { NULL, NULL, NULL, NULL }; - ret = do_ide_setup_pci_device(dev, d, &index_list, 1); - if (ret < 0) + for (i = 0; i < n_ports / 2; i++) { + ret = ide_setup_pci_controller(pdev[i], d, !i); + if (ret < 0) + goto out; + + ide_pci_setup_ports(pdev[i], d, &hw[i*2], &hws[i*2]); + } + + host = ide_host_alloc(d, hws, n_ports); + if (host == NULL) { + ret = -ENOMEM; goto out; + } - if ((index_list.b.low & 0xf0) != 0xf0) - probe_hwif_init_with_fixup(&ide_hwifs[index_list.b.low], d->fixup); - if ((index_list.b.high & 0xf0) != 0xf0) - probe_hwif_init_with_fixup(&ide_hwifs[index_list.b.high], d->fixup); + host->dev[0] = &dev1->dev; + if (dev2) + host->dev[1] = &dev2->dev; - create_proc_ide_interfaces(); -out: - return ret; -} + host->host_priv = priv; + host->irq_flags = IRQF_SHARED; -EXPORT_SYMBOL_GPL(ide_setup_pci_device); + pci_set_drvdata(pdev[0], host); + if (dev2) + pci_set_drvdata(pdev[1], host); -int ide_setup_pci_devices(struct pci_dev *dev1, struct pci_dev *dev2, - ide_pci_device_t *d) -{ - struct pci_dev *pdev[] = { dev1, dev2 }; - ata_index_t index_list[2]; - int ret, i; + for (i = 0; i < n_ports / 2; i++) { + ret = do_ide_setup_pci_device(pdev[i], d, !i); - for (i = 0; i < 2; i++) { - ret = do_ide_setup_pci_device(pdev[i], d, index_list + i, !i); /* * FIXME: Mom, mom, they stole me the helper function to undo * do_ide_setup_pci_device() on the first device! */ if (ret < 0) goto out; - } - for (i = 0; i < 2; i++) { - u8 idx[2] = { index_list[i].b.low, index_list[i].b.high }; - int j; - - for (j = 0; j < 2; j++) { - if ((idx[j] & 0xf0) != 0xf0) - probe_hwif_init(ide_hwifs + idx[j]); - } + /* fixup IRQ */ + if (ide_pci_is_in_compatibility_mode(pdev[i])) { + hw[i*2].irq = pci_get_legacy_ide_irq(pdev[i], 0); + hw[i*2 + 1].irq = pci_get_legacy_ide_irq(pdev[i], 1); + } else + hw[i*2 + 1].irq = hw[i*2].irq = ret; } - create_proc_ide_interfaces(); + ret = ide_host_register(host, d, hws); + if (ret) + ide_host_free(host); out: return ret; } +EXPORT_SYMBOL_GPL(ide_pci_init_two); -EXPORT_SYMBOL_GPL(ide_setup_pci_devices); - -/* - * Module interfaces - */ - -static int pre_init = 1; /* Before first ordered IDE scan */ -static LIST_HEAD(ide_pci_drivers); - -/* - * __ide_pci_register_driver - attach IDE driver - * @driver: pci driver - * @module: owner module of the driver - * - * Registers a driver with the IDE layer. The IDE layer arranges that - * boot time setup is done in the expected device order and then - * hands the controllers off to the core PCI code to do the rest of - * the work. - * - * The driver_data of the driver table must point to an ide_pci_device_t - * describing the interface. - * - * Returns are the same as for pci_register_driver - */ - -int __ide_pci_register_driver(struct pci_driver *driver, struct module *module) +int ide_pci_init_one(struct pci_dev *dev, const struct ide_port_info *d, + void *priv) { - if(!pre_init) - return __pci_register_driver(driver, module); - driver->driver.owner = module; - list_add_tail(&driver->node, &ide_pci_drivers); - return 0; + return ide_pci_init_two(dev, NULL, d, priv); } +EXPORT_SYMBOL_GPL(ide_pci_init_one); -EXPORT_SYMBOL_GPL(__ide_pci_register_driver); - -/** - * ide_unregister_pci_driver - unregister an IDE driver - * @driver: driver to remove - * - * Unregister a currently installed IDE driver. Returns are the same - * as for pci_unregister_driver - */ - -void ide_pci_unregister_driver(struct pci_driver *driver) +void ide_pci_remove(struct pci_dev *dev) { - if(!pre_init) - pci_unregister_driver(driver); + struct ide_host *host = pci_get_drvdata(dev); + struct pci_dev *dev2 = host->dev[1] ? to_pci_dev(host->dev[1]) : NULL; + int bars; + + if (host->host_flags & IDE_HFLAG_SINGLE) + bars = (1 << 2) - 1; else - list_del(&driver->node); -} + bars = (1 << 4) - 1; + + if ((host->host_flags & IDE_HFLAG_NO_DMA) == 0) { + if (host->host_flags & IDE_HFLAG_CS5520) + bars |= (1 << 2); + else + bars |= (1 << 4); + } -EXPORT_SYMBOL_GPL(ide_pci_unregister_driver); + ide_host_remove(host); -/** - * ide_scan_pcidev - find an IDE driver for a device - * @dev: PCI device to check - * - * Look for an IDE driver to handle the device we are considering. - * This is only used during boot up to get the ordering correct. After - * boot up the pci layer takes over the job. - */ - -static int __init ide_scan_pcidev(struct pci_dev *dev) + if (dev2) + pci_release_selected_regions(dev2, bars); + pci_release_selected_regions(dev, bars); + + if (dev2) + pci_disable_device(dev2); + pci_disable_device(dev); +} +EXPORT_SYMBOL_GPL(ide_pci_remove); + +#ifdef CONFIG_PM +int ide_pci_suspend(struct pci_dev *dev, pm_message_t state) { - struct list_head *l; - struct pci_driver *d; - - list_for_each(l, &ide_pci_drivers) - { - d = list_entry(l, struct pci_driver, node); - if(d->id_table) - { - const struct pci_device_id *id = pci_match_id(d->id_table, dev); - if(id != NULL) - { - if(d->probe(dev, id) >= 0) - { - dev->driver = d; - return 1; - } - } - } - } + pci_save_state(dev); + pci_disable_device(dev); + pci_set_power_state(dev, pci_choose_state(dev, state)); + return 0; } +EXPORT_SYMBOL_GPL(ide_pci_suspend); -/** - * ide_scan_pcibus - perform the initial IDE driver scan - * @scan_direction: set for reverse order scanning - * - * Perform the initial bus rather than driver ordered scan of the - * PCI drivers. After this all IDE pci handling becomes standard - * module ordering not traditionally ordered. - */ - -void __init ide_scan_pcibus (int scan_direction) +int ide_pci_resume(struct pci_dev *dev) { - struct pci_dev *dev = NULL; - struct pci_driver *d; - struct list_head *l, *n; - - pre_init = 0; - if (!scan_direction) { - while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { - ide_scan_pcidev(dev); - } - } else { - while ((dev = pci_find_device_reverse(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { - ide_scan_pcidev(dev); - } - } - - /* - * Hand the drivers over to the PCI layer now we - * are post init. - */ + struct ide_host *host = pci_get_drvdata(dev); + int rc; - list_for_each_safe(l, n, &ide_pci_drivers) - { - list_del(l); - d = list_entry(l, struct pci_driver, node); - __pci_register_driver(d, d->driver.owner); - } + pci_set_power_state(dev, PCI_D0); + + rc = pci_enable_device(dev); + if (rc) + return rc; + + pci_restore_state(dev); + pci_set_master(dev); + + if (host->init_chipset) + host->init_chipset(dev); + + return 0; } +EXPORT_SYMBOL_GPL(ide_pci_resume); +#endif diff --git a/drivers/ide/sgiioc4.c b/drivers/ide/sgiioc4.c new file mode 100644 index 00000000000..63761db6138 --- /dev/null +++ b/drivers/ide/sgiioc4.c @@ -0,0 +1,630 @@ +/* + * Copyright (c) 2003-2006 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (C) 2008-2009 MontaVista Software, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan + */ + +#include <linux/module.h> +#include <linux/types.h> +#include <linux/pci.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/ioport.h> +#include <linux/blkdev.h> +#include <linux/scatterlist.h> +#include <linux/ioc4.h> +#include <linux/io.h> +#include <linux/ide.h> + +#define DRV_NAME "SGIIOC4" + +/* IOC4 Specific Definitions */ +#define IOC4_CMD_OFFSET 0x100 +#define IOC4_CTRL_OFFSET 0x120 +#define IOC4_DMA_OFFSET 0x140 +#define IOC4_INTR_OFFSET 0x0 + +#define IOC4_TIMING 0x00 +#define IOC4_DMA_PTR_L 0x01 +#define IOC4_DMA_PTR_H 0x02 +#define IOC4_DMA_ADDR_L 0x03 +#define IOC4_DMA_ADDR_H 0x04 +#define IOC4_BC_DEV 0x05 +#define IOC4_BC_MEM 0x06 +#define IOC4_DMA_CTRL 0x07 +#define IOC4_DMA_END_ADDR 0x08 + +/* Bits in the IOC4 Control/Status Register */ +#define IOC4_S_DMA_START 0x01 +#define IOC4_S_DMA_STOP 0x02 +#define IOC4_S_DMA_DIR 0x04 +#define IOC4_S_DMA_ACTIVE 0x08 +#define IOC4_S_DMA_ERROR 0x10 +#define IOC4_ATA_MEMERR 0x02 + +/* Read/Write Directions */ +#define IOC4_DMA_WRITE 0x04 +#define IOC4_DMA_READ 0x00 + +/* Interrupt Register Offsets */ +#define IOC4_INTR_REG 0x03 +#define IOC4_INTR_SET 0x05 +#define IOC4_INTR_CLEAR 0x07 + +#define IOC4_IDE_CACHELINE_SIZE 128 +#define IOC4_CMD_CTL_BLK_SIZE 0x20 +#define IOC4_SUPPORTED_FIRMWARE_REV 46 + +struct ioc4_dma_regs { + u32 timing_reg0; + u32 timing_reg1; + u32 low_mem_ptr; + u32 high_mem_ptr; + u32 low_mem_addr; + u32 high_mem_addr; + u32 dev_byte_count; + u32 mem_byte_count; + u32 status; +}; + +/* Each Physical Region Descriptor Entry size is 16 bytes (2 * 64 bits) */ +/* IOC4 has only 1 IDE channel */ +#define IOC4_PRD_BYTES 16 +#define IOC4_PRD_ENTRIES (PAGE_SIZE / (4 * IOC4_PRD_BYTES)) + + +static void sgiioc4_init_hwif_ports(struct ide_hw *hw, + unsigned long data_port, + unsigned long ctrl_port, + unsigned long irq_port) +{ + unsigned long reg = data_port; + int i; + + /* Registers are word (32 bit) aligned */ + for (i = 0; i <= 7; i++) + hw->io_ports_array[i] = reg + i * 4; + + hw->io_ports.ctl_addr = ctrl_port; + hw->io_ports.irq_addr = irq_port; +} + +static int sgiioc4_checkirq(ide_hwif_t *hwif) +{ + unsigned long intr_addr = hwif->io_ports.irq_addr + IOC4_INTR_REG * 4; + + if (readl((void __iomem *)intr_addr) & 0x03) + return 1; + + return 0; +} + +static u8 sgiioc4_read_status(ide_hwif_t *); + +static int sgiioc4_clearirq(ide_drive_t *drive) +{ + u32 intr_reg; + ide_hwif_t *hwif = drive->hwif; + struct ide_io_ports *io_ports = &hwif->io_ports; + unsigned long other_ir = io_ports->irq_addr + (IOC4_INTR_REG << 2); + + /* Code to check for PCI error conditions */ + intr_reg = readl((void __iomem *)other_ir); + if (intr_reg & 0x03) { /* Valid IOC4-IDE interrupt */ + /* + * Using sgiioc4_read_status to read the Status register has a + * side effect of clearing the interrupt. The first read should + * clear it if it is set. The second read should return + * a "clear" status if it got cleared. If not, then spin + * for a bit trying to clear it. + */ + u8 stat = sgiioc4_read_status(hwif); + int count = 0; + + stat = sgiioc4_read_status(hwif); + while ((stat & ATA_BUSY) && (count++ < 100)) { + udelay(1); + stat = sgiioc4_read_status(hwif); + } + + if (intr_reg & 0x02) { + struct pci_dev *dev = to_pci_dev(hwif->dev); + /* Error when transferring DMA data on PCI bus */ + u32 pci_err_addr_low, pci_err_addr_high, + pci_stat_cmd_reg; + + pci_err_addr_low = + readl((void __iomem *)io_ports->irq_addr); + pci_err_addr_high = + readl((void __iomem *)(io_ports->irq_addr + 4)); + pci_read_config_dword(dev, PCI_COMMAND, + &pci_stat_cmd_reg); + printk(KERN_ERR "%s(%s): PCI Bus Error when doing DMA: " + "status-cmd reg is 0x%x\n", + __func__, drive->name, pci_stat_cmd_reg); + printk(KERN_ERR "%s(%s): PCI Error Address is 0x%x%x\n", + __func__, drive->name, + pci_err_addr_high, pci_err_addr_low); + /* Clear the PCI Error indicator */ + pci_write_config_dword(dev, PCI_COMMAND, 0x00000146); + } + + /* Clear the Interrupt, Error bits on the IOC4 */ + writel(0x03, (void __iomem *)other_ir); + + intr_reg = readl((void __iomem *)other_ir); + } + + return intr_reg & 3; +} + +static void sgiioc4_dma_start(ide_drive_t *drive) +{ + ide_hwif_t *hwif = drive->hwif; + unsigned long ioc4_dma_addr = hwif->dma_base + IOC4_DMA_CTRL * 4; + unsigned int reg = readl((void __iomem *)ioc4_dma_addr); + unsigned int temp_reg = reg | IOC4_S_DMA_START; + + writel(temp_reg, (void __iomem *)ioc4_dma_addr); +} + +static u32 sgiioc4_ide_dma_stop(ide_hwif_t *hwif, u64 dma_base) +{ + unsigned long ioc4_dma_addr = dma_base + IOC4_DMA_CTRL * 4; + u32 ioc4_dma; + int count; + + count = 0; + ioc4_dma = readl((void __iomem *)ioc4_dma_addr); + while ((ioc4_dma & IOC4_S_DMA_STOP) && (count++ < 200)) { + udelay(1); + ioc4_dma = readl((void __iomem *)ioc4_dma_addr); + } + return ioc4_dma; +} + +/* Stops the IOC4 DMA Engine */ +static int sgiioc4_dma_end(ide_drive_t *drive) +{ + u32 ioc4_dma, bc_dev, bc_mem, num, valid = 0, cnt = 0; + ide_hwif_t *hwif = drive->hwif; + unsigned long dma_base = hwif->dma_base; + int dma_stat = 0; + unsigned long *ending_dma = ide_get_hwifdata(hwif); + + writel(IOC4_S_DMA_STOP, (void __iomem *)(dma_base + IOC4_DMA_CTRL * 4)); + + ioc4_dma = sgiioc4_ide_dma_stop(hwif, dma_base); + + if (ioc4_dma & IOC4_S_DMA_STOP) { + printk(KERN_ERR + "%s(%s): IOC4 DMA STOP bit is still 1 :" + "ioc4_dma_reg 0x%x\n", + __func__, drive->name, ioc4_dma); + dma_stat = 1; + } + + /* + * The IOC4 will DMA 1's to the ending DMA area to indicate that + * previous data DMA is complete. This is necessary because of relaxed + * ordering between register reads and DMA writes on the Altix. + */ + while ((cnt++ < 200) && (!valid)) { + for (num = 0; num < 16; num++) { + if (ending_dma[num]) { + valid = 1; + break; + } + } + udelay(1); + } + if (!valid) { + printk(KERN_ERR "%s(%s) : DMA incomplete\n", __func__, + drive->name); + dma_stat = 1; + } + + bc_dev = readl((void __iomem *)(dma_base + IOC4_BC_DEV * 4)); + bc_mem = readl((void __iomem *)(dma_base + IOC4_BC_MEM * 4)); + + if ((bc_dev & 0x01FF) || (bc_mem & 0x1FF)) { + if (bc_dev > bc_mem + 8) { + printk(KERN_ERR + "%s(%s): WARNING!! byte_count_dev %d " + "!= byte_count_mem %d\n", + __func__, drive->name, bc_dev, bc_mem); + } + } + + return dma_stat; +} + +static void sgiioc4_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive) +{ +} + +/* Returns 1 if DMA IRQ issued, 0 otherwise */ +static int sgiioc4_dma_test_irq(ide_drive_t *drive) +{ + return sgiioc4_checkirq(drive->hwif); +} + +static void sgiioc4_dma_host_set(ide_drive_t *drive, int on) +{ + if (!on) + sgiioc4_clearirq(drive); +} + +static void sgiioc4_resetproc(ide_drive_t *drive) +{ + struct ide_cmd *cmd = &drive->hwif->cmd; + + sgiioc4_dma_end(drive); + ide_dma_unmap_sg(drive, cmd); + sgiioc4_clearirq(drive); +} + +static void sgiioc4_dma_lost_irq(ide_drive_t *drive) +{ + sgiioc4_resetproc(drive); + + ide_dma_lost_irq(drive); +} + +static u8 sgiioc4_read_status(ide_hwif_t *hwif) +{ + unsigned long port = hwif->io_ports.status_addr; + u8 reg = (u8) readb((void __iomem *) port); + + if (!(reg & ATA_BUSY)) { /* Not busy... check for interrupt */ + unsigned long other_ir = port - 0x110; + unsigned int intr_reg = (u32) readl((void __iomem *) other_ir); + + /* Clear the Interrupt, Error bits on the IOC4 */ + if (intr_reg & 0x03) { + writel(0x03, (void __iomem *) other_ir); + intr_reg = (u32) readl((void __iomem *) other_ir); + } + } + + return reg; +} + +/* Creates a DMA map for the scatter-gather list entries */ +static int ide_dma_sgiioc4(ide_hwif_t *hwif, const struct ide_port_info *d) +{ + struct pci_dev *dev = to_pci_dev(hwif->dev); + unsigned long dma_base = pci_resource_start(dev, 0) + IOC4_DMA_OFFSET; + int num_ports = sizeof(struct ioc4_dma_regs); + void *pad; + + printk(KERN_INFO " %s: MMIO-DMA\n", hwif->name); + + if (request_mem_region(dma_base, num_ports, hwif->name) == NULL) { + printk(KERN_ERR "%s(%s) -- ERROR: addresses 0x%08lx to 0x%08lx " + "already in use\n", __func__, hwif->name, + dma_base, dma_base + num_ports - 1); + return -1; + } + + hwif->dma_base = (unsigned long)hwif->io_ports.irq_addr + + IOC4_DMA_OFFSET; + + hwif->sg_max_nents = IOC4_PRD_ENTRIES; + + hwif->prd_max_nents = IOC4_PRD_ENTRIES; + hwif->prd_ent_size = IOC4_PRD_BYTES; + + if (ide_allocate_dma_engine(hwif)) + goto dma_pci_alloc_failure; + + pad = pci_alloc_consistent(dev, IOC4_IDE_CACHELINE_SIZE, + (dma_addr_t *)&hwif->extra_base); + if (pad) { + ide_set_hwifdata(hwif, pad); + return 0; + } + + ide_release_dma_engine(hwif); + + printk(KERN_ERR "%s(%s) -- ERROR: Unable to allocate DMA maps\n", + __func__, hwif->name); + printk(KERN_INFO "%s: changing from DMA to PIO mode", hwif->name); + +dma_pci_alloc_failure: + release_mem_region(dma_base, num_ports); + + return -1; +} + +/* Initializes the IOC4 DMA Engine */ +static void sgiioc4_configure_for_dma(int dma_direction, ide_drive_t *drive) +{ + u32 ioc4_dma; + ide_hwif_t *hwif = drive->hwif; + unsigned long dma_base = hwif->dma_base; + unsigned long ioc4_dma_addr = dma_base + IOC4_DMA_CTRL * 4; + u32 dma_addr, ending_dma_addr; + + ioc4_dma = readl((void __iomem *)ioc4_dma_addr); + + if (ioc4_dma & IOC4_S_DMA_ACTIVE) { + printk(KERN_WARNING "%s(%s): Warning!! DMA from previous " + "transfer was still active\n", __func__, drive->name); + writel(IOC4_S_DMA_STOP, (void __iomem *)ioc4_dma_addr); + ioc4_dma = sgiioc4_ide_dma_stop(hwif, dma_base); + + if (ioc4_dma & IOC4_S_DMA_STOP) + printk(KERN_ERR "%s(%s): IOC4 DMA STOP bit is " + "still 1\n", __func__, drive->name); + } + + ioc4_dma = readl((void __iomem *)ioc4_dma_addr); + if (ioc4_dma & IOC4_S_DMA_ERROR) { + printk(KERN_WARNING "%s(%s): Warning!! DMA Error during " + "previous transfer, status 0x%x\n", + __func__, drive->name, ioc4_dma); + writel(IOC4_S_DMA_STOP, (void __iomem *)ioc4_dma_addr); + ioc4_dma = sgiioc4_ide_dma_stop(hwif, dma_base); + + if (ioc4_dma & IOC4_S_DMA_STOP) + printk(KERN_ERR "%s(%s): IOC4 DMA STOP bit is " + "still 1\n", __func__, drive->name); + } + + /* Address of the Scatter Gather List */ + dma_addr = cpu_to_le32(hwif->dmatable_dma); + writel(dma_addr, (void __iomem *)(dma_base + IOC4_DMA_PTR_L * 4)); + + /* Address of the Ending DMA */ + memset(ide_get_hwifdata(hwif), 0, IOC4_IDE_CACHELINE_SIZE); + ending_dma_addr = cpu_to_le32(hwif->extra_base); + writel(ending_dma_addr, (void __iomem *)(dma_base + + IOC4_DMA_END_ADDR * 4)); + + writel(dma_direction, (void __iomem *)ioc4_dma_addr); +} + +/* IOC4 Scatter Gather list Format */ +/* 128 Bit entries to support 64 bit addresses in the future */ +/* The Scatter Gather list Entry should be in the BIG-ENDIAN Format */ +/* --------------------------------------------------------------------- */ +/* | Upper 32 bits - Zero | Lower 32 bits- address | */ +/* --------------------------------------------------------------------- */ +/* | Upper 32 bits - Zero |EOL| 15 unused | 16 Bit Length| */ +/* --------------------------------------------------------------------- */ +/* Creates the scatter gather list, DMA Table */ + +static int sgiioc4_build_dmatable(ide_drive_t *drive, struct ide_cmd *cmd) +{ + ide_hwif_t *hwif = drive->hwif; + unsigned int *table = hwif->dmatable_cpu; + unsigned int count = 0, i = cmd->sg_nents; + struct scatterlist *sg = hwif->sg_table; + + while (i && sg_dma_len(sg)) { + dma_addr_t cur_addr; + int cur_len; + cur_addr = sg_dma_address(sg); + cur_len = sg_dma_len(sg); + + while (cur_len) { + if (count++ >= IOC4_PRD_ENTRIES) { + printk(KERN_WARNING + "%s: DMA table too small\n", + drive->name); + return 0; + } else { + u32 bcount = + 0x10000 - (cur_addr & 0xffff); + + if (bcount > cur_len) + bcount = cur_len; + + /* + * Put the address, length in + * the IOC4 dma-table format + */ + *table = 0x0; + table++; + *table = cpu_to_be32(cur_addr); + table++; + *table = 0x0; + table++; + + *table = cpu_to_be32(bcount); + table++; + + cur_addr += bcount; + cur_len -= bcount; + } + } + + sg = sg_next(sg); + i--; + } + + if (count) { + table--; + *table |= cpu_to_be32(0x80000000); + return count; + } + + return 0; /* revert to PIO for this request */ +} + +static int sgiioc4_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd) +{ + int ddir; + u8 write = !!(cmd->tf_flags & IDE_TFLAG_WRITE); + + if (sgiioc4_build_dmatable(drive, cmd) == 0) + /* try PIO instead of DMA */ + return 1; + + if (write) + /* Writes TO the IOC4 FROM Main Memory */ + ddir = IOC4_DMA_READ; + else + /* Writes FROM the IOC4 TO Main Memory */ + ddir = IOC4_DMA_WRITE; + + sgiioc4_configure_for_dma(ddir, drive); + + return 0; +} + +static const struct ide_tp_ops sgiioc4_tp_ops = { + .exec_command = ide_exec_command, + .read_status = sgiioc4_read_status, + .read_altstatus = ide_read_altstatus, + .write_devctl = ide_write_devctl, + + .dev_select = ide_dev_select, + .tf_load = ide_tf_load, + .tf_read = ide_tf_read, + + .input_data = ide_input_data, + .output_data = ide_output_data, +}; + +static const struct ide_port_ops sgiioc4_port_ops = { + .set_dma_mode = sgiioc4_set_dma_mode, + /* reset DMA engine, clear IRQs */ + .resetproc = sgiioc4_resetproc, +}; + +static const struct ide_dma_ops sgiioc4_dma_ops = { + .dma_host_set = sgiioc4_dma_host_set, + .dma_setup = sgiioc4_dma_setup, + .dma_start = sgiioc4_dma_start, + .dma_end = sgiioc4_dma_end, + .dma_test_irq = sgiioc4_dma_test_irq, + .dma_lost_irq = sgiioc4_dma_lost_irq, +}; + +static const struct ide_port_info sgiioc4_port_info = { + .name = DRV_NAME, + .chipset = ide_pci, + .init_dma = ide_dma_sgiioc4, + .tp_ops = &sgiioc4_tp_ops, + .port_ops = &sgiioc4_port_ops, + .dma_ops = &sgiioc4_dma_ops, + .host_flags = IDE_HFLAG_MMIO, + .irq_flags = IRQF_SHARED, + .mwdma_mask = ATA_MWDMA2_ONLY, +}; + +static int sgiioc4_ide_setup_pci_device(struct pci_dev *dev) +{ + unsigned long cmd_base, irqport; + unsigned long bar0, cmd_phys_base, ctl; + void __iomem *virt_base; + struct ide_hw hw, *hws[] = { &hw }; + int rc; + + /* Get the CmdBlk and CtrlBlk base registers */ + bar0 = pci_resource_start(dev, 0); + virt_base = pci_ioremap_bar(dev, 0); + if (virt_base == NULL) { + printk(KERN_ERR "%s: Unable to remap BAR 0 address: 0x%lx\n", + DRV_NAME, bar0); + return -ENOMEM; + } + cmd_base = (unsigned long)virt_base + IOC4_CMD_OFFSET; + ctl = (unsigned long)virt_base + IOC4_CTRL_OFFSET; + irqport = (unsigned long)virt_base + IOC4_INTR_OFFSET; + + cmd_phys_base = bar0 + IOC4_CMD_OFFSET; + if (request_mem_region(cmd_phys_base, IOC4_CMD_CTL_BLK_SIZE, + DRV_NAME) == NULL) { + printk(KERN_ERR "%s %s -- ERROR: addresses 0x%08lx to 0x%08lx " + "already in use\n", DRV_NAME, pci_name(dev), + cmd_phys_base, cmd_phys_base + IOC4_CMD_CTL_BLK_SIZE); + rc = -EBUSY; + goto req_mem_rgn_err; + } + + /* Initialize the IO registers */ + memset(&hw, 0, sizeof(hw)); + sgiioc4_init_hwif_ports(&hw, cmd_base, ctl, irqport); + hw.irq = dev->irq; + hw.dev = &dev->dev; + + /* Initialize chipset IRQ registers */ + writel(0x03, (void __iomem *)(irqport + IOC4_INTR_SET * 4)); + + rc = ide_host_add(&sgiioc4_port_info, hws, 1, NULL); + if (!rc) + return 0; + + release_mem_region(cmd_phys_base, IOC4_CMD_CTL_BLK_SIZE); +req_mem_rgn_err: + iounmap(virt_base); + return rc; +} + +static unsigned int pci_init_sgiioc4(struct pci_dev *dev) +{ + int ret; + + printk(KERN_INFO "%s: IDE controller at PCI slot %s, revision %d\n", + DRV_NAME, pci_name(dev), dev->revision); + + if (dev->revision < IOC4_SUPPORTED_FIRMWARE_REV) { + printk(KERN_ERR "Skipping %s IDE controller in slot %s: " + "firmware is obsolete - please upgrade to " + "revision46 or higher\n", + DRV_NAME, pci_name(dev)); + ret = -EAGAIN; + goto out; + } + ret = sgiioc4_ide_setup_pci_device(dev); +out: + return ret; +} + +static int ioc4_ide_attach_one(struct ioc4_driver_data *idd) +{ + /* + * PCI-RT does not bring out IDE connection. + * Do not attach to this particular IOC4. + */ + if (idd->idd_variant == IOC4_VARIANT_PCI_RT) + return 0; + + return pci_init_sgiioc4(idd->idd_pdev); +} + +static struct ioc4_submodule ioc4_ide_submodule = { + .is_name = "IOC4_ide", + .is_owner = THIS_MODULE, + .is_probe = ioc4_ide_attach_one, +}; + +static int __init ioc4_ide_init(void) +{ + return ioc4_register_submodule(&ioc4_ide_submodule); +} + +late_initcall(ioc4_ide_init); /* Call only after IDE init is done */ + +MODULE_AUTHOR("Aniket Malatpure/Jeremy Higdon"); +MODULE_DESCRIPTION("IDE PCI driver module for SGI IOC4 Base-IO Card"); +MODULE_LICENSE("GPL"); diff --git a/drivers/ide/siimage.c b/drivers/ide/siimage.c new file mode 100644 index 00000000000..6a1849bb476 --- /dev/null +++ b/drivers/ide/siimage.c @@ -0,0 +1,844 @@ +/* + * Copyright (C) 2001-2002 Andre Hedrick <andre@linux-ide.org> + * Copyright (C) 2003 Red Hat + * Copyright (C) 2007-2008 MontaVista Software, Inc. + * Copyright (C) 2007-2008 Bartlomiej Zolnierkiewicz + * + * May be copied or modified under the terms of the GNU General Public License + * + * Documentation for CMD680: + * http://gkernel.sourceforge.net/specs/sii/sii-0680a-v1.31.pdf.bz2 + * + * Documentation for SiI 3112: + * http://gkernel.sourceforge.net/specs/sii/3112A_SiI-DS-0095-B2.pdf.bz2 + * + * Errata and other documentation only available under NDA. + * + * + * FAQ Items: + * If you are using Marvell SATA-IDE adapters with Maxtor drives + * ensure the system is set up for ATA100/UDMA5, not UDMA6. + * + * If you are using WD drives with SATA bridges you must set the + * drive to "Single". "Master" will hang. + * + * If you have strange problems with nVidia chipset systems please + * see the SI support documentation and update your system BIOS + * if necessary + * + * The Dell DRAC4 has some interesting features including effectively hot + * unplugging/replugging the virtual CD interface when the DRAC is reset. + * This often causes drivers/ide/siimage to panic but is ok with the rather + * smarter code in libata. + * + * TODO: + * - VDMA support + */ + +#include <linux/types.h> +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/ide.h> +#include <linux/init.h> +#include <linux/io.h> + +#define DRV_NAME "siimage" + +/** + * pdev_is_sata - check if device is SATA + * @pdev: PCI device to check + * + * Returns true if this is a SATA controller + */ + +static int pdev_is_sata(struct pci_dev *pdev) +{ +#ifdef CONFIG_BLK_DEV_IDE_SATA + switch (pdev->device) { + case PCI_DEVICE_ID_SII_3112: + case PCI_DEVICE_ID_SII_1210SA: + return 1; + case PCI_DEVICE_ID_SII_680: + return 0; + } + BUG(); +#endif + return 0; +} + +/** + * is_sata - check if hwif is SATA + * @hwif: interface to check + * + * Returns true if this is a SATA controller + */ + +static inline int is_sata(ide_hwif_t *hwif) +{ + return pdev_is_sata(to_pci_dev(hwif->dev)); +} + +/** + * siimage_selreg - return register base + * @hwif: interface + * @r: config offset + * + * Turn a config register offset into the right address in either + * PCI space or MMIO space to access the control register in question + * Thankfully this is a configuration operation, so isn't performance + * critical. + */ + +static unsigned long siimage_selreg(ide_hwif_t *hwif, int r) +{ + unsigned long base = (unsigned long)hwif->hwif_data; + + base += 0xA0 + r; + if (hwif->host_flags & IDE_HFLAG_MMIO) + base += hwif->channel << 6; + else + base += hwif->channel << 4; + return base; +} + +/** + * siimage_seldev - return register base + * @hwif: interface + * @r: config offset + * + * Turn a config register offset into the right address in either + * PCI space or MMIO space to access the control register in question + * including accounting for the unit shift. + */ + +static inline unsigned long siimage_seldev(ide_drive_t *drive, int r) +{ + ide_hwif_t *hwif = drive->hwif; + unsigned long base = (unsigned long)hwif->hwif_data; + u8 unit = drive->dn & 1; + + base += 0xA0 + r; + if (hwif->host_flags & IDE_HFLAG_MMIO) + base += hwif->channel << 6; + else + base += hwif->channel << 4; + base |= unit << unit; + return base; +} + +static u8 sil_ioread8(struct pci_dev *dev, unsigned long addr) +{ + struct ide_host *host = pci_get_drvdata(dev); + u8 tmp = 0; + + if (host->host_priv) + tmp = readb((void __iomem *)addr); + else + pci_read_config_byte(dev, addr, &tmp); + + return tmp; +} + +static u16 sil_ioread16(struct pci_dev *dev, unsigned long addr) +{ + struct ide_host *host = pci_get_drvdata(dev); + u16 tmp = 0; + + if (host->host_priv) + tmp = readw((void __iomem *)addr); + else + pci_read_config_word(dev, addr, &tmp); + + return tmp; +} + +static void sil_iowrite8(struct pci_dev *dev, u8 val, unsigned long addr) +{ + struct ide_host *host = pci_get_drvdata(dev); + + if (host->host_priv) + writeb(val, (void __iomem *)addr); + else + pci_write_config_byte(dev, addr, val); +} + +static void sil_iowrite16(struct pci_dev *dev, u16 val, unsigned long addr) +{ + struct ide_host *host = pci_get_drvdata(dev); + + if (host->host_priv) + writew(val, (void __iomem *)addr); + else + pci_write_config_word(dev, addr, val); +} + +static void sil_iowrite32(struct pci_dev *dev, u32 val, unsigned long addr) +{ + struct ide_host *host = pci_get_drvdata(dev); + + if (host->host_priv) + writel(val, (void __iomem *)addr); + else + pci_write_config_dword(dev, addr, val); +} + +/** + * sil_udma_filter - compute UDMA mask + * @drive: IDE device + * + * Compute the available UDMA speeds for the device on the interface. + * + * For the CMD680 this depends on the clocking mode (scsc), for the + * SI3112 SATA controller life is a bit simpler. + */ + +static u8 sil_pata_udma_filter(ide_drive_t *drive) +{ + ide_hwif_t *hwif = drive->hwif; + struct pci_dev *dev = to_pci_dev(hwif->dev); + unsigned long base = (unsigned long)hwif->hwif_data; + u8 scsc, mask = 0; + + base += (hwif->host_flags & IDE_HFLAG_MMIO) ? 0x4A : 0x8A; + + scsc = sil_ioread8(dev, base); + + switch (scsc & 0x30) { + case 0x10: /* 133 */ + mask = ATA_UDMA6; + break; + case 0x20: /* 2xPCI */ + mask = ATA_UDMA6; + break; + case 0x00: /* 100 */ + mask = ATA_UDMA5; + break; + default: /* Disabled ? */ + BUG(); + } + + return mask; +} + +static u8 sil_sata_udma_filter(ide_drive_t *drive) +{ + char *m = (char *)&drive->id[ATA_ID_PROD]; + + return strstr(m, "Maxtor") ? ATA_UDMA5 : ATA_UDMA6; +} + +/** + * sil_set_pio_mode - set host controller for PIO mode + * @hwif: port + * @drive: drive + * + * Load the timing settings for this device mode into the + * controller. + */ + +static void sil_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) +{ + static const u16 tf_speed[] = { 0x328a, 0x2283, 0x1281, 0x10c3, 0x10c1 }; + static const u16 data_speed[] = { 0x328a, 0x2283, 0x1104, 0x10c3, 0x10c1 }; + + struct pci_dev *dev = to_pci_dev(hwif->dev); + ide_drive_t *pair = ide_get_pair_dev(drive); + u32 speedt = 0; + u16 speedp = 0; + unsigned long addr = siimage_seldev(drive, 0x04); + unsigned long tfaddr = siimage_selreg(hwif, 0x02); + unsigned long base = (unsigned long)hwif->hwif_data; + const u8 pio = drive->pio_mode - XFER_PIO_0; + u8 tf_pio = pio; + u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0; + u8 addr_mask = hwif->channel ? (mmio ? 0xF4 : 0x84) + : (mmio ? 0xB4 : 0x80); + u8 mode = 0; + u8 unit = drive->dn & 1; + + /* trim *taskfile* PIO to the slowest of the master/slave */ + if (pair) { + u8 pair_pio = pair->pio_mode - XFER_PIO_0; + + if (pair_pio < tf_pio) + tf_pio = pair_pio; + } + + /* cheat for now and use the docs */ + speedp = data_speed[pio]; + speedt = tf_speed[tf_pio]; + + sil_iowrite16(dev, speedp, addr); + sil_iowrite16(dev, speedt, tfaddr); + + /* now set up IORDY */ + speedp = sil_ioread16(dev, tfaddr - 2); + speedp &= ~0x200; + + mode = sil_ioread8(dev, base + addr_mask); + mode &= ~(unit ? 0x30 : 0x03); + + if (ide_pio_need_iordy(drive, pio)) { + speedp |= 0x200; + mode |= unit ? 0x10 : 0x01; + } + + sil_iowrite16(dev, speedp, tfaddr - 2); + sil_iowrite8(dev, mode, base + addr_mask); +} + +/** + * sil_set_dma_mode - set host controller for DMA mode + * @hwif: port + * @drive: drive + * + * Tune the SiI chipset for the desired DMA mode. + */ + +static void sil_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive) +{ + static const u8 ultra6[] = { 0x0F, 0x0B, 0x07, 0x05, 0x03, 0x02, 0x01 }; + static const u8 ultra5[] = { 0x0C, 0x07, 0x05, 0x04, 0x02, 0x01 }; + static const u16 dma[] = { 0x2208, 0x10C2, 0x10C1 }; + + struct pci_dev *dev = to_pci_dev(hwif->dev); + unsigned long base = (unsigned long)hwif->hwif_data; + u16 ultra = 0, multi = 0; + u8 mode = 0, unit = drive->dn & 1; + u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0; + u8 scsc = 0, addr_mask = hwif->channel ? (mmio ? 0xF4 : 0x84) + : (mmio ? 0xB4 : 0x80); + unsigned long ma = siimage_seldev(drive, 0x08); + unsigned long ua = siimage_seldev(drive, 0x0C); + const u8 speed = drive->dma_mode; + + scsc = sil_ioread8 (dev, base + (mmio ? 0x4A : 0x8A)); + mode = sil_ioread8 (dev, base + addr_mask); + multi = sil_ioread16(dev, ma); + ultra = sil_ioread16(dev, ua); + + mode &= ~(unit ? 0x30 : 0x03); + ultra &= ~0x3F; + scsc = ((scsc & 0x30) == 0x00) ? 0 : 1; + + scsc = is_sata(hwif) ? 1 : scsc; + + if (speed >= XFER_UDMA_0) { + multi = dma[2]; + ultra |= scsc ? ultra6[speed - XFER_UDMA_0] : + ultra5[speed - XFER_UDMA_0]; + mode |= unit ? 0x30 : 0x03; + } else { + multi = dma[speed - XFER_MW_DMA_0]; + mode |= unit ? 0x20 : 0x02; + } + + sil_iowrite8 (dev, mode, base + addr_mask); + sil_iowrite16(dev, multi, ma); + sil_iowrite16(dev, ultra, ua); +} + +static int sil_test_irq(ide_hwif_t *hwif) +{ + struct pci_dev *dev = to_pci_dev(hwif->dev); + unsigned long addr = siimage_selreg(hwif, 1); + u8 val = sil_ioread8(dev, addr); + + /* Return 1 if INTRQ asserted */ + return (val & 8) ? 1 : 0; +} + +/** + * siimage_mmio_dma_test_irq - check we caused an IRQ + * @drive: drive we are testing + * + * Check if we caused an IDE DMA interrupt. We may also have caused + * SATA status interrupts, if so we clean them up and continue. + */ + +static int siimage_mmio_dma_test_irq(ide_drive_t *drive) +{ + ide_hwif_t *hwif = drive->hwif; + void __iomem *sata_error_addr + = (void __iomem *)hwif->sata_scr[SATA_ERROR_OFFSET]; + + if (sata_error_addr) { + unsigned long base = (unsigned long)hwif->hwif_data; + u32 ext_stat = readl((void __iomem *)(base + 0x10)); + u8 watchdog = 0; + + if (ext_stat & ((hwif->channel) ? 0x40 : 0x10)) { + u32 sata_error = readl(sata_error_addr); + + writel(sata_error, sata_error_addr); + watchdog = (sata_error & 0x00680000) ? 1 : 0; + printk(KERN_WARNING "%s: sata_error = 0x%08x, " + "watchdog = %d, %s\n", + drive->name, sata_error, watchdog, __func__); + } else + watchdog = (ext_stat & 0x8000) ? 1 : 0; + + ext_stat >>= 16; + if (!(ext_stat & 0x0404) && !watchdog) + return 0; + } + + /* return 1 if INTR asserted */ + if (readb((void __iomem *)(hwif->dma_base + ATA_DMA_STATUS)) & 4) + return 1; + + return 0; +} + +static int siimage_dma_test_irq(ide_drive_t *drive) +{ + if (drive->hwif->host_flags & IDE_HFLAG_MMIO) + return siimage_mmio_dma_test_irq(drive); + else + return ide_dma_test_irq(drive); +} + +/** + * sil_sata_reset_poll - wait for SATA reset + * @drive: drive we are resetting + * + * Poll the SATA phy and see whether it has come back from the dead + * yet. + */ + +static int sil_sata_reset_poll(ide_drive_t *drive) +{ + ide_hwif_t *hwif = drive->hwif; + void __iomem *sata_status_addr + = (void __iomem *)hwif->sata_scr[SATA_STATUS_OFFSET]; + + if (sata_status_addr) { + /* SATA Status is available only when in MMIO mode */ + u32 sata_stat = readl(sata_status_addr); + + if ((sata_stat & 0x03) != 0x03) { + printk(KERN_WARNING "%s: reset phy dead, status=0x%08x\n", + hwif->name, sata_stat); + return -ENXIO; + } + } + + return 0; +} + +/** + * sil_sata_pre_reset - reset hook + * @drive: IDE device being reset + * + * For the SATA devices we need to handle recalibration/geometry + * differently + */ + +static void sil_sata_pre_reset(ide_drive_t *drive) +{ + if (drive->media == ide_disk) { + drive->special_flags &= + ~(IDE_SFLAG_SET_GEOMETRY | IDE_SFLAG_RECALIBRATE); + } +} + +/** + * init_chipset_siimage - set up an SI device + * @dev: PCI device + * + * Perform the initial PCI set up for this device. Attempt to switch + * to 133 MHz clocking if the system isn't already set up to do it. + */ + +static int init_chipset_siimage(struct pci_dev *dev) +{ + struct ide_host *host = pci_get_drvdata(dev); + void __iomem *ioaddr = host->host_priv; + unsigned long base, scsc_addr; + u8 rev = dev->revision, tmp; + + pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, rev ? 1 : 255); + + if (ioaddr) + pci_set_master(dev); + + base = (unsigned long)ioaddr; + + if (ioaddr && pdev_is_sata(dev)) { + u32 tmp32, irq_mask; + + /* make sure IDE0/1 interrupts are not masked */ + irq_mask = (1 << 22) | (1 << 23); + tmp32 = readl(ioaddr + 0x48); + if (tmp32 & irq_mask) { + tmp32 &= ~irq_mask; + writel(tmp32, ioaddr + 0x48); + readl(ioaddr + 0x48); /* flush */ + } + writel(0, ioaddr + 0x148); + writel(0, ioaddr + 0x1C8); + } + + sil_iowrite8(dev, 0, base ? (base + 0xB4) : 0x80); + sil_iowrite8(dev, 0, base ? (base + 0xF4) : 0x84); + + scsc_addr = base ? (base + 0x4A) : 0x8A; + tmp = sil_ioread8(dev, scsc_addr); + + switch (tmp & 0x30) { + case 0x00: + /* On 100 MHz clocking, try and switch to 133 MHz */ + sil_iowrite8(dev, tmp | 0x10, scsc_addr); + break; + case 0x30: + /* Clocking is disabled, attempt to force 133MHz clocking. */ + sil_iowrite8(dev, tmp & ~0x20, scsc_addr); + case 0x10: + /* On 133Mhz clocking. */ + break; + case 0x20: + /* On PCIx2 clocking. */ + break; + } + + tmp = sil_ioread8(dev, scsc_addr); + + sil_iowrite8 (dev, 0x72, base + 0xA1); + sil_iowrite16(dev, 0x328A, base + 0xA2); + sil_iowrite32(dev, 0x62DD62DD, base + 0xA4); + sil_iowrite32(dev, 0x43924392, base + 0xA8); + sil_iowrite32(dev, 0x40094009, base + 0xAC); + sil_iowrite8 (dev, 0x72, base ? (base + 0xE1) : 0xB1); + sil_iowrite16(dev, 0x328A, base ? (base + 0xE2) : 0xB2); + sil_iowrite32(dev, 0x62DD62DD, base ? (base + 0xE4) : 0xB4); + sil_iowrite32(dev, 0x43924392, base ? (base + 0xE8) : 0xB8); + sil_iowrite32(dev, 0x40094009, base ? (base + 0xEC) : 0xBC); + + if (base && pdev_is_sata(dev)) { + writel(0xFFFF0000, ioaddr + 0x108); + writel(0xFFFF0000, ioaddr + 0x188); + writel(0x00680000, ioaddr + 0x148); + writel(0x00680000, ioaddr + 0x1C8); + } + + /* report the clocking mode of the controller */ + if (!pdev_is_sata(dev)) { + static const char *clk_str[] = + { "== 100", "== 133", "== 2X PCI", "DISABLED!" }; + + tmp >>= 4; + printk(KERN_INFO DRV_NAME " %s: BASE CLOCK %s\n", + pci_name(dev), clk_str[tmp & 3]); + } + + return 0; +} + +/** + * init_mmio_iops_siimage - set up the iops for MMIO + * @hwif: interface to set up + * + * The basic setup here is fairly simple, we can use standard MMIO + * operations. However we do have to set the taskfile register offsets + * by hand as there isn't a standard defined layout for them this time. + * + * The hardware supports buffered taskfiles and also some rather nice + * extended PRD tables. For better SI3112 support use the libata driver + */ + +static void init_mmio_iops_siimage(ide_hwif_t *hwif) +{ + struct pci_dev *dev = to_pci_dev(hwif->dev); + struct ide_host *host = pci_get_drvdata(dev); + void *addr = host->host_priv; + u8 ch = hwif->channel; + struct ide_io_ports *io_ports = &hwif->io_ports; + unsigned long base; + + /* + * Fill in the basic hwif bits + */ + hwif->host_flags |= IDE_HFLAG_MMIO; + + hwif->hwif_data = addr; + + /* + * Now set up the hw. We have to do this ourselves as the + * MMIO layout isn't the same as the standard port based I/O. + */ + memset(io_ports, 0, sizeof(*io_ports)); + + base = (unsigned long)addr; + if (ch) + base += 0xC0; + else + base += 0x80; + + /* + * The buffered task file doesn't have status/control, so we + * can't currently use it sanely since we want to use LBA48 mode. + */ + io_ports->data_addr = base; + io_ports->error_addr = base + 1; + io_ports->nsect_addr = base + 2; + io_ports->lbal_addr = base + 3; + io_ports->lbam_addr = base + 4; + io_ports->lbah_addr = base + 5; + io_ports->device_addr = base + 6; + io_ports->status_addr = base + 7; + io_ports->ctl_addr = base + 10; + + if (pdev_is_sata(dev)) { + base = (unsigned long)addr; + if (ch) + base += 0x80; + hwif->sata_scr[SATA_STATUS_OFFSET] = base + 0x104; + hwif->sata_scr[SATA_ERROR_OFFSET] = base + 0x108; + hwif->sata_scr[SATA_CONTROL_OFFSET] = base + 0x100; + } + + hwif->irq = dev->irq; + + hwif->dma_base = (unsigned long)addr + (ch ? 0x08 : 0x00); +} + +static int is_dev_seagate_sata(ide_drive_t *drive) +{ + const char *s = (const char *)&drive->id[ATA_ID_PROD]; + unsigned len = strnlen(s, ATA_ID_PROD_LEN); + + if ((len > 4) && (!memcmp(s, "ST", 2))) + if ((!memcmp(s + len - 2, "AS", 2)) || + (!memcmp(s + len - 3, "ASL", 3))) { + printk(KERN_INFO "%s: applying pessimistic Seagate " + "errata fix\n", drive->name); + return 1; + } + + return 0; +} + +/** + * sil_quirkproc - post probe fixups + * @drive: drive + * + * Called after drive probe we use this to decide whether the + * Seagate fixup must be applied. This used to be in init_iops but + * that can occur before we know what drives are present. + */ + +static void sil_quirkproc(ide_drive_t *drive) +{ + ide_hwif_t *hwif = drive->hwif; + + /* Try and rise the rqsize */ + if (!is_sata(hwif) || !is_dev_seagate_sata(drive)) + hwif->rqsize = 128; +} + +/** + * init_iops_siimage - set up iops + * @hwif: interface to set up + * + * Do the basic setup for the SIIMAGE hardware interface + * and then do the MMIO setup if we can. This is the first + * look in we get for setting up the hwif so that we + * can get the iops right before using them. + */ + +static void init_iops_siimage(ide_hwif_t *hwif) +{ + struct pci_dev *dev = to_pci_dev(hwif->dev); + struct ide_host *host = pci_get_drvdata(dev); + + hwif->hwif_data = NULL; + + /* Pessimal until we finish probing */ + hwif->rqsize = 15; + + if (host->host_priv) + init_mmio_iops_siimage(hwif); +} + +/** + * sil_cable_detect - cable detection + * @hwif: interface to check + * + * Check for the presence of an ATA66 capable cable on the interface. + */ + +static u8 sil_cable_detect(ide_hwif_t *hwif) +{ + struct pci_dev *dev = to_pci_dev(hwif->dev); + unsigned long addr = siimage_selreg(hwif, 0); + u8 ata66 = sil_ioread8(dev, addr); + + return (ata66 & 0x01) ? ATA_CBL_PATA80 : ATA_CBL_PATA40; +} + +static const struct ide_port_ops sil_pata_port_ops = { + .set_pio_mode = sil_set_pio_mode, + .set_dma_mode = sil_set_dma_mode, + .quirkproc = sil_quirkproc, + .test_irq = sil_test_irq, + .udma_filter = sil_pata_udma_filter, + .cable_detect = sil_cable_detect, +}; + +static const struct ide_port_ops sil_sata_port_ops = { + .set_pio_mode = sil_set_pio_mode, + .set_dma_mode = sil_set_dma_mode, + .reset_poll = sil_sata_reset_poll, + .pre_reset = sil_sata_pre_reset, + .quirkproc = sil_quirkproc, + .test_irq = sil_test_irq, + .udma_filter = sil_sata_udma_filter, + .cable_detect = sil_cable_detect, +}; + +static const struct ide_dma_ops sil_dma_ops = { + .dma_host_set = ide_dma_host_set, + .dma_setup = ide_dma_setup, + .dma_start = ide_dma_start, + .dma_end = ide_dma_end, + .dma_test_irq = siimage_dma_test_irq, + .dma_timer_expiry = ide_dma_sff_timer_expiry, + .dma_lost_irq = ide_dma_lost_irq, + .dma_sff_read_status = ide_dma_sff_read_status, +}; + +#define DECLARE_SII_DEV(p_ops) \ + { \ + .name = DRV_NAME, \ + .init_chipset = init_chipset_siimage, \ + .init_iops = init_iops_siimage, \ + .port_ops = p_ops, \ + .dma_ops = &sil_dma_ops, \ + .pio_mask = ATA_PIO4, \ + .mwdma_mask = ATA_MWDMA2, \ + .udma_mask = ATA_UDMA6, \ + } + +static const struct ide_port_info siimage_chipsets[] = { + /* 0: SiI680 */ DECLARE_SII_DEV(&sil_pata_port_ops), + /* 1: SiI3112 */ DECLARE_SII_DEV(&sil_sata_port_ops) +}; + +/** + * siimage_init_one - PCI layer discovery entry + * @dev: PCI device + * @id: ident table entry + * + * Called by the PCI code when it finds an SiI680 or SiI3112 controller. + * We then use the IDE PCI generic helper to do most of the work. + */ + +static int siimage_init_one(struct pci_dev *dev, const struct pci_device_id *id) +{ + void __iomem *ioaddr = NULL; + resource_size_t bar5 = pci_resource_start(dev, 5); + unsigned long barsize = pci_resource_len(dev, 5); + int rc; + struct ide_port_info d; + u8 idx = id->driver_data; + u8 BA5_EN; + + d = siimage_chipsets[idx]; + + if (idx) { + static int first = 1; + + if (first) { + printk(KERN_INFO DRV_NAME ": For full SATA support you " + "should use the libata sata_sil module.\n"); + first = 0; + } + + d.host_flags |= IDE_HFLAG_NO_ATAPI_DMA; + } + + rc = pci_enable_device(dev); + if (rc) + return rc; + + pci_read_config_byte(dev, 0x8A, &BA5_EN); + if ((BA5_EN & 0x01) || bar5) { + /* + * Drop back to PIO if we can't map the MMIO. Some systems + * seem to get terminally confused in the PCI spaces. + */ + if (!request_mem_region(bar5, barsize, d.name)) { + printk(KERN_WARNING DRV_NAME " %s: MMIO ports not " + "available\n", pci_name(dev)); + } else { + ioaddr = pci_ioremap_bar(dev, 5); + if (ioaddr == NULL) + release_mem_region(bar5, barsize); + } + } + + rc = ide_pci_init_one(dev, &d, ioaddr); + if (rc) { + if (ioaddr) { + iounmap(ioaddr); + release_mem_region(bar5, barsize); + } + pci_disable_device(dev); + } + + return rc; +} + +static void siimage_remove(struct pci_dev *dev) +{ + struct ide_host *host = pci_get_drvdata(dev); + void __iomem *ioaddr = host->host_priv; + + ide_pci_remove(dev); + + if (ioaddr) { + resource_size_t bar5 = pci_resource_start(dev, 5); + unsigned long barsize = pci_resource_len(dev, 5); + + iounmap(ioaddr); + release_mem_region(bar5, barsize); + } + + pci_disable_device(dev); +} + +static const struct pci_device_id siimage_pci_tbl[] = { + { PCI_VDEVICE(CMD, PCI_DEVICE_ID_SII_680), 0 }, +#ifdef CONFIG_BLK_DEV_IDE_SATA + { PCI_VDEVICE(CMD, PCI_DEVICE_ID_SII_3112), 1 }, + { PCI_VDEVICE(CMD, PCI_DEVICE_ID_SII_1210SA), 1 }, +#endif + { 0, }, +}; +MODULE_DEVICE_TABLE(pci, siimage_pci_tbl); + +static struct pci_driver siimage_pci_driver = { + .name = "SiI_IDE", + .id_table = siimage_pci_tbl, + .probe = siimage_init_one, + .remove = siimage_remove, + .suspend = ide_pci_suspend, + .resume = ide_pci_resume, +}; + +static int __init siimage_ide_init(void) +{ + return ide_pci_register_driver(&siimage_pci_driver); +} + +static void __exit siimage_ide_exit(void) +{ + pci_unregister_driver(&siimage_pci_driver); +} + +module_init(siimage_ide_init); +module_exit(siimage_ide_exit); + +MODULE_AUTHOR("Andre Hedrick, Alan Cox"); +MODULE_DESCRIPTION("PCI driver module for SiI IDE"); +MODULE_LICENSE("GPL"); diff --git a/drivers/ide/sis5513.c b/drivers/ide/sis5513.c new file mode 100644 index 00000000000..247853ea136 --- /dev/null +++ b/drivers/ide/sis5513.c @@ -0,0 +1,636 @@ +/* + * Copyright (C) 1999-2000 Andre Hedrick <andre@linux-ide.org> + * Copyright (C) 2002 Lionel Bouton <Lionel.Bouton@inet6.fr>, Maintainer + * Copyright (C) 2003 Vojtech Pavlik <vojtech@suse.cz> + * Copyright (C) 2007-2009 Bartlomiej Zolnierkiewicz + * + * May be copied or modified under the terms of the GNU General Public License + * + * + * Thanks : + * + * SiS Taiwan : for direct support and hardware. + * Daniela Engert : for initial ATA100 advices and numerous others. + * John Fremlin, Manfred Spraul, Dave Morgan, Peter Kjellerstedt : + * for checking code correctness, providing patches. + * + * + * Original tests and design on the SiS620 chipset. + * ATA100 tests and design on the SiS735 chipset. + * ATA16/33 support from specs + * ATA133 support for SiS961/962 by L.C. Chang <lcchang@sis.com.tw> + * ATA133 961/962/963 fixes by Vojtech Pavlik <vojtech@suse.cz> + * + * Documentation: + * SiS chipset documentation available under NDA to companies only + * (not to individuals). + */ + +/* + * The original SiS5513 comes from a SiS5511/55112/5513 chipset. The original + * SiS5513 was also used in the SiS5596/5513 chipset. Thus if we see a SiS5511 + * or SiS5596, we can assume we see the first MWDMA-16 capable SiS5513 chip. + * + * Later SiS chipsets integrated the 5513 functionality into the NorthBridge, + * starting with SiS5571 and up to SiS745. The PCI ID didn't change, though. We + * can figure out that we have a more modern and more capable 5513 by looking + * for the respective NorthBridge IDs. + * + * Even later (96x family) SiS chipsets use the MuTIOL link and place the 5513 + * into the SouthBrige. Here we cannot rely on looking up the NorthBridge PCI + * ID, while the now ATA-133 capable 5513 still has the same PCI ID. + * Fortunately the 5513 can be 'unmasked' by fiddling with some config space + * bits, changing its device id to the true one - 5517 for 961 and 5518 for + * 962/963. + */ + +#include <linux/types.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/pci.h> +#include <linux/init.h> +#include <linux/ide.h> + +#define DRV_NAME "sis5513" + +/* registers layout and init values are chipset family dependent */ + +#define ATA_16 0x01 +#define ATA_33 0x02 +#define ATA_66 0x03 +#define ATA_100a 0x04 /* SiS730/SiS550 is ATA100 with ATA66 layout */ +#define ATA_100 0x05 +#define ATA_133a 0x06 /* SiS961b with 133 support */ +#define ATA_133 0x07 /* SiS962/963 */ + +static u8 chipset_family; + +/* + * Devices supported + */ +static const struct { + const char *name; + u16 host_id; + u8 chipset_family; + u8 flags; +} SiSHostChipInfo[] = { + { "SiS968", PCI_DEVICE_ID_SI_968, ATA_133 }, + { "SiS966", PCI_DEVICE_ID_SI_966, ATA_133 }, + { "SiS965", PCI_DEVICE_ID_SI_965, ATA_133 }, + { "SiS745", PCI_DEVICE_ID_SI_745, ATA_100 }, + { "SiS735", PCI_DEVICE_ID_SI_735, ATA_100 }, + { "SiS733", PCI_DEVICE_ID_SI_733, ATA_100 }, + { "SiS635", PCI_DEVICE_ID_SI_635, ATA_100 }, + { "SiS633", PCI_DEVICE_ID_SI_633, ATA_100 }, + + { "SiS730", PCI_DEVICE_ID_SI_730, ATA_100a }, + { "SiS550", PCI_DEVICE_ID_SI_550, ATA_100a }, + + { "SiS640", PCI_DEVICE_ID_SI_640, ATA_66 }, + { "SiS630", PCI_DEVICE_ID_SI_630, ATA_66 }, + { "SiS620", PCI_DEVICE_ID_SI_620, ATA_66 }, + { "SiS540", PCI_DEVICE_ID_SI_540, ATA_66 }, + { "SiS530", PCI_DEVICE_ID_SI_530, ATA_66 }, + + { "SiS5600", PCI_DEVICE_ID_SI_5600, ATA_33 }, + { "SiS5598", PCI_DEVICE_ID_SI_5598, ATA_33 }, + { "SiS5597", PCI_DEVICE_ID_SI_5597, ATA_33 }, + { "SiS5591/2", PCI_DEVICE_ID_SI_5591, ATA_33 }, + { "SiS5582", PCI_DEVICE_ID_SI_5582, ATA_33 }, + { "SiS5581", PCI_DEVICE_ID_SI_5581, ATA_33 }, + + { "SiS5596", PCI_DEVICE_ID_SI_5596, ATA_16 }, + { "SiS5571", PCI_DEVICE_ID_SI_5571, ATA_16 }, + { "SiS5517", PCI_DEVICE_ID_SI_5517, ATA_16 }, + { "SiS551x", PCI_DEVICE_ID_SI_5511, ATA_16 }, +}; + +/* Cycle time bits and values vary across chip dma capabilities + These three arrays hold the register layout and the values to set. + Indexed by chipset_family and (dma_mode - XFER_UDMA_0) */ + +/* {0, ATA_16, ATA_33, ATA_66, ATA_100a, ATA_100, ATA_133} */ +static u8 cycle_time_offset[] = { 0, 0, 5, 4, 4, 0, 0 }; +static u8 cycle_time_range[] = { 0, 0, 2, 3, 3, 4, 4 }; +static u8 cycle_time_value[][XFER_UDMA_6 - XFER_UDMA_0 + 1] = { + { 0, 0, 0, 0, 0, 0, 0 }, /* no UDMA */ + { 0, 0, 0, 0, 0, 0, 0 }, /* no UDMA */ + { 3, 2, 1, 0, 0, 0, 0 }, /* ATA_33 */ + { 7, 5, 3, 2, 1, 0, 0 }, /* ATA_66 */ + { 7, 5, 3, 2, 1, 0, 0 }, /* ATA_100a (730 specific), + different cycle_time range and offset */ + { 11, 7, 5, 4, 2, 1, 0 }, /* ATA_100 */ + { 15, 10, 7, 5, 3, 2, 1 }, /* ATA_133a (earliest 691 southbridges) */ + { 15, 10, 7, 5, 3, 2, 1 }, /* ATA_133 */ +}; +/* CRC Valid Setup Time vary across IDE clock setting 33/66/100/133 + See SiS962 data sheet for more detail */ +static u8 cvs_time_value[][XFER_UDMA_6 - XFER_UDMA_0 + 1] = { + { 0, 0, 0, 0, 0, 0, 0 }, /* no UDMA */ + { 0, 0, 0, 0, 0, 0, 0 }, /* no UDMA */ + { 2, 1, 1, 0, 0, 0, 0 }, + { 4, 3, 2, 1, 0, 0, 0 }, + { 4, 3, 2, 1, 0, 0, 0 }, + { 6, 4, 3, 1, 1, 1, 0 }, + { 9, 6, 4, 2, 2, 2, 2 }, + { 9, 6, 4, 2, 2, 2, 2 }, +}; +/* Initialize time, Active time, Recovery time vary across + IDE clock settings. These 3 arrays hold the register value + for PIO0/1/2/3/4 and DMA0/1/2 mode in order */ +static u8 ini_time_value[][8] = { + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 2, 1, 0, 0, 0, 1, 0, 0 }, + { 4, 3, 1, 1, 1, 3, 1, 1 }, + { 4, 3, 1, 1, 1, 3, 1, 1 }, + { 6, 4, 2, 2, 2, 4, 2, 2 }, + { 9, 6, 3, 3, 3, 6, 3, 3 }, + { 9, 6, 3, 3, 3, 6, 3, 3 }, +}; +static u8 act_time_value[][8] = { + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 9, 9, 9, 2, 2, 7, 2, 2 }, + { 19, 19, 19, 5, 4, 14, 5, 4 }, + { 19, 19, 19, 5, 4, 14, 5, 4 }, + { 28, 28, 28, 7, 6, 21, 7, 6 }, + { 38, 38, 38, 10, 9, 28, 10, 9 }, + { 38, 38, 38, 10, 9, 28, 10, 9 }, +}; +static u8 rco_time_value[][8] = { + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 9, 2, 0, 2, 0, 7, 1, 1 }, + { 19, 5, 1, 5, 2, 16, 3, 2 }, + { 19, 5, 1, 5, 2, 16, 3, 2 }, + { 30, 9, 3, 9, 4, 25, 6, 4 }, + { 40, 12, 4, 12, 5, 34, 12, 5 }, + { 40, 12, 4, 12, 5, 34, 12, 5 }, +}; + +/* + * Printing configuration + */ +/* Used for chipset type printing at boot time */ +static char *chipset_capability[] = { + "ATA", "ATA 16", + "ATA 33", "ATA 66", + "ATA 100 (1st gen)", "ATA 100 (2nd gen)", + "ATA 133 (1st gen)", "ATA 133 (2nd gen)" +}; + +/* + * Configuration functions + */ + +static u8 sis_ata133_get_base(ide_drive_t *drive) +{ + struct pci_dev *dev = to_pci_dev(drive->hwif->dev); + u32 reg54 = 0; + + pci_read_config_dword(dev, 0x54, ®54); + + return ((reg54 & 0x40000000) ? 0x70 : 0x40) + drive->dn * 4; +} + +static void sis_ata16_program_timings(ide_drive_t *drive, const u8 mode) +{ + struct pci_dev *dev = to_pci_dev(drive->hwif->dev); + u16 t1 = 0; + u8 drive_pci = 0x40 + drive->dn * 2; + + const u16 pio_timings[] = { 0x000, 0x607, 0x404, 0x303, 0x301 }; + const u16 mwdma_timings[] = { 0x008, 0x302, 0x301 }; + + pci_read_config_word(dev, drive_pci, &t1); + + /* clear active/recovery timings */ + t1 &= ~0x070f; + if (mode >= XFER_MW_DMA_0) { + if (chipset_family > ATA_16) + t1 &= ~0x8000; /* disable UDMA */ + t1 |= mwdma_timings[mode - XFER_MW_DMA_0]; + } else + t1 |= pio_timings[mode - XFER_PIO_0]; + + pci_write_config_word(dev, drive_pci, t1); +} + +static void sis_ata100_program_timings(ide_drive_t *drive, const u8 mode) +{ + struct pci_dev *dev = to_pci_dev(drive->hwif->dev); + u8 t1, drive_pci = 0x40 + drive->dn * 2; + + /* timing bits: 7:4 active 3:0 recovery */ + const u8 pio_timings[] = { 0x00, 0x67, 0x44, 0x33, 0x31 }; + const u8 mwdma_timings[] = { 0x08, 0x32, 0x31 }; + + if (mode >= XFER_MW_DMA_0) { + u8 t2 = 0; + + pci_read_config_byte(dev, drive_pci, &t2); + t2 &= ~0x80; /* disable UDMA */ + pci_write_config_byte(dev, drive_pci, t2); + + t1 = mwdma_timings[mode - XFER_MW_DMA_0]; + } else + t1 = pio_timings[mode - XFER_PIO_0]; + + pci_write_config_byte(dev, drive_pci + 1, t1); +} + +static void sis_ata133_program_timings(ide_drive_t *drive, const u8 mode) +{ + struct pci_dev *dev = to_pci_dev(drive->hwif->dev); + u32 t1 = 0; + u8 drive_pci = sis_ata133_get_base(drive), clk, idx; + + pci_read_config_dword(dev, drive_pci, &t1); + + t1 &= 0xc0c00fff; + clk = (t1 & 0x08) ? ATA_133 : ATA_100; + if (mode >= XFER_MW_DMA_0) { + t1 &= ~0x04; /* disable UDMA */ + idx = mode - XFER_MW_DMA_0 + 5; + } else + idx = mode - XFER_PIO_0; + t1 |= ini_time_value[clk][idx] << 12; + t1 |= act_time_value[clk][idx] << 16; + t1 |= rco_time_value[clk][idx] << 24; + + pci_write_config_dword(dev, drive_pci, t1); +} + +static void sis_program_timings(ide_drive_t *drive, const u8 mode) +{ + if (chipset_family < ATA_100) /* ATA_16/33/66/100a */ + sis_ata16_program_timings(drive, mode); + else if (chipset_family < ATA_133) /* ATA_100/133a */ + sis_ata100_program_timings(drive, mode); + else /* ATA_133 */ + sis_ata133_program_timings(drive, mode); +} + +static void config_drive_art_rwp(ide_drive_t *drive) +{ + ide_hwif_t *hwif = drive->hwif; + struct pci_dev *dev = to_pci_dev(hwif->dev); + u8 reg4bh = 0; + u8 rw_prefetch = 0; + + pci_read_config_byte(dev, 0x4b, ®4bh); + + rw_prefetch = reg4bh & ~(0x11 << drive->dn); + + if (drive->media == ide_disk) + rw_prefetch |= 0x11 << drive->dn; + + if (reg4bh != rw_prefetch) + pci_write_config_byte(dev, 0x4b, rw_prefetch); +} + +static void sis_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) +{ + config_drive_art_rwp(drive); + sis_program_timings(drive, drive->pio_mode); +} + +static void sis_ata133_program_udma_timings(ide_drive_t *drive, const u8 mode) +{ + struct pci_dev *dev = to_pci_dev(drive->hwif->dev); + u32 regdw = 0; + u8 drive_pci = sis_ata133_get_base(drive), clk, idx; + + pci_read_config_dword(dev, drive_pci, ®dw); + + regdw |= 0x04; + regdw &= 0xfffff00f; + /* check if ATA133 enable */ + clk = (regdw & 0x08) ? ATA_133 : ATA_100; + idx = mode - XFER_UDMA_0; + regdw |= cycle_time_value[clk][idx] << 4; + regdw |= cvs_time_value[clk][idx] << 8; + + pci_write_config_dword(dev, drive_pci, regdw); +} + +static void sis_ata33_program_udma_timings(ide_drive_t *drive, const u8 mode) +{ + struct pci_dev *dev = to_pci_dev(drive->hwif->dev); + u8 drive_pci = 0x40 + drive->dn * 2, reg = 0, i = chipset_family; + + pci_read_config_byte(dev, drive_pci + 1, ®); + + /* force the UDMA bit on if we want to use UDMA */ + reg |= 0x80; + /* clean reg cycle time bits */ + reg &= ~((0xff >> (8 - cycle_time_range[i])) << cycle_time_offset[i]); + /* set reg cycle time bits */ + reg |= cycle_time_value[i][mode - XFER_UDMA_0] << cycle_time_offset[i]; + + pci_write_config_byte(dev, drive_pci + 1, reg); +} + +static void sis_program_udma_timings(ide_drive_t *drive, const u8 mode) +{ + if (chipset_family >= ATA_133) /* ATA_133 */ + sis_ata133_program_udma_timings(drive, mode); + else /* ATA_33/66/100a/100/133a */ + sis_ata33_program_udma_timings(drive, mode); +} + +static void sis_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive) +{ + const u8 speed = drive->dma_mode; + + if (speed >= XFER_UDMA_0) + sis_program_udma_timings(drive, speed); + else + sis_program_timings(drive, speed); +} + +static u8 sis_ata133_udma_filter(ide_drive_t *drive) +{ + struct pci_dev *dev = to_pci_dev(drive->hwif->dev); + u32 regdw = 0; + u8 drive_pci = sis_ata133_get_base(drive); + + pci_read_config_dword(dev, drive_pci, ®dw); + + /* if ATA133 disable, we should not set speed above UDMA5 */ + return (regdw & 0x08) ? ATA_UDMA6 : ATA_UDMA5; +} + +static int sis_find_family(struct pci_dev *dev) +{ + struct pci_dev *host; + int i = 0; + + chipset_family = 0; + + for (i = 0; i < ARRAY_SIZE(SiSHostChipInfo) && !chipset_family; i++) { + + host = pci_get_device(PCI_VENDOR_ID_SI, SiSHostChipInfo[i].host_id, NULL); + + if (!host) + continue; + + chipset_family = SiSHostChipInfo[i].chipset_family; + + /* Special case for SiS630 : 630S/ET is ATA_100a */ + if (SiSHostChipInfo[i].host_id == PCI_DEVICE_ID_SI_630) { + if (host->revision >= 0x30) + chipset_family = ATA_100a; + } + pci_dev_put(host); + + printk(KERN_INFO DRV_NAME " %s: %s %s controller\n", + pci_name(dev), SiSHostChipInfo[i].name, + chipset_capability[chipset_family]); + } + + if (!chipset_family) { /* Belongs to pci-quirks */ + + u32 idemisc; + u16 trueid; + + /* Disable ID masking and register remapping */ + pci_read_config_dword(dev, 0x54, &idemisc); + pci_write_config_dword(dev, 0x54, (idemisc & 0x7fffffff)); + pci_read_config_word(dev, PCI_DEVICE_ID, &trueid); + pci_write_config_dword(dev, 0x54, idemisc); + + if (trueid == 0x5518) { + printk(KERN_INFO DRV_NAME " %s: SiS 962/963 MuTIOL IDE UDMA133 controller\n", + pci_name(dev)); + chipset_family = ATA_133; + + /* Check for 5513 compatibility mapping + * We must use this, else the port enabled code will fail, + * as it expects the enablebits at 0x4a. + */ + if ((idemisc & 0x40000000) == 0) { + pci_write_config_dword(dev, 0x54, idemisc | 0x40000000); + printk(KERN_INFO DRV_NAME " %s: Switching to 5513 register mapping\n", + pci_name(dev)); + } + } + } + + if (!chipset_family) { /* Belongs to pci-quirks */ + + struct pci_dev *lpc_bridge; + u16 trueid; + u8 prefctl; + u8 idecfg; + + pci_read_config_byte(dev, 0x4a, &idecfg); + pci_write_config_byte(dev, 0x4a, idecfg | 0x10); + pci_read_config_word(dev, PCI_DEVICE_ID, &trueid); + pci_write_config_byte(dev, 0x4a, idecfg); + + if (trueid == 0x5517) { /* SiS 961/961B */ + + lpc_bridge = pci_get_slot(dev->bus, 0x10); /* Bus 0, Dev 2, Fn 0 */ + pci_read_config_byte(dev, 0x49, &prefctl); + pci_dev_put(lpc_bridge); + + if (lpc_bridge->revision == 0x10 && (prefctl & 0x80)) { + printk(KERN_INFO DRV_NAME " %s: SiS 961B MuTIOL IDE UDMA133 controller\n", + pci_name(dev)); + chipset_family = ATA_133a; + } else { + printk(KERN_INFO DRV_NAME " %s: SiS 961 MuTIOL IDE UDMA100 controller\n", + pci_name(dev)); + chipset_family = ATA_100; + } + } + } + + return chipset_family; +} + +static int init_chipset_sis5513(struct pci_dev *dev) +{ + /* Make general config ops here + 1/ tell IDE channels to operate in Compatibility mode only + 2/ tell old chips to allow per drive IDE timings */ + + u8 reg; + u16 regw; + + switch (chipset_family) { + case ATA_133: + /* SiS962 operation mode */ + pci_read_config_word(dev, 0x50, ®w); + if (regw & 0x08) + pci_write_config_word(dev, 0x50, regw&0xfff7); + pci_read_config_word(dev, 0x52, ®w); + if (regw & 0x08) + pci_write_config_word(dev, 0x52, regw&0xfff7); + break; + case ATA_133a: + case ATA_100: + /* Fixup latency */ + pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x80); + /* Set compatibility bit */ + pci_read_config_byte(dev, 0x49, ®); + if (!(reg & 0x01)) + pci_write_config_byte(dev, 0x49, reg|0x01); + break; + case ATA_100a: + case ATA_66: + /* Fixup latency */ + pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x10); + + /* On ATA_66 chips the bit was elsewhere */ + pci_read_config_byte(dev, 0x52, ®); + if (!(reg & 0x04)) + pci_write_config_byte(dev, 0x52, reg|0x04); + break; + case ATA_33: + /* On ATA_33 we didn't have a single bit to set */ + pci_read_config_byte(dev, 0x09, ®); + if ((reg & 0x0f) != 0x00) + pci_write_config_byte(dev, 0x09, reg&0xf0); + case ATA_16: + /* force per drive recovery and active timings + needed on ATA_33 and below chips */ + pci_read_config_byte(dev, 0x52, ®); + if (!(reg & 0x08)) + pci_write_config_byte(dev, 0x52, reg|0x08); + break; + } + + return 0; +} + +struct sis_laptop { + u16 device; + u16 subvendor; + u16 subdevice; +}; + +static const struct sis_laptop sis_laptop[] = { + /* devid, subvendor, subdev */ + { 0x5513, 0x1043, 0x1107 }, /* ASUS A6K */ + { 0x5513, 0x1734, 0x105f }, /* FSC Amilo A1630 */ + { 0x5513, 0x1071, 0x8640 }, /* EasyNote K5305 */ + /* end marker */ + { 0, } +}; + +static u8 sis_cable_detect(ide_hwif_t *hwif) +{ + struct pci_dev *pdev = to_pci_dev(hwif->dev); + const struct sis_laptop *lap = &sis_laptop[0]; + u8 ata66 = 0; + + while (lap->device) { + if (lap->device == pdev->device && + lap->subvendor == pdev->subsystem_vendor && + lap->subdevice == pdev->subsystem_device) + return ATA_CBL_PATA40_SHORT; + lap++; + } + + if (chipset_family >= ATA_133) { + u16 regw = 0; + u16 reg_addr = hwif->channel ? 0x52: 0x50; + pci_read_config_word(pdev, reg_addr, ®w); + ata66 = (regw & 0x8000) ? 0 : 1; + } else if (chipset_family >= ATA_66) { + u8 reg48h = 0; + u8 mask = hwif->channel ? 0x20 : 0x10; + pci_read_config_byte(pdev, 0x48, ®48h); + ata66 = (reg48h & mask) ? 0 : 1; + } + + return ata66 ? ATA_CBL_PATA80 : ATA_CBL_PATA40; +} + +static const struct ide_port_ops sis_port_ops = { + .set_pio_mode = sis_set_pio_mode, + .set_dma_mode = sis_set_dma_mode, + .cable_detect = sis_cable_detect, +}; + +static const struct ide_port_ops sis_ata133_port_ops = { + .set_pio_mode = sis_set_pio_mode, + .set_dma_mode = sis_set_dma_mode, + .udma_filter = sis_ata133_udma_filter, + .cable_detect = sis_cable_detect, +}; + +static const struct ide_port_info sis5513_chipset = { + .name = DRV_NAME, + .init_chipset = init_chipset_sis5513, + .enablebits = { {0x4a, 0x02, 0x02}, {0x4a, 0x04, 0x04} }, + .host_flags = IDE_HFLAG_NO_AUTODMA, + .pio_mask = ATA_PIO4, + .mwdma_mask = ATA_MWDMA2, +}; + +static int sis5513_init_one(struct pci_dev *dev, const struct pci_device_id *id) +{ + struct ide_port_info d = sis5513_chipset; + u8 udma_rates[] = { 0x00, 0x00, 0x07, 0x1f, 0x3f, 0x3f, 0x7f, 0x7f }; + int rc; + + rc = pci_enable_device(dev); + if (rc) + return rc; + + if (sis_find_family(dev) == 0) + return -ENOTSUPP; + + if (chipset_family >= ATA_133) + d.port_ops = &sis_ata133_port_ops; + else + d.port_ops = &sis_port_ops; + + d.udma_mask = udma_rates[chipset_family]; + + return ide_pci_init_one(dev, &d, NULL); +} + +static void sis5513_remove(struct pci_dev *dev) +{ + ide_pci_remove(dev); + pci_disable_device(dev); +} + +static const struct pci_device_id sis5513_pci_tbl[] = { + { PCI_VDEVICE(SI, PCI_DEVICE_ID_SI_5513), 0 }, + { PCI_VDEVICE(SI, PCI_DEVICE_ID_SI_5518), 0 }, + { PCI_VDEVICE(SI, PCI_DEVICE_ID_SI_1180), 0 }, + { 0, }, +}; +MODULE_DEVICE_TABLE(pci, sis5513_pci_tbl); + +static struct pci_driver sis5513_pci_driver = { + .name = "SIS_IDE", + .id_table = sis5513_pci_tbl, + .probe = sis5513_init_one, + .remove = sis5513_remove, + .suspend = ide_pci_suspend, + .resume = ide_pci_resume, +}; + +static int __init sis5513_ide_init(void) +{ + return ide_pci_register_driver(&sis5513_pci_driver); +} + +static void __exit sis5513_ide_exit(void) +{ + pci_unregister_driver(&sis5513_pci_driver); +} + +module_init(sis5513_ide_init); +module_exit(sis5513_ide_exit); + +MODULE_AUTHOR("Lionel Bouton, L C Chang, Andre Hedrick, Vojtech Pavlik"); +MODULE_DESCRIPTION("PCI driver module for SIS IDE"); +MODULE_LICENSE("GPL"); diff --git a/drivers/ide/sl82c105.c b/drivers/ide/sl82c105.c new file mode 100644 index 00000000000..8755df3330a --- /dev/null +++ b/drivers/ide/sl82c105.c @@ -0,0 +1,365 @@ +/* + * SL82C105/Winbond 553 IDE driver + * + * Maintainer unknown. + * + * Drive tuning added from Rebel.com's kernel sources + * -- Russell King (15/11/98) linux@arm.linux.org.uk + * + * Merge in Russell's HW workarounds, fix various problems + * with the timing registers setup. + * -- Benjamin Herrenschmidt (01/11/03) benh@kernel.crashing.org + * + * Copyright (C) 2006-2007,2009 MontaVista Software, Inc. <source@mvista.com> + * Copyright (C) 2007 Bartlomiej Zolnierkiewicz + */ + +#include <linux/types.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/pci.h> +#include <linux/ide.h> + +#include <asm/io.h> + +#define DRV_NAME "sl82c105" + +/* + * SL82C105 PCI config register 0x40 bits. + */ +#define CTRL_IDE_IRQB (1 << 30) +#define CTRL_IDE_IRQA (1 << 28) +#define CTRL_LEGIRQ (1 << 11) +#define CTRL_P1F16 (1 << 5) +#define CTRL_P1EN (1 << 4) +#define CTRL_P0F16 (1 << 1) +#define CTRL_P0EN (1 << 0) + +/* + * Convert a PIO mode and cycle time to the required on/off times + * for the interface. This has protection against runaway timings. + */ +static unsigned int get_pio_timings(ide_drive_t *drive, u8 pio) +{ + struct ide_timing *t = ide_timing_find_mode(XFER_PIO_0 + pio); + unsigned int cmd_on, cmd_off; + u8 iordy = 0; + + cmd_on = (t->active + 29) / 30; + cmd_off = (ide_pio_cycle_time(drive, pio) - 30 * cmd_on + 29) / 30; + + if (cmd_on == 0) + cmd_on = 1; + + if (cmd_off == 0) + cmd_off = 1; + + if (ide_pio_need_iordy(drive, pio)) + iordy = 0x40; + + return (cmd_on - 1) << 8 | (cmd_off - 1) | iordy; +} + +/* + * Configure the chipset for PIO mode. + */ +static void sl82c105_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) +{ + struct pci_dev *dev = to_pci_dev(hwif->dev); + unsigned long timings = (unsigned long)ide_get_drivedata(drive); + int reg = 0x44 + drive->dn * 4; + u16 drv_ctrl; + const u8 pio = drive->pio_mode - XFER_PIO_0; + + drv_ctrl = get_pio_timings(drive, pio); + + /* + * Store the PIO timings so that we can restore them + * in case DMA will be turned off... + */ + timings &= 0xffff0000; + timings |= drv_ctrl; + ide_set_drivedata(drive, (void *)timings); + + pci_write_config_word(dev, reg, drv_ctrl); + pci_read_config_word (dev, reg, &drv_ctrl); + + printk(KERN_DEBUG "%s: selected %s (%dns) (%04X)\n", drive->name, + ide_xfer_verbose(pio + XFER_PIO_0), + ide_pio_cycle_time(drive, pio), drv_ctrl); +} + +/* + * Configure the chipset for DMA mode. + */ +static void sl82c105_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive) +{ + static u16 mwdma_timings[] = {0x0707, 0x0201, 0x0200}; + unsigned long timings = (unsigned long)ide_get_drivedata(drive); + u16 drv_ctrl; + const u8 speed = drive->dma_mode; + + drv_ctrl = mwdma_timings[speed - XFER_MW_DMA_0]; + + /* + * Store the DMA timings so that we can actually program + * them when DMA will be turned on... + */ + timings &= 0x0000ffff; + timings |= (unsigned long)drv_ctrl << 16; + ide_set_drivedata(drive, (void *)timings); +} + +static int sl82c105_test_irq(ide_hwif_t *hwif) +{ + struct pci_dev *dev = to_pci_dev(hwif->dev); + u32 val, mask = hwif->channel ? CTRL_IDE_IRQB : CTRL_IDE_IRQA; + + pci_read_config_dword(dev, 0x40, &val); + + return (val & mask) ? 1 : 0; +} + +/* + * The SL82C105 holds off all IDE interrupts while in DMA mode until + * all DMA activity is completed. Sometimes this causes problems (eg, + * when the drive wants to report an error condition). + * + * 0x7e is a "chip testing" register. Bit 2 resets the DMA controller + * state machine. We need to kick this to work around various bugs. + */ +static inline void sl82c105_reset_host(struct pci_dev *dev) +{ + u16 val; + + pci_read_config_word(dev, 0x7e, &val); + pci_write_config_word(dev, 0x7e, val | (1 << 2)); + pci_write_config_word(dev, 0x7e, val & ~(1 << 2)); +} + +/* + * If we get an IRQ timeout, it might be that the DMA state machine + * got confused. Fix from Todd Inglett. Details from Winbond. + * + * This function is called when the IDE timer expires, the drive + * indicates that it is READY, and we were waiting for DMA to complete. + */ +static void sl82c105_dma_lost_irq(ide_drive_t *drive) +{ + ide_hwif_t *hwif = drive->hwif; + struct pci_dev *dev = to_pci_dev(hwif->dev); + u32 val, mask = hwif->channel ? CTRL_IDE_IRQB : CTRL_IDE_IRQA; + u8 dma_cmd; + + printk(KERN_WARNING "sl82c105: lost IRQ, resetting host\n"); + + /* + * Check the raw interrupt from the drive. + */ + pci_read_config_dword(dev, 0x40, &val); + if (val & mask) + printk(KERN_INFO "sl82c105: drive was requesting IRQ, " + "but host lost it\n"); + + /* + * Was DMA enabled? If so, disable it - we're resetting the + * host. The IDE layer will be handling the drive for us. + */ + dma_cmd = inb(hwif->dma_base + ATA_DMA_CMD); + if (dma_cmd & 1) { + outb(dma_cmd & ~1, hwif->dma_base + ATA_DMA_CMD); + printk(KERN_INFO "sl82c105: DMA was enabled\n"); + } + + sl82c105_reset_host(dev); +} + +/* + * ATAPI devices can cause the SL82C105 DMA state machine to go gaga. + * Winbond recommend that the DMA state machine is reset prior to + * setting the bus master DMA enable bit. + * + * The generic IDE core will have disabled the BMEN bit before this + * function is called. + */ +static void sl82c105_dma_start(ide_drive_t *drive) +{ + ide_hwif_t *hwif = drive->hwif; + struct pci_dev *dev = to_pci_dev(hwif->dev); + int reg = 0x44 + drive->dn * 4; + + pci_write_config_word(dev, reg, + (unsigned long)ide_get_drivedata(drive) >> 16); + + sl82c105_reset_host(dev); + ide_dma_start(drive); +} + +static void sl82c105_dma_clear(ide_drive_t *drive) +{ + struct pci_dev *dev = to_pci_dev(drive->hwif->dev); + + sl82c105_reset_host(dev); +} + +static int sl82c105_dma_end(ide_drive_t *drive) +{ + struct pci_dev *dev = to_pci_dev(drive->hwif->dev); + int reg = 0x44 + drive->dn * 4; + int ret = ide_dma_end(drive); + + pci_write_config_word(dev, reg, + (unsigned long)ide_get_drivedata(drive)); + + return ret; +} + +/* + * ATA reset will clear the 16 bits mode in the control + * register, we need to reprogram it + */ +static void sl82c105_resetproc(ide_drive_t *drive) +{ + struct pci_dev *dev = to_pci_dev(drive->hwif->dev); + u32 val; + + pci_read_config_dword(dev, 0x40, &val); + val |= (CTRL_P1F16 | CTRL_P0F16); + pci_write_config_dword(dev, 0x40, val); +} + +/* + * Return the revision of the Winbond bridge + * which this function is part of. + */ +static u8 sl82c105_bridge_revision(struct pci_dev *dev) +{ + struct pci_dev *bridge; + + /* + * The bridge should be part of the same device, but function 0. + */ + bridge = pci_get_bus_and_slot(dev->bus->number, + PCI_DEVFN(PCI_SLOT(dev->devfn), 0)); + if (!bridge) + return -1; + + /* + * Make sure it is a Winbond 553 and is an ISA bridge. + */ + if (bridge->vendor != PCI_VENDOR_ID_WINBOND || + bridge->device != PCI_DEVICE_ID_WINBOND_83C553 || + bridge->class >> 8 != PCI_CLASS_BRIDGE_ISA) { + pci_dev_put(bridge); + return -1; + } + /* + * We need to find function 0's revision, not function 1 + */ + pci_dev_put(bridge); + + return bridge->revision; +} + +/* + * Enable the PCI device + * + * --BenH: It's arch fixup code that should enable channels that + * have not been enabled by firmware. I decided we can still enable + * channel 0 here at least, but channel 1 has to be enabled by + * firmware or arch code. We still set both to 16 bits mode. + */ +static int init_chipset_sl82c105(struct pci_dev *dev) +{ + u32 val; + + pci_read_config_dword(dev, 0x40, &val); + val |= CTRL_P0EN | CTRL_P0F16 | CTRL_P1F16; + pci_write_config_dword(dev, 0x40, val); + + return 0; +} + +static const struct ide_port_ops sl82c105_port_ops = { + .set_pio_mode = sl82c105_set_pio_mode, + .set_dma_mode = sl82c105_set_dma_mode, + .resetproc = sl82c105_resetproc, + .test_irq = sl82c105_test_irq, +}; + +static const struct ide_dma_ops sl82c105_dma_ops = { + .dma_host_set = ide_dma_host_set, + .dma_setup = ide_dma_setup, + .dma_start = sl82c105_dma_start, + .dma_end = sl82c105_dma_end, + .dma_test_irq = ide_dma_test_irq, + .dma_lost_irq = sl82c105_dma_lost_irq, + .dma_timer_expiry = ide_dma_sff_timer_expiry, + .dma_clear = sl82c105_dma_clear, + .dma_sff_read_status = ide_dma_sff_read_status, +}; + +static const struct ide_port_info sl82c105_chipset = { + .name = DRV_NAME, + .init_chipset = init_chipset_sl82c105, + .enablebits = {{0x40,0x01,0x01}, {0x40,0x10,0x10}}, + .port_ops = &sl82c105_port_ops, + .dma_ops = &sl82c105_dma_ops, + .host_flags = IDE_HFLAG_IO_32BIT | + IDE_HFLAG_UNMASK_IRQS | + IDE_HFLAG_SERIALIZE_DMA | + IDE_HFLAG_NO_AUTODMA, + .pio_mask = ATA_PIO5, + .mwdma_mask = ATA_MWDMA2, +}; + +static int sl82c105_init_one(struct pci_dev *dev, const struct pci_device_id *id) +{ + struct ide_port_info d = sl82c105_chipset; + u8 rev = sl82c105_bridge_revision(dev); + + if (rev <= 5) { + /* + * Never ever EVER under any circumstances enable + * DMA when the bridge is this old. + */ + printk(KERN_INFO DRV_NAME ": Winbond W83C553 bridge " + "revision %d, BM-DMA disabled\n", rev); + d.dma_ops = NULL; + d.mwdma_mask = 0; + d.host_flags &= ~IDE_HFLAG_SERIALIZE_DMA; + } + + return ide_pci_init_one(dev, &d, NULL); +} + +static const struct pci_device_id sl82c105_pci_tbl[] = { + { PCI_VDEVICE(WINBOND, PCI_DEVICE_ID_WINBOND_82C105), 0 }, + { 0, }, +}; +MODULE_DEVICE_TABLE(pci, sl82c105_pci_tbl); + +static struct pci_driver sl82c105_pci_driver = { + .name = "W82C105_IDE", + .id_table = sl82c105_pci_tbl, + .probe = sl82c105_init_one, + .remove = ide_pci_remove, + .suspend = ide_pci_suspend, + .resume = ide_pci_resume, +}; + +static int __init sl82c105_ide_init(void) +{ + return ide_pci_register_driver(&sl82c105_pci_driver); +} + +static void __exit sl82c105_ide_exit(void) +{ + pci_unregister_driver(&sl82c105_pci_driver); +} + +module_init(sl82c105_ide_init); +module_exit(sl82c105_ide_exit); + +MODULE_DESCRIPTION("PCI driver module for W82C105 IDE"); +MODULE_LICENSE("GPL"); diff --git a/drivers/ide/slc90e66.c b/drivers/ide/slc90e66.c new file mode 100644 index 00000000000..8af92bbb3dc --- /dev/null +++ b/drivers/ide/slc90e66.c @@ -0,0 +1,181 @@ +/* + * Copyright (C) 2000-2002 Andre Hedrick <andre@linux-ide.org> + * Copyright (C) 2006-2007 MontaVista Software, Inc. <source@mvista.com> + * + * This is a look-alike variation of the ICH0 PIIX4 Ultra-66, + * but this keeps the ISA-Bridge and slots alive. + * + */ + +#include <linux/types.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/pci.h> +#include <linux/ide.h> +#include <linux/init.h> + +#define DRV_NAME "slc90e66" + +static DEFINE_SPINLOCK(slc90e66_lock); + +static void slc90e66_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) +{ + struct pci_dev *dev = to_pci_dev(hwif->dev); + int is_slave = drive->dn & 1; + int master_port = hwif->channel ? 0x42 : 0x40; + int slave_port = 0x44; + unsigned long flags; + u16 master_data; + u8 slave_data; + int control = 0; + const u8 pio = drive->pio_mode - XFER_PIO_0; + + /* ISP RTC */ + static const u8 timings[][2] = { + { 0, 0 }, + { 0, 0 }, + { 1, 0 }, + { 2, 1 }, + { 2, 3 }, }; + + spin_lock_irqsave(&slc90e66_lock, flags); + pci_read_config_word(dev, master_port, &master_data); + + if (pio > 1) + control |= 1; /* Programmable timing on */ + if (drive->media == ide_disk) + control |= 4; /* Prefetch, post write */ + if (ide_pio_need_iordy(drive, pio)) + control |= 2; /* IORDY */ + if (is_slave) { + master_data |= 0x4000; + master_data &= ~0x0070; + if (pio > 1) { + /* Set PPE, IE and TIME */ + master_data |= control << 4; + } + pci_read_config_byte(dev, slave_port, &slave_data); + slave_data &= hwif->channel ? 0x0f : 0xf0; + slave_data |= ((timings[pio][0] << 2) | timings[pio][1]) << + (hwif->channel ? 4 : 0); + } else { + master_data &= ~0x3307; + if (pio > 1) { + /* enable PPE, IE and TIME */ + master_data |= control; + } + master_data |= (timings[pio][0] << 12) | (timings[pio][1] << 8); + } + pci_write_config_word(dev, master_port, master_data); + if (is_slave) + pci_write_config_byte(dev, slave_port, slave_data); + spin_unlock_irqrestore(&slc90e66_lock, flags); +} + +static void slc90e66_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive) +{ + struct pci_dev *dev = to_pci_dev(hwif->dev); + u8 maslave = hwif->channel ? 0x42 : 0x40; + int sitre = 0, a_speed = 7 << (drive->dn * 4); + int u_speed = 0, u_flag = 1 << drive->dn; + u16 reg4042, reg44, reg48, reg4a; + const u8 speed = drive->dma_mode; + + pci_read_config_word(dev, maslave, ®4042); + sitre = (reg4042 & 0x4000) ? 1 : 0; + pci_read_config_word(dev, 0x44, ®44); + pci_read_config_word(dev, 0x48, ®48); + pci_read_config_word(dev, 0x4a, ®4a); + + if (speed >= XFER_UDMA_0) { + u_speed = (speed - XFER_UDMA_0) << (drive->dn * 4); + + if (!(reg48 & u_flag)) + pci_write_config_word(dev, 0x48, reg48|u_flag); + if ((reg4a & a_speed) != u_speed) { + pci_write_config_word(dev, 0x4a, reg4a & ~a_speed); + pci_read_config_word(dev, 0x4a, ®4a); + pci_write_config_word(dev, 0x4a, reg4a|u_speed); + } + } else { + const u8 mwdma_to_pio[] = { 0, 3, 4 }; + + if (reg48 & u_flag) + pci_write_config_word(dev, 0x48, reg48 & ~u_flag); + if (reg4a & a_speed) + pci_write_config_word(dev, 0x4a, reg4a & ~a_speed); + + if (speed >= XFER_MW_DMA_0) + drive->pio_mode = + mwdma_to_pio[speed - XFER_MW_DMA_0] + XFER_PIO_0; + else + drive->pio_mode = XFER_PIO_2; /* for SWDMA2 */ + + slc90e66_set_pio_mode(hwif, drive); + } +} + +static u8 slc90e66_cable_detect(ide_hwif_t *hwif) +{ + struct pci_dev *dev = to_pci_dev(hwif->dev); + u8 reg47 = 0, mask = hwif->channel ? 0x01 : 0x02; + + pci_read_config_byte(dev, 0x47, ®47); + + /* bit[0(1)]: 0:80, 1:40 */ + return (reg47 & mask) ? ATA_CBL_PATA40 : ATA_CBL_PATA80; +} + +static const struct ide_port_ops slc90e66_port_ops = { + .set_pio_mode = slc90e66_set_pio_mode, + .set_dma_mode = slc90e66_set_dma_mode, + .cable_detect = slc90e66_cable_detect, +}; + +static const struct ide_port_info slc90e66_chipset = { + .name = DRV_NAME, + .enablebits = { {0x41, 0x80, 0x80}, {0x43, 0x80, 0x80} }, + .port_ops = &slc90e66_port_ops, + .pio_mask = ATA_PIO4, + .swdma_mask = ATA_SWDMA2_ONLY, + .mwdma_mask = ATA_MWDMA12_ONLY, + .udma_mask = ATA_UDMA4, +}; + +static int slc90e66_init_one(struct pci_dev *dev, + const struct pci_device_id *id) +{ + return ide_pci_init_one(dev, &slc90e66_chipset, NULL); +} + +static const struct pci_device_id slc90e66_pci_tbl[] = { + { PCI_VDEVICE(EFAR, PCI_DEVICE_ID_EFAR_SLC90E66_1), 0 }, + { 0, }, +}; +MODULE_DEVICE_TABLE(pci, slc90e66_pci_tbl); + +static struct pci_driver slc90e66_pci_driver = { + .name = "SLC90e66_IDE", + .id_table = slc90e66_pci_tbl, + .probe = slc90e66_init_one, + .remove = ide_pci_remove, + .suspend = ide_pci_suspend, + .resume = ide_pci_resume, +}; + +static int __init slc90e66_ide_init(void) +{ + return ide_pci_register_driver(&slc90e66_pci_driver); +} + +static void __exit slc90e66_ide_exit(void) +{ + pci_unregister_driver(&slc90e66_pci_driver); +} + +module_init(slc90e66_ide_init); +module_exit(slc90e66_ide_exit); + +MODULE_AUTHOR("Andre Hedrick"); +MODULE_DESCRIPTION("PCI driver module for SLC90E66 IDE"); +MODULE_LICENSE("GPL"); diff --git a/drivers/ide/tc86c001.c b/drivers/ide/tc86c001.c new file mode 100644 index 00000000000..17e6132b99b --- /dev/null +++ b/drivers/ide/tc86c001.c @@ -0,0 +1,270 @@ +/* + * Copyright (C) 2002 Toshiba Corporation + * Copyright (C) 2005-2006 MontaVista Software, Inc. <source@mvista.com> + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include <linux/types.h> +#include <linux/pci.h> +#include <linux/ide.h> +#include <linux/module.h> + +#define DRV_NAME "tc86c001" + +static void tc86c001_set_mode(ide_hwif_t *hwif, ide_drive_t *drive) +{ + unsigned long scr_port = hwif->config_data + (drive->dn ? 0x02 : 0x00); + u16 mode, scr = inw(scr_port); + const u8 speed = drive->dma_mode; + + switch (speed) { + case XFER_UDMA_4: mode = 0x00c0; break; + case XFER_UDMA_3: mode = 0x00b0; break; + case XFER_UDMA_2: mode = 0x00a0; break; + case XFER_UDMA_1: mode = 0x0090; break; + case XFER_UDMA_0: mode = 0x0080; break; + case XFER_MW_DMA_2: mode = 0x0070; break; + case XFER_MW_DMA_1: mode = 0x0060; break; + case XFER_MW_DMA_0: mode = 0x0050; break; + case XFER_PIO_4: mode = 0x0400; break; + case XFER_PIO_3: mode = 0x0300; break; + case XFER_PIO_2: mode = 0x0200; break; + case XFER_PIO_1: mode = 0x0100; break; + case XFER_PIO_0: + default: mode = 0x0000; break; + } + + scr &= (speed < XFER_MW_DMA_0) ? 0xf8ff : 0xff0f; + scr |= mode; + outw(scr, scr_port); +} + +static void tc86c001_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) +{ + drive->dma_mode = drive->pio_mode; + tc86c001_set_mode(hwif, drive); +} + +/* + * HACKITY HACK + * + * This is a workaround for the limitation 5 of the TC86C001 IDE controller: + * if a DMA transfer terminates prematurely, the controller leaves the device's + * interrupt request (INTRQ) pending and does not generate a PCI interrupt (or + * set the interrupt bit in the DMA status register), thus no PCI interrupt + * will occur until a DMA transfer has been successfully completed. + * + * We work around this by initiating dummy, zero-length DMA transfer on + * a DMA timeout expiration. I found no better way to do this with the current + * IDE core than to temporarily replace a higher level driver's timer expiry + * handler with our own backing up to that handler in case our recovery fails. + */ +static int tc86c001_timer_expiry(ide_drive_t *drive) +{ + ide_hwif_t *hwif = drive->hwif; + ide_expiry_t *expiry = ide_get_hwifdata(hwif); + u8 dma_stat = inb(hwif->dma_base + ATA_DMA_STATUS); + + /* Restore a higher level driver's expiry handler first. */ + hwif->expiry = expiry; + + if ((dma_stat & 5) == 1) { /* DMA active and no interrupt */ + unsigned long sc_base = hwif->config_data; + unsigned long twcr_port = sc_base + (drive->dn ? 0x06 : 0x04); + u8 dma_cmd = inb(hwif->dma_base + ATA_DMA_CMD); + + printk(KERN_WARNING "%s: DMA interrupt possibly stuck, " + "attempting recovery...\n", drive->name); + + /* Stop DMA */ + outb(dma_cmd & ~0x01, hwif->dma_base + ATA_DMA_CMD); + + /* Setup the dummy DMA transfer */ + outw(0, sc_base + 0x0a); /* Sector Count */ + outw(0, twcr_port); /* Transfer Word Count 1 or 2 */ + + /* Start the dummy DMA transfer */ + + /* clear R_OR_WCTR for write */ + outb(0x00, hwif->dma_base + ATA_DMA_CMD); + /* set START_STOPBM */ + outb(0x01, hwif->dma_base + ATA_DMA_CMD); + + /* + * If an interrupt was pending, it should come thru shortly. + * If not, a higher level driver's expiry handler should + * eventually cause some kind of recovery from the DMA stall. + */ + return WAIT_MIN_SLEEP; + } + + /* Chain to the restored expiry handler if DMA wasn't active. */ + if (likely(expiry != NULL)) + return expiry(drive); + + /* If there was no handler, "emulate" that for ide_timer_expiry()... */ + return -1; +} + +static void tc86c001_dma_start(ide_drive_t *drive) +{ + ide_hwif_t *hwif = drive->hwif; + unsigned long sc_base = hwif->config_data; + unsigned long twcr_port = sc_base + (drive->dn ? 0x06 : 0x04); + unsigned long nsectors = blk_rq_sectors(hwif->rq); + + /* + * We have to manually load the sector count and size into + * the appropriate system control registers for DMA to work + * with LBA48 and ATAPI devices... + */ + outw(nsectors, sc_base + 0x0a); /* Sector Count */ + outw(SECTOR_SIZE / 2, twcr_port); /* Transfer Word Count 1/2 */ + + /* Install our timeout expiry hook, saving the current handler... */ + ide_set_hwifdata(hwif, hwif->expiry); + hwif->expiry = &tc86c001_timer_expiry; + + ide_dma_start(drive); +} + +static u8 tc86c001_cable_detect(ide_hwif_t *hwif) +{ + struct pci_dev *dev = to_pci_dev(hwif->dev); + unsigned long sc_base = pci_resource_start(dev, 5); + u16 scr1 = inw(sc_base + 0x00); + + /* + * System Control 1 Register bit 13 (PDIAGN): + * 0=80-pin cable, 1=40-pin cable + */ + return (scr1 & 0x2000) ? ATA_CBL_PATA40 : ATA_CBL_PATA80; +} + +static void init_hwif_tc86c001(ide_hwif_t *hwif) +{ + struct pci_dev *dev = to_pci_dev(hwif->dev); + unsigned long sc_base = pci_resource_start(dev, 5); + u16 scr1 = inw(sc_base + 0x00); + + /* System Control 1 Register bit 15 (Soft Reset) set */ + outw(scr1 | 0x8000, sc_base + 0x00); + + /* System Control 1 Register bit 14 (FIFO Reset) set */ + outw(scr1 | 0x4000, sc_base + 0x00); + + /* System Control 1 Register: reset clear */ + outw(scr1 & ~0xc000, sc_base + 0x00); + + /* Store the system control register base for convenience... */ + hwif->config_data = sc_base; + + if (!hwif->dma_base) + return; + + /* + * Sector Count Control Register bits 0 and 1 set: + * software sets Sector Count Register for master and slave device + */ + outw(0x0003, sc_base + 0x0c); + + /* Sector Count Register limit */ + hwif->rqsize = 0xffff; +} + +static const struct ide_port_ops tc86c001_port_ops = { + .set_pio_mode = tc86c001_set_pio_mode, + .set_dma_mode = tc86c001_set_mode, + .cable_detect = tc86c001_cable_detect, +}; + +static const struct ide_dma_ops tc86c001_dma_ops = { + .dma_host_set = ide_dma_host_set, + .dma_setup = ide_dma_setup, + .dma_start = tc86c001_dma_start, + .dma_end = ide_dma_end, + .dma_test_irq = ide_dma_test_irq, + .dma_lost_irq = ide_dma_lost_irq, + .dma_timer_expiry = ide_dma_sff_timer_expiry, + .dma_sff_read_status = ide_dma_sff_read_status, +}; + +static const struct ide_port_info tc86c001_chipset = { + .name = DRV_NAME, + .init_hwif = init_hwif_tc86c001, + .port_ops = &tc86c001_port_ops, + .dma_ops = &tc86c001_dma_ops, + .host_flags = IDE_HFLAG_SINGLE | IDE_HFLAG_OFF_BOARD, + .pio_mask = ATA_PIO4, + .mwdma_mask = ATA_MWDMA2, + .udma_mask = ATA_UDMA4, +}; + +static int tc86c001_init_one(struct pci_dev *dev, + const struct pci_device_id *id) +{ + int rc; + + rc = pci_enable_device(dev); + if (rc) + goto out; + + rc = pci_request_region(dev, 5, DRV_NAME); + if (rc) { + printk(KERN_ERR DRV_NAME ": system control regs already in use"); + goto out_disable; + } + + rc = ide_pci_init_one(dev, &tc86c001_chipset, NULL); + if (rc) + goto out_release; + + goto out; + +out_release: + pci_release_region(dev, 5); +out_disable: + pci_disable_device(dev); +out: + return rc; +} + +static void tc86c001_remove(struct pci_dev *dev) +{ + ide_pci_remove(dev); + pci_release_region(dev, 5); + pci_disable_device(dev); +} + +static const struct pci_device_id tc86c001_pci_tbl[] = { + { PCI_VDEVICE(TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC86C001_IDE), 0 }, + { 0, } +}; +MODULE_DEVICE_TABLE(pci, tc86c001_pci_tbl); + +static struct pci_driver tc86c001_pci_driver = { + .name = "TC86C001", + .id_table = tc86c001_pci_tbl, + .probe = tc86c001_init_one, + .remove = tc86c001_remove, +}; + +static int __init tc86c001_ide_init(void) +{ + return ide_pci_register_driver(&tc86c001_pci_driver); +} + +static void __exit tc86c001_ide_exit(void) +{ + pci_unregister_driver(&tc86c001_pci_driver); +} + +module_init(tc86c001_ide_init); +module_exit(tc86c001_ide_exit); + +MODULE_AUTHOR("MontaVista Software, Inc. <source@mvista.com>"); +MODULE_DESCRIPTION("PCI driver module for TC86C001 IDE"); +MODULE_LICENSE("GPL"); diff --git a/drivers/ide/triflex.c b/drivers/ide/triflex.c new file mode 100644 index 00000000000..7f1af9493f0 --- /dev/null +++ b/drivers/ide/triflex.c @@ -0,0 +1,155 @@ +/* + * IDE Chipset driver for the Compaq TriFlex IDE controller. + * + * Known to work with the Compaq Workstation 5x00 series. + * + * Copyright (C) 2002 Hewlett-Packard Development Group, L.P. + * Author: Torben Mathiasen <torben.mathiasen@hp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Loosely based on the piix & svwks drivers. + * + * Documentation: + * Not publicly available. + */ + +#include <linux/types.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/pci.h> +#include <linux/ide.h> +#include <linux/init.h> + +#define DRV_NAME "triflex" + +static void triflex_set_mode(ide_hwif_t *hwif, ide_drive_t *drive) +{ + struct pci_dev *dev = to_pci_dev(hwif->dev); + u32 triflex_timings = 0; + u16 timing = 0; + u8 channel_offset = hwif->channel ? 0x74 : 0x70, unit = drive->dn & 1; + + pci_read_config_dword(dev, channel_offset, &triflex_timings); + + switch (drive->dma_mode) { + case XFER_MW_DMA_2: + timing = 0x0103; + break; + case XFER_MW_DMA_1: + timing = 0x0203; + break; + case XFER_MW_DMA_0: + timing = 0x0808; + break; + case XFER_SW_DMA_2: + case XFER_SW_DMA_1: + case XFER_SW_DMA_0: + timing = 0x0f0f; + break; + case XFER_PIO_4: + timing = 0x0202; + break; + case XFER_PIO_3: + timing = 0x0204; + break; + case XFER_PIO_2: + timing = 0x0404; + break; + case XFER_PIO_1: + timing = 0x0508; + break; + case XFER_PIO_0: + timing = 0x0808; + break; + } + + triflex_timings &= ~(0xFFFF << (16 * unit)); + triflex_timings |= (timing << (16 * unit)); + + pci_write_config_dword(dev, channel_offset, triflex_timings); +} + +static void triflex_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) +{ + drive->dma_mode = drive->pio_mode; + triflex_set_mode(hwif, drive); +} + +static const struct ide_port_ops triflex_port_ops = { + .set_pio_mode = triflex_set_pio_mode, + .set_dma_mode = triflex_set_mode, +}; + +static const struct ide_port_info triflex_device = { + .name = DRV_NAME, + .enablebits = {{0x80, 0x01, 0x01}, {0x80, 0x02, 0x02}}, + .port_ops = &triflex_port_ops, + .pio_mask = ATA_PIO4, + .swdma_mask = ATA_SWDMA2, + .mwdma_mask = ATA_MWDMA2, +}; + +static int triflex_init_one(struct pci_dev *dev, const struct pci_device_id *id) +{ + return ide_pci_init_one(dev, &triflex_device, NULL); +} + +static const struct pci_device_id triflex_pci_tbl[] = { + { PCI_VDEVICE(COMPAQ, PCI_DEVICE_ID_COMPAQ_TRIFLEX_IDE), 0 }, + { 0, }, +}; +MODULE_DEVICE_TABLE(pci, triflex_pci_tbl); + +#ifdef CONFIG_PM +static int triflex_ide_pci_suspend(struct pci_dev *dev, pm_message_t state) +{ + /* + * We must not disable or powerdown the device. + * APM bios refuses to suspend if IDE is not accessible. + */ + pci_save_state(dev); + return 0; +} +#else +#define triflex_ide_pci_suspend NULL +#endif + +static struct pci_driver triflex_pci_driver = { + .name = "TRIFLEX_IDE", + .id_table = triflex_pci_tbl, + .probe = triflex_init_one, + .remove = ide_pci_remove, + .suspend = triflex_ide_pci_suspend, + .resume = ide_pci_resume, +}; + +static int __init triflex_ide_init(void) +{ + return ide_pci_register_driver(&triflex_pci_driver); +} + +static void __exit triflex_ide_exit(void) +{ + pci_unregister_driver(&triflex_pci_driver); +} + +module_init(triflex_ide_init); +module_exit(triflex_ide_exit); + +MODULE_AUTHOR("Torben Mathiasen"); +MODULE_DESCRIPTION("PCI driver module for Compaq Triflex IDE"); +MODULE_LICENSE("GPL"); + + diff --git a/drivers/ide/pci/trm290.c b/drivers/ide/trm290.c index 2a282529bfc..0069f6ce74c 100644 --- a/drivers/ide/pci/trm290.c +++ b/drivers/ide/trm290.c @@ -1,7 +1,7 @@ /* - * linux/drivers/ide/pci/trm290.c Version 1.02 Mar. 18, 2000 - * * Copyright (c) 1997-1998 Mark Lord + * Copyright (c) 2007 MontaVista Software, Inc. <source@mvista.com> + * * May be copied or modified under the terms of the GNU General Public License * * June 22, 2004 - get rid of check_region @@ -131,21 +131,20 @@ #include <linux/types.h> #include <linux/module.h> #include <linux/kernel.h> -#include <linux/mm.h> #include <linux/ioport.h> #include <linux/interrupt.h> #include <linux/blkdev.h> #include <linux/init.h> -#include <linux/hdreg.h> #include <linux/pci.h> -#include <linux/delay.h> #include <linux/ide.h> #include <asm/io.h> +#define DRV_NAME "trm290" + static void trm290_prepare_drive (ide_drive_t *drive, unsigned int use_dma) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; u16 reg = 0; unsigned long flags; @@ -157,150 +156,121 @@ static void trm290_prepare_drive (ide_drive_t *drive, unsigned int use_dma) if (reg != hwif->select_data) { hwif->select_data = reg; /* set PIO/DMA */ - hwif->OUTB(0x51|(hwif->channel<<3), hwif->config_data+1); - hwif->OUTW(reg & 0xff, hwif->config_data); + outb(0x51 | (hwif->channel << 3), hwif->config_data + 1); + outw(reg & 0xff, hwif->config_data); } /* enable IRQ if not probing */ - if (drive->present) { - reg = hwif->INW(hwif->config_data + 3); + if (drive->dev_flags & IDE_DFLAG_PRESENT) { + reg = inw(hwif->config_data + 3); reg &= 0x13; reg &= ~(1 << hwif->channel); - hwif->OUTW(reg, hwif->config_data+3); + outw(reg, hwif->config_data + 3); } local_irq_restore(flags); } -static void trm290_selectproc (ide_drive_t *drive) +static void trm290_dev_select(ide_drive_t *drive) { - trm290_prepare_drive(drive, drive->using_dma); -} + trm290_prepare_drive(drive, !!(drive->dev_flags & IDE_DFLAG_USING_DMA)); -#ifdef CONFIG_BLK_DEV_IDEDMA -static void trm290_ide_dma_exec_cmd(ide_drive_t *drive, u8 command) -{ - ide_hwif_t *hwif = HWIF(drive); - - BUG_ON(HWGROUP(drive)->handler != NULL); /* paranoia check */ - ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL); - /* issue cmd to drive */ - hwif->OUTB(command, IDE_COMMAND_REG); + outb(drive->select | ATA_DEVICE_OBS, drive->hwif->io_ports.device_addr); } -static int trm290_ide_dma_setup(ide_drive_t *drive) +static int trm290_dma_check(ide_drive_t *drive, struct ide_cmd *cmd) { - ide_hwif_t *hwif = drive->hwif; - struct request *rq = hwif->hwgroup->rq; - unsigned int count, rw; - - if (rq_data_dir(rq)) { + if (cmd->tf_flags & IDE_TFLAG_WRITE) { #ifdef TRM290_NO_DMA_WRITES /* always use PIO for writes */ - trm290_prepare_drive(drive, 0); /* select PIO xfer */ return 1; #endif - rw = 1; - } else - rw = 2; + } + return 0; +} - if (!(count = ide_build_dmatable(drive, rq))) { +static int trm290_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd) +{ + ide_hwif_t *hwif = drive->hwif; + unsigned int count, rw = (cmd->tf_flags & IDE_TFLAG_WRITE) ? 1 : 2; + + count = ide_build_dmatable(drive, cmd); + if (count == 0) /* try PIO instead of DMA */ - trm290_prepare_drive(drive, 0); /* select PIO xfer */ return 1; - } - /* select DMA xfer */ - trm290_prepare_drive(drive, 1); - hwif->OUTL(hwif->dmatable_dma|rw, hwif->dma_command); - drive->waiting_for_dma = 1; + + outl(hwif->dmatable_dma | rw, hwif->dma_base); /* start DMA */ - hwif->OUTW((count * 2) - 1, hwif->dma_status); + outw(count * 2 - 1, hwif->dma_base + 2); + return 0; } -static void trm290_ide_dma_start(ide_drive_t *drive) +static void trm290_dma_start(ide_drive_t *drive) { + trm290_prepare_drive(drive, 1); } -static int trm290_ide_dma_end (ide_drive_t *drive) +static int trm290_dma_end(ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); - u16 status = 0; - - drive->waiting_for_dma = 0; - /* purge DMA mappings */ - ide_destroy_dmatable(drive); - status = hwif->INW(hwif->dma_status); - return (status != 0x00ff); + u16 status = inw(drive->hwif->dma_base + 2); + + trm290_prepare_drive(drive, 0); + + return status != 0x00ff; } -static int trm290_ide_dma_test_irq (ide_drive_t *drive) +static int trm290_dma_test_irq(ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); - u16 status = 0; + u16 status = inw(drive->hwif->dma_base + 2); - status = hwif->INW(hwif->dma_status); - return (status == 0x00ff); + return status == 0x00ff; } -#endif /* CONFIG_BLK_DEV_IDEDMA */ -/* - * Invoked from ide-dma.c at boot time. - */ -static void __devinit init_hwif_trm290(ide_hwif_t *hwif) +static void trm290_dma_host_set(ide_drive_t *drive, int on) +{ +} + +static void init_hwif_trm290(ide_hwif_t *hwif) { - unsigned int cfgbase = 0; + struct pci_dev *dev = to_pci_dev(hwif->dev); + unsigned int cfg_base = pci_resource_start(dev, 4); unsigned long flags; u8 reg = 0; - struct pci_dev *dev = hwif->pci_dev; - - hwif->no_lba48 = 1; - hwif->chipset = ide_trm290; - cfgbase = pci_resource_start(dev, 4); - if ((dev->class & 5) && cfgbase) { - hwif->config_data = cfgbase; - printk(KERN_INFO "TRM290: chip config base at 0x%04lx\n", - hwif->config_data); - } else { - hwif->config_data = 0x3df0; - printk(KERN_INFO "TRM290: using default config base at 0x%04lx\n", - hwif->config_data); + + if ((dev->class & 5) && cfg_base) + printk(KERN_INFO DRV_NAME " %s: chip", pci_name(dev)); + else { + cfg_base = 0x3df0; + printk(KERN_INFO DRV_NAME " %s: using default", pci_name(dev)); } + printk(KERN_CONT " config base at 0x%04x\n", cfg_base); + hwif->config_data = cfg_base; + hwif->dma_base = (cfg_base + 4) ^ (hwif->channel ? 0x80 : 0); + + printk(KERN_INFO " %s: BM-DMA at 0x%04lx-0x%04lx\n", + hwif->name, hwif->dma_base, hwif->dma_base + 3); + + if (ide_allocate_dma_engine(hwif)) + return; local_irq_save(flags); /* put config reg into first byte of hwif->select_data */ - hwif->OUTB(0x51|(hwif->channel<<3), hwif->config_data+1); + outb(0x51 | (hwif->channel << 3), hwif->config_data + 1); /* select PIO as default */ hwif->select_data = 0x21; - hwif->OUTB(hwif->select_data, hwif->config_data); + outb(hwif->select_data, hwif->config_data); /* get IRQ info */ - reg = hwif->INB(hwif->config_data+3); + reg = inb(hwif->config_data + 3); /* mask IRQs for both ports */ reg = (reg & 0x10) | 0x03; - hwif->OUTB(reg, hwif->config_data+3); + outb(reg, hwif->config_data + 3); local_irq_restore(flags); - if ((reg & 0x10)) + if (reg & 0x10) /* legacy mode */ hwif->irq = hwif->channel ? 15 : 14; - else if (!hwif->irq && hwif->mate && hwif->mate->irq) - /* sharing IRQ with mate */ - hwif->irq = hwif->mate->irq; - - ide_setup_dma(hwif, (hwif->config_data + 4) ^ (hwif->channel ? 0x0080 : 0x0000), 3); - -#ifdef CONFIG_BLK_DEV_IDEDMA - hwif->dma_setup = &trm290_ide_dma_setup; - hwif->dma_exec_cmd = &trm290_ide_dma_exec_cmd; - hwif->dma_start = &trm290_ide_dma_start; - hwif->ide_dma_end = &trm290_ide_dma_end; - hwif->ide_dma_test_irq = &trm290_ide_dma_test_irq; -#endif /* CONFIG_BLK_DEV_IDEDMA */ - - hwif->selectproc = &trm290_selectproc; - hwif->autodma = 0; /* play it safe for now */ - hwif->drives[0].autodma = hwif->autodma; - hwif->drives[1].autodma = hwif->autodma; + #if 1 { /* @@ -312,16 +282,16 @@ static void __devinit init_hwif_trm290(ide_hwif_t *hwif) static u16 next_offset = 0; u8 old_mask; - hwif->OUTB(0x54|(hwif->channel<<3), hwif->config_data+1); - old = hwif->INW(hwif->config_data); + outb(0x54 | (hwif->channel << 3), hwif->config_data + 1); + old = inw(hwif->config_data); old &= ~1; - old_mask = hwif->INB(old+2); + old_mask = inb(old + 2); if (old != compat && old_mask == 0xff) { /* leave lower 10 bits untouched */ compat += (next_offset += 0x400); - hwif->io_ports[IDE_CONTROL_OFFSET] = compat + 2; - hwif->OUTW(compat|1, hwif->config_data); - new = hwif->INW(hwif->config_data); + hwif->io_ports.ctl_addr = compat + 2; + outw(compat | 1, hwif->config_data); + new = inw(hwif->config_data); printk(KERN_INFO "%s: control basereg workaround: " "old=0x%04x, new=0x%04x\n", hwif->name, old, new & ~1); @@ -330,37 +300,74 @@ static void __devinit init_hwif_trm290(ide_hwif_t *hwif) #endif } -static ide_pci_device_t trm290_chipset __devinitdata = { - .name = "TRM290", +static const struct ide_tp_ops trm290_tp_ops = { + .exec_command = ide_exec_command, + .read_status = ide_read_status, + .read_altstatus = ide_read_altstatus, + .write_devctl = ide_write_devctl, + + .dev_select = trm290_dev_select, + .tf_load = ide_tf_load, + .tf_read = ide_tf_read, + + .input_data = ide_input_data, + .output_data = ide_output_data, +}; + +static struct ide_dma_ops trm290_dma_ops = { + .dma_host_set = trm290_dma_host_set, + .dma_setup = trm290_dma_setup, + .dma_start = trm290_dma_start, + .dma_end = trm290_dma_end, + .dma_test_irq = trm290_dma_test_irq, + .dma_lost_irq = ide_dma_lost_irq, + .dma_check = trm290_dma_check, +}; + +static const struct ide_port_info trm290_chipset = { + .name = DRV_NAME, .init_hwif = init_hwif_trm290, - .channels = 2, - .autodma = NOAUTODMA, - .bootable = ON_BOARD, + .tp_ops = &trm290_tp_ops, + .dma_ops = &trm290_dma_ops, + .host_flags = IDE_HFLAG_TRM290 | + IDE_HFLAG_NO_ATAPI_DMA | +#if 0 /* play it safe for now */ + IDE_HFLAG_TRUST_BIOS_FOR_DMA | +#endif + IDE_HFLAG_NO_AUTODMA | + IDE_HFLAG_NO_LBA48, }; -static int __devinit trm290_init_one(struct pci_dev *dev, const struct pci_device_id *id) +static int trm290_init_one(struct pci_dev *dev, const struct pci_device_id *id) { - return ide_setup_pci_device(dev, &trm290_chipset); + return ide_pci_init_one(dev, &trm290_chipset, NULL); } -static struct pci_device_id trm290_pci_tbl[] = { - { PCI_VENDOR_ID_TEKRAM, PCI_DEVICE_ID_TEKRAM_DC290, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, +static const struct pci_device_id trm290_pci_tbl[] = { + { PCI_VDEVICE(TEKRAM, PCI_DEVICE_ID_TEKRAM_DC290), 0 }, { 0, }, }; MODULE_DEVICE_TABLE(pci, trm290_pci_tbl); -static struct pci_driver driver = { +static struct pci_driver trm290_pci_driver = { .name = "TRM290_IDE", .id_table = trm290_pci_tbl, .probe = trm290_init_one, + .remove = ide_pci_remove, }; -static int trm290_ide_init(void) +static int __init trm290_ide_init(void) +{ + return ide_pci_register_driver(&trm290_pci_driver); +} + +static void __exit trm290_ide_exit(void) { - return ide_pci_register_driver(&driver); + pci_unregister_driver(&trm290_pci_driver); } module_init(trm290_ide_init); +module_exit(trm290_ide_exit); MODULE_AUTHOR("Mark Lord"); MODULE_DESCRIPTION("PCI driver module for Tekram TRM290 IDE"); diff --git a/drivers/ide/tx4938ide.c b/drivers/ide/tx4938ide.c new file mode 100644 index 00000000000..68edd4f58a2 --- /dev/null +++ b/drivers/ide/tx4938ide.c @@ -0,0 +1,210 @@ +/* + * TX4938 internal IDE driver + * Based on tx4939ide.c. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * (C) Copyright TOSHIBA CORPORATION 2005-2007 + */ + +#include <linux/module.h> +#include <linux/types.h> +#include <linux/ide.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/io.h> + +#include <asm/ide.h> +#include <asm/txx9/tx4938.h> + +static void tx4938ide_tune_ebusc(unsigned int ebus_ch, + unsigned int gbus_clock, + u8 pio) +{ + struct ide_timing *t = ide_timing_find_mode(XFER_PIO_0 + pio); + u64 cr = __raw_readq(&tx4938_ebuscptr->cr[ebus_ch]); + unsigned int sp = (cr >> 4) & 3; + unsigned int clock = gbus_clock / (4 - sp); + unsigned int cycle = 1000000000 / clock; + unsigned int shwt; + int wt; + + /* Minimum DIOx- active time */ + wt = DIV_ROUND_UP(t->act8b, cycle) - 2; + /* IORDY setup time: 35ns */ + wt = max_t(int, wt, DIV_ROUND_UP(35, cycle)); + /* actual wait-cycle is max(wt & ~1, 1) */ + if (wt > 2 && (wt & 1)) + wt++; + wt &= ~1; + /* Address-valid to DIOR/DIOW setup */ + shwt = DIV_ROUND_UP(t->setup, cycle); + + /* -DIOx recovery time (SHWT * 4) and cycle time requirement */ + while ((shwt * 4 + wt + (wt ? 2 : 3)) * cycle < t->cycle) + shwt++; + if (shwt > 7) { + pr_warning("tx4938ide: SHWT violation (%d)\n", shwt); + shwt = 7; + } + pr_debug("tx4938ide: ebus %d, bus cycle %dns, WT %d, SHWT %d\n", + ebus_ch, cycle, wt, shwt); + + __raw_writeq((cr & ~0x3f007ull) | (wt << 12) | shwt, + &tx4938_ebuscptr->cr[ebus_ch]); +} + +static void tx4938ide_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) +{ + struct tx4938ide_platform_info *pdata = dev_get_platdata(hwif->dev); + u8 safe = drive->pio_mode - XFER_PIO_0; + ide_drive_t *pair; + + pair = ide_get_pair_dev(drive); + if (pair) + safe = min_t(u8, safe, pair->pio_mode - XFER_PIO_0); + tx4938ide_tune_ebusc(pdata->ebus_ch, pdata->gbus_clock, safe); +} + +#ifdef __BIG_ENDIAN + +/* custom iops (independent from SWAP_IO_SPACE) */ +static void tx4938ide_input_data_swap(ide_drive_t *drive, struct ide_cmd *cmd, + void *buf, unsigned int len) +{ + unsigned long port = drive->hwif->io_ports.data_addr; + unsigned short *ptr = buf; + unsigned int count = (len + 1) / 2; + + while (count--) + *ptr++ = cpu_to_le16(__raw_readw((void __iomem *)port)); + __ide_flush_dcache_range((unsigned long)buf, roundup(len, 2)); +} + +static void tx4938ide_output_data_swap(ide_drive_t *drive, struct ide_cmd *cmd, + void *buf, unsigned int len) +{ + unsigned long port = drive->hwif->io_ports.data_addr; + unsigned short *ptr = buf; + unsigned int count = (len + 1) / 2; + + while (count--) { + __raw_writew(le16_to_cpu(*ptr), (void __iomem *)port); + ptr++; + } + __ide_flush_dcache_range((unsigned long)buf, roundup(len, 2)); +} + +static const struct ide_tp_ops tx4938ide_tp_ops = { + .exec_command = ide_exec_command, + .read_status = ide_read_status, + .read_altstatus = ide_read_altstatus, + .write_devctl = ide_write_devctl, + + .dev_select = ide_dev_select, + .tf_load = ide_tf_load, + .tf_read = ide_tf_read, + + .input_data = tx4938ide_input_data_swap, + .output_data = tx4938ide_output_data_swap, +}; + +#endif /* __BIG_ENDIAN */ + +static const struct ide_port_ops tx4938ide_port_ops = { + .set_pio_mode = tx4938ide_set_pio_mode, +}; + +static const struct ide_port_info tx4938ide_port_info __initconst = { + .port_ops = &tx4938ide_port_ops, +#ifdef __BIG_ENDIAN + .tp_ops = &tx4938ide_tp_ops, +#endif + .host_flags = IDE_HFLAG_MMIO | IDE_HFLAG_NO_DMA, + .pio_mask = ATA_PIO5, + .chipset = ide_generic, +}; + +static int __init tx4938ide_probe(struct platform_device *pdev) +{ + struct ide_hw hw, *hws[] = { &hw }; + struct ide_host *host; + struct resource *res; + struct tx4938ide_platform_info *pdata = dev_get_platdata(&pdev->dev); + int irq, ret, i; + unsigned long mapbase, mapctl; + struct ide_port_info d = tx4938ide_port_info; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return -ENODEV; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENODEV; + + if (!devm_request_mem_region(&pdev->dev, res->start, + resource_size(res), "tx4938ide")) + return -EBUSY; + mapbase = (unsigned long)devm_ioremap(&pdev->dev, res->start, + 8 << pdata->ioport_shift); + mapctl = (unsigned long)devm_ioremap(&pdev->dev, + res->start + 0x10000 + + (6 << pdata->ioport_shift), + 1 << pdata->ioport_shift); + if (!mapbase || !mapctl) + return -EBUSY; + + memset(&hw, 0, sizeof(hw)); + if (pdata->ioport_shift) { + unsigned long port = mapbase; + unsigned long ctl = mapctl; + + hw.io_ports_array[0] = port; +#ifdef __BIG_ENDIAN + port++; + ctl++; +#endif + for (i = 1; i <= 7; i++) + hw.io_ports_array[i] = + port + (i << pdata->ioport_shift); + hw.io_ports.ctl_addr = ctl; + } else + ide_std_init_ports(&hw, mapbase, mapctl); + hw.irq = irq; + hw.dev = &pdev->dev; + + pr_info("TX4938 IDE interface (base %#lx, ctl %#lx, irq %d)\n", + mapbase, mapctl, hw.irq); + if (pdata->gbus_clock) + tx4938ide_tune_ebusc(pdata->ebus_ch, pdata->gbus_clock, 0); + else + d.port_ops = NULL; + ret = ide_host_add(&d, hws, 1, &host); + if (!ret) + platform_set_drvdata(pdev, host); + return ret; +} + +static int __exit tx4938ide_remove(struct platform_device *pdev) +{ + struct ide_host *host = platform_get_drvdata(pdev); + + ide_host_remove(host); + return 0; +} + +static struct platform_driver tx4938ide_driver = { + .driver = { + .name = "tx4938ide", + .owner = THIS_MODULE, + }, + .remove = __exit_p(tx4938ide_remove), +}; + +module_platform_driver_probe(tx4938ide_driver, tx4938ide_probe); + +MODULE_DESCRIPTION("TX4938 internal IDE driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:tx4938ide"); diff --git a/drivers/ide/tx4939ide.c b/drivers/ide/tx4939ide.c new file mode 100644 index 00000000000..4ecdee5eca8 --- /dev/null +++ b/drivers/ide/tx4939ide.c @@ -0,0 +1,631 @@ +/* + * TX4939 internal IDE driver + * Based on RBTX49xx patch from CELF patch archive. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * (C) Copyright TOSHIBA CORPORATION 2005-2007 + */ + +#include <linux/module.h> +#include <linux/types.h> +#include <linux/ide.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/platform_device.h> +#include <linux/io.h> +#include <linux/scatterlist.h> + +#include <asm/ide.h> + +#define MODNAME "tx4939ide" + +/* ATA Shadow Registers (8-bit except for Data which is 16-bit) */ +#define TX4939IDE_Data 0x000 +#define TX4939IDE_Error_Feature 0x001 +#define TX4939IDE_Sec 0x002 +#define TX4939IDE_LBA0 0x003 +#define TX4939IDE_LBA1 0x004 +#define TX4939IDE_LBA2 0x005 +#define TX4939IDE_DevHead 0x006 +#define TX4939IDE_Stat_Cmd 0x007 +#define TX4939IDE_AltStat_DevCtl 0x402 +/* H/W DMA Registers */ +#define TX4939IDE_DMA_Cmd 0x800 /* 8-bit */ +#define TX4939IDE_DMA_Stat 0x802 /* 8-bit */ +#define TX4939IDE_PRD_Ptr 0x804 /* 32-bit */ +/* ATA100 CORE Registers (16-bit) */ +#define TX4939IDE_Sys_Ctl 0xc00 +#define TX4939IDE_Xfer_Cnt_1 0xc08 +#define TX4939IDE_Xfer_Cnt_2 0xc0a +#define TX4939IDE_Sec_Cnt 0xc10 +#define TX4939IDE_Start_Lo_Addr 0xc18 +#define TX4939IDE_Start_Up_Addr 0xc20 +#define TX4939IDE_Add_Ctl 0xc28 +#define TX4939IDE_Lo_Burst_Cnt 0xc30 +#define TX4939IDE_Up_Burst_Cnt 0xc38 +#define TX4939IDE_PIO_Addr 0xc88 +#define TX4939IDE_H_Rst_Tim 0xc90 +#define TX4939IDE_Int_Ctl 0xc98 +#define TX4939IDE_Pkt_Cmd 0xcb8 +#define TX4939IDE_Bxfer_Cnt_Hi 0xcc0 +#define TX4939IDE_Bxfer_Cnt_Lo 0xcc8 +#define TX4939IDE_Dev_TErr 0xcd0 +#define TX4939IDE_Pkt_Xfer_Ctl 0xcd8 +#define TX4939IDE_Start_TAddr 0xce0 + +/* bits for Int_Ctl */ +#define TX4939IDE_INT_ADDRERR 0x80 +#define TX4939IDE_INT_REACHMUL 0x40 +#define TX4939IDE_INT_DEVTIMING 0x20 +#define TX4939IDE_INT_UDMATERM 0x10 +#define TX4939IDE_INT_TIMER 0x08 +#define TX4939IDE_INT_BUSERR 0x04 +#define TX4939IDE_INT_XFEREND 0x02 +#define TX4939IDE_INT_HOST 0x01 + +#define TX4939IDE_IGNORE_INTS \ + (TX4939IDE_INT_ADDRERR | TX4939IDE_INT_REACHMUL | \ + TX4939IDE_INT_DEVTIMING | TX4939IDE_INT_UDMATERM | \ + TX4939IDE_INT_TIMER | TX4939IDE_INT_XFEREND) + +#ifdef __BIG_ENDIAN +#define tx4939ide_swizzlel(a) ((a) ^ 4) +#define tx4939ide_swizzlew(a) ((a) ^ 6) +#define tx4939ide_swizzleb(a) ((a) ^ 7) +#else +#define tx4939ide_swizzlel(a) (a) +#define tx4939ide_swizzlew(a) (a) +#define tx4939ide_swizzleb(a) (a) +#endif + +static u16 tx4939ide_readw(void __iomem *base, u32 reg) +{ + return __raw_readw(base + tx4939ide_swizzlew(reg)); +} +static u8 tx4939ide_readb(void __iomem *base, u32 reg) +{ + return __raw_readb(base + tx4939ide_swizzleb(reg)); +} +static void tx4939ide_writel(u32 val, void __iomem *base, u32 reg) +{ + __raw_writel(val, base + tx4939ide_swizzlel(reg)); +} +static void tx4939ide_writew(u16 val, void __iomem *base, u32 reg) +{ + __raw_writew(val, base + tx4939ide_swizzlew(reg)); +} +static void tx4939ide_writeb(u8 val, void __iomem *base, u32 reg) +{ + __raw_writeb(val, base + tx4939ide_swizzleb(reg)); +} + +#define TX4939IDE_BASE(hwif) ((void __iomem *)(hwif)->extra_base) + +static void tx4939ide_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) +{ + int is_slave = drive->dn; + u32 mask, val; + const u8 pio = drive->pio_mode - XFER_PIO_0; + u8 safe = pio; + ide_drive_t *pair; + + pair = ide_get_pair_dev(drive); + if (pair) + safe = min_t(u8, safe, pair->pio_mode - XFER_PIO_0); + /* + * Update Command Transfer Mode for master/slave and Data + * Transfer Mode for this drive. + */ + mask = is_slave ? 0x07f00000 : 0x000007f0; + val = ((safe << 8) | (pio << 4)) << (is_slave ? 16 : 0); + hwif->select_data = (hwif->select_data & ~mask) | val; + /* tx4939ide_tf_load_fixup() will set the Sys_Ctl register */ +} + +static void tx4939ide_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive) +{ + u32 mask, val; + const u8 mode = drive->dma_mode; + + /* Update Data Transfer Mode for this drive. */ + if (mode >= XFER_UDMA_0) + val = mode - XFER_UDMA_0 + 8; + else + val = mode - XFER_MW_DMA_0 + 5; + if (drive->dn) { + mask = 0x00f00000; + val <<= 20; + } else { + mask = 0x000000f0; + val <<= 4; + } + hwif->select_data = (hwif->select_data & ~mask) | val; + /* tx4939ide_tf_load_fixup() will set the Sys_Ctl register */ +} + +static u16 tx4939ide_check_error_ints(ide_hwif_t *hwif) +{ + void __iomem *base = TX4939IDE_BASE(hwif); + u16 ctl = tx4939ide_readw(base, TX4939IDE_Int_Ctl); + + if (ctl & TX4939IDE_INT_BUSERR) { + /* reset FIFO */ + u16 sysctl = tx4939ide_readw(base, TX4939IDE_Sys_Ctl); + + tx4939ide_writew(sysctl | 0x4000, base, TX4939IDE_Sys_Ctl); + mmiowb(); + /* wait 12GBUSCLK (typ. 60ns @ GBUS200MHz, max 270ns) */ + ndelay(270); + tx4939ide_writew(sysctl, base, TX4939IDE_Sys_Ctl); + } + if (ctl & (TX4939IDE_INT_ADDRERR | + TX4939IDE_INT_DEVTIMING | TX4939IDE_INT_BUSERR)) + pr_err("%s: Error interrupt %#x (%s%s%s )\n", + hwif->name, ctl, + ctl & TX4939IDE_INT_ADDRERR ? " Address-Error" : "", + ctl & TX4939IDE_INT_DEVTIMING ? " DEV-Timing" : "", + ctl & TX4939IDE_INT_BUSERR ? " Bus-Error" : ""); + return ctl; +} + +static void tx4939ide_clear_irq(ide_drive_t *drive) +{ + ide_hwif_t *hwif; + void __iomem *base; + u16 ctl; + + /* + * tx4939ide_dma_test_irq() and tx4939ide_dma_end() do all job + * for DMA case. + */ + if (drive->waiting_for_dma) + return; + hwif = drive->hwif; + base = TX4939IDE_BASE(hwif); + ctl = tx4939ide_check_error_ints(hwif); + tx4939ide_writew(ctl, base, TX4939IDE_Int_Ctl); +} + +static u8 tx4939ide_cable_detect(ide_hwif_t *hwif) +{ + void __iomem *base = TX4939IDE_BASE(hwif); + + return tx4939ide_readw(base, TX4939IDE_Sys_Ctl) & 0x2000 ? + ATA_CBL_PATA40 : ATA_CBL_PATA80; +} + +#ifdef __BIG_ENDIAN +static void tx4939ide_dma_host_set(ide_drive_t *drive, int on) +{ + ide_hwif_t *hwif = drive->hwif; + u8 unit = drive->dn; + void __iomem *base = TX4939IDE_BASE(hwif); + u8 dma_stat = tx4939ide_readb(base, TX4939IDE_DMA_Stat); + + if (on) + dma_stat |= (1 << (5 + unit)); + else + dma_stat &= ~(1 << (5 + unit)); + + tx4939ide_writeb(dma_stat, base, TX4939IDE_DMA_Stat); +} +#else +#define tx4939ide_dma_host_set ide_dma_host_set +#endif + +static u8 tx4939ide_clear_dma_status(void __iomem *base) +{ + u8 dma_stat; + + /* read DMA status for INTR & ERROR flags */ + dma_stat = tx4939ide_readb(base, TX4939IDE_DMA_Stat); + /* clear INTR & ERROR flags */ + tx4939ide_writeb(dma_stat | ATA_DMA_INTR | ATA_DMA_ERR, base, + TX4939IDE_DMA_Stat); + /* recover intmask cleared by writing to bit2 of DMA_Stat */ + tx4939ide_writew(TX4939IDE_IGNORE_INTS << 8, base, TX4939IDE_Int_Ctl); + return dma_stat; +} + +#ifdef __BIG_ENDIAN +/* custom ide_build_dmatable to handle swapped layout */ +static int tx4939ide_build_dmatable(ide_drive_t *drive, struct ide_cmd *cmd) +{ + ide_hwif_t *hwif = drive->hwif; + u32 *table = (u32 *)hwif->dmatable_cpu; + unsigned int count = 0; + int i; + struct scatterlist *sg; + + for_each_sg(hwif->sg_table, sg, cmd->sg_nents, i) { + u32 cur_addr, cur_len, bcount; + + cur_addr = sg_dma_address(sg); + cur_len = sg_dma_len(sg); + + /* + * Fill in the DMA table, without crossing any 64kB boundaries. + */ + + while (cur_len) { + if (count++ >= PRD_ENTRIES) + goto use_pio_instead; + + bcount = 0x10000 - (cur_addr & 0xffff); + if (bcount > cur_len) + bcount = cur_len; + /* + * This workaround for zero count seems required. + * (standard ide_build_dmatable does it too) + */ + if (bcount == 0x10000) + bcount = 0x8000; + *table++ = bcount & 0xffff; + *table++ = cur_addr; + cur_addr += bcount; + cur_len -= bcount; + } + } + + if (count) { + *(table - 2) |= 0x80000000; + return count; + } + +use_pio_instead: + printk(KERN_ERR "%s: %s\n", drive->name, + count ? "DMA table too small" : "empty DMA table?"); + + return 0; /* revert to PIO for this request */ +} +#else +#define tx4939ide_build_dmatable ide_build_dmatable +#endif + +static int tx4939ide_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd) +{ + ide_hwif_t *hwif = drive->hwif; + void __iomem *base = TX4939IDE_BASE(hwif); + u8 rw = (cmd->tf_flags & IDE_TFLAG_WRITE) ? 0 : ATA_DMA_WR; + + /* fall back to PIO! */ + if (tx4939ide_build_dmatable(drive, cmd) == 0) + return 1; + + /* PRD table */ + tx4939ide_writel(hwif->dmatable_dma, base, TX4939IDE_PRD_Ptr); + + /* specify r/w */ + tx4939ide_writeb(rw, base, TX4939IDE_DMA_Cmd); + + /* clear INTR & ERROR flags */ + tx4939ide_clear_dma_status(base); + + tx4939ide_writew(SECTOR_SIZE / 2, base, drive->dn ? + TX4939IDE_Xfer_Cnt_2 : TX4939IDE_Xfer_Cnt_1); + + tx4939ide_writew(blk_rq_sectors(cmd->rq), base, TX4939IDE_Sec_Cnt); + + return 0; +} + +static int tx4939ide_dma_end(ide_drive_t *drive) +{ + ide_hwif_t *hwif = drive->hwif; + u8 dma_stat, dma_cmd; + void __iomem *base = TX4939IDE_BASE(hwif); + u16 ctl = tx4939ide_readw(base, TX4939IDE_Int_Ctl); + + /* get DMA command mode */ + dma_cmd = tx4939ide_readb(base, TX4939IDE_DMA_Cmd); + /* stop DMA */ + tx4939ide_writeb(dma_cmd & ~ATA_DMA_START, base, TX4939IDE_DMA_Cmd); + + /* read and clear the INTR & ERROR bits */ + dma_stat = tx4939ide_clear_dma_status(base); + +#define CHECK_DMA_MASK (ATA_DMA_ACTIVE | ATA_DMA_ERR | ATA_DMA_INTR) + + /* verify good DMA status */ + if ((dma_stat & CHECK_DMA_MASK) == 0 && + (ctl & (TX4939IDE_INT_XFEREND | TX4939IDE_INT_HOST)) == + (TX4939IDE_INT_XFEREND | TX4939IDE_INT_HOST)) + /* INT_IDE lost... bug? */ + return 0; + return ((dma_stat & CHECK_DMA_MASK) != + ATA_DMA_INTR) ? 0x10 | dma_stat : 0; +} + +/* returns 1 if DMA IRQ issued, 0 otherwise */ +static int tx4939ide_dma_test_irq(ide_drive_t *drive) +{ + ide_hwif_t *hwif = drive->hwif; + void __iomem *base = TX4939IDE_BASE(hwif); + u16 ctl, ide_int; + u8 dma_stat, stat; + int found = 0; + + ctl = tx4939ide_check_error_ints(hwif); + ide_int = ctl & (TX4939IDE_INT_XFEREND | TX4939IDE_INT_HOST); + switch (ide_int) { + case TX4939IDE_INT_HOST: + /* On error, XFEREND might not be asserted. */ + stat = tx4939ide_readb(base, TX4939IDE_AltStat_DevCtl); + if ((stat & (ATA_BUSY | ATA_DRQ | ATA_ERR)) == ATA_ERR) + found = 1; + else + /* Wait for XFEREND (Mask HOST and unmask XFEREND) */ + ctl &= ~TX4939IDE_INT_XFEREND << 8; + ctl |= ide_int << 8; + break; + case TX4939IDE_INT_HOST | TX4939IDE_INT_XFEREND: + dma_stat = tx4939ide_readb(base, TX4939IDE_DMA_Stat); + if (!(dma_stat & ATA_DMA_INTR)) + pr_warning("%s: weird interrupt status. " + "DMA_Stat %#02x int_ctl %#04x\n", + hwif->name, dma_stat, ctl); + found = 1; + break; + } + /* + * Do not clear XFEREND, HOST now. They will be cleared by + * clearing bit2 of DMA_Stat. + */ + ctl &= ~ide_int; + tx4939ide_writew(ctl, base, TX4939IDE_Int_Ctl); + return found; +} + +#ifdef __BIG_ENDIAN +static u8 tx4939ide_dma_sff_read_status(ide_hwif_t *hwif) +{ + void __iomem *base = TX4939IDE_BASE(hwif); + + return tx4939ide_readb(base, TX4939IDE_DMA_Stat); +} +#else +#define tx4939ide_dma_sff_read_status ide_dma_sff_read_status +#endif + +static void tx4939ide_init_hwif(ide_hwif_t *hwif) +{ + void __iomem *base = TX4939IDE_BASE(hwif); + + /* Soft Reset */ + tx4939ide_writew(0x8000, base, TX4939IDE_Sys_Ctl); + mmiowb(); + /* at least 20 GBUSCLK (typ. 100ns @ GBUS200MHz, max 450ns) */ + ndelay(450); + tx4939ide_writew(0x0000, base, TX4939IDE_Sys_Ctl); + /* mask some interrupts and clear all interrupts */ + tx4939ide_writew((TX4939IDE_IGNORE_INTS << 8) | 0xff, base, + TX4939IDE_Int_Ctl); + + tx4939ide_writew(0x0008, base, TX4939IDE_Lo_Burst_Cnt); + tx4939ide_writew(0, base, TX4939IDE_Up_Burst_Cnt); +} + +static int tx4939ide_init_dma(ide_hwif_t *hwif, const struct ide_port_info *d) +{ + hwif->dma_base = + hwif->extra_base + tx4939ide_swizzleb(TX4939IDE_DMA_Cmd); + /* + * Note that we cannot use ATA_DMA_TABLE_OFS, ATA_DMA_STATUS + * for big endian. + */ + return ide_allocate_dma_engine(hwif); +} + +static void tx4939ide_tf_load_fixup(ide_drive_t *drive) +{ + ide_hwif_t *hwif = drive->hwif; + void __iomem *base = TX4939IDE_BASE(hwif); + u16 sysctl = hwif->select_data >> (drive->dn ? 16 : 0); + + /* + * Fix ATA100 CORE System Control Register. (The write to the + * Device/Head register may write wrong data to the System + * Control Register) + * While Sys_Ctl is written here, dev_select() is not needed. + */ + tx4939ide_writew(sysctl, base, TX4939IDE_Sys_Ctl); +} + +static void tx4939ide_tf_load(ide_drive_t *drive, struct ide_taskfile *tf, + u8 valid) +{ + ide_tf_load(drive, tf, valid); + + if (valid & IDE_VALID_DEVICE) + tx4939ide_tf_load_fixup(drive); +} + +#ifdef __BIG_ENDIAN + +/* custom iops (independent from SWAP_IO_SPACE) */ +static void tx4939ide_input_data_swap(ide_drive_t *drive, struct ide_cmd *cmd, + void *buf, unsigned int len) +{ + unsigned long port = drive->hwif->io_ports.data_addr; + unsigned short *ptr = buf; + unsigned int count = (len + 1) / 2; + + while (count--) + *ptr++ = cpu_to_le16(__raw_readw((void __iomem *)port)); + __ide_flush_dcache_range((unsigned long)buf, roundup(len, 2)); +} + +static void tx4939ide_output_data_swap(ide_drive_t *drive, struct ide_cmd *cmd, + void *buf, unsigned int len) +{ + unsigned long port = drive->hwif->io_ports.data_addr; + unsigned short *ptr = buf; + unsigned int count = (len + 1) / 2; + + while (count--) { + __raw_writew(le16_to_cpu(*ptr), (void __iomem *)port); + ptr++; + } + __ide_flush_dcache_range((unsigned long)buf, roundup(len, 2)); +} + +static const struct ide_tp_ops tx4939ide_tp_ops = { + .exec_command = ide_exec_command, + .read_status = ide_read_status, + .read_altstatus = ide_read_altstatus, + .write_devctl = ide_write_devctl, + + .dev_select = ide_dev_select, + .tf_load = tx4939ide_tf_load, + .tf_read = ide_tf_read, + + .input_data = tx4939ide_input_data_swap, + .output_data = tx4939ide_output_data_swap, +}; + +#else /* __LITTLE_ENDIAN */ + +static const struct ide_tp_ops tx4939ide_tp_ops = { + .exec_command = ide_exec_command, + .read_status = ide_read_status, + .read_altstatus = ide_read_altstatus, + .write_devctl = ide_write_devctl, + + .dev_select = ide_dev_select, + .tf_load = tx4939ide_tf_load, + .tf_read = ide_tf_read, + + .input_data = ide_input_data, + .output_data = ide_output_data, +}; + +#endif /* __LITTLE_ENDIAN */ + +static const struct ide_port_ops tx4939ide_port_ops = { + .set_pio_mode = tx4939ide_set_pio_mode, + .set_dma_mode = tx4939ide_set_dma_mode, + .clear_irq = tx4939ide_clear_irq, + .cable_detect = tx4939ide_cable_detect, +}; + +static const struct ide_dma_ops tx4939ide_dma_ops = { + .dma_host_set = tx4939ide_dma_host_set, + .dma_setup = tx4939ide_dma_setup, + .dma_start = ide_dma_start, + .dma_end = tx4939ide_dma_end, + .dma_test_irq = tx4939ide_dma_test_irq, + .dma_lost_irq = ide_dma_lost_irq, + .dma_timer_expiry = ide_dma_sff_timer_expiry, + .dma_sff_read_status = tx4939ide_dma_sff_read_status, +}; + +static const struct ide_port_info tx4939ide_port_info __initconst = { + .init_hwif = tx4939ide_init_hwif, + .init_dma = tx4939ide_init_dma, + .port_ops = &tx4939ide_port_ops, + .dma_ops = &tx4939ide_dma_ops, + .tp_ops = &tx4939ide_tp_ops, + .host_flags = IDE_HFLAG_MMIO, + .pio_mask = ATA_PIO4, + .mwdma_mask = ATA_MWDMA2, + .udma_mask = ATA_UDMA5, + .chipset = ide_generic, +}; + +static int __init tx4939ide_probe(struct platform_device *pdev) +{ + struct ide_hw hw, *hws[] = { &hw }; + struct ide_host *host; + struct resource *res; + int irq, ret; + unsigned long mapbase; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return -ENODEV; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENODEV; + + if (!devm_request_mem_region(&pdev->dev, res->start, + resource_size(res), "tx4938ide")) + return -EBUSY; + mapbase = (unsigned long)devm_ioremap(&pdev->dev, res->start, + resource_size(res)); + if (!mapbase) + return -EBUSY; + memset(&hw, 0, sizeof(hw)); + hw.io_ports.data_addr = + mapbase + tx4939ide_swizzlew(TX4939IDE_Data); + hw.io_ports.error_addr = + mapbase + tx4939ide_swizzleb(TX4939IDE_Error_Feature); + hw.io_ports.nsect_addr = + mapbase + tx4939ide_swizzleb(TX4939IDE_Sec); + hw.io_ports.lbal_addr = + mapbase + tx4939ide_swizzleb(TX4939IDE_LBA0); + hw.io_ports.lbam_addr = + mapbase + tx4939ide_swizzleb(TX4939IDE_LBA1); + hw.io_ports.lbah_addr = + mapbase + tx4939ide_swizzleb(TX4939IDE_LBA2); + hw.io_ports.device_addr = + mapbase + tx4939ide_swizzleb(TX4939IDE_DevHead); + hw.io_ports.command_addr = + mapbase + tx4939ide_swizzleb(TX4939IDE_Stat_Cmd); + hw.io_ports.ctl_addr = + mapbase + tx4939ide_swizzleb(TX4939IDE_AltStat_DevCtl); + hw.irq = irq; + hw.dev = &pdev->dev; + + pr_info("TX4939 IDE interface (base %#lx, irq %d)\n", mapbase, irq); + host = ide_host_alloc(&tx4939ide_port_info, hws, 1); + if (!host) + return -ENOMEM; + /* use extra_base for base address of the all registers */ + host->ports[0]->extra_base = mapbase; + ret = ide_host_register(host, &tx4939ide_port_info, hws); + if (ret) { + ide_host_free(host); + return ret; + } + platform_set_drvdata(pdev, host); + return 0; +} + +static int __exit tx4939ide_remove(struct platform_device *pdev) +{ + struct ide_host *host = platform_get_drvdata(pdev); + + ide_host_remove(host); + return 0; +} + +#ifdef CONFIG_PM +static int tx4939ide_resume(struct platform_device *dev) +{ + struct ide_host *host = platform_get_drvdata(dev); + ide_hwif_t *hwif = host->ports[0]; + + tx4939ide_init_hwif(hwif); + return 0; +} +#else +#define tx4939ide_resume NULL +#endif + +static struct platform_driver tx4939ide_driver = { + .driver = { + .name = MODNAME, + .owner = THIS_MODULE, + }, + .remove = __exit_p(tx4939ide_remove), + .resume = tx4939ide_resume, +}; + +module_platform_driver_probe(tx4939ide_driver, tx4939ide_probe); + +MODULE_DESCRIPTION("TX4939 internal IDE driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:tx4939ide"); diff --git a/drivers/ide/legacy/umc8672.c b/drivers/ide/umc8672.c index 6e2c58c5f6a..3aa0fea0f3d 100644 --- a/drivers/ide/legacy/umc8672.c +++ b/drivers/ide/umc8672.c @@ -1,6 +1,4 @@ /* - * linux/drivers/ide/legacy/umc8672.c Version 0.05 Jul 31, 1996 - * * Copyright (C) 1995-1996 Linus Torvalds & author (see below) */ @@ -21,7 +19,7 @@ */ /* - * VLB Controller Support from + * VLB Controller Support from * Wolfram Podien * Rohoefe 3 * D28832 Achim @@ -34,7 +32,7 @@ * #define UMC_DRIVE0 11 * in the beginning of the driver, which sets the speed of drive 0 to 11 (there * are some lines present). 0 - 11 are allowed speed values. These values are - * the results from the DOS speed test program supplied from UMC. 11 is the + * the results from the DOS speed test program supplied from UMC. 11 is the * highest speed (about PIO mode 3) */ #define REALLY_SLOW_IO /* some systems can safely undef this */ @@ -47,12 +45,13 @@ #include <linux/mm.h> #include <linux/ioport.h> #include <linux/blkdev.h> -#include <linux/hdreg.h> #include <linux/ide.h> #include <linux/init.h> #include <asm/io.h> +#define DRV_NAME "umc8672" + /* * Default speeds. These can be changed with "auto-tune" and/or hdparm. */ @@ -62,120 +61,122 @@ #define UMC_DRIVE3 1 /* In case of crash reduce speed */ static u8 current_speeds[4] = {UMC_DRIVE0, UMC_DRIVE1, UMC_DRIVE2, UMC_DRIVE3}; -static const u8 pio_to_umc [5] = {0,3,7,10,11}; /* rough guesses */ +static const u8 pio_to_umc [5] = {0, 3, 7, 10, 11}; /* rough guesses */ /* 0 1 2 3 4 5 6 7 8 9 10 11 */ static const u8 speedtab [3][12] = { - {0xf, 0xb, 0x2, 0x2, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 }, - {0x3, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 }, - {0xff,0xcb,0xc0,0x58,0x36,0x33,0x23,0x22,0x21,0x11,0x10,0x0}}; + {0x0f, 0x0b, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x1}, + {0x03, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x1}, + {0xff, 0xcb, 0xc0, 0x58, 0x36, 0x33, 0x23, 0x22, 0x21, 0x11, 0x10, 0x0} +}; -static void out_umc (char port,char wert) +static void out_umc(char port, char wert) { - outb_p(port,0x108); - outb_p(wert,0x109); + outb_p(port, 0x108); + outb_p(wert, 0x109); } -static inline u8 in_umc (char port) +static inline u8 in_umc(char port) { - outb_p(port,0x108); + outb_p(port, 0x108); return inb_p(0x109); } -static void umc_set_speeds (u8 speeds[]) +static void umc_set_speeds(u8 speeds[]) { int i, tmp; - outb_p(0x5A,0x108); /* enable umc */ + outb_p(0x5A, 0x108); /* enable umc */ - out_umc (0xd7,(speedtab[0][speeds[2]] | (speedtab[0][speeds[3]]<<4))); - out_umc (0xd6,(speedtab[0][speeds[0]] | (speedtab[0][speeds[1]]<<4))); + out_umc(0xd7, (speedtab[0][speeds[2]] | (speedtab[0][speeds[3]]<<4))); + out_umc(0xd6, (speedtab[0][speeds[0]] | (speedtab[0][speeds[1]]<<4))); tmp = 0; - for (i = 3; i >= 0; i--) { + for (i = 3; i >= 0; i--) tmp = (tmp << 2) | speedtab[1][speeds[i]]; + out_umc(0xdc, tmp); + for (i = 0; i < 4; i++) { + out_umc(0xd0 + i, speedtab[2][speeds[i]]); + out_umc(0xd8 + i, speedtab[2][speeds[i]]); } - out_umc (0xdc,tmp); - for (i = 0;i < 4; i++) { - out_umc (0xd0+i,speedtab[2][speeds[i]]); - out_umc (0xd8+i,speedtab[2][speeds[i]]); - } - outb_p(0xa5,0x108); /* disable umc */ + outb_p(0xa5, 0x108); /* disable umc */ - printk ("umc8672: drive speeds [0 to 11]: %d %d %d %d\n", + printk("umc8672: drive speeds [0 to 11]: %d %d %d %d\n", speeds[0], speeds[1], speeds[2], speeds[3]); } -static void tune_umc (ide_drive_t *drive, u8 pio) +static void umc_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) { - unsigned long flags; - ide_hwgroup_t *hwgroup = ide_hwifs[HWIF(drive)->index^1].hwgroup; + ide_hwif_t *mate = hwif->mate; + unsigned long uninitialized_var(flags); + const u8 pio = drive->pio_mode - XFER_PIO_0; - pio = ide_get_best_pio_mode(drive, pio, 4, NULL); printk("%s: setting umc8672 to PIO mode%d (speed %d)\n", drive->name, pio, pio_to_umc[pio]); - spin_lock_irqsave(&ide_lock, flags); - if (hwgroup && hwgroup->handler != NULL) { + if (mate) + spin_lock_irqsave(&mate->lock, flags); + if (mate && mate->handler) { printk(KERN_ERR "umc8672: other interface is busy: exiting tune_umc()\n"); } else { current_speeds[drive->name[2] - 'a'] = pio_to_umc[pio]; - umc_set_speeds (current_speeds); + umc_set_speeds(current_speeds); } - spin_unlock_irqrestore(&ide_lock, flags); + if (mate) + spin_unlock_irqrestore(&mate->lock, flags); } +static const struct ide_port_ops umc8672_port_ops = { + .set_pio_mode = umc_set_pio_mode, +}; + +static const struct ide_port_info umc8672_port_info __initconst = { + .name = DRV_NAME, + .chipset = ide_umc8672, + .port_ops = &umc8672_port_ops, + .host_flags = IDE_HFLAG_NO_DMA, + .pio_mask = ATA_PIO4, +}; + static int __init umc8672_probe(void) { unsigned long flags; - ide_hwif_t *hwif, *mate; if (!request_region(0x108, 2, "umc8672")) { printk(KERN_ERR "umc8672: ports 0x108-0x109 already in use.\n"); return 1; } local_irq_save(flags); - outb_p(0x5A,0x108); /* enable umc */ + outb_p(0x5A, 0x108); /* enable umc */ if (in_umc (0xd5) != 0xa0) { local_irq_restore(flags); printk(KERN_ERR "umc8672: not found\n"); release_region(0x108, 2); - return 1; + return 1; } - outb_p(0xa5,0x108); /* disable umc */ + outb_p(0xa5, 0x108); /* disable umc */ - umc_set_speeds (current_speeds); + umc_set_speeds(current_speeds); local_irq_restore(flags); - hwif = &ide_hwifs[0]; - mate = &ide_hwifs[1]; - - hwif->chipset = ide_umc8672; - hwif->tuneproc = &tune_umc; - hwif->mate = mate; - - mate->chipset = ide_umc8672; - mate->tuneproc = &tune_umc; - mate->mate = hwif; - mate->channel = 1; - - probe_hwif_init(hwif); - probe_hwif_init(mate); + return ide_legacy_device_add(&umc8672_port_info, 0); +} - create_proc_ide_interfaces(); +static bool probe_umc8672; - return 0; -} +module_param_named(probe, probe_umc8672, bool, 0); +MODULE_PARM_DESC(probe, "probe for UMC8672 chipset"); -/* Can be called directly from ide.c. */ -int __init umc8672_init(void) +static int __init umc8672_init(void) { - if (umc8672_probe()) - return -ENODEV; - return 0; + if (probe_umc8672 == 0) + goto out; + + if (umc8672_probe() == 0) + return 0; +out: + return -ENODEV; } -#ifdef MODULE module_init(umc8672_init); -#endif MODULE_AUTHOR("Wolfram Podien"); MODULE_DESCRIPTION("Support for UMC 8672 IDE chipset"); diff --git a/drivers/ide/via82cxxx.c b/drivers/ide/via82cxxx.c new file mode 100644 index 00000000000..01464f1e233 --- /dev/null +++ b/drivers/ide/via82cxxx.c @@ -0,0 +1,537 @@ +/* + * VIA IDE driver for Linux. Supported southbridges: + * + * vt82c576, vt82c586, vt82c586a, vt82c586b, vt82c596a, vt82c596b, + * vt82c686, vt82c686a, vt82c686b, vt8231, vt8233, vt8233c, vt8233a, + * vt8235, vt8237, vt8237a + * + * Copyright (c) 2000-2002 Vojtech Pavlik + * Copyright (c) 2007-2010 Bartlomiej Zolnierkiewicz + * + * Based on the work of: + * Michel Aubry + * Jeff Garzik + * Andre Hedrick + * + * Documentation: + * Obsolete device documentation publicly available from via.com.tw + * Current device documentation available under NDA only + */ + +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/pci.h> +#include <linux/init.h> +#include <linux/ide.h> +#include <linux/dmi.h> + +#ifdef CONFIG_PPC_CHRP +#include <asm/processor.h> +#endif + +#define DRV_NAME "via82cxxx" + +#define VIA_IDE_ENABLE 0x40 +#define VIA_IDE_CONFIG 0x41 +#define VIA_FIFO_CONFIG 0x43 +#define VIA_MISC_1 0x44 +#define VIA_MISC_2 0x45 +#define VIA_MISC_3 0x46 +#define VIA_DRIVE_TIMING 0x48 +#define VIA_8BIT_TIMING 0x4e +#define VIA_ADDRESS_SETUP 0x4c +#define VIA_UDMA_TIMING 0x50 + +#define VIA_BAD_PREQ 0x01 /* Crashes if PREQ# till DDACK# set */ +#define VIA_BAD_CLK66 0x02 /* 66 MHz clock doesn't work correctly */ +#define VIA_SET_FIFO 0x04 /* Needs to have FIFO split set */ +#define VIA_NO_UNMASK 0x08 /* Doesn't work with IRQ unmasking on */ +#define VIA_BAD_ID 0x10 /* Has wrong vendor ID (0x1107) */ +#define VIA_BAD_AST 0x20 /* Don't touch Address Setup Timing */ +#define VIA_SATA_PATA 0x80 /* SATA/PATA combined configuration */ + +enum { + VIA_IDFLAG_SINGLE = (1 << 1), /* single channel controller */ +}; + +/* + * VIA SouthBridge chips. + */ + +static struct via_isa_bridge { + char *name; + u16 id; + u8 rev_min; + u8 rev_max; + u8 udma_mask; + u8 flags; +} via_isa_bridges[] = { + { "vx855", PCI_DEVICE_ID_VIA_VX855, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST | VIA_SATA_PATA }, + { "vx800", PCI_DEVICE_ID_VIA_VX800, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST | VIA_SATA_PATA }, + { "cx700", PCI_DEVICE_ID_VIA_CX700, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST | VIA_SATA_PATA }, + { "vt8261", PCI_DEVICE_ID_VIA_8261, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST }, + { "vt8237s", PCI_DEVICE_ID_VIA_8237S, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST }, + { "vt6410", PCI_DEVICE_ID_VIA_6410, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST }, + { "vt6415", PCI_DEVICE_ID_VIA_6415, 0x00, 0xff, ATA_UDMA6, VIA_BAD_AST }, + { "vt8251", PCI_DEVICE_ID_VIA_8251, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST }, + { "vt8237", PCI_DEVICE_ID_VIA_8237, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST }, + { "vt8237a", PCI_DEVICE_ID_VIA_8237A, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST }, + { "vt8235", PCI_DEVICE_ID_VIA_8235, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST }, + { "vt8233a", PCI_DEVICE_ID_VIA_8233A, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST }, + { "vt8233c", PCI_DEVICE_ID_VIA_8233C_0, 0x00, 0x2f, ATA_UDMA5, }, + { "vt8233", PCI_DEVICE_ID_VIA_8233_0, 0x00, 0x2f, ATA_UDMA5, }, + { "vt8231", PCI_DEVICE_ID_VIA_8231, 0x00, 0x2f, ATA_UDMA5, }, + { "vt82c686b", PCI_DEVICE_ID_VIA_82C686, 0x40, 0x4f, ATA_UDMA5, }, + { "vt82c686a", PCI_DEVICE_ID_VIA_82C686, 0x10, 0x2f, ATA_UDMA4, }, + { "vt82c686", PCI_DEVICE_ID_VIA_82C686, 0x00, 0x0f, ATA_UDMA2, VIA_BAD_CLK66 }, + { "vt82c596b", PCI_DEVICE_ID_VIA_82C596, 0x10, 0x2f, ATA_UDMA4, }, + { "vt82c596a", PCI_DEVICE_ID_VIA_82C596, 0x00, 0x0f, ATA_UDMA2, VIA_BAD_CLK66 }, + { "vt82c586b", PCI_DEVICE_ID_VIA_82C586_0, 0x47, 0x4f, ATA_UDMA2, VIA_SET_FIFO }, + { "vt82c586b", PCI_DEVICE_ID_VIA_82C586_0, 0x40, 0x46, ATA_UDMA2, VIA_SET_FIFO | VIA_BAD_PREQ }, + { "vt82c586b", PCI_DEVICE_ID_VIA_82C586_0, 0x30, 0x3f, ATA_UDMA2, VIA_SET_FIFO }, + { "vt82c586a", PCI_DEVICE_ID_VIA_82C586_0, 0x20, 0x2f, ATA_UDMA2, VIA_SET_FIFO }, + { "vt82c586", PCI_DEVICE_ID_VIA_82C586_0, 0x00, 0x0f, 0x00, VIA_SET_FIFO }, + { "vt82c576", PCI_DEVICE_ID_VIA_82C576, 0x00, 0x2f, 0x00, VIA_SET_FIFO | VIA_NO_UNMASK }, + { "vt82c576", PCI_DEVICE_ID_VIA_82C576, 0x00, 0x2f, 0x00, VIA_SET_FIFO | VIA_NO_UNMASK | VIA_BAD_ID }, + { "vtxxxx", PCI_DEVICE_ID_VIA_ANON, 0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST }, + { NULL } +}; + +static unsigned int via_clock; +static char *via_dma[] = { "16", "25", "33", "44", "66", "100", "133" }; + +struct via82cxxx_dev +{ + struct via_isa_bridge *via_config; + unsigned int via_80w; +}; + +/** + * via_set_speed - write timing registers + * @dev: PCI device + * @dn: device + * @timing: IDE timing data to use + * + * via_set_speed writes timing values to the chipset registers + */ + +static void via_set_speed(ide_hwif_t *hwif, u8 dn, struct ide_timing *timing) +{ + struct pci_dev *dev = to_pci_dev(hwif->dev); + struct ide_host *host = pci_get_drvdata(dev); + struct via82cxxx_dev *vdev = host->host_priv; + u8 t; + + if (~vdev->via_config->flags & VIA_BAD_AST) { + pci_read_config_byte(dev, VIA_ADDRESS_SETUP, &t); + t = (t & ~(3 << ((3 - dn) << 1))) | ((clamp_val(timing->setup, 1, 4) - 1) << ((3 - dn) << 1)); + pci_write_config_byte(dev, VIA_ADDRESS_SETUP, t); + } + + pci_write_config_byte(dev, VIA_8BIT_TIMING + (1 - (dn >> 1)), + ((clamp_val(timing->act8b, 1, 16) - 1) << 4) | (clamp_val(timing->rec8b, 1, 16) - 1)); + + pci_write_config_byte(dev, VIA_DRIVE_TIMING + (3 - dn), + ((clamp_val(timing->active, 1, 16) - 1) << 4) | (clamp_val(timing->recover, 1, 16) - 1)); + + switch (vdev->via_config->udma_mask) { + case ATA_UDMA2: t = timing->udma ? (0xe0 | (clamp_val(timing->udma, 2, 5) - 2)) : 0x03; break; + case ATA_UDMA4: t = timing->udma ? (0xe8 | (clamp_val(timing->udma, 2, 9) - 2)) : 0x0f; break; + case ATA_UDMA5: t = timing->udma ? (0xe0 | (clamp_val(timing->udma, 2, 9) - 2)) : 0x07; break; + case ATA_UDMA6: t = timing->udma ? (0xe0 | (clamp_val(timing->udma, 2, 9) - 2)) : 0x07; break; + } + + /* Set UDMA unless device is not UDMA capable */ + if (vdev->via_config->udma_mask) { + u8 udma_etc; + + pci_read_config_byte(dev, VIA_UDMA_TIMING + 3 - dn, &udma_etc); + + /* clear transfer mode bit */ + udma_etc &= ~0x20; + + if (timing->udma) { + /* preserve 80-wire cable detection bit */ + udma_etc &= 0x10; + udma_etc |= t; + } + + pci_write_config_byte(dev, VIA_UDMA_TIMING + 3 - dn, udma_etc); + } +} + +/** + * via_set_drive - configure transfer mode + * @hwif: port + * @drive: Drive to set up + * + * via_set_drive() computes timing values configures the chipset to + * a desired transfer mode. It also can be called by upper layers. + */ + +static void via_set_drive(ide_hwif_t *hwif, ide_drive_t *drive) +{ + ide_drive_t *peer = ide_get_pair_dev(drive); + struct pci_dev *dev = to_pci_dev(hwif->dev); + struct ide_host *host = pci_get_drvdata(dev); + struct via82cxxx_dev *vdev = host->host_priv; + struct ide_timing t, p; + unsigned int T, UT; + const u8 speed = drive->dma_mode; + + T = 1000000000 / via_clock; + + switch (vdev->via_config->udma_mask) { + case ATA_UDMA2: UT = T; break; + case ATA_UDMA4: UT = T/2; break; + case ATA_UDMA5: UT = T/3; break; + case ATA_UDMA6: UT = T/4; break; + default: UT = T; + } + + ide_timing_compute(drive, speed, &t, T, UT); + + if (peer) { + ide_timing_compute(peer, peer->pio_mode, &p, T, UT); + ide_timing_merge(&p, &t, &t, IDE_TIMING_8BIT); + } + + via_set_speed(hwif, drive->dn, &t); +} + +/** + * via_set_pio_mode - set host controller for PIO mode + * @hwif: port + * @drive: drive + * + * A callback from the upper layers for PIO-only tuning. + */ + +static void via_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) +{ + drive->dma_mode = drive->pio_mode; + via_set_drive(hwif, drive); +} + +static struct via_isa_bridge *via_config_find(struct pci_dev **isa) +{ + struct via_isa_bridge *via_config; + + for (via_config = via_isa_bridges; + via_config->id != PCI_DEVICE_ID_VIA_ANON; via_config++) + if ((*isa = pci_get_device(PCI_VENDOR_ID_VIA + + !!(via_config->flags & VIA_BAD_ID), + via_config->id, NULL))) { + + if ((*isa)->revision >= via_config->rev_min && + (*isa)->revision <= via_config->rev_max) + break; + pci_dev_put(*isa); + } + + return via_config; +} + +/* + * Check and handle 80-wire cable presence + */ +static void via_cable_detect(struct via82cxxx_dev *vdev, u32 u) +{ + int i; + + switch (vdev->via_config->udma_mask) { + case ATA_UDMA4: + for (i = 24; i >= 0; i -= 8) + if (((u >> (i & 16)) & 8) && + ((u >> i) & 0x20) && + (((u >> i) & 7) < 2)) { + /* + * 2x PCI clock and + * UDMA w/ < 3T/cycle + */ + vdev->via_80w |= (1 << (1 - (i >> 4))); + } + break; + + case ATA_UDMA5: + for (i = 24; i >= 0; i -= 8) + if (((u >> i) & 0x10) || + (((u >> i) & 0x20) && + (((u >> i) & 7) < 4))) { + /* BIOS 80-wire bit or + * UDMA w/ < 60ns/cycle + */ + vdev->via_80w |= (1 << (1 - (i >> 4))); + } + break; + + case ATA_UDMA6: + for (i = 24; i >= 0; i -= 8) + if (((u >> i) & 0x10) || + (((u >> i) & 0x20) && + (((u >> i) & 7) < 6))) { + /* BIOS 80-wire bit or + * UDMA w/ < 60ns/cycle + */ + vdev->via_80w |= (1 << (1 - (i >> 4))); + } + break; + } +} + +/** + * init_chipset_via82cxxx - initialization handler + * @dev: PCI device + * + * The initialization callback. Here we determine the IDE chip type + * and initialize its drive independent registers. + */ + +static int init_chipset_via82cxxx(struct pci_dev *dev) +{ + struct ide_host *host = pci_get_drvdata(dev); + struct via82cxxx_dev *vdev = host->host_priv; + struct via_isa_bridge *via_config = vdev->via_config; + u8 t, v; + u32 u; + + /* + * Detect cable and configure Clk66 + */ + pci_read_config_dword(dev, VIA_UDMA_TIMING, &u); + + via_cable_detect(vdev, u); + + if (via_config->udma_mask == ATA_UDMA4) { + /* Enable Clk66 */ + pci_write_config_dword(dev, VIA_UDMA_TIMING, u|0x80008); + } else if (via_config->flags & VIA_BAD_CLK66) { + /* Would cause trouble on 596a and 686 */ + pci_write_config_dword(dev, VIA_UDMA_TIMING, u & ~0x80008); + } + + /* + * Check whether interfaces are enabled. + */ + + pci_read_config_byte(dev, VIA_IDE_ENABLE, &v); + + /* + * Set up FIFO sizes and thresholds. + */ + + pci_read_config_byte(dev, VIA_FIFO_CONFIG, &t); + + /* Disable PREQ# till DDACK# */ + if (via_config->flags & VIA_BAD_PREQ) { + /* Would crash on 586b rev 41 */ + t &= 0x7f; + } + + /* Fix FIFO split between channels */ + if (via_config->flags & VIA_SET_FIFO) { + t &= (t & 0x9f); + switch (v & 3) { + case 2: t |= 0x00; break; /* 16 on primary */ + case 1: t |= 0x60; break; /* 16 on secondary */ + case 3: t |= 0x20; break; /* 8 pri 8 sec */ + } + } + + pci_write_config_byte(dev, VIA_FIFO_CONFIG, t); + + return 0; +} + +/* + * Cable special cases + */ + +static const struct dmi_system_id cable_dmi_table[] = { + { + .ident = "Acer Ferrari 3400", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "Acer,Inc."), + DMI_MATCH(DMI_BOARD_NAME, "Ferrari 3400"), + }, + }, + { } +}; + +static int via_cable_override(struct pci_dev *pdev) +{ + /* Systems by DMI */ + if (dmi_check_system(cable_dmi_table)) + return 1; + + /* Arima W730-K8/Targa Visionary 811/... */ + if (pdev->subsystem_vendor == 0x161F && + pdev->subsystem_device == 0x2032) + return 1; + + return 0; +} + +static u8 via82cxxx_cable_detect(ide_hwif_t *hwif) +{ + struct pci_dev *pdev = to_pci_dev(hwif->dev); + struct ide_host *host = pci_get_drvdata(pdev); + struct via82cxxx_dev *vdev = host->host_priv; + + if (via_cable_override(pdev)) + return ATA_CBL_PATA40_SHORT; + + if ((vdev->via_config->flags & VIA_SATA_PATA) && hwif->channel == 0) + return ATA_CBL_SATA; + + if ((vdev->via_80w >> hwif->channel) & 1) + return ATA_CBL_PATA80; + else + return ATA_CBL_PATA40; +} + +static const struct ide_port_ops via_port_ops = { + .set_pio_mode = via_set_pio_mode, + .set_dma_mode = via_set_drive, + .cable_detect = via82cxxx_cable_detect, +}; + +static const struct ide_port_info via82cxxx_chipset = { + .name = DRV_NAME, + .init_chipset = init_chipset_via82cxxx, + .enablebits = { { 0x40, 0x02, 0x02 }, { 0x40, 0x01, 0x01 } }, + .port_ops = &via_port_ops, + .host_flags = IDE_HFLAG_PIO_NO_BLACKLIST | + IDE_HFLAG_POST_SET_MODE | + IDE_HFLAG_IO_32BIT, + .pio_mask = ATA_PIO5, + .swdma_mask = ATA_SWDMA2, + .mwdma_mask = ATA_MWDMA2, +}; + +static int via_init_one(struct pci_dev *dev, const struct pci_device_id *id) +{ + struct pci_dev *isa = NULL; + struct via_isa_bridge *via_config; + struct via82cxxx_dev *vdev; + int rc; + u8 idx = id->driver_data; + struct ide_port_info d; + + d = via82cxxx_chipset; + + /* + * Find the ISA bridge and check we know what it is. + */ + via_config = via_config_find(&isa); + + /* + * Print the boot message. + */ + printk(KERN_INFO DRV_NAME " %s: VIA %s (rev %02x) IDE %sDMA%s\n", + pci_name(dev), via_config->name, isa->revision, + via_config->udma_mask ? "U" : "MW", + via_dma[via_config->udma_mask ? + (fls(via_config->udma_mask) - 1) : 0]); + + pci_dev_put(isa); + + /* + * Determine system bus clock. + */ + via_clock = (ide_pci_clk ? ide_pci_clk : 33) * 1000; + + switch (via_clock) { + case 33000: via_clock = 33333; break; + case 37000: via_clock = 37500; break; + case 41000: via_clock = 41666; break; + } + + if (via_clock < 20000 || via_clock > 50000) { + printk(KERN_WARNING DRV_NAME ": User given PCI clock speed " + "impossible (%d), using 33 MHz instead.\n", via_clock); + via_clock = 33333; + } + + if (idx == 1) + d.enablebits[1].reg = d.enablebits[0].reg = 0; + else + d.host_flags |= IDE_HFLAG_NO_AUTODMA; + + if (idx == VIA_IDFLAG_SINGLE) + d.host_flags |= IDE_HFLAG_SINGLE; + + if ((via_config->flags & VIA_NO_UNMASK) == 0) + d.host_flags |= IDE_HFLAG_UNMASK_IRQS; + + d.udma_mask = via_config->udma_mask; + + vdev = kzalloc(sizeof(*vdev), GFP_KERNEL); + if (!vdev) { + printk(KERN_ERR DRV_NAME " %s: out of memory :(\n", + pci_name(dev)); + return -ENOMEM; + } + + vdev->via_config = via_config; + + rc = ide_pci_init_one(dev, &d, vdev); + if (rc) + kfree(vdev); + + return rc; +} + +static void via_remove(struct pci_dev *dev) +{ + struct ide_host *host = pci_get_drvdata(dev); + struct via82cxxx_dev *vdev = host->host_priv; + + ide_pci_remove(dev); + kfree(vdev); +} + +static const struct pci_device_id via_pci_tbl[] = { + { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_82C576_1), 0 }, + { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_82C586_1), 0 }, + { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_CX700_IDE), 0 }, + { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_VX855_IDE), VIA_IDFLAG_SINGLE }, + { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_6410), 1 }, + { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_6415), 1 }, + { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_SATA_EIDE), 1 }, + { 0, }, +}; +MODULE_DEVICE_TABLE(pci, via_pci_tbl); + +static struct pci_driver via_pci_driver = { + .name = "VIA_IDE", + .id_table = via_pci_tbl, + .probe = via_init_one, + .remove = via_remove, + .suspend = ide_pci_suspend, + .resume = ide_pci_resume, +}; + +static int __init via_ide_init(void) +{ + return ide_pci_register_driver(&via_pci_driver); +} + +static void __exit via_ide_exit(void) +{ + pci_unregister_driver(&via_pci_driver); +} + +module_init(via_ide_init); +module_exit(via_ide_exit); + +MODULE_AUTHOR("Vojtech Pavlik, Bartlomiej Zolnierkiewicz, Michel Aubry, Jeff Garzik, Andre Hedrick"); +MODULE_DESCRIPTION("PCI driver module for VIA IDE"); +MODULE_LICENSE("GPL"); |
