Skip to content

Commit

Permalink
sata_via: Implement hotplug for VT6421
Browse files Browse the repository at this point in the history
Enable IRQ on hotplug and add an interrupt handler to handle it.

This allows hotplug to work:
ata5: exception Emask 0x10 SAct 0x0 SErr 0x70000 action 0xe frozen
ata5: SError: { PHYRdyChg PHYInt CommWake }
ata5: hard resetting link
ata5: SATA link up 1.5 Gbps (SStatus 113 SControl 310)
ata5.00: LPM support broken, forcing max_power
ata5.00: ATA-7: WDC WD800JD-75MSA3, 10.01E04, max UDMA/133
ata5.00: 156250000 sectors, multi 0: LBA48 NCQ (depth 0/32)
ata5.00: LPM support broken, forcing max_power
ata5.00: configured for UDMA/133
ata5: EH complete
scsi 4:0:0:0: Direct-Access     ATA      WDC WD800JD-75MS 1E04 PQ: 0 ANSI: 5
sd 4:0:0:0: [sdb] 156250000 512-byte logical blocks: (80.0 GB/74.5 GiB)
sd 4:0:0:0: [sdb] Write Protect is off
sd 4:0:0:0: [sdb] Mode Sense: 00 3a 00 00
sd 4:0:0:0: [sdb] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
sd 4:0:0:0: Attached scsi generic sg1 type 0
sd 4:0:0:0: [sdb] Attached SCSI disk

And also hot unplug:
ata5: exception Emask 0x10 SAct 0x0 SErr 0x1b0000 action 0xe frozen
ata5: SError: { PHYRdyChg PHYInt 10B8B Dispar }
ata5: hard resetting link
ata5: SATA link down (SStatus 0 SControl 310)
ata5: hard resetting link
ata5: SATA link down (SStatus 0 SControl 310)
ata5: hard resetting link
ata5: SATA link down (SStatus 0 SControl 310)
ata5.00: disabled
ata5: EH complete
ata5.00: detaching (SCSI 4:0:0:0)
sd 4:0:0:0: [sdb] Synchronizing SCSI cache
sd 4:0:0:0: [sdb] Synchronize Cache(10) failed: Result: hostbyte=DID_BAD_TARGET driverbyte=DRIVER_OK
sd 4:0:0:0: [sdb] Stopping disk
sd 4:0:0:0: [sdb] Start/Stop Unit failed: Result: hostbyte=DID_BAD_TARGET driverbyte=DRIVER_OK

Signed-off-by: Ondrej Zary <linux@rainbow-software.org>
Signed-off-by: Tejun Heo <tj@kernel.org>
  • Loading branch information
Ondrej Zary authored and htejun committed Feb 25, 2016
1 parent 44a9b49 commit 57e5568
Showing 1 changed file with 50 additions and 2 deletions.
52 changes: 50 additions & 2 deletions drivers/ata/sata_via.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ enum {
SATA_CHAN_ENAB = 0x40, /* SATA channel enable */
SATA_INT_GATE = 0x41, /* SATA interrupt gating */
SATA_NATIVE_MODE = 0x42, /* Native mode enable */
SVIA_MISC_3 = 0x46, /* Miscellaneous Control III */
PATA_UDMA_TIMING = 0xB3, /* PATA timing for DMA/ cable detect */
PATA_PIO_TIMING = 0xAB, /* PATA timing register */

Expand All @@ -71,6 +72,8 @@ enum {
NATIVE_MODE_ALL = (1 << 7) | (1 << 6) | (1 << 5) | (1 << 4),

SATA_EXT_PHY = (1 << 6), /* 0==use PATA, 1==ext phy */

SATA_HOTPLUG = (1 << 5), /* enable IRQ on hotplug */
};

struct svia_priv {
Expand Down Expand Up @@ -553,6 +556,37 @@ static void svia_wd_fix(struct pci_dev *pdev)
pci_write_config_byte(pdev, 0x52, tmp8 | BIT(2));
}

static irqreturn_t vt6421_interrupt(int irq, void *dev_instance)
{
struct ata_host *host = dev_instance;
irqreturn_t rc = ata_bmdma_interrupt(irq, dev_instance);

/* if the IRQ was not handled, it might be a hotplug IRQ */
if (rc != IRQ_HANDLED) {
u32 serror;
unsigned long flags;

spin_lock_irqsave(&host->lock, flags);
/* check for hotplug on port 0 */
svia_scr_read(&host->ports[0]->link, SCR_ERROR, &serror);
if (serror & SERR_PHYRDY_CHG) {
ata_ehi_hotplugged(&host->ports[0]->link.eh_info);
ata_port_freeze(host->ports[0]);
rc = IRQ_HANDLED;
}
/* check for hotplug on port 1 */
svia_scr_read(&host->ports[1]->link, SCR_ERROR, &serror);
if (serror & SERR_PHYRDY_CHG) {
ata_ehi_hotplugged(&host->ports[1]->link.eh_info);
ata_port_freeze(host->ports[1]);
rc = IRQ_HANDLED;
}
spin_unlock_irqrestore(&host->lock, flags);
}

return rc;
}

static void vt6421_error_handler(struct ata_port *ap)
{
struct svia_priv *hpriv = ap->host->private_data;
Expand Down Expand Up @@ -610,6 +644,16 @@ static void svia_configure(struct pci_dev *pdev, int board_id,
pci_write_config_byte(pdev, SATA_NATIVE_MODE, tmp8);
}

/* enable IRQ on hotplug */
pci_read_config_byte(pdev, SVIA_MISC_3, &tmp8);
if ((tmp8 & SATA_HOTPLUG) != SATA_HOTPLUG) {
dev_dbg(&pdev->dev,
"enabling SATA hotplug (0x%x)\n",
(int) tmp8);
tmp8 |= SATA_HOTPLUG;
pci_write_config_byte(pdev, SVIA_MISC_3, tmp8);
}

/*
* vt6420/1 has problems talking to some drives. The following
* is the fix from Joseph Chan <JosephChan@via.com.tw>.
Expand Down Expand Up @@ -698,8 +742,12 @@ static int svia_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
svia_configure(pdev, board_id, hpriv);

pci_set_master(pdev);
return ata_host_activate(host, pdev->irq, ata_bmdma_interrupt,
IRQF_SHARED, &svia_sht);
if (board_id == vt6421)
return ata_host_activate(host, pdev->irq, vt6421_interrupt,
IRQF_SHARED, &svia_sht);
else
return ata_host_activate(host, pdev->irq, ata_bmdma_interrupt,
IRQF_SHARED, &svia_sht);
}

#ifdef CONFIG_PM_SLEEP
Expand Down

0 comments on commit 57e5568

Please sign in to comment.