Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / drivers / ide / pci / sgiioc4.c
index 6a3d79b..27c9eb9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003 Silicon Graphics, Inc.  All Rights Reserved.
+ * 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
  * License along with this program; if not, write the Free Software
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
  *
- * Contact information:  Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
- * Mountain View, CA  94043, or:
- *
- * http://www.sgi.com
- *
  * For further information regarding this notice, see:
  *
  * http://oss.sgi.com/projects/GenInfo/NoticeExplan
@@ -34,6 +29,7 @@
 #include <linux/mm.h>
 #include <linux/ioport.h>
 #include <linux/blkdev.h>
+#include <linux/ioc4.h>
 #include <asm/io.h>
 
 #include <linux/ide.h>
@@ -192,16 +188,13 @@ sgiioc4_clearirq(ide_drive_t * drive)
        return intr_reg & 3;
 }
 
-static int
-sgiioc4_ide_dma_begin(ide_drive_t * drive)
+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);
-
-       return 0;
 }
 
 static u32
@@ -334,17 +327,6 @@ sgiioc4_ide_dma_host_off(ide_drive_t * drive)
        return 0;
 }
 
-static int
-sgiioc4_ide_dma_verbose(ide_drive_t * drive)
-{
-       if (drive->using_dma == 1)
-               printk(", UDMA(16)");
-       else
-               printk(", PIO");
-
-       return 1;
-}
-
 static int
 sgiioc4_ide_dma_lostirq(ide_drive_t * drive)
 {
@@ -363,17 +345,17 @@ sgiioc4_resetproc(ide_drive_t * drive)
 static u8
 sgiioc4_INB(unsigned long port)
 {
-       u8 reg = (u8) inb(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) inl(other_ir);
+                       unsigned int intr_reg = (u32) readl((void __iomem *) other_ir);
 
                        /* Clear the Interrupt, Error bits on the IOC4 */
                        if (intr_reg & 0x03) {
-                               outl(0x03, other_ir);
-                               intr_reg = (u32) inl(other_ir);
+                               writel(0x03, (void __iomem *) other_ir);
+                               intr_reg = (u32) readl((void __iomem *) other_ir);
                        }
                }
        }
@@ -382,7 +364,7 @@ sgiioc4_INB(unsigned long port)
 }
 
 /* Creates a dma map for the scatter-gather list entries */
-static void __init
+static void __devinit
 ide_dma_sgiioc4(ide_hwif_t * hwif, unsigned long dma_base)
 {
        int num_ports = sizeof (ioc4_dma_regs_t);
@@ -407,11 +389,7 @@ ide_dma_sgiioc4(ide_hwif_t * hwif, unsigned long dma_base)
        if (!hwif->dmatable_cpu)
                goto dma_alloc_failure;
 
-       hwif->sg_table =
-           kmalloc(sizeof (struct scatterlist) * IOC4_PRD_ENTRIES, GFP_KERNEL);
-
-       if (!hwif->sg_table)
-               goto dma_sgalloc_failure;
+       hwif->sg_max_nents = IOC4_PRD_ENTRIES;
 
        hwif->dma_base2 = (unsigned long)
                pci_alloc_consistent(hwif->pci_dev,
@@ -424,9 +402,6 @@ ide_dma_sgiioc4(ide_hwif_t * hwif, unsigned long dma_base)
        return;
 
 dma_base2alloc_failure:
-       kfree(hwif->sg_table);
-
-dma_sgalloc_failure:
        pci_free_consistent(hwif->pci_dev,
                            IOC4_PRD_ENTRIES * IOC4_PRD_BYTES,
                            hwif->dmatable_cpu, hwif->dmatable_dma);
@@ -511,10 +486,7 @@ sgiioc4_build_dma_table(ide_drive_t * drive, struct request *rq, int ddir)
        unsigned int count = 0, i = 1;
        struct scatterlist *sg;
 
-       if (HWGROUP(drive)->rq->flags & REQ_DRIVE_TASKFILE)
-               hwif->sg_nents = i = ide_raw_build_sglist(drive, rq);
-       else
-               hwif->sg_nents = i = ide_build_sglist(drive, rq);
+       hwif->sg_nents = i = ide_build_sglist(drive, rq);
 
        if (!i)
                return 0;       /* sglist of length Zero */
@@ -533,7 +505,7 @@ sgiioc4_build_dma_table(ide_drive_t * drive, struct request *rq, int ddir)
                                       drive->name);
                                goto use_pio_instead;
                        } else {
-                               u32 xcount, bcount =
+                               u32 bcount =
                                    0x10000 - (cur_addr & 0xffff);
 
                                if (bcount > cur_len)
@@ -548,8 +520,7 @@ sgiioc4_build_dma_table(ide_drive_t * drive, struct request *rq, int ddir)
                                *table = 0x0;
                                table++;
 
-                               xcount = bcount & 0xffff;
-                               *table = cpu_to_be32(xcount);
+                               *table = cpu_to_be32(bcount);
                                table++;
 
                                cur_addr += bcount;
@@ -574,40 +545,36 @@ use_pio_instead:
        return 0;               /* revert to PIO for this request */
 }
 
-static int
-sgiioc4_ide_dma_read(ide_drive_t * drive)
+static int sgiioc4_ide_dma_setup(ide_drive_t *drive)
 {
        struct request *rq = HWGROUP(drive)->rq;
        unsigned int count = 0;
+       int ddir;
 
-       if (!(count = sgiioc4_build_dma_table(drive, rq, PCI_DMA_FROMDEVICE))) {
-               /* try PIO instead of DMA */
-               return 1;
-       }
-       /* Writes FROM the IOC4 TO Main Memory */
-       sgiioc4_configure_for_dma(IOC4_DMA_WRITE, drive);
-
-       return 0;
-}
-
-static int
-sgiioc4_ide_dma_write(ide_drive_t * drive)
-{
-       struct request *rq = HWGROUP(drive)->rq;
-       unsigned int count = 0;
+       if (rq_data_dir(rq))
+               ddir = PCI_DMA_TODEVICE;
+       else
+               ddir = PCI_DMA_FROMDEVICE;
 
-       if (!(count = sgiioc4_build_dma_table(drive, rq, PCI_DMA_TODEVICE))) {
+       if (!(count = sgiioc4_build_dma_table(drive, rq, ddir))) {
                /* try PIO instead of DMA */
+               ide_map_sg(drive, rq);
                return 1;
        }
 
-       sgiioc4_configure_for_dma(IOC4_DMA_READ, drive);
-       /* Writes TO the IOC4 FROM Main Memory */
+       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 __init
+static void __devinit
 ide_init_sgiioc4(ide_hwif_t * hwif)
 {
        hwif->mmio = 2;
@@ -616,7 +583,6 @@ ide_init_sgiioc4(ide_hwif_t * hwif)
        hwif->ultra_mask = 0x0; /* Disable Ultra DMA */
        hwif->mwdma_mask = 0x2; /* Multimode-2 DMA  */
        hwif->swdma_mask = 0x2;
-       hwif->identify = NULL;
        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 */
@@ -629,9 +595,8 @@ ide_init_sgiioc4(ide_hwif_t * hwif)
        hwif->quirkproc = NULL;
        hwif->busproc = NULL;
 
-       hwif->ide_dma_read = &sgiioc4_ide_dma_read;
-       hwif->ide_dma_write = &sgiioc4_ide_dma_write;
-       hwif->ide_dma_begin = &sgiioc4_ide_dma_begin;
+       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;
@@ -639,25 +604,36 @@ ide_init_sgiioc4(ide_hwif_t * hwif)
        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_verbose = &sgiioc4_ide_dma_verbose;
        hwif->ide_dma_lostirq = &sgiioc4_ide_dma_lostirq;
        hwif->ide_dma_timeout = &__ide_dma_timeout;
+
+       /*
+        * The IOC4 uses MMIO rather than Port IO.
+        * It also needs special workarounds for INB.
+        */
+       default_hwif_mmiops(hwif);
        hwif->INB = &sgiioc4_INB;
 }
 
-static int __init
+static int __devinit
 sgiioc4_ide_setup_pci_device(struct pci_dev *dev, ide_pci_device_t * d)
 {
        unsigned long base, ctl, dma_base, irqport;
        ide_hwif_t *hwif;
        int h;
 
+       /*
+        * Find an empty HWIF; if none available, return -ENOMEM.
+        */
        for (h = 0; h < MAX_HWIFS; ++h) {
                hwif = &ide_hwifs[h];
-               /* Find an empty HWIF */
                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 */
        base = pci_resource_start(dev, 0) + IOC4_CMD_OFFSET;
@@ -700,61 +676,35 @@ sgiioc4_ide_setup_pci_device(struct pci_dev *dev, ide_pci_device_t * d)
                printk(KERN_INFO "%s: %s Bus-Master DMA disabled\n",
                       hwif->name, d->name);
 
-       probe_hwif_init(hwif);
+       if (probe_hwif_init(hwif))
+               return -EIO;
 
        /* Create /proc/ide entries */
-       create_proc_ide_interfaces(); 
+       create_proc_ide_interfaces();
 
        return 0;
 }
 
-/* This ensures that we can build this for generic kernels without
- * having all the SN2 code sync'd and merged.
- */
-typedef enum pciio_endian_e {
-       PCIDMA_ENDIAN_BIG,
-       PCIDMA_ENDIAN_LITTLE
-} pciio_endian_t;
-pciio_endian_t snia_pciio_endian_set(struct pci_dev
-                                    *pci_dev, pciio_endian_t device_end,
-                                    pciio_endian_t desired_end);
-
-static unsigned int __init
+static unsigned int __devinit
 pci_init_sgiioc4(struct pci_dev *dev, ide_pci_device_t * d)
 {
        unsigned int class_rev;
-       pciio_endian_t endian_status;
-
-       if (pci_enable_device(dev)) {
-               printk(KERN_ERR
-                      "Failed to enable device %s at slot %s\n",
-                      d->name, dev->slot_name);
-               return -ENODEV;
-       }
-       pci_set_master(dev);
+       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, dev->slot_name, class_rev);
+                       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, dev->slot_name);
-               return -ENODEV;
+                       "46 or higher\n", d->name, pci_name(dev));
+               ret = -EAGAIN;
+               goto out;
        }
-
-       /* Enable Byte Swapping in the PIC... */
-       endian_status = snia_pciio_endian_set(dev, PCIDMA_ENDIAN_LITTLE,
-                                             PCIDMA_ENDIAN_BIG);
-       if (endian_status != PCIDMA_ENDIAN_BIG) {
-               printk(KERN_ERR
-                      "Failed to set endianness for device %s at slot %s\n",
-                      d->name, dev->slot_name);
-               return -ENODEV;
-       }
-
-       return sgiioc4_ide_setup_pci_device(dev, d);
+       ret = sgiioc4_ide_setup_pci_device(dev, d);
+out:
+       return ret;
 }
 
 static ide_pci_device_t sgiioc4_chipsets[] __devinitdata = {
@@ -770,34 +720,35 @@ static ide_pci_device_t sgiioc4_chipsets[] __devinitdata = {
        }
 };
 
-static int __devinit
-sgiioc4_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+int
+ioc4_ide_attach_one(struct ioc4_driver_data *idd)
 {
-       pci_init_sgiioc4(dev, &sgiioc4_chipsets[id->driver_data]);
-       return 0;
+       return pci_init_sgiioc4(idd->idd_pdev,
+                               &sgiioc4_chipsets[idd->idd_pci_id->driver_data]);
 }
 
-static struct pci_device_id sgiioc4_pci_tbl[] = {
-       {PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC4, PCI_ANY_ID,
-        PCI_ANY_ID, 0x0b4000, 0xFFFFFF, 0},
-       {0}
+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,       */
 };
-MODULE_DEVICE_TABLE(pci, sgiioc4_pci_tbl);
 
-static struct pci_driver driver = {
-       .name = "SGI-IOC4_IDE",
-       .id_table = sgiioc4_pci_tbl,
-       .probe = sgiioc4_init_one,
-};
+static int __devinit
+ioc4_ide_init(void)
+{
+       return ioc4_register_submodule(&ioc4_ide_submodule);
+}
 
-static int
-sgiioc4_ide_init(void)
+static void __devexit
+ioc4_ide_exit(void)
 {
-       return ide_pci_register_driver(&driver);
+       ioc4_unregister_submodule(&ioc4_ide_submodule);
 }
 
-module_init(sgiioc4_ide_init);
+module_init(ioc4_ide_init);
+module_exit(ioc4_ide_exit);
 
-MODULE_AUTHOR("Aniket Malatpure - Silicon Graphics Inc. (SGI)");
-MODULE_DESCRIPTION("PCI driver module for SGI IOC4 Base-IO Card");
+MODULE_AUTHOR("Aniket Malatpure/Jeremy Higdon");
+MODULE_DESCRIPTION("IDE PCI driver module for SGI IOC4 Base-IO Card");
 MODULE_LICENSE("GPL");