]> err.no Git - linux-2.6/blobdiff - drivers/ata/sata_promise.c
ahci: implement AHCI_HFLAG_NO_PMP
[linux-2.6] / drivers / ata / sata_promise.c
index 2ad5872fe90c2deaea8270ff8a7e51295270637b..903213153b5d98ada9df5d817f3a06506a52e053 100644 (file)
@@ -45,7 +45,7 @@
 #include "sata_promise.h"
 
 #define DRV_NAME       "sata_promise"
-#define DRV_VERSION    "2.08"
+#define DRV_VERSION    "2.10"
 
 enum {
        PDC_MAX_PORTS           = 4,
@@ -128,8 +128,8 @@ struct pdc_port_priv {
        dma_addr_t              pkt_dma;
 };
 
-static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg);
-static void pdc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int pdc_sata_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
+static int pdc_sata_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);
 static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
 static int pdc_common_port_start(struct ata_port *ap);
 static int pdc_sata_port_start(struct ata_port *ap);
@@ -167,7 +167,6 @@ static struct scsi_host_template pdc_ata_sht = {
 };
 
 static const struct ata_port_operations pdc_sata_ops = {
-       .port_disable           = ata_port_disable,
        .tf_load                = pdc_tf_load_mmio,
        .tf_read                = ata_tf_read,
        .check_status           = ata_check_status,
@@ -185,7 +184,6 @@ static const struct ata_port_operations pdc_sata_ops = {
        .data_xfer              = ata_data_xfer,
        .irq_clear              = pdc_irq_clear,
        .irq_on                 = ata_irq_on,
-       .irq_ack                = ata_irq_ack,
 
        .scr_read               = pdc_sata_scr_read,
        .scr_write              = pdc_sata_scr_write,
@@ -194,7 +192,6 @@ static const struct ata_port_operations pdc_sata_ops = {
 
 /* First-generation chips need a more restrictive ->check_atapi_dma op */
 static const struct ata_port_operations pdc_old_sata_ops = {
-       .port_disable           = ata_port_disable,
        .tf_load                = pdc_tf_load_mmio,
        .tf_read                = ata_tf_read,
        .check_status           = ata_check_status,
@@ -212,7 +209,6 @@ static const struct ata_port_operations pdc_old_sata_ops = {
        .data_xfer              = ata_data_xfer,
        .irq_clear              = pdc_irq_clear,
        .irq_on                 = ata_irq_on,
-       .irq_ack                = ata_irq_ack,
 
        .scr_read               = pdc_sata_scr_read,
        .scr_write              = pdc_sata_scr_write,
@@ -220,7 +216,6 @@ static const struct ata_port_operations pdc_old_sata_ops = {
 };
 
 static const struct ata_port_operations pdc_pata_ops = {
-       .port_disable           = ata_port_disable,
        .tf_load                = pdc_tf_load_mmio,
        .tf_read                = ata_tf_read,
        .check_status           = ata_check_status,
@@ -238,7 +233,6 @@ static const struct ata_port_operations pdc_pata_ops = {
        .data_xfer              = ata_data_xfer,
        .irq_clear              = pdc_irq_clear,
        .irq_on                 = ata_irq_on,
-       .irq_ack                = ata_irq_ack,
 
        .port_start             = pdc_common_port_start,
 };
@@ -328,8 +322,8 @@ static const struct pci_device_id pdc_ata_pci_tbl[] = {
 
        { PCI_VDEVICE(PROMISE, 0x3318), board_20319 },
        { PCI_VDEVICE(PROMISE, 0x3319), board_20319 },
-       { PCI_VDEVICE(PROMISE, 0x3515), board_20319 },
-       { PCI_VDEVICE(PROMISE, 0x3519), board_20319 },
+       { PCI_VDEVICE(PROMISE, 0x3515), board_40518 },
+       { PCI_VDEVICE(PROMISE, 0x3519), board_40518 },
        { PCI_VDEVICE(PROMISE, 0x3d17), board_40518 },
        { PCI_VDEVICE(PROMISE, 0x3d18), board_40518 },
 
@@ -427,19 +421,20 @@ static int pdc_sata_cable_detect(struct ata_port *ap)
        return ATA_CBL_SATA;
 }
 
-static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg)
+static int pdc_sata_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
 {
        if (sc_reg > SCR_CONTROL)
-               return 0xffffffffU;
-       return readl(ap->ioaddr.scr_addr + (sc_reg * 4));
+               return -EINVAL;
+       *val = readl(ap->ioaddr.scr_addr + (sc_reg * 4));
+       return 0;
 }
 
-static void pdc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg,
-                              u32 val)
+static int pdc_sata_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
 {
        if (sc_reg > SCR_CONTROL)
-               return;
+               return -EINVAL;
        writel(val, ap->ioaddr.scr_addr + (sc_reg * 4));
+       return 0;
 }
 
 static void pdc_atapi_pkt(struct ata_queued_cmd *qc)
@@ -474,7 +469,7 @@ static void pdc_atapi_pkt(struct ata_queued_cmd *qc)
        buf32[2] = 0;                           /* no next-packet */
 
        /* select drive */
-       if (sata_scr_valid(ap)) {
+       if (sata_scr_valid(&ap->link)) {
                dev_sel = PDC_DEVICE_SATA;
        } else {
                dev_sel = ATA_DEVICE_OBS;
@@ -625,7 +620,7 @@ static void pdc_post_internal_cmd(struct ata_queued_cmd *qc)
 static void pdc_error_intr(struct ata_port *ap, struct ata_queued_cmd *qc,
                           u32 port_status, u32 err_mask)
 {
-       struct ata_eh_info *ehi = &ap->eh_info;
+       struct ata_eh_info *ehi = &ap->link.eh_info;
        unsigned int ac_err_mask = 0;
 
        ata_ehi_clear_desc(ehi);
@@ -642,8 +637,12 @@ static void pdc_error_intr(struct ata_port *ap, struct ata_queued_cmd *qc,
                           | PDC_PCI_SYS_ERR | PDC1_PCI_PARITY_ERR))
                ac_err_mask |= AC_ERR_HOST_BUS;
 
-       if (sata_scr_valid(ap))
-               ehi->serror |= pdc_sata_scr_read(ap, SCR_ERROR);
+       if (sata_scr_valid(&ap->link)) {
+               u32 serror;
+
+               pdc_sata_scr_read(ap, SCR_ERROR, &serror);
+               ehi->serror |= serror;
+       }
 
        qc->err_mask |= ac_err_mask;
 
@@ -716,6 +715,9 @@ static irqreturn_t pdc_interrupt (int irq, void *dev_instance)
        unsigned int i, tmp;
        unsigned int handled = 0;
        void __iomem *mmio_base;
+       unsigned int hotplug_offset, ata_no;
+       u32 hotplug_status;
+       int is_sataii_tx4;
 
        VPRINTK("ENTER\n");
 
@@ -726,10 +728,20 @@ static irqreturn_t pdc_interrupt (int irq, void *dev_instance)
 
        mmio_base = host->iomap[PDC_MMIO_BAR];
 
+       /* read and clear hotplug flags for all ports */
+       if (host->ports[0]->flags & PDC_FLAG_GEN_II)
+               hotplug_offset = PDC2_SATA_PLUG_CSR;
+       else
+               hotplug_offset = PDC_SATA_PLUG_CSR;
+       hotplug_status = readl(mmio_base + hotplug_offset);
+       if (hotplug_status & 0xff)
+               writel(hotplug_status | 0xff, mmio_base + hotplug_offset);
+       hotplug_status &= 0xff; /* clear uninteresting bits */
+
        /* reading should also clear interrupts */
        mask = readl(mmio_base + PDC_INT_SEQMASK);
 
-       if (mask == 0xffffffff) {
+       if (mask == 0xffffffff && hotplug_status == 0) {
                VPRINTK("QUICK EXIT 2\n");
                return IRQ_NONE;
        }
@@ -737,22 +749,40 @@ static irqreturn_t pdc_interrupt (int irq, void *dev_instance)
        spin_lock(&host->lock);
 
        mask &= 0xffff;         /* only 16 tags possible */
-       if (!mask) {
+       if (mask == 0 && hotplug_status == 0) {
                VPRINTK("QUICK EXIT 3\n");
                goto done_irq;
        }
 
        writel(mask, mmio_base + PDC_INT_SEQMASK);
 
+       is_sataii_tx4 = pdc_is_sataii_tx4(host->ports[0]->flags);
+
        for (i = 0; i < host->n_ports; i++) {
                VPRINTK("port %u\n", i);
                ap = host->ports[i];
+
+               /* check for a plug or unplug event */
+               ata_no = pdc_port_no_to_ata_no(i, is_sataii_tx4);
+               tmp = hotplug_status & (0x11 << ata_no);
+               if (tmp && ap &&
+                   !(ap->flags & ATA_FLAG_DISABLED)) {
+                       struct ata_eh_info *ehi = &ap->link.eh_info;
+                       ata_ehi_clear_desc(ehi);
+                       ata_ehi_hotplugged(ehi);
+                       ata_ehi_push_desc(ehi, "hotplug_status %#x", tmp);
+                       ata_port_freeze(ap);
+                       ++handled;
+                       continue;
+               }
+
+               /* check for a packet interrupt */
                tmp = mask & (1 << (i + 1));
                if (tmp && ap &&
                    !(ap->flags & ATA_FLAG_DISABLED)) {
                        struct ata_queued_cmd *qc;
 
-                       qc = ata_qc_from_tag(ap, ap->active_tag);
+                       qc = ata_qc_from_tag(ap, ap->link.active_tag);
                        if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)))
                                handled += pdc_host_intr(ap, qc);
                }
@@ -902,9 +932,9 @@ static void pdc_host_init(struct ata_host *host)
        tmp = readl(mmio + hotplug_offset);
        writel(tmp | 0xff, mmio + hotplug_offset);
 
-       /* mask plug/unplug ints */
+       /* unmask plug/unplug ints */
        tmp = readl(mmio + hotplug_offset);
-       writel(tmp 0xff0000, mmio + hotplug_offset);
+       writel(tmp & ~0xff0000, mmio + hotplug_offset);
 
        /* don't initialise TBG or SLEW on 2nd generation chips */
        if (is_gen2)
@@ -973,10 +1003,15 @@ static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *e
 
        is_sataii_tx4 = pdc_is_sataii_tx4(pi->flags);
        for (i = 0; i < host->n_ports; i++) {
+               struct ata_port *ap = host->ports[i];
                unsigned int ata_no = pdc_port_no_to_ata_no(i, is_sataii_tx4);
-               pdc_ata_setup_port(host->ports[i],
-                                  base + 0x200 + ata_no * 0x80,
-                                  base + 0x400 + ata_no * 0x100);
+               unsigned int port_offset = 0x200 + ata_no * 0x80;
+               unsigned int scr_offset = 0x400 + ata_no * 0x100;
+
+               pdc_ata_setup_port(ap, base + port_offset, base + scr_offset);
+
+               ata_port_pbar_desc(ap, PDC_MMIO_BAR, -1, "mmio");
+               ata_port_pbar_desc(ap, PDC_MMIO_BAR, port_offset, "port");
        }
 
        /* initialize adapter */