summaryrefslogtreecommitdiffstats
path: root/drivers/ide
diff options
context:
space:
mode:
authorRussell King <rmk@dyn-67.arm.linux.org.uk>2009-03-13 21:44:51 +0000
committerRussell King <rmk+kernel@arm.linux.org.uk>2009-03-13 21:44:51 +0000
commit97fb44eb6bc01f4ffed4300e475aa15e44877375 (patch)
tree481ed6efd0babe7185cae04f2fd295426b36411d /drivers/ide
parente4707dd3e9d0cb57597b6568a5e51fea5d6fca41 (diff)
parent148854c65ea8046b045672fd49f4333aefaa3ab5 (diff)
Merge branch 'for-rmk' of git://git.pengutronix.de/git/imx/linux-2.6 into devel
Conflicts: arch/arm/mach-at91/gpio.c
Diffstat (limited to 'drivers/ide')
-rw-r--r--drivers/ide/Kconfig7
-rw-r--r--drivers/ide/Makefile1
-rw-r--r--drivers/ide/amd74xx.c2
-rw-r--r--drivers/ide/at91_ide.c467
-rw-r--r--drivers/ide/atiixp.c4
-rw-r--r--drivers/ide/ide-cd.c35
-rw-r--r--drivers/ide/ide-cd.h2
-rw-r--r--drivers/ide/ide-disk_proc.c2
-rw-r--r--drivers/ide/ide-floppy_proc.c2
-rw-r--r--drivers/ide/ide-gd.c26
-rw-r--r--drivers/ide/ide-gd.h2
-rw-r--r--drivers/ide/ide-io.c3
-rw-r--r--drivers/ide/ide-iops.c2
-rw-r--r--drivers/ide/ide-probe.c7
-rw-r--r--drivers/ide/ide-proc.c2
-rw-r--r--drivers/ide/ide-tape.c31
-rw-r--r--drivers/ide/ide.c11
-rw-r--r--drivers/ide/it821x.c5
18 files changed, 565 insertions, 46 deletions
diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig
index 3dad2299d9c..5ea3bfad172 100644
--- a/drivers/ide/Kconfig
+++ b/drivers/ide/Kconfig
@@ -46,7 +46,7 @@ menuconfig IDE
SMART parameters from disk drives.
To compile this driver as a module, choose M here: the
- module will be called ide.
+ module will be called ide-core.ko.
For further information, please read <file:Documentation/ide/ide.txt>.
@@ -721,6 +721,11 @@ config BLK_DEV_IDE_TX4939
depends on SOC_TX4939
select BLK_DEV_IDEDMA_SFF
+config BLK_DEV_IDE_AT91
+ tristate "Atmel AT91 (SAM9, CAP9, AT572D940HF) IDE support"
+ depends on ARM && ARCH_AT91 && !ARCH_AT91RM9200 && !ARCH_AT91X40
+ select IDE_TIMINGS
+
config IDE_ARM
tristate "ARM IDE support"
depends on ARM && (ARCH_RPC || ARCH_SHARK)
diff --git a/drivers/ide/Makefile b/drivers/ide/Makefile
index d0e3d7d5b46..1c326d94aa6 100644
--- a/drivers/ide/Makefile
+++ b/drivers/ide/Makefile
@@ -116,3 +116,4 @@ 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
+obj-$(CONFIG_BLK_DEV_IDE_AT91) += at91_ide.o
diff --git a/drivers/ide/amd74xx.c b/drivers/ide/amd74xx.c
index 69660a431cd..77267c85996 100644
--- a/drivers/ide/amd74xx.c
+++ b/drivers/ide/amd74xx.c
@@ -166,7 +166,7 @@ static unsigned int init_chipset_amd74xx(struct pci_dev *dev)
* Check for broken FIFO support.
*/
if (dev->vendor == PCI_VENDOR_ID_AMD &&
- dev->vendor == PCI_DEVICE_ID_AMD_VIPER_7411)
+ dev->device == PCI_DEVICE_ID_AMD_VIPER_7411)
t &= 0x0f;
else
t |= 0xf0;
diff --git a/drivers/ide/at91_ide.c b/drivers/ide/at91_ide.c
new file mode 100644
index 00000000000..1bb50f46388
--- /dev/null
+++ b/drivers/ide/at91_ide.c
@@ -0,0 +1,467 @@
+/*
+ * IDE host driver for AT91 (SAM9, CAP9, AT572D940HF) Static Memory Controller
+ * with Compact Flash True IDE logic
+ *
+ * Copyright (c) 2008, 2009 Kelvatek Ltd.
+ *
+ * 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/version.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/ide.h>
+#include <linux/platform_device.h>
+
+#include <mach/board.h>
+#include <mach/gpio.h>
+#include <mach/at91sam9263.h>
+#include <mach/at91sam9_smc.h>
+#include <mach/at91sam9263_matrix.h>
+
+#define DRV_NAME "at91_ide"
+
+#define perr(fmt, args...) pr_err(DRV_NAME ": " fmt, ##args)
+#define pdbg(fmt, args...) pr_debug("%s " fmt, __func__, ##args)
+
+/*
+ * Access to IDE device is possible through EBI Static Memory Controller
+ * with Compact Flash logic. For details see EBI and SMC datasheet sections
+ * of any microcontroller from AT91SAM9 family.
+ *
+ * Within SMC chip select address space, lines A[23:21] distinguish Compact
+ * Flash modes (I/O, common memory, attribute memory, True IDE). IDE modes are:
+ * 0x00c0000 - True IDE
+ * 0x00e0000 - Alternate True IDE (Alt Status Register)
+ *
+ * On True IDE mode Task File and Data Register are mapped at the same address.
+ * To distinguish access between these two different bus data width is used:
+ * 8Bit for Task File, 16Bit for Data I/O.
+ *
+ * After initialization we do 8/16 bit flipping (changes in SMC MODE register)
+ * only inside IDE callback routines which are serialized by IDE layer,
+ * so no additional locking needed.
+ */
+
+#define TASK_FILE 0x00c00000
+#define ALT_MODE 0x00e00000
+#define REGS_SIZE 8
+
+#define enter_16bit(cs, mode) do { \
+ mode = at91_sys_read(AT91_SMC_MODE(cs)); \
+ at91_sys_write(AT91_SMC_MODE(cs), mode | AT91_SMC_DBW_16); \
+} while (0)
+
+#define leave_16bit(cs, mode) at91_sys_write(AT91_SMC_MODE(cs), mode);
+
+static void set_smc_timings(const u8 chipselect, const u16 cycle,
+ const u16 setup, const u16 pulse,
+ const u16 data_float, int use_iordy)
+{
+ unsigned long mode = AT91_SMC_READMODE | AT91_SMC_WRITEMODE |
+ AT91_SMC_BAT_SELECT;
+
+ /* disable or enable waiting for IORDY signal */
+ if (use_iordy)
+ mode |= AT91_SMC_EXNWMODE_READY;
+
+ /* add data float cycles if needed */
+ if (data_float)
+ mode |= AT91_SMC_TDF_(data_float);
+
+ at91_sys_write(AT91_SMC_MODE(chipselect), mode);
+
+ /* setup timings in SMC */
+ at91_sys_write(AT91_SMC_SETUP(chipselect), AT91_SMC_NWESETUP_(setup) |
+ AT91_SMC_NCS_WRSETUP_(0) |
+ AT91_SMC_NRDSETUP_(setup) |
+ AT91_SMC_NCS_RDSETUP_(0));
+ at91_sys_write(AT91_SMC_PULSE(chipselect), AT91_SMC_NWEPULSE_(pulse) |
+ AT91_SMC_NCS_WRPULSE_(cycle) |
+ AT91_SMC_NRDPULSE_(pulse) |
+ AT91_SMC_NCS_RDPULSE_(cycle));
+ at91_sys_write(AT91_SMC_CYCLE(chipselect), AT91_SMC_NWECYCLE_(cycle) |
+ AT91_SMC_NRDCYCLE_(cycle));
+}
+
+static unsigned int calc_mck_cycles(unsigned int ns, unsigned int mck_hz)
+{
+ u64 tmp = ns;
+
+ tmp *= mck_hz;
+ tmp += 1000*1000*1000 - 1; /* round up */
+ do_div(tmp, 1000*1000*1000);
+ return (unsigned int) tmp;
+}
+
+static void apply_timings(const u8 chipselect, const u8 pio,
+ const struct ide_timing *timing, int use_iordy)
+{
+ unsigned int t0, t1, t2, t6z;
+ unsigned int cycle, setup, pulse, data_float;
+ unsigned int mck_hz;
+ struct clk *mck;
+
+ /* see table 22 of Compact Flash standard 4.1 for the meaning,
+ * we do not stretch active (t2) time, so setup (t1) + hold time (th)
+ * assure at least minimal recovery (t2i) time */
+ t0 = timing->cyc8b;
+ t1 = timing->setup;
+ t2 = timing->act8b;
+ t6z = (pio < 5) ? 30 : 20;
+
+ pdbg("t0=%u t1=%u t2=%u t6z=%u\n", t0, t1, t2, t6z);
+
+ mck = clk_get(NULL, "mck");
+ BUG_ON(IS_ERR(mck));
+ mck_hz = clk_get_rate(mck);
+ pdbg("mck_hz=%u\n", mck_hz);
+
+ cycle = calc_mck_cycles(t0, mck_hz);
+ setup = calc_mck_cycles(t1, mck_hz);
+ pulse = calc_mck_cycles(t2, mck_hz);
+ data_float = calc_mck_cycles(t6z, mck_hz);
+
+ pdbg("cycle=%u setup=%u pulse=%u data_float=%u\n",
+ cycle, setup, pulse, data_float);
+
+ set_smc_timings(chipselect, cycle, setup, pulse, data_float, use_iordy);
+}
+
+static void at91_ide_input_data(ide_drive_t *drive, struct request *rq,
+ void *buf, unsigned int len)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ struct ide_io_ports *io_ports = &hwif->io_ports;
+ u8 chipselect = hwif->select_data;
+ unsigned long mode;
+
+ pdbg("cs %u buf %p len %d\n", chipselect, buf, len);
+
+ len++;
+
+ enter_16bit(chipselect, mode);
+ __ide_mm_insw((void __iomem *) io_ports->data_addr, buf, len / 2);
+ leave_16bit(chipselect, mode);
+}
+
+static void at91_ide_output_data(ide_drive_t *drive, struct request *rq,
+ void *buf, unsigned int len)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ struct ide_io_ports *io_ports = &hwif->io_ports;
+ u8 chipselect = hwif->select_data;
+ unsigned long mode;
+
+ pdbg("cs %u buf %p len %d\n", chipselect, buf, len);
+
+ enter_16bit(chipselect, mode);
+ __ide_mm_outsw((void __iomem *) io_ports->data_addr, buf, len / 2);
+ leave_16bit(chipselect, mode);
+}
+
+static u8 ide_mm_inb(unsigned long port)
+{
+ return readb((void __iomem *) port);
+}
+
+static void ide_mm_outb(u8 value, unsigned long port)
+{
+ writeb(value, (void __iomem *) port);
+}
+
+static void at91_ide_tf_load(ide_drive_t *drive, ide_task_t *task)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ struct ide_io_ports *io_ports = &hwif->io_ports;
+ struct ide_taskfile *tf = &task->tf;
+ u8 HIHI = (task->tf_flags & IDE_TFLAG_LBA48) ? 0xE0 : 0xEF;
+
+ if (task->tf_flags & IDE_TFLAG_FLAGGED)
+ HIHI = 0xFF;
+
+ if (task->tf_flags & IDE_TFLAG_OUT_DATA) {
+ u16 data = (tf->hob_data << 8) | tf->data;
+
+ at91_ide_output_data(drive, NULL, &data, 2);
+ }
+
+ if (task->tf_flags & IDE_TFLAG_OUT_HOB_FEATURE)
+ ide_mm_outb(tf->hob_feature, io_ports->feature_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_HOB_NSECT)
+ ide_mm_outb(tf->hob_nsect, io_ports->nsect_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAL)
+ ide_mm_outb(tf->hob_lbal, io_ports->lbal_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAM)
+ ide_mm_outb(tf->hob_lbam, io_ports->lbam_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAH)
+ ide_mm_outb(tf->hob_lbah, io_ports->lbah_addr);
+
+ if (task->tf_flags & IDE_TFLAG_OUT_FEATURE)
+ ide_mm_outb(tf->feature, io_ports->feature_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_NSECT)
+ ide_mm_outb(tf->nsect, io_ports->nsect_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_LBAL)
+ ide_mm_outb(tf->lbal, io_ports->lbal_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_LBAM)
+ ide_mm_outb(tf->lbam, io_ports->lbam_addr);
+ if (task->tf_flags & IDE_TFLAG_OUT_LBAH)
+ ide_mm_outb(tf->lbah, io_ports->lbah_addr);
+
+ if (task->tf_flags & IDE_TFLAG_OUT_DEVICE)
+ ide_mm_outb((tf->device & HIHI) | drive->select, io_ports->device_addr);
+}
+
+static void at91_ide_tf_read(ide_drive_t *drive, ide_task_t *task)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ struct ide_io_ports *io_ports = &hwif->io_ports;
+ struct ide_taskfile *tf = &task->tf;
+
+ if (task->tf_flags & IDE_TFLAG_IN_DATA) {
+ u16 data;
+
+ at91_ide_input_data(drive, NULL, &data, 2);
+ tf->data = data & 0xff;
+ tf->hob_data = (data >> 8) & 0xff;
+ }
+
+ /* be sure we're looking at the low order bits */
+ ide_mm_outb(ATA_DEVCTL_OBS & ~0x80, io_ports->ctl_addr);
+
+ if (task->tf_flags & IDE_TFLAG_IN_FEATURE)
+ tf->feature = ide_mm_inb(io_ports->feature_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_NSECT)
+ tf->nsect = ide_mm_inb(io_ports->nsect_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_LBAL)
+ tf->lbal = ide_mm_inb(io_ports->lbal_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_LBAM)
+ tf->lbam = ide_mm_inb(io_ports->lbam_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_LBAH)
+ tf->lbah = ide_mm_inb(io_ports->lbah_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_DEVICE)
+ tf->device = ide_mm_inb(io_ports->device_addr);
+
+ if (task->tf_flags & IDE_TFLAG_LBA48) {
+ ide_mm_outb(ATA_DEVCTL_OBS | 0x80, io_ports->ctl_addr);
+
+ if (task->tf_flags & IDE_TFLAG_IN_HOB_FEATURE)
+ tf->hob_feature = ide_mm_inb(io_ports->feature_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_HOB_NSECT)
+ tf->hob_nsect = ide_mm_inb(io_ports->nsect_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAL)
+ tf->hob_lbal = ide_mm_inb(io_ports->lbal_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAM)
+ tf->hob_lbam = ide_mm_inb(io_ports->lbam_addr);
+ if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAH)
+ tf->hob_lbah = ide_mm_inb(io_ports->lbah_addr);
+ }
+}
+
+static void at91_ide_set_pio_mode(ide_drive_t *drive, const u8 pio)
+{
+ struct ide_timing *timing;
+ u8 chipselect = drive->hwif->select_data;
+ int use_iordy = 0;
+
+ pdbg("chipselect %u pio %u\n", chipselect, pio);
+
+ timing = ide_timing_find_mode(XFER_PIO_0 + pio);
+ BUG_ON(!timing);
+
+ if ((pio > 2 || ata_id_has_iordy(drive->id)) &&
+ !(ata_id_is_cfa(drive->id) && pio > 4))
+ use_iordy = 1;
+
+ apply_timings(chipselect, pio, timing, use_iordy);
+}
+
+static const struct ide_tp_ops at91_ide_tp_ops = {
+ .exec_command = ide_exec_command,
+ .read_status = ide_read_status,
+ .read_altstatus = ide_read_altstatus,
+ .set_irq = ide_set_irq,
+
+ .tf_load = at91_ide_tf_load,
+ .tf_read = at91_ide_tf_read,
+
+ .input_data = at91_ide_input_data,
+ .output_data = at91_ide_output_data,
+};
+
+static const struct ide_port_ops at91_ide_port_ops = {
+ .set_pio_mode = at91_ide_set_pio_mode,
+};
+
+static const struct ide_port_info at91_ide_port_info __initdata = {
+ .port_ops = &at91_ide_port_ops,
+ .tp_ops = &at91_ide_tp_ops,
+ .host_flags = IDE_HFLAG_MMIO | IDE_HFLAG_NO_DMA | IDE_HFLAG_SINGLE |
+ IDE_HFLAG_NO_IO_32BIT | IDE_HFLAG_UNMASK_IRQS,
+ .pio_mask = ATA_PIO5,
+};
+
+/*
+ * If interrupt is delivered through GPIO, IRQ are triggered on falling
+ * and rising edge of signal. Whereas IDE device request interrupt on high
+ * level (rising edge in our case). This mean we have fake interrupts, so
+ * we need to check interrupt pin and exit instantly from ISR when line
+ * is on low level.
+ */
+
+irqreturn_t at91_irq_handler(int irq, void *dev_id)
+{
+ int ntries = 8;
+ int pin_val1, pin_val2;
+
+ /* additional deglitch, line can be noisy in badly designed PCB */
+ do {
+ pin_val1 = at91_get_gpio_value(irq);
+ pin_val2 = at91_get_gpio_value(irq);
+ } while (pin_val1 != pin_val2 && --ntries > 0);
+
+ if (pin_val1 == 0 || ntries <= 0)
+ return IRQ_HANDLED;
+
+ return ide_intr(irq, dev_id);
+}
+
+static int __init at91_ide_probe(struct platform_device *pdev)
+{
+ int ret;
+ hw_regs_t hw;
+ hw_regs_t *hws[] = { &hw, NULL, NULL, NULL };
+ struct ide_host *host;
+ struct resource *res;
+ unsigned long tf_base = 0, ctl_base = 0;
+ struct at91_cf_data *board = pdev->dev.platform_data;
+
+ if (!board)
+ return -ENODEV;
+
+ if (board->det_pin && at91_get_gpio_value(board->det_pin) != 0) {
+ perr("no device detected\n");
+ return -ENODEV;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ perr("can't get memory resource\n");
+ return -ENODEV;
+ }
+
+ if (!devm_request_mem_region(&pdev->dev, res->start + TASK_FILE,
+ REGS_SIZE, "ide") ||
+ !devm_request_mem_region(&pdev->dev, res->start + ALT_MODE,
+ REGS_SIZE, "alt")) {
+ perr("memory resources in use\n");
+ return -EBUSY;
+ }
+
+ pdbg("chipselect %u irq %u res %08lx\n", board->chipselect,
+ board->irq_pin, (unsigned long) res->start);
+
+ tf_base = (unsigned long) devm_ioremap(&pdev->dev, res->start + TASK_FILE,
+ REGS_SIZE);
+ ctl_base = (unsigned long) devm_ioremap(&pdev->dev, res->start + ALT_MODE,
+ REGS_SIZE);
+ if (!tf_base || !ctl_base) {
+ perr("can't map memory regions\n");
+ return -EBUSY;
+ }
+
+ memset(&hw, 0, sizeof(hw));
+
+ if (board->flags & AT91_IDE_SWAP_A0_A2) {
+ /* workaround for stupid hardware bug */
+ hw.io_ports.data_addr = tf_base + 0;
+ hw.io_ports.error_addr = tf_base + 4;
+ hw.io_ports.nsect_addr = tf_base + 2;
+ hw.io_ports.lbal_addr = tf_base + 6;
+ hw.io_ports.lbam_addr = tf_base + 1;
+ hw.io_ports.lbah_addr = tf_base + 5;
+ hw.io_ports.device_addr = tf_base + 3;
+ hw.io_ports.command_addr = tf_base + 7;
+ hw.io_ports.ctl_addr = ctl_base + 3;
+ } else
+ ide_std_init_ports(&hw, tf_base, ctl_base + 6);
+
+ hw.irq = board->irq_pin;
+ hw.chipset = ide_generic;
+ hw.dev = &pdev->dev;
+
+ host = ide_host_alloc(&at91_ide_port_info, hws);
+ if (!host) {
+ perr("failed to allocate ide host\n");
+ return -ENOMEM;
+ }
+
+ /* setup Static Memory Controller - PIO 0 as default */
+ apply_timings(board->chipselect, 0, ide_timing_find_mode(XFER_PIO_0), 0);
+
+ /* with GPIO interrupt we have to do quirks in handler */
+ if (board->irq_pin >= PIN_BASE)
+ host->irq_handler = at91_irq_handler;
+
+ host->ports[0]->select_data = board->chipselect;
+
+ ret = ide_host_register(host, &at91_ide_port_info, hws);
+ if (ret) {
+ perr("failed to register ide host\n");
+ goto err_free_host;
+ }
+ platform_set_drvdata(pdev, host);
+ return 0;
+
+err_free_host:
+ ide_host_free(host);
+ return ret;
+}
+
+static int __exit at91_ide_remove(struct platform_device *pdev)
+{
+ struct ide_host *host = platform_get_drvdata(pdev);
+
+ ide_host_remove(host);
+ return 0;
+}
+
+static struct platform_driver at91_ide_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+ .remove = __exit_p(at91_ide_remove),
+};
+
+static int __init at91_ide_init(void)
+{
+ return platform_driver_probe(&at91_ide_driver, at91_ide_probe);
+}
+
+static void __exit at91_ide_exit(void)
+{
+ platform_driver_unregister(&at91_ide_driver);
+}
+
+module_init(at91_ide_init);
+module_exit(at91_ide_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Stanislaw Gruszka <stf_xl@wp.pl>");
+
diff --git a/drivers/ide/atiixp.c b/drivers/ide/atiixp.c
index b2735d28f5c..ecd1e62ca91 100644
--- a/drivers/ide/atiixp.c
+++ b/drivers/ide/atiixp.c
@@ -52,7 +52,7 @@ static void atiixp_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
unsigned long flags;
- int timing_shift = (drive->dn & 2) ? 16 : 0 + (drive->dn & 1) ? 0 : 8;
+ int timing_shift = (drive->dn ^ 1) * 8;
u32 pio_timing_data;
u16 pio_mode_data;
@@ -85,7 +85,7 @@ static void atiixp_set_dma_mode(ide_drive_t *drive, const u8 speed)
{
struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
unsigned long flags;
- int timing_shift = (drive->dn & 2) ? 16 : 0 + (drive->dn & 1) ? 0 : 8;
+ int timing_shift = (drive->dn ^ 1) * 8;
u32 tmp32;
u16 tmp16;
u16 udma_ctl = 0;
diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c
index 0bfeb0c79d6..ddfbea41d29 100644
--- a/drivers/ide/ide-cd.c
+++ b/drivers/ide/ide-cd.c
@@ -55,7 +55,7 @@
static DEFINE_MUTEX(idecd_ref_mutex);
-static void ide_cd_release(struct kref *);
+static void ide_cd_release(struct device *);
static struct cdrom_info *ide_cd_get(struct gendisk *disk)
{
@@ -67,7 +67,7 @@ static struct cdrom_info *ide_cd_get(struct gendisk *disk)
if (ide_device_get(cd->drive))
cd = NULL;
else
- kref_get(&cd->kref);
+ get_device(&cd->dev);
}
mutex_unlock(&idecd_ref_mutex);
@@ -79,7 +79,7 @@ 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);
}
@@ -194,6 +194,14 @@ static void cdrom_analyze_sense_data(ide_drive_t *drive,
bio_sectors = max(bio_sectors(failed_command->bio), 4U);
sector &= ~(bio_sectors - 1);
+ /*
+ * 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)
set_capacity(info->disk, sector);
@@ -1790,15 +1798,17 @@ static void ide_cd_remove(ide_drive_t *drive)
ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__);
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_drv(kref, cdrom_info);
+ 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;
@@ -1997,7 +2007,12 @@ static int ide_cd_probe(ide_drive_t *drive)
ide_init_disk(g, drive);
- kref_init(&info->kref);
+ info->dev.parent = &drive->gendev;
+ info->dev.release = ide_cd_release;
+ dev_set_name(&info->dev, dev_name(&drive->gendev));
+
+ if (device_register(&info->dev))
+ goto out_free_disk;
info->drive = drive;
info->driver = &ide_cdrom_driver;
@@ -2011,7 +2026,7 @@ 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)) {
- ide_cd_release(&info->kref);
+ put_device(&info->dev);
goto failed;
}
@@ -2021,6 +2036,8 @@ static int ide_cd_probe(ide_drive_t *drive)
add_disk(g);
return 0;
+out_free_disk:
+ put_disk(g);
out_free_cd:
kfree(info);
failed:
diff --git a/drivers/ide/ide-cd.h b/drivers/ide/ide-cd.h
index ac40d6cb90a..c878bfcf111 100644
--- a/drivers/ide/ide-cd.h
+++ b/drivers/ide/ide-cd.h
@@ -80,7 +80,7 @@ struct cdrom_info {
ide_drive_t *drive;
struct ide_driver *driver;
struct gendisk *disk;
- struct kref kref;
+ struct device dev;
/* Buffer for table of contents. NULL if we haven't allocated
a TOC buffer for this device yet. */
diff --git a/drivers/ide/ide-disk_proc.c b/drivers/ide/ide-disk_proc.c
index 1146f4204c6..1f86dcbd2b1 100644
--- a/drivers/ide/ide-disk_proc.c
+++ b/drivers/ide/ide-disk_proc.c
@@ -125,5 +125,5 @@ const struct ide_proc_devset ide_disk_settings[] = {
IDE_PROC_DEVSET(multcount, 0, 16),
IDE_PROC_DEVSET(nowerr, 0, 1),
IDE_PROC_DEVSET(wcache, 0, 1),
- { 0 },
+ { NULL },
};
diff --git a/drivers/ide/ide-floppy_proc.c b/drivers/ide/ide-floppy_proc.c
index 3ec762cb60a..fcd4d8153df 100644
--- a/drivers/ide/ide-floppy_proc.c
+++ b/drivers/ide/ide-floppy_proc.c
@@ -29,5 +29,5 @@ const struct ide_proc_devset ide_floppy_settings[] = {
IDE_PROC_DEVSET(bios_head, 0, 255),
IDE_PROC_DEVSET(bios_sect, 0, 63),
IDE_PROC_DEVSET(ticks, 0, 255),
- { 0 },
+ { NULL },
};
diff --git a/drivers/ide/ide-gd.c b/drivers/ide/ide-gd.c
index 7857b209c6d..04710941990 100644
--- a/drivers/ide/ide-gd.c
+++ b/drivers/ide/ide-gd.c
@@ -25,7 +25,7 @@ module_param(debug_mask, ulong, 0644);
static DEFINE_MUTEX(ide_disk_ref_mutex);
-static void ide_disk_release(struct kref *);
+static void ide_disk_release(struct device *);
static struct ide_disk_obj *ide_disk_get(struct gendisk *disk)
{
@@ -37,7 +37,7 @@ static struct ide_disk_obj *ide_disk_get(struct gendisk *disk)
if (ide_device_get(idkp->drive))
idkp = NULL;
else
- kref_get(&idkp->kref);
+ get_device(&idkp->dev);
}
mutex_unlock(&ide_disk_ref_mutex);
return idkp;
@@ -48,7 +48,7 @@ static void ide_disk_put(struct ide_disk_obj *idkp)
ide_drive_t *drive = idkp->drive;
mutex_lock(&ide_disk_ref_mutex);
- kref_put(&idkp->kref, ide_disk_release);
+ put_device(&idkp->dev);
ide_device_put(drive);
mutex_unlock(&ide_disk_ref_mutex);
}
@@ -66,17 +66,18 @@ static void ide_gd_remove(ide_drive_t *drive)
struct gendisk *g = idkp->disk;
ide_proc_unregister_driver(drive, idkp->driver);
-
+ device_del(&idkp->dev);
del_gendisk(g);
-
drive->disk_ops->flush(drive);
- ide_disk_put(idkp);
+ mutex_lock(&ide_disk_ref_mutex);
+ put_device(&idkp->dev);
+ mutex_unlock(&ide_disk_ref_mutex);
}
-static void ide_disk_release(struct kref *kref)
+static void ide_disk_release(struct device *dev)
{
- struct ide_disk_obj *idkp = to_ide_drv(kref, ide_disk_obj);
+ struct ide_disk_obj *idkp = to_ide_drv(dev, ide_disk_obj);
ide_drive_t *drive = idkp->drive;
struct gendisk *g = idkp->disk;
@@ -348,7 +349,12 @@ static int ide_gd_probe(ide_drive_t *drive)
ide_init_disk(g, drive);
- kref_init(&idkp->kref);
+ idkp->dev.parent = &drive->gendev;
+ idkp->dev.release = ide_disk_release;
+ dev_set_name(&idkp->dev, dev_name(&drive->gendev));
+
+ if (device_register(&idkp->dev))
+ goto out_free_disk;
idkp->drive = drive;
idkp->driver = &ide_gd_driver;
@@ -373,6 +379,8 @@ static int ide_gd_probe(ide_drive_t *drive)
add_disk(g);
return 0;
+out_free_disk:
+ put_disk(g);
out_free_idkp:
kfree(idkp);
failed:
diff --git a/drivers/ide/ide-gd.h b/drivers/ide/ide-gd.h
index a86779f0756..b604bdd318a 100644
--- a/drivers/ide/ide-gd.h
+++ b/drivers/ide/ide-gd.h
@@ -17,7 +17,7 @@ struct ide_disk_obj {
ide_drive_t *drive;
struct ide_driver *driver;
struct gendisk *disk;
- struct kref kref;
+ struct device dev;
unsigned int openers; /* protected by BKL for now */
/* Last failed packet command */
diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c
index 9ee51adf567..a9a6c208288 100644
--- a/drivers/ide/ide-io.c
+++ b/drivers/ide/ide-io.c
@@ -908,7 +908,7 @@ void ide_timer_expiry (unsigned long data)
ide_drive_t *uninitialized_var(drive);
ide_handler_t *handler;
unsigned long flags;
- unsigned long wait = -1;
+ int wait = -1;
int plug_device = 0;
spin_lock_irqsave(&hwif->lock, flags);
@@ -1162,6 +1162,7 @@ out_early:
return irq_ret;
}
+EXPORT_SYMBOL_GPL(ide_intr);
/**
* ide_do_drive_cmd - issue IDE special command
diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c
index 753b92ebe0a..b1892bd95c6 100644
--- a/drivers/ide/ide-iops.c
+++ b/drivers/ide/ide-iops.c
@@ -315,6 +315,8 @@ void ide_output_data(ide_drive_t *drive, struct request *rq, void *buf,
u8 io_32bit = drive->io_32bit;
u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0;
+ len++;
+
if (io_32bit) {
unsigned long uninitialized_var(flags);
diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c
index ce0818a993f..ee8e3e7cad5 100644
--- a/drivers/ide/ide-probe.c
+++ b/drivers/ide/ide-probe.c
@@ -950,6 +950,7 @@ static int ide_port_setup_devices(ide_hwif_t *hwif)
static int init_irq (ide_hwif_t *hwif)
{
struct ide_io_ports *io_ports = &hwif->io_ports;
+ irq_handler_t irq_handler;
int sa = 0;
mutex_lock(&ide_cfg_mtx);
@@ -959,6 +960,10 @@ static int init_irq (ide_hwif_t *hwif)
hwif->timer.function = &ide_timer_expiry;
hwif->timer.data = (unsigned long)hwif;
+ irq_handler = hwif->host->irq_handler;
+ if (irq_handler == NULL)
+ irq_handler = ide_intr;
+
#if defined(__mc68000__)
sa = IRQF_SHARED;
#endif /* __mc68000__ */
@@ -969,7 +974,7 @@ static int init_irq (ide_hwif_t *hwif)
if (io_ports->ctl_addr)
hwif->tp_ops->set_irq(hwif, 1);
- if (request_irq(hwif->irq, &ide_intr, sa, hwif->name, hwif))
+ if (request_irq(hwif->irq, irq_handler, sa, hwif->name, hwif))
goto out_up;
if (!hwif->rqsize) {
diff --git a/drivers/ide/ide-proc.c b/drivers/ide/ide-proc.c
index 1d8978b3314..a7b9287ee0d 100644
--- a/drivers/ide/ide-proc.c
+++ b/drivers/ide/ide-proc.c
@@ -231,7 +231,7 @@ static const struct ide_proc_devset ide_generic_settings[] = {
IDE_PROC_DEVSET(pio_mode, 0, 255),
IDE_PROC_DEVSET(unmaskirq, 0, 1),
IDE_PROC_DEVSET(using_dma, 0, 1),
- { 0 },
+ { NULL },
};
static void proc_ide_settings_warn(void)
diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c
index d7ecd3c7975..4e6181c7bbd 100644
--- a/drivers/ide/ide-tape.c
+++ b/drivers/ide/ide-tape.c
@@ -169,7 +169,7 @@ typedef struct ide_tape_obj {
ide_drive_t *drive;
struct ide_driver *driver;
struct gendisk *disk;
- struct kref kref;
+ struct device dev;
/*
* failed_pc points to the last failed packet command, or contains
@@ -267,7 +267,7 @@ static DEFINE_MUTEX(idetape_ref_mutex);
static struct class *idetape_sysfs_class;
-static void ide_tape_release(struct kref *);
+static void ide_tape_release(struct device *);
static struct ide_tape_obj *ide_tape_get(struct gendisk *disk)
{
@@ -279,7 +279,7 @@ static struct ide_tape_obj *ide_tape_get(struct gendisk *disk)
if (ide_device_get(tape->drive))
tape = NULL;
else
- kref_get(&tape->kref);
+ get_device(&tape->dev);
}
mutex_unlock(&idetape_ref_mutex);
return tape;
@@ -290,7 +290,7 @@ static void ide_tape_put(struct ide_tape_obj *tape)
ide_drive_t *drive = tape->drive;
mutex_lock(&idetape_ref_mutex);
- kref_put(&tape->kref, ide_tape_release);
+ put_device(&tape->dev);
ide_device_put(drive);
mutex_unlock(&idetape_ref_mutex);
}
@@ -308,7 +308,7 @@ static struct ide_tape_obj *ide_tape_chrdev_get(unsigned int i)
mutex_lock(&idetape_ref_mutex);
tape = idetape_devs[i];
if (tape)
- kref_get(&tape->kref);
+ get_device(&tape->dev);
mutex_unlock(&idetape_ref_mutex);
return tape;
}
@@ -2166,7 +2166,7 @@ static const struct ide_proc_devset idetape_settings[] = {
__IDE_PROC_DEVSET(speed, 0, 0xffff, NULL, NULL),
__IDE_PROC_DEVSET(tdsc, IDETAPE_DSC_RW_MIN, IDETAPE_DSC_RW_MAX,
mulf_tdsc, divf_tdsc),
- { 0 },
+ { NULL },
};
#endif
@@ -2256,15 +2256,17 @@ static void ide_tape_remove(ide_drive_t *drive)
idetape_tape_t *tape = drive->driver_data;
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_drv(kref, ide_tape_obj);
+ struct ide_tape_obj *tape = to_ide_drv(dev, ide_tape_obj);
ide_drive_t *drive = tape->drive;
struct gendisk *g = tape->disk;
@@ -2407,7 +2409,12 @@ static int ide_tape_probe(ide_drive_t *drive)
ide_init_disk(g, drive);
- kref_init(&tape->kref);
+ tape->dev.parent = &drive->gendev;
+ tape->dev.release = ide_tape_release;
+ dev_set_name(&tape->dev, dev_name(&drive->gendev));
+
+ if (device_register(&tape->dev))
+ goto out_free_disk;
tape->drive = drive;
tape->driver = &idetape_driver;
@@ -2436,6 +2443,8 @@ static int ide_tape_probe(ide_drive_t *drive)
return 0;
+out_free_disk:
+ put_disk(g);
out_free_tape:
kfree(tape);
failed:
diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c
index 258805da15c..0920e3b0c96 100644
--- a/drivers/ide/ide.c
+++ b/drivers/ide/ide.c
@@ -337,6 +337,7 @@ static int ide_set_dev_param_mask(const char *s, struct kernel_param *kp)
int a, b, i, j = 1;
unsigned int *dev_param_mask = (unsigned int *)kp->arg;
+ /* 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;
@@ -349,7 +350,7 @@ static int ide_set_dev_param_mask(const char *s, struct kernel_param *kp)
if (j)
*dev_param_mask |= (1 << i);
else
- *dev_param_mask &= (1 << i);
+ *dev_param_mask &= ~(1 << i);
return 0;
}
@@ -392,6 +393,8 @@ static int ide_set_disk_chs(const char *str, struct kernel_param *kp)
{
int a, b, c = 0, h = 0, s = 0, i, j = 1;
+ /* 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;
@@ -407,7 +410,7 @@ static int ide_set_disk_chs(const char *str, struct kernel_param *kp)
if (j)
ide_disks |= (1 << i);
else
- ide_disks &= (1 << i);
+ ide_disks &= ~(1 << i);
ide_disks_chs[i].cyl = c;
ide_disks_chs[i].head = h;
@@ -469,6 +472,8 @@ static int ide_set_ignore_cable(const char *s, struct kernel_param *kp)
{
int i, j = 1;
+ /* controller (ignore) */
+ /* controller : 1 (ignore) | 0 (use) */
if (sscanf(s, "%d:%d", &i, &j) != 2 && sscanf(s, "%d", &i) != 1)
return -EINVAL;
@@ -478,7 +483,7 @@ static int ide_set_ignore_cable(const char *s, struct kernel_param *kp)
if (j)
ide_ignore_cable |= (1 << i);
else
- ide_ignore_cable &= (1 << i);
+ ide_ignore_cable &= ~(1 << i);
return 0;
}
diff --git a/drivers/ide/it821x.c b/drivers/ide/it821x.c
index e1c4f543739..13b8153112e 100644
--- a/drivers/ide/it821x.c
+++ b/drivers/ide/it821x.c
@@ -5,9 +5,8 @@
* 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