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_via.c
index f43183c..a3727af 100644 (file)
@@ -1,34 +1,38 @@
 /*
-   sata_via.c - VIA Serial ATA controllers
-
-   Maintained by:  Jeff Garzik <jgarzik@pobox.com>
                 Please ALWAYS copy linux-ide@vger.kernel.org
*  sata_via.c - VIA Serial ATA controllers
+ *
*  Maintained by:  Jeff Garzik <jgarzik@pobox.com>
*                Please ALWAYS copy linux-ide@vger.kernel.org
                   on emails.
-
-   Copyright 2003-2004 Red Hat, Inc.  All rights reserved.
-   Copyright 2003-2004 Jeff Garzik
-
-   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.
-
-   ----------------------------------------------------------------------
-
-   To-do list:
-   * VT6421 PATA support
-
+ *
+ *  Copyright 2003-2004 Red Hat, Inc.  All rights reserved.
+ *  Copyright 2003-2004 Jeff Garzik
+ *
+ *
+ *  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.
+ *
+ *
+ *  To-do list:
+ *  - VT6421 PATA support
+ *
  */
 
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/delay.h>
-#include "scsi.h"
+#include <linux/device.h>
 #include <scsi/scsi_host.h>
 #include <linux/libata.h>
 #include <asm/io.h>
 
 #define DRV_NAME       "sata_via"
-#define DRV_VERSION    "1.1"
+#define DRV_VERSION    "2.0"
 
 enum board_ids_enum {
        vt6420,
@@ -70,8 +74,10 @@ enum {
 static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
 static u32 svia_scr_read (struct ata_port *ap, unsigned int sc_reg);
 static void svia_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+static void vt6420_error_handler(struct ata_port *ap);
 
-static struct pci_device_id svia_pci_tbl[] = {
+static const struct pci_device_id svia_pci_tbl[] = {
+       { 0x1106, 0x0591, PCI_ANY_ID, PCI_ANY_ID, 0, 0, vt6420 },
        { 0x1106, 0x3149, PCI_ANY_ID, PCI_ANY_ID, 0, 0, vt6420 },
        { 0x1106, 0x3249, PCI_ANY_ID, PCI_ANY_ID, 0, 0, vt6421 },
 
@@ -85,27 +91,25 @@ static struct pci_driver svia_pci_driver = {
        .remove                 = ata_pci_remove_one,
 };
 
-static Scsi_Host_Template svia_sht = {
+static struct scsi_host_template svia_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,
-       .ordered_flush          = 1,
 };
 
-static struct ata_port_operations svia_sata_ops = {
+static const struct ata_port_operations vt6420_sata_ops = {
        .port_disable           = ata_port_disable,
 
        .tf_load                = ata_tf_load,
@@ -114,7 +118,36 @@ static struct ata_port_operations svia_sata_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,
+
+       .freeze                 = ata_bmdma_freeze,
+       .thaw                   = ata_bmdma_thaw,
+       .error_handler          = vt6420_error_handler,
+       .post_internal_cmd      = ata_bmdma_post_internal_cmd,
+
+       .irq_handler            = ata_interrupt,
+       .irq_clear              = ata_bmdma_irq_clear,
+
+       .port_start             = ata_port_start,
+       .port_stop              = ata_port_stop,
+       .host_stop              = ata_host_stop,
+};
+
+static const struct ata_port_operations vt6421_sata_ops = {
+       .port_disable           = ata_port_disable,
+
+       .tf_load                = ata_tf_load,
+       .tf_read                = ata_tf_read,
+       .check_status           = ata_check_status,
+       .exec_command           = ata_exec_command,
+       .dev_select             = ata_std_dev_select,
 
        .bmdma_setup            = ata_bmdma_setup,
        .bmdma_start            = ata_bmdma_start,
@@ -123,8 +156,12 @@ static struct ata_port_operations svia_sata_ops = {
 
        .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,
@@ -137,13 +174,13 @@ static struct ata_port_operations svia_sata_ops = {
        .host_stop              = ata_host_stop,
 };
 
-static struct ata_port_info svia_port_info = {
+static struct ata_port_info vt6420_port_info = {
        .sht            = &svia_sht,
-       .host_flags     = ATA_FLAG_SATA | ATA_FLAG_SRST | ATA_FLAG_NO_LEGACY,
+       .host_flags     = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
        .pio_mask       = 0x1f,
        .mwdma_mask     = 0x07,
        .udma_mask      = 0x7f,
-       .port_ops       = &svia_sata_ops,
+       .port_ops       = &vt6420_sata_ops,
 };
 
 MODULE_AUTHOR("Jeff Garzik");
@@ -166,6 +203,81 @@ static void svia_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
        outl(val, ap->ioaddr.scr_addr + (4 * sc_reg));
 }
 
+/**
+ *     vt6420_prereset - prereset for vt6420
+ *     @ap: target ATA port
+ *
+ *     SCR registers on vt6420 are pieces of shit and may hang the
+ *     whole machine completely if accessed with the wrong timing.
+ *     To avoid such catastrophe, vt6420 doesn't provide generic SCR
+ *     access operations, but uses SStatus and SControl only during
+ *     boot probing in controlled way.
+ *
+ *     As the old (pre EH update) probing code is proven to work, we
+ *     strictly follow the access pattern.
+ *
+ *     LOCKING:
+ *     Kernel thread context (may sleep)
+ *
+ *     RETURNS:
+ *     0 on success, -errno otherwise.
+ */
+static int vt6420_prereset(struct ata_port *ap)
+{
+       struct ata_eh_context *ehc = &ap->eh_context;
+       unsigned long timeout = jiffies + (HZ * 5);
+       u32 sstatus, scontrol;
+       int online;
+
+       /* don't do any SCR stuff if we're not loading */
+       if (!ATA_PFLAG_LOADING)
+               goto skip_scr;
+
+       /* Resume phy.  This is the old resume sequence from
+        * __sata_phy_reset().
+        */
+       svia_scr_write(ap, SCR_CONTROL, 0x300);
+       svia_scr_read(ap, SCR_CONTROL); /* flush */
+
+       /* wait for phy to become ready, if necessary */
+       do {
+               msleep(200);
+               if ((svia_scr_read(ap, SCR_STATUS) & 0xf) != 1)
+                       break;
+       } while (time_before(jiffies, timeout));
+
+       /* open code sata_print_link_status() */
+       sstatus = svia_scr_read(ap, SCR_STATUS);
+       scontrol = svia_scr_read(ap, SCR_CONTROL);
+
+       online = (sstatus & 0xf) == 0x3;
+
+       ata_port_printk(ap, KERN_INFO,
+                       "SATA link %s 1.5 Gbps (SStatus %X SControl %X)\n",
+                       online ? "up" : "down", sstatus, scontrol);
+
+       /* SStatus is read one more time */
+       svia_scr_read(ap, SCR_STATUS);
+
+       if (!online) {
+               /* tell EH to bail */
+               ehc->i.action &= ~ATA_EH_RESET_MASK;
+               return 0;
+       }
+
+ skip_scr:
+       /* wait for !BSY */
+       ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
+
+       return 0;
+}
+
+static void vt6420_error_handler(struct ata_port *ap)
+{
+       return ata_bmdma_drive_eh(ap, vt6420_prereset, ata_std_softreset,
+                                 NULL, ata_std_postreset);
+}
+
 static const unsigned int svia_bar_sizes[] = {
        8, 4, 8, 4, 16, 256
 };
@@ -206,9 +318,9 @@ static void vt6421_init_addrs(struct ata_probe_ent *probe_ent,
 static struct ata_probe_ent *vt6420_init_probe_ent(struct pci_dev *pdev)
 {
        struct ata_probe_ent *probe_ent;
-       struct ata_port_info *ppi = &svia_port_info;
+       struct ata_port_info *ppi = &vt6420_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)
                return NULL;
 
@@ -234,12 +346,11 @@ static struct ata_probe_ent *vt6421_init_probe_ent(struct pci_dev *pdev)
        INIT_LIST_HEAD(&probe_ent->node);
 
        probe_ent->sht          = &svia_sht;
-       probe_ent->host_flags   = ATA_FLAG_SATA | ATA_FLAG_SATA_RESET |
-                                 ATA_FLAG_NO_LEGACY;
-       probe_ent->port_ops     = &svia_sata_ops;
+       probe_ent->host_flags   = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY;
+       probe_ent->port_ops     = &vt6421_sata_ops;
        probe_ent->n_ports      = N_PORTS;
        probe_ent->irq          = pdev->irq;
-       probe_ent->irq_flags    = SA_SHIRQ;
+       probe_ent->irq_flags    = IRQF_SHARED;
        probe_ent->pio_mask     = 0x1f;
        probe_ent->mwdma_mask   = 0x07;
        probe_ent->udma_mask    = 0x7f;
@@ -255,15 +366,15 @@ static void svia_configure(struct pci_dev *pdev)
        u8 tmp8;
 
        pci_read_config_byte(pdev, PCI_INTERRUPT_LINE, &tmp8);
-       printk(KERN_INFO DRV_NAME "(%s): routed to hard irq line %d\n",
-              pci_name(pdev),
+       dev_printk(KERN_INFO, &pdev->dev, "routed to hard irq line %d\n",
               (int) (tmp8 & 0xf0) == 0xf0 ? 0 : tmp8 & 0x0f);
 
        /* make sure SATA channels are enabled */
        pci_read_config_byte(pdev, SATA_CHAN_ENAB, &tmp8);
        if ((tmp8 & ALL_PORTS) != ALL_PORTS) {
-               printk(KERN_DEBUG DRV_NAME "(%s): enabling SATA channels (0x%x)\n",
-                      pci_name(pdev), (int) tmp8);
+               dev_printk(KERN_DEBUG, &pdev->dev,
+                          "enabling SATA channels (0x%x)\n",
+                          (int) tmp8);
                tmp8 |= ALL_PORTS;
                pci_write_config_byte(pdev, SATA_CHAN_ENAB, tmp8);
        }
@@ -271,8 +382,9 @@ static void svia_configure(struct pci_dev *pdev)
        /* make sure interrupts for each channel sent to us */
        pci_read_config_byte(pdev, SATA_INT_GATE, &tmp8);
        if ((tmp8 & ALL_PORTS) != ALL_PORTS) {
-               printk(KERN_DEBUG DRV_NAME "(%s): enabling SATA channel interrupts (0x%x)\n",
-                      pci_name(pdev), (int) tmp8);
+               dev_printk(KERN_DEBUG, &pdev->dev,
+                          "enabling SATA channel interrupts (0x%x)\n",
+                          (int) tmp8);
                tmp8 |= ALL_PORTS;
                pci_write_config_byte(pdev, SATA_INT_GATE, tmp8);
        }
@@ -280,8 +392,9 @@ static void svia_configure(struct pci_dev *pdev)
        /* make sure native mode is enabled */
        pci_read_config_byte(pdev, SATA_NATIVE_MODE, &tmp8);
        if ((tmp8 & NATIVE_MODE_ALL) != NATIVE_MODE_ALL) {
-               printk(KERN_DEBUG DRV_NAME "(%s): enabling SATA channel native mode (0x%x)\n",
-                      pci_name(pdev), (int) tmp8);
+               dev_printk(KERN_DEBUG, &pdev->dev,
+                          "enabling SATA channel native mode (0x%x)\n",
+                          (int) tmp8);
                tmp8 |= NATIVE_MODE_ALL;
                pci_write_config_byte(pdev, SATA_NATIVE_MODE, tmp8);
        }
@@ -299,7 +412,7 @@ static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
        u8 tmp8;
 
        if (!printed_version++)
-               printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n");
+               dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
 
        rc = pci_enable_device(pdev);
        if (rc)
@@ -314,8 +427,9 @@ static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
        if (board_id == vt6420) {
                pci_read_config_byte(pdev, SATA_PATA_SHARING, &tmp8);
                if (tmp8 & SATA_2DEV) {
-                       printk(KERN_ERR DRV_NAME "(%s): SATA master/slave not supported (0x%x)\n",
-                       pci_name(pdev), (int) tmp8);
+                       dev_printk(KERN_ERR, &pdev->dev,
+                                  "SATA master/slave not supported (0x%x)\n",
+                                  (int) tmp8);
                        rc = -EIO;
                        goto err_out_regions;
                }
@@ -328,10 +442,11 @@ static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
        for (i = 0; i < ARRAY_SIZE(svia_bar_sizes); i++)
                if ((pci_resource_start(pdev, i) == 0) ||
                    (pci_resource_len(pdev, i) < bar_sizes[i])) {
-                       printk(KERN_ERR DRV_NAME "(%s): invalid PCI BAR %u (sz 0x%lx, val 0x%lx)\n",
-                              pci_name(pdev), i,
-                              pci_resource_start(pdev, i),
-                              pci_resource_len(pdev, i));
+                       dev_printk(KERN_ERR, &pdev->dev,
+                               "invalid PCI BAR %u (sz 0x%llx, val 0x%llx)\n",
+                               i,
+                               (unsigned long long)pci_resource_start(pdev, i),
+                               (unsigned long long)pci_resource_len(pdev, i));
                        rc = -ENODEV;
                        goto err_out_regions;
                }
@@ -347,10 +462,9 @@ static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
                probe_ent = vt6420_init_probe_ent(pdev);
        else
                probe_ent = vt6421_init_probe_ent(pdev);
-       
+
        if (!probe_ent) {
-               printk(KERN_ERR DRV_NAME "(%s): out of memory\n",
-                      pci_name(pdev));
+               dev_printk(KERN_ERR, &pdev->dev, "out of memory\n");
                rc = -ENOMEM;
                goto err_out_regions;
        }