Merge to Fedora kernel-2.6.18-1.2224_FC5 patched with stable patch-2.6.18.1-vs2.0...
[linux-2.6.git] / drivers / scsi / sata_uli.c
index 1becb36..33cdb48 100644 (file)
@@ -1,25 +1,29 @@
 /*
  *  sata_uli.c - ULi Electronics SATA
  *
- *  The contents of this file are subject to the Open
- *  Software License version 1.1 that can be found at
- *  http://www.opensource.org/licenses/osl-1.1.txt and is included herein
- *  by reference.
  *
- *  Alternatively, the contents of this file may be used under the terms
- *  of the GNU General Public License version 2 (the "GPL") as distributed
- *  in the kernel source COPYING file, 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 OSL, 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 OSL or the GPL.
+ *  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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; see the file COPYING.  If not, write to
+ *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ *  libata documentation is available via 'make {ps|pdf}docs',
+ *  as Documentation/DocBook/libata.*
+ *
+ *  Hardware documentation available under NDA.
  *
  */
 
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
-#include "scsi.h"
+#include <linux/device.h>
 #include <scsi/scsi_host.h>
 #include <linux/libata.h>
 
 #define DRV_NAME       "sata_uli"
-#define DRV_VERSION    "0.11"
+#define DRV_VERSION    "1.0"
 
 enum {
        uli_5289                = 0,
        uli_5287                = 1,
+       uli_5281                = 2,
+
+       uli_max_ports           = 4,
 
        /* PCI configuration registers */
-       ULI_SCR_BASE            = 0x90, /* sata0 phy SCR registers */
-       ULI_SATA1_OFS           = 0x10, /* offset from sata0->sata1 phy regs */
+       ULI5287_BASE            = 0x90, /* sata0 phy SCR registers */
+       ULI5287_OFFS            = 0x10, /* offset from sata0->sata1 phy regs */
+       ULI5281_BASE            = 0x60, /* sata0 phy SCR  registers */
+       ULI5281_OFFS            = 0x60, /* offset from sata0->sata1 phy regs */
+};
 
+struct uli_priv {
+       unsigned int            scr_cfg_addr[uli_max_ports];
 };
 
 static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
 static u32 uli_scr_read (struct ata_port *ap, unsigned int sc_reg);
 static void uli_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
 
-static struct pci_device_id uli_pci_tbl[] = {
+static const struct pci_device_id uli_pci_tbl[] = {
        { PCI_VENDOR_ID_AL, 0x5289, PCI_ANY_ID, PCI_ANY_ID, 0, 0, uli_5289 },
        { PCI_VENDOR_ID_AL, 0x5287, PCI_ANY_ID, PCI_ANY_ID, 0, 0, uli_5287 },
+       { PCI_VENDOR_ID_AL, 0x5281, PCI_ANY_ID, PCI_ANY_ID, 0, 0, uli_5281 },
        { }     /* terminate list */
 };
 
@@ -62,26 +75,25 @@ static struct pci_driver uli_pci_driver = {
        .remove                 = ata_pci_remove_one,
 };
 
-static Scsi_Host_Template uli_sht = {
+static struct scsi_host_template uli_sht = {
        .module                 = THIS_MODULE,
        .name                   = DRV_NAME,
        .ioctl                  = ata_scsi_ioctl,
        .queuecommand           = ata_scsi_queuecmd,
-       .eh_strategy_handler    = ata_scsi_error,
        .can_queue              = ATA_DEF_QUEUE,
        .this_id                = ATA_SHT_THIS_ID,
        .sg_tablesize           = LIBATA_MAX_PRD,
-       .max_sectors            = ATA_MAX_SECTORS,
        .cmd_per_lun            = ATA_SHT_CMD_PER_LUN,
        .emulated               = ATA_SHT_EMULATED,
        .use_clustering         = ATA_SHT_USE_CLUSTERING,
        .proc_name              = DRV_NAME,
        .dma_boundary           = ATA_DMA_BOUNDARY,
        .slave_configure        = ata_scsi_slave_config,
+       .slave_destroy          = ata_scsi_slave_destroy,
        .bios_param             = ata_std_bios_param,
 };
 
-static struct ata_port_operations uli_ops = {
+static const struct ata_port_operations uli_ops = {
        .port_disable           = ata_port_disable,
 
        .tf_load                = ata_tf_load,
@@ -90,14 +102,18 @@ static struct ata_port_operations uli_ops = {
        .exec_command           = ata_exec_command,
        .dev_select             = ata_std_dev_select,
 
-       .phy_reset              = sata_phy_reset,
-
        .bmdma_setup            = ata_bmdma_setup,
        .bmdma_start            = ata_bmdma_start,
+       .bmdma_stop             = ata_bmdma_stop,
+       .bmdma_status           = ata_bmdma_status,
        .qc_prep                = ata_qc_prep,
        .qc_issue               = ata_qc_issue_prot,
+       .data_xfer              = ata_pio_data_xfer,
 
-       .eng_timeout            = ata_eng_timeout,
+       .freeze                 = ata_bmdma_freeze,
+       .thaw                   = ata_bmdma_thaw,
+       .error_handler          = ata_bmdma_error_handler,
+       .post_internal_cmd      = ata_bmdma_post_internal_cmd,
 
        .irq_handler            = ata_interrupt,
        .irq_clear              = ata_bmdma_irq_clear,
@@ -107,14 +123,14 @@ static struct ata_port_operations uli_ops = {
 
        .port_start             = ata_port_start,
        .port_stop              = ata_port_stop,
+       .host_stop              = ata_host_stop,
 };
 
 static struct ata_port_info uli_port_info = {
        .sht            = &uli_sht,
-       .host_flags     = ATA_FLAG_SATA | ATA_FLAG_SATA_RESET |
-                         ATA_FLAG_NO_LEGACY,
-       .pio_mask       = 0x03,         //support pio mode 4 (FIXME)
-       .udma_mask      = 0x7f,         //support udma mode 6
+       .host_flags     = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
+       .pio_mask       = 0x1f,         /* pio0-4 */
+       .udma_mask      = 0x7f,         /* udma0-6 */
        .port_ops       = &uli_ops,
 };
 
@@ -125,43 +141,28 @@ MODULE_LICENSE("GPL");
 MODULE_DEVICE_TABLE(pci, uli_pci_tbl);
 MODULE_VERSION(DRV_VERSION);
 
-static unsigned int get_scr_cfg_addr(unsigned int port_no, unsigned int sc_reg)
+static unsigned int get_scr_cfg_addr(struct ata_port *ap, unsigned int sc_reg)
 {
-       unsigned int addr = ULI_SCR_BASE + (4 * sc_reg);
-
-       switch (port_no) {
-       case 0:
-               break;
-       case 1:
-               addr += ULI_SATA1_OFS;
-               break;
-       case 2:
-               addr += ULI_SATA1_OFS*4;
-               break;
-       case 3:
-               addr += ULI_SATA1_OFS*5;
-               break;
-       default:
-               BUG();
-               break;
-       }
-       return addr;
+       struct uli_priv *hpriv = ap->host_set->private_data;
+       return hpriv->scr_cfg_addr[ap->port_no] + (4 * sc_reg);
 }
 
 static u32 uli_scr_cfg_read (struct ata_port *ap, unsigned int sc_reg)
 {
-       unsigned int cfg_addr = get_scr_cfg_addr(ap->port_no, sc_reg);
+       struct pci_dev *pdev = to_pci_dev(ap->host_set->dev);
+       unsigned int cfg_addr = get_scr_cfg_addr(ap, sc_reg);
        u32 val;
 
-       pci_read_config_dword(ap->host_set->pdev, cfg_addr, &val);
+       pci_read_config_dword(pdev, cfg_addr, &val);
        return val;
 }
 
 static void uli_scr_cfg_write (struct ata_port *ap, unsigned int scr, u32 val)
 {
-       unsigned int cfg_addr = get_scr_cfg_addr(ap->port_no, scr);
+       struct pci_dev *pdev = to_pci_dev(ap->host_set->dev);
+       unsigned int cfg_addr = get_scr_cfg_addr(ap, scr);
 
-       pci_write_config_dword(ap->host_set->pdev, cfg_addr, val);
+       pci_write_config_dword(pdev, cfg_addr, val);
 }
 
 static u32 uli_scr_read (struct ata_port *ap, unsigned int sc_reg)
@@ -180,32 +181,28 @@ static void uli_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
        uli_scr_cfg_write(ap, sc_reg, val);
 }
 
-/* move to PCI layer, integrate w/ MSI stuff */
-static void pci_enable_intx(struct pci_dev *pdev)
-{
-       u16 pci_command;
-
-       pci_read_config_word(pdev, PCI_COMMAND, &pci_command);
-       if (pci_command & PCI_COMMAND_INTX_DISABLE) {
-               pci_command &= ~PCI_COMMAND_INTX_DISABLE;
-               pci_write_config_word(pdev, PCI_COMMAND, pci_command);
-       }
-}
-
 static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
 {
+       static int printed_version;
        struct ata_probe_ent *probe_ent;
        struct ata_port_info *ppi;
        int rc;
        unsigned int board_idx = (unsigned int) ent->driver_data;
+       int pci_dev_busy = 0;
+       struct uli_priv *hpriv;
+
+       if (!printed_version++)
+               dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n");
 
        rc = pci_enable_device(pdev);
        if (rc)
                return rc;
 
        rc = pci_request_regions(pdev, DRV_NAME);
-       if (rc)
+       if (rc) {
+               pci_dev_busy = 1;
                goto err_out;
+       }
 
        rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
        if (rc)
@@ -215,14 +212,24 @@ static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
                goto err_out_regions;
 
        ppi = &uli_port_info;
-       probe_ent = ata_pci_init_native_mode(pdev, &ppi);
+       probe_ent = ata_pci_init_native_mode(pdev, &ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY);
        if (!probe_ent) {
                rc = -ENOMEM;
                goto err_out_regions;
        }
 
+       hpriv = kzalloc(sizeof(*hpriv), GFP_KERNEL);
+       if (!hpriv) {
+               rc = -ENOMEM;
+               goto err_out_probe_ent;
+       }
+
+       probe_ent->private_data = hpriv;
+
        switch (board_idx) {
        case uli_5287:
+               hpriv->scr_cfg_addr[0] = ULI5287_BASE;
+               hpriv->scr_cfg_addr[1] = ULI5287_BASE + ULI5287_OFFS;
                        probe_ent->n_ports = 4;
 
                        probe_ent->port[2].cmd_addr = pci_resource_start(pdev, 0) + 8;
@@ -230,19 +237,27 @@ static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
                probe_ent->port[2].ctl_addr =
                        (pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS) + 4;
                probe_ent->port[2].bmdma_addr = pci_resource_start(pdev, 4) + 16;
+               hpriv->scr_cfg_addr[2] = ULI5287_BASE + ULI5287_OFFS*4;
 
                probe_ent->port[3].cmd_addr = pci_resource_start(pdev, 2) + 8;
                probe_ent->port[3].altstatus_addr =
                probe_ent->port[3].ctl_addr =
                        (pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS) + 4;
                probe_ent->port[3].bmdma_addr = pci_resource_start(pdev, 4) + 24;
+               hpriv->scr_cfg_addr[3] = ULI5287_BASE + ULI5287_OFFS*5;
 
                ata_std_ports(&probe_ent->port[2]);
                ata_std_ports(&probe_ent->port[3]);
                break;
 
        case uli_5289:
-               /* do nothing; ata_pci_init_native_mode did it all */
+               hpriv->scr_cfg_addr[0] = ULI5287_BASE;
+               hpriv->scr_cfg_addr[1] = ULI5287_BASE + ULI5287_OFFS;
+               break;
+
+       case uli_5281:
+               hpriv->scr_cfg_addr[0] = ULI5281_BASE;
+               hpriv->scr_cfg_addr[1] = ULI5281_BASE + ULI5281_OFFS;
                break;
 
        default:
@@ -251,7 +266,7 @@ static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
        }
 
        pci_set_master(pdev);
-       pci_enable_intx(pdev);
+       pci_intx(pdev, 1);
 
        /* FIXME: check ata_device_add return value */
        ata_device_add(probe_ent);
@@ -259,11 +274,13 @@ static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
 
        return 0;
 
+err_out_probe_ent:
+       kfree(probe_ent);
 err_out_regions:
        pci_release_regions(pdev);
-
 err_out:
-       pci_disable_device(pdev);
+       if (!pci_dev_busy)
+               pci_disable_device(pdev);
        return rc;
 
 }