sata_svw: Add support for HT1100 SATA controller
authorAnantha Subramanyam <ananth@broadcom.com>
Thu, 28 Feb 2008 23:58:35 +0000 (15:58 -0800)
committerJeff Garzik <jeff@garzik.org>
Fri, 29 Feb 2008 00:02:29 +0000 (19:02 -0500)
This patch adds support (including ATAPI DMA) for HT1100 (aka BCM11000) SATA controller.

Signed-off-by: Anantha Subramanyam <ananth@broadcom.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
drivers/ata/sata_svw.c

index 69f651e..840d1c4 100644 (file)
@@ -45,6 +45,8 @@
 #include <linux/interrupt.h>
 #include <linux/device.h>
 #include <scsi/scsi_host.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi.h>
 #include <linux/libata.h>
 
 #ifdef CONFIG_PPC_OF
@@ -59,6 +61,7 @@ enum {
        /* ap->flags bits */
        K2_FLAG_SATA_8_PORTS            = (1 << 24),
        K2_FLAG_NO_ATAPI_DMA            = (1 << 25),
+       K2_FLAG_BAR_POS_3                       = (1 << 26),
 
        /* Taskfile registers offsets */
        K2_SATA_TF_CMD_OFFSET           = 0x00,
@@ -88,8 +91,10 @@ enum {
        /* Port stride */
        K2_SATA_PORT_OFFSET             = 0x100,
 
-       board_svw4                      = 0,
-       board_svw8                      = 1,
+       chip_svw4                       = 0,
+       chip_svw8                       = 1,
+       chip_svw42                      = 2,    /* bar 3 */
+       chip_svw43                      = 3,    /* bar 5 */
 };
 
 static u8 k2_stat_check_status(struct ata_port *ap);
@@ -97,10 +102,25 @@ static u8 k2_stat_check_status(struct ata_port *ap);
 
 static int k2_sata_check_atapi_dma(struct ata_queued_cmd *qc)
 {
+       u8 cmnd = qc->scsicmd->cmnd[0];
+
        if (qc->ap->flags & K2_FLAG_NO_ATAPI_DMA)
                return -1;      /* ATAPI DMA not supported */
+       else {
+               switch (cmnd) {
+               case READ_10:
+               case READ_12:
+               case READ_16:
+               case WRITE_10:
+               case WRITE_12:
+               case WRITE_16:
+                       return 0;
+
+               default:
+                       return -1;
+               }
 
-       return 0;
+       }
 }
 
 static int k2_sata_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
@@ -354,7 +374,7 @@ static const struct ata_port_operations k2_sata_ops = {
 };
 
 static const struct ata_port_info k2_port_info[] = {
-       /* board_svw4 */
+       /* chip_svw4 */
        {
                .flags          = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
                                  ATA_FLAG_MMIO | K2_FLAG_NO_ATAPI_DMA,
@@ -363,7 +383,7 @@ static const struct ata_port_info k2_port_info[] = {
                .udma_mask      = ATA_UDMA6,
                .port_ops       = &k2_sata_ops,
        },
-       /* board_svw8 */
+       /* chip_svw8 */
        {
                .flags          = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
                                  ATA_FLAG_MMIO | K2_FLAG_NO_ATAPI_DMA |
@@ -373,6 +393,24 @@ static const struct ata_port_info k2_port_info[] = {
                .udma_mask      = ATA_UDMA6,
                .port_ops       = &k2_sata_ops,
        },
+       /* chip_svw42 */
+       {
+               .flags          = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+                                 ATA_FLAG_MMIO | K2_FLAG_BAR_POS_3,
+               .pio_mask       = 0x1f,
+               .mwdma_mask     = 0x07,
+               .udma_mask      = ATA_UDMA6,
+               .port_ops       = &k2_sata_ops,
+       },
+       /* chip_svw43 */
+       {
+               .flags          = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+                                 ATA_FLAG_MMIO,
+               .pio_mask       = 0x1f,
+               .mwdma_mask     = 0x07,
+               .udma_mask      = ATA_UDMA6,
+               .port_ops       = &k2_sata_ops,
+       },
 };
 
 static void k2_sata_setup_port(struct ata_ioports *port, void __iomem *base)
@@ -402,7 +440,7 @@ static int k2_sata_init_one(struct pci_dev *pdev, const struct pci_device_id *en
                { &k2_port_info[ent->driver_data], NULL };
        struct ata_host *host;
        void __iomem *mmio_base;
-       int n_ports, i, rc;
+       int n_ports, i, rc, bar_pos;
 
        if (!printed_version++)
                dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
@@ -416,6 +454,9 @@ static int k2_sata_init_one(struct pci_dev *pdev, const struct pci_device_id *en
        if (!host)
                return -ENOMEM;
 
+       bar_pos = 5;
+       if (ppi[0]->flags & K2_FLAG_BAR_POS_3)
+               bar_pos = 3;
        /*
         * If this driver happens to only be useful on Apple's K2, then
         * we should check that here as it has a normal Serverworks ID
@@ -428,17 +469,23 @@ static int k2_sata_init_one(struct pci_dev *pdev, const struct pci_device_id *en
         * Check if we have resources mapped at all (second function may
         * have been disabled by firmware)
         */
-       if (pci_resource_len(pdev, 5) == 0)
+       if (pci_resource_len(pdev, bar_pos) == 0) {
+               /* In IDE mode we need to pin the device to ensure that
+                       pcim_release does not clear the busmaster bit in config
+                       space, clearing causes busmaster DMA to fail on
+                       ports 3 & 4 */
+               pcim_pin_device(pdev);
                return -ENODEV;
+       }
 
        /* Request and iomap PCI regions */
-       rc = pcim_iomap_regions(pdev, 1 << 5, DRV_NAME);
+       rc = pcim_iomap_regions(pdev, 1 << bar_pos, DRV_NAME);
        if (rc == -EBUSY)
                pcim_pin_device(pdev);
        if (rc)
                return rc;
        host->iomap = pcim_iomap_table(pdev);
-       mmio_base = host->iomap[5];
+       mmio_base = host->iomap[bar_pos];
 
        /* different controllers have different number of ports - currently 4 or 8 */
        /* All ports are on the same function. Multi-function device is no
@@ -483,11 +530,13 @@ static int k2_sata_init_one(struct pci_dev *pdev, const struct pci_device_id *en
  * controller
  * */
 static const struct pci_device_id k2_sata_pci_tbl[] = {
-       { PCI_VDEVICE(SERVERWORKS, 0x0240), board_svw4 },
-       { PCI_VDEVICE(SERVERWORKS, 0x0241), board_svw4 },
-       { PCI_VDEVICE(SERVERWORKS, 0x0242), board_svw8 },
-       { PCI_VDEVICE(SERVERWORKS, 0x024a), board_svw4 },
-       { PCI_VDEVICE(SERVERWORKS, 0x024b), board_svw4 },
+       { PCI_VDEVICE(SERVERWORKS, 0x0240), chip_svw4 },
+       { PCI_VDEVICE(SERVERWORKS, 0x0241), chip_svw4 },
+       { PCI_VDEVICE(SERVERWORKS, 0x0242), chip_svw8 },
+       { PCI_VDEVICE(SERVERWORKS, 0x024a), chip_svw4 },
+       { PCI_VDEVICE(SERVERWORKS, 0x024b), chip_svw4 },
+       { PCI_VDEVICE(SERVERWORKS, 0x0410), chip_svw42 },
+       { PCI_VDEVICE(SERVERWORKS, 0x0411), chip_svw43 },
 
        { }
 };