nfsd: minor nfsd_vfs_write cleanup
[safe/jmp/linux-2.6] / drivers / ata / sata_via.c
index 9be877c..bdd43c7 100644 (file)
 #include <linux/libata.h>
 
 #define DRV_NAME       "sata_via"
-#define DRV_VERSION    "2.3"
+#define DRV_VERSION    "2.4"
 
+/*
+ * vt8251 is different from other sata controllers of VIA.  It has two
+ * channels, each channel has both Master and Slave slot.
+ */
 enum board_ids_enum {
        vt6420,
        vt6421,
+       vt8251,
 };
 
 enum {
@@ -68,22 +73,27 @@ enum {
 };
 
 static int svia_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
-static int svia_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
-static int svia_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int svia_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val);
+static int svia_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val);
+static int vt8251_scr_read(struct ata_link *link, unsigned int scr, u32 *val);
+static int vt8251_scr_write(struct ata_link *link, unsigned int scr, u32 val);
+static void svia_tf_load(struct ata_port *ap, const struct ata_taskfile *tf);
 static void svia_noop_freeze(struct ata_port *ap);
-static void vt6420_error_handler(struct ata_port *ap);
+static int vt6420_prereset(struct ata_link *link, unsigned long deadline);
 static int vt6421_pata_cable_detect(struct ata_port *ap);
 static void vt6421_set_pio_mode(struct ata_port *ap, struct ata_device *adev);
 static void vt6421_set_dma_mode(struct ata_port *ap, struct ata_device *adev);
 
 static const struct pci_device_id svia_pci_tbl[] = {
        { PCI_VDEVICE(VIA, 0x5337), vt6420 },
-       { PCI_VDEVICE(VIA, 0x0591), vt6420 },
-       { PCI_VDEVICE(VIA, 0x3149), vt6420 },
-       { PCI_VDEVICE(VIA, 0x3249), vt6421 },
-       { PCI_VDEVICE(VIA, 0x5287), vt6420 },
+       { PCI_VDEVICE(VIA, 0x0591), vt6420 }, /* 2 sata chnls (Master) */
+       { PCI_VDEVICE(VIA, 0x3149), vt6420 }, /* 2 sata chnls (Master) */
+       { PCI_VDEVICE(VIA, 0x3249), vt6421 }, /* 2 sata chnls, 1 pata chnl */
        { PCI_VDEVICE(VIA, 0x5372), vt6420 },
        { PCI_VDEVICE(VIA, 0x7372), vt6420 },
+       { PCI_VDEVICE(VIA, 0x5287), vt8251 }, /* 2 sata chnls (Master/Slave) */
+       { PCI_VDEVICE(VIA, 0x9000), vt8251 },
+       { PCI_VDEVICE(VIA, 0x9040), vt8251 },
 
        { }     /* terminate list */
 };
@@ -103,152 +113,199 @@ static struct scsi_host_template svia_sht = {
        ATA_BMDMA_SHT(DRV_NAME),
 };
 
-static const struct ata_port_operations vt6420_sata_ops = {
-       .mode_filter            = ata_pci_default_filter,
-
-       .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,
-       .bmdma_stop             = ata_bmdma_stop,
-       .bmdma_status           = ata_bmdma_status,
-
-       .qc_prep                = ata_qc_prep,
-       .qc_issue               = ata_qc_issue_prot,
-       .data_xfer              = ata_data_xfer,
+static struct ata_port_operations svia_base_ops = {
+       .inherits               = &ata_bmdma_port_ops,
+       .sff_tf_load            = svia_tf_load,
+};
 
+static struct ata_port_operations vt6420_sata_ops = {
+       .inherits               = &svia_base_ops,
        .freeze                 = svia_noop_freeze,
-       .thaw                   = ata_bmdma_thaw,
-       .error_handler          = vt6420_error_handler,
-       .post_internal_cmd      = ata_bmdma_post_internal_cmd,
-
-       .irq_clear              = ata_bmdma_irq_clear,
-       .irq_on                 = ata_irq_on,
-
-       .port_start             = ata_sff_port_start,
+       .prereset               = vt6420_prereset,
 };
 
-static const struct ata_port_operations vt6421_pata_ops = {
+static struct ata_port_operations vt6421_pata_ops = {
+       .inherits               = &svia_base_ops,
+       .cable_detect           = vt6421_pata_cable_detect,
        .set_piomode            = vt6421_set_pio_mode,
        .set_dmamode            = vt6421_set_dma_mode,
-       .mode_filter            = ata_pci_default_filter,
-
-       .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,
-       .bmdma_stop             = ata_bmdma_stop,
-       .bmdma_status           = ata_bmdma_status,
-
-       .qc_prep                = ata_qc_prep,
-       .qc_issue               = ata_qc_issue_prot,
-       .data_xfer              = ata_data_xfer,
-
-       .freeze                 = ata_bmdma_freeze,
-       .thaw                   = ata_bmdma_thaw,
-       .error_handler          = ata_bmdma_error_handler,
-       .post_internal_cmd      = ata_bmdma_post_internal_cmd,
-       .cable_detect           = vt6421_pata_cable_detect,
-
-       .irq_clear              = ata_bmdma_irq_clear,
-       .irq_on                 = ata_irq_on,
-
-       .port_start             = ata_sff_port_start,
 };
 
-static const struct ata_port_operations vt6421_sata_ops = {
-       .mode_filter            = ata_pci_default_filter,
-
-       .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,
-       .bmdma_stop             = ata_bmdma_stop,
-       .bmdma_status           = ata_bmdma_status,
-
-       .qc_prep                = ata_qc_prep,
-       .qc_issue               = ata_qc_issue_prot,
-       .data_xfer              = ata_data_xfer,
-
-       .freeze                 = ata_bmdma_freeze,
-       .thaw                   = ata_bmdma_thaw,
-       .error_handler          = ata_bmdma_error_handler,
-       .post_internal_cmd      = ata_bmdma_post_internal_cmd,
-
-       .irq_clear              = ata_bmdma_irq_clear,
-       .irq_on                 = ata_irq_on,
-
+static struct ata_port_operations vt6421_sata_ops = {
+       .inherits               = &svia_base_ops,
        .scr_read               = svia_scr_read,
        .scr_write              = svia_scr_write,
+};
 
-       .port_start             = ata_sff_port_start,
+static struct ata_port_operations vt8251_ops = {
+       .inherits               = &svia_base_ops,
+       .hardreset              = sata_std_hardreset,
+       .scr_read               = vt8251_scr_read,
+       .scr_write              = vt8251_scr_write,
 };
 
 static const struct ata_port_info vt6420_port_info = {
        .flags          = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
-       .pio_mask       = 0x1f,
-       .mwdma_mask     = 0x07,
+       .pio_mask       = ATA_PIO4,
+       .mwdma_mask     = ATA_MWDMA2,
        .udma_mask      = ATA_UDMA6,
        .port_ops       = &vt6420_sata_ops,
 };
 
 static struct ata_port_info vt6421_sport_info = {
        .flags          = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
-       .pio_mask       = 0x1f,
-       .mwdma_mask     = 0x07,
+       .pio_mask       = ATA_PIO4,
+       .mwdma_mask     = ATA_MWDMA2,
        .udma_mask      = ATA_UDMA6,
        .port_ops       = &vt6421_sata_ops,
 };
 
 static struct ata_port_info vt6421_pport_info = {
        .flags          = ATA_FLAG_SLAVE_POSS | ATA_FLAG_NO_LEGACY,
-       .pio_mask       = 0x1f,
-       .mwdma_mask     = 0,
+       .pio_mask       = ATA_PIO4,
+       /* No MWDMA */
        .udma_mask      = ATA_UDMA6,
        .port_ops       = &vt6421_pata_ops,
 };
 
+static struct ata_port_info vt8251_port_info = {
+       .flags          = ATA_FLAG_SATA | ATA_FLAG_SLAVE_POSS |
+                         ATA_FLAG_NO_LEGACY,
+       .pio_mask       = ATA_PIO4,
+       .mwdma_mask     = ATA_MWDMA2,
+       .udma_mask      = ATA_UDMA6,
+       .port_ops       = &vt8251_ops,
+};
+
 MODULE_AUTHOR("Jeff Garzik");
 MODULE_DESCRIPTION("SCSI low-level driver for VIA SATA controllers");
 MODULE_LICENSE("GPL");
 MODULE_DEVICE_TABLE(pci, svia_pci_tbl);
 MODULE_VERSION(DRV_VERSION);
 
-static int svia_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
+static int svia_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val)
 {
        if (sc_reg > SCR_CONTROL)
                return -EINVAL;
-       *val = ioread32(ap->ioaddr.scr_addr + (4 * sc_reg));
+       *val = ioread32(link->ap->ioaddr.scr_addr + (4 * sc_reg));
        return 0;
 }
 
-static int svia_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int svia_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val)
 {
        if (sc_reg > SCR_CONTROL)
                return -EINVAL;
-       iowrite32(val, ap->ioaddr.scr_addr + (4 * sc_reg));
+       iowrite32(val, link->ap->ioaddr.scr_addr + (4 * sc_reg));
+       return 0;
+}
+
+static int vt8251_scr_read(struct ata_link *link, unsigned int scr, u32 *val)
+{
+       static const u8 ipm_tbl[] = { 1, 2, 6, 0 };
+       struct pci_dev *pdev = to_pci_dev(link->ap->host->dev);
+       int slot = 2 * link->ap->port_no + link->pmp;
+       u32 v = 0;
+       u8 raw;
+
+       switch (scr) {
+       case SCR_STATUS:
+               pci_read_config_byte(pdev, 0xA0 + slot, &raw);
+
+               /* read the DET field, bit0 and 1 of the config byte */
+               v |= raw & 0x03;
+
+               /* read the SPD field, bit4 of the configure byte */
+               if (raw & (1 << 4))
+                       v |= 0x02 << 4;
+               else
+                       v |= 0x01 << 4;
+
+               /* read the IPM field, bit2 and 3 of the config byte */
+               v |= ipm_tbl[(raw >> 2) & 0x3];
+               break;
+
+       case SCR_ERROR:
+               /* devices other than 5287 uses 0xA8 as base */
+               WARN_ON(pdev->device != 0x5287);
+               pci_read_config_dword(pdev, 0xB0 + slot * 4, &v);
+               break;
+
+       case SCR_CONTROL:
+               pci_read_config_byte(pdev, 0xA4 + slot, &raw);
+
+               /* read the DET field, bit0 and bit1 */
+               v |= ((raw & 0x02) << 1) | (raw & 0x01);
+
+               /* read the IPM field, bit2 and bit3 */
+               v |= ((raw >> 2) & 0x03) << 8;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       *val = v;
        return 0;
 }
 
+static int vt8251_scr_write(struct ata_link *link, unsigned int scr, u32 val)
+{
+       struct pci_dev *pdev = to_pci_dev(link->ap->host->dev);
+       int slot = 2 * link->ap->port_no + link->pmp;
+       u32 v = 0;
+
+       switch (scr) {
+       case SCR_ERROR:
+               /* devices other than 5287 uses 0xA8 as base */
+               WARN_ON(pdev->device != 0x5287);
+               pci_write_config_dword(pdev, 0xB0 + slot * 4, val);
+               return 0;
+
+       case SCR_CONTROL:
+               /* set the DET field */
+               v |= ((val & 0x4) >> 1) | (val & 0x1);
+
+               /* set the IPM field */
+               v |= ((val >> 8) & 0x3) << 2;
+
+               pci_write_config_byte(pdev, 0xA4 + slot, v);
+               return 0;
+
+       default:
+               return -EINVAL;
+       }
+}
+
+/**
+ *     svia_tf_load - send taskfile registers to host controller
+ *     @ap: Port to which output is sent
+ *     @tf: ATA taskfile register set
+ *
+ *     Outputs ATA taskfile to standard ATA host controller.
+ *
+ *     This is to fix the internal bug of via chipsets, which will
+ *     reset the device register after changing the IEN bit on ctl
+ *     register.
+ */
+static void svia_tf_load(struct ata_port *ap, const struct ata_taskfile *tf)
+{
+       struct ata_taskfile ttf;
+
+       if (tf->ctl != ap->last_ctl)  {
+               ttf = *tf;
+               ttf.flags |= ATA_TFLAG_DEVICE;
+               tf = &ttf;
+       }
+       ata_sff_tf_load(ap, tf);
+}
+
 static void svia_noop_freeze(struct ata_port *ap)
 {
        /* Some VIA controllers choke if ATA_NIEN is manipulated in
         * certain way.  Leave it alone and just clear pending IRQ.
         */
-       ata_chk_status(ap);
-       ata_bmdma_irq_clear(ap);
+       ap->ops->sff_check_status(ap);
+       ata_sff_irq_clear(ap);
 }
 
 /**
@@ -284,20 +341,20 @@ static int vt6420_prereset(struct ata_link *link, unsigned long deadline)
                goto skip_scr;
 
        /* Resume phy.  This is the old SATA resume sequence */
-       svia_scr_write(ap, SCR_CONTROL, 0x300);
-       svia_scr_read(ap, SCR_CONTROL, &scontrol); /* flush */
+       svia_scr_write(link, SCR_CONTROL, 0x300);
+       svia_scr_read(link, SCR_CONTROL, &scontrol); /* flush */
 
        /* wait for phy to become ready, if necessary */
        do {
                msleep(200);
-               svia_scr_read(ap, SCR_STATUS, &sstatus);
+               svia_scr_read(link, SCR_STATUS, &sstatus);
                if ((sstatus & 0xf) != 1)
                        break;
        } while (time_before(jiffies, timeout));
 
        /* open code sata_print_link_status() */
-       svia_scr_read(ap, SCR_STATUS, &sstatus);
-       svia_scr_read(ap, SCR_CONTROL, &scontrol);
+       svia_scr_read(link, SCR_STATUS, &sstatus);
+       svia_scr_read(link, SCR_CONTROL, &scontrol);
 
        online = (sstatus & 0xf) == 0x3;
 
@@ -306,7 +363,7 @@ static int vt6420_prereset(struct ata_link *link, unsigned long deadline)
                        online ? "up" : "down", sstatus, scontrol);
 
        /* SStatus is read one more time */
-       svia_scr_read(ap, SCR_STATUS, &sstatus);
+       svia_scr_read(link, SCR_STATUS, &sstatus);
 
        if (!online) {
                /* tell EH to bail */
@@ -316,17 +373,11 @@ static int vt6420_prereset(struct ata_link *link, unsigned long deadline)
 
  skip_scr:
        /* wait for !BSY */
-       ata_wait_ready(ap, deadline);
+       ata_sff_wait_ready(link, deadline);
 
        return 0;
 }
 
-static void vt6420_error_handler(struct ata_port *ap)
-{
-       ata_bmdma_drive_eh(ap, vt6420_prereset, ata_std_softreset, NULL,
-                          ata_std_postreset);
-}
-
 static int vt6421_pata_cable_detect(struct ata_port *ap)
 {
        struct pci_dev *pdev = to_pci_dev(ap->host->dev);
@@ -384,7 +435,7 @@ static void vt6421_init_addrs(struct ata_port *ap)
        ioaddr->bmdma_addr = bmdma_addr;
        ioaddr->scr_addr = vt6421_scr_addr(iomap[5], ap->port_no);
 
-       ata_std_ports(ioaddr);
+       ata_sff_std_ports(ioaddr);
 
        ata_port_pbar_desc(ap, ap->port_no, -1, "port");
        ata_port_pbar_desc(ap, 4, ap->port_no * 8, "bmdma");
@@ -396,7 +447,7 @@ static int vt6420_prepare_host(struct pci_dev *pdev, struct ata_host **r_host)
        struct ata_host *host;
        int rc;
 
-       rc = ata_pci_prepare_sff_host(pdev, ppi, &host);
+       rc = ata_pci_sff_prepare_host(pdev, ppi, &host);
        if (rc)
                return rc;
        *r_host = host;
@@ -447,6 +498,30 @@ static int vt6421_prepare_host(struct pci_dev *pdev, struct ata_host **r_host)
        return 0;
 }
 
+static int vt8251_prepare_host(struct pci_dev *pdev, struct ata_host **r_host)
+{
+       const struct ata_port_info *ppi[] = { &vt8251_port_info, NULL };
+       struct ata_host *host;
+       int i, rc;
+
+       rc = ata_pci_sff_prepare_host(pdev, ppi, &host);
+       if (rc)
+               return rc;
+       *r_host = host;
+
+       rc = pcim_iomap_regions(pdev, 1 << 5, DRV_NAME);
+       if (rc) {
+               dev_printk(KERN_ERR, &pdev->dev, "failed to iomap PCI BAR 5\n");
+               return rc;
+       }
+
+       /* 8251 hosts four sata ports as M/S of the two channels */
+       for (i = 0; i < host->n_ports; i++)
+               ata_slave_link_init(host->ports[i]);
+
+       return 0;
+}
+
 static void svia_configure(struct pci_dev *pdev)
 {
        u8 tmp8;
@@ -491,7 +566,7 @@ static int svia_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        static int printed_version;
        unsigned int i;
        int rc;
-       struct ata_host *host;
+       struct ata_host *host = NULL;
        int board_id = (int) ent->driver_data;
        const unsigned *bar_sizes;
 
@@ -502,10 +577,10 @@ static int svia_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (rc)
                return rc;
 
-       if (board_id == vt6420)
-               bar_sizes = &svia_bar_sizes[0];
-       else
+       if (board_id == vt6421)
                bar_sizes = &vt6421_bar_sizes[0];
+       else
+               bar_sizes = &svia_bar_sizes[0];
 
        for (i = 0; i < ARRAY_SIZE(svia_bar_sizes); i++)
                if ((pci_resource_start(pdev, i) == 0) ||
@@ -518,18 +593,27 @@ static int svia_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
                        return -ENODEV;
                }
 
-       if (board_id == vt6420)
+       switch (board_id) {
+       case vt6420:
                rc = vt6420_prepare_host(pdev, &host);
-       else
+               break;
+       case vt6421:
                rc = vt6421_prepare_host(pdev, &host);
+               break;
+       case vt8251:
+               rc = vt8251_prepare_host(pdev, &host);
+               break;
+       default:
+               rc = -EINVAL;
+       }
        if (rc)
                return rc;
 
        svia_configure(pdev);
 
        pci_set_master(pdev);
-       return ata_host_activate(host, pdev->irq, ata_interrupt, IRQF_SHARED,
-                                &svia_sht);
+       return ata_host_activate(host, pdev->irq, ata_sff_interrupt,
+                                IRQF_SHARED, &svia_sht);
 }
 
 static int __init svia_init(void)