diff options
Diffstat (limited to 'drivers/scsi')
-rw-r--r-- | drivers/scsi/sata_sil24.c | 76 |
1 files changed, 66 insertions, 10 deletions
diff --git a/drivers/scsi/sata_sil24.c b/drivers/scsi/sata_sil24.c index a6836a07a9e..59aab163bcd 100644 --- a/drivers/scsi/sata_sil24.c +++ b/drivers/scsi/sata_sil24.c @@ -333,7 +333,7 @@ static struct ata_port_info sil24_port_info[] = { { .sht = &sil24_sht, .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | - ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO | + ATA_FLAG_SRST | ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | SIL24_NPORTS2FLAG(4), .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ @@ -344,7 +344,7 @@ static struct ata_port_info sil24_port_info[] = { { .sht = &sil24_sht, .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | - ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO | + ATA_FLAG_SRST | ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | SIL24_NPORTS2FLAG(2), .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ @@ -355,7 +355,7 @@ static struct ata_port_info sil24_port_info[] = { { .sht = &sil24_sht, .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | - ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO | + ATA_FLAG_SRST | ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | SIL24_NPORTS2FLAG(1), .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ @@ -415,16 +415,72 @@ static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf) *tf = pp->tf; } -static void sil24_phy_reset(struct ata_port *ap) +static int sil24_issue_SRST(struct ata_port *ap) { - __sata_phy_reset(ap); + void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr; + struct sil24_port_priv *pp = ap->private_data; + struct sil24_prb *prb = &pp->cmd_block[0].prb; + dma_addr_t paddr = pp->cmd_block_dma; + u32 irq_enable, irq_stat; + int cnt; + + /* temporarily turn off IRQs during SRST */ + irq_enable = readl(port + PORT_IRQ_ENABLE_SET); + writel(irq_enable, port + PORT_IRQ_ENABLE_CLR); + /* - * No ATAPI yet. Just unconditionally indicate ATA device. - * If ATAPI device is attached, it will fail ATA_CMD_ID_ATA - * and libata core will ignore the device. + * XXX: Not sure whether the following sleep is needed or not. + * The original driver had it. So.... */ - if (!(ap->flags & ATA_FLAG_PORT_DISABLED)) - ap->device[0].class = ATA_DEV_ATA; + msleep(10); + + prb->ctrl = PRB_CTRL_SRST; + prb->fis[1] = 0; /* no PM yet */ + + writel((u32)paddr, port + PORT_CMD_ACTIVATE); + + for (cnt = 0; cnt < 100; cnt++) { + irq_stat = readl(port + PORT_IRQ_STAT); + writel(irq_stat, port + PORT_IRQ_STAT); /* clear irq */ + + irq_stat >>= PORT_IRQ_RAW_SHIFT; + if (irq_stat & (PORT_IRQ_COMPLETE | PORT_IRQ_ERROR)) + break; + + msleep(1); + } + + /* restore IRQs */ + writel(irq_enable, port + PORT_IRQ_ENABLE_SET); + + if (!(irq_stat & PORT_IRQ_COMPLETE)) + return -1; + + /* update TF */ + sil24_update_tf(ap); + return 0; +} + +static void sil24_phy_reset(struct ata_port *ap) +{ + struct sil24_port_priv *pp = ap->private_data; + + __sata_phy_reset(ap); + if (ap->flags & ATA_FLAG_PORT_DISABLED) + return; + + if (sil24_issue_SRST(ap) < 0) { + printk(KERN_ERR DRV_NAME + " ata%u: SRST failed, disabling port\n", ap->id); + ap->ops->port_disable(ap); + return; + } + + ap->device->class = ata_dev_classify(&pp->tf); + + /* No ATAPI yet */ + if (ap->device->class == ATA_DEV_ATAPI) + ap->ops->port_disable(ap); } static inline void sil24_fill_sg(struct ata_queued_cmd *qc, |