diff options
Diffstat (limited to 'drivers/ata/sata_promise.c')
-rw-r--r-- | drivers/ata/sata_promise.c | 66 |
1 files changed, 51 insertions, 15 deletions
diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c index 2ad5872fe90..d39ebc23c4a 100644 --- a/drivers/ata/sata_promise.c +++ b/drivers/ata/sata_promise.c @@ -45,7 +45,7 @@ #include "sata_promise.h" #define DRV_NAME "sata_promise" -#define DRV_VERSION "2.08" +#define DRV_VERSION "2.09" 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); @@ -427,19 +427,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) @@ -642,8 +643,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)) { + u32 serror; + + pdc_sata_scr_read(ap, SCR_ERROR, &serror); + ehi->serror |= serror; + } qc->err_mask |= ac_err_mask; @@ -716,6 +721,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 +734,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,16 +755,34 @@ 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->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)) { @@ -902,9 +938,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) |