diff options
author | Ondrej Zary <linux@rainbow-software.org> | 2016-02-25 11:22:25 -0500 |
---|---|---|
committer | Tejun Heo <tj@kernel.org> | 2016-02-25 13:22:16 -0500 |
commit | 57e5568fda276d47fe9b9499ba487066d299e0e7 (patch) | |
tree | 5dc31a7c3dbeb8ae7941cc5dbcc2b28963326490 | |
parent | 44a9b494f20b37dc9c9f94577ff98c856f594b96 (diff) |
sata_via: Implement hotplug for VT6421
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>
-rw-r--r-- | drivers/ata/sata_via.c | 52 |
1 files changed, 50 insertions, 2 deletions
diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c index 9804054e22a7..0636d84fbefe 100644 --- a/drivers/ata/sata_via.c +++ b/drivers/ata/sata_via.c | |||
@@ -61,6 +61,7 @@ enum { | |||
61 | SATA_CHAN_ENAB = 0x40, /* SATA channel enable */ | 61 | SATA_CHAN_ENAB = 0x40, /* SATA channel enable */ |
62 | SATA_INT_GATE = 0x41, /* SATA interrupt gating */ | 62 | SATA_INT_GATE = 0x41, /* SATA interrupt gating */ |
63 | SATA_NATIVE_MODE = 0x42, /* Native mode enable */ | 63 | SATA_NATIVE_MODE = 0x42, /* Native mode enable */ |
64 | SVIA_MISC_3 = 0x46, /* Miscellaneous Control III */ | ||
64 | PATA_UDMA_TIMING = 0xB3, /* PATA timing for DMA/ cable detect */ | 65 | PATA_UDMA_TIMING = 0xB3, /* PATA timing for DMA/ cable detect */ |
65 | PATA_PIO_TIMING = 0xAB, /* PATA timing register */ | 66 | PATA_PIO_TIMING = 0xAB, /* PATA timing register */ |
66 | 67 | ||
@@ -71,6 +72,8 @@ enum { | |||
71 | NATIVE_MODE_ALL = (1 << 7) | (1 << 6) | (1 << 5) | (1 << 4), | 72 | NATIVE_MODE_ALL = (1 << 7) | (1 << 6) | (1 << 5) | (1 << 4), |
72 | 73 | ||
73 | SATA_EXT_PHY = (1 << 6), /* 0==use PATA, 1==ext phy */ | 74 | SATA_EXT_PHY = (1 << 6), /* 0==use PATA, 1==ext phy */ |
75 | |||
76 | SATA_HOTPLUG = (1 << 5), /* enable IRQ on hotplug */ | ||
74 | }; | 77 | }; |
75 | 78 | ||
76 | struct svia_priv { | 79 | struct svia_priv { |
@@ -553,6 +556,37 @@ static void svia_wd_fix(struct pci_dev *pdev) | |||
553 | pci_write_config_byte(pdev, 0x52, tmp8 | BIT(2)); | 556 | pci_write_config_byte(pdev, 0x52, tmp8 | BIT(2)); |
554 | } | 557 | } |
555 | 558 | ||
559 | static irqreturn_t vt6421_interrupt(int irq, void *dev_instance) | ||
560 | { | ||
561 | struct ata_host *host = dev_instance; | ||
562 | irqreturn_t rc = ata_bmdma_interrupt(irq, dev_instance); | ||
563 | |||
564 | /* if the IRQ was not handled, it might be a hotplug IRQ */ | ||
565 | if (rc != IRQ_HANDLED) { | ||
566 | u32 serror; | ||
567 | unsigned long flags; | ||
568 | |||
569 | spin_lock_irqsave(&host->lock, flags); | ||
570 | /* check for hotplug on port 0 */ | ||
571 | svia_scr_read(&host->ports[0]->link, SCR_ERROR, &serror); | ||
572 | if (serror & SERR_PHYRDY_CHG) { | ||
573 | ata_ehi_hotplugged(&host->ports[0]->link.eh_info); | ||
574 | ata_port_freeze(host->ports[0]); | ||
575 | rc = IRQ_HANDLED; | ||
576 | } | ||
577 | /* check for hotplug on port 1 */ | ||
578 | svia_scr_read(&host->ports[1]->link, SCR_ERROR, &serror); | ||
579 | if (serror & SERR_PHYRDY_CHG) { | ||
580 | ata_ehi_hotplugged(&host->ports[1]->link.eh_info); | ||
581 | ata_port_freeze(host->ports[1]); | ||
582 | rc = IRQ_HANDLED; | ||
583 | } | ||
584 | spin_unlock_irqrestore(&host->lock, flags); | ||
585 | } | ||
586 | |||
587 | return rc; | ||
588 | } | ||
589 | |||
556 | static void vt6421_error_handler(struct ata_port *ap) | 590 | static void vt6421_error_handler(struct ata_port *ap) |
557 | { | 591 | { |
558 | struct svia_priv *hpriv = ap->host->private_data; | 592 | struct svia_priv *hpriv = ap->host->private_data; |
@@ -610,6 +644,16 @@ static void svia_configure(struct pci_dev *pdev, int board_id, | |||
610 | pci_write_config_byte(pdev, SATA_NATIVE_MODE, tmp8); | 644 | pci_write_config_byte(pdev, SATA_NATIVE_MODE, tmp8); |
611 | } | 645 | } |
612 | 646 | ||
647 | /* enable IRQ on hotplug */ | ||
648 | pci_read_config_byte(pdev, SVIA_MISC_3, &tmp8); | ||
649 | if ((tmp8 & SATA_HOTPLUG) != SATA_HOTPLUG) { | ||
650 | dev_dbg(&pdev->dev, | ||
651 | "enabling SATA hotplug (0x%x)\n", | ||
652 | (int) tmp8); | ||
653 | tmp8 |= SATA_HOTPLUG; | ||
654 | pci_write_config_byte(pdev, SVIA_MISC_3, tmp8); | ||
655 | } | ||
656 | |||
613 | /* | 657 | /* |
614 | * vt6420/1 has problems talking to some drives. The following | 658 | * vt6420/1 has problems talking to some drives. The following |
615 | * is the fix from Joseph Chan <JosephChan@via.com.tw>. | 659 | * is the fix from Joseph Chan <JosephChan@via.com.tw>. |
@@ -698,8 +742,12 @@ static int svia_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
698 | svia_configure(pdev, board_id, hpriv); | 742 | svia_configure(pdev, board_id, hpriv); |
699 | 743 | ||
700 | pci_set_master(pdev); | 744 | pci_set_master(pdev); |
701 | return ata_host_activate(host, pdev->irq, ata_bmdma_interrupt, | 745 | if (board_id == vt6421) |
702 | IRQF_SHARED, &svia_sht); | 746 | return ata_host_activate(host, pdev->irq, vt6421_interrupt, |
747 | IRQF_SHARED, &svia_sht); | ||
748 | else | ||
749 | return ata_host_activate(host, pdev->irq, ata_bmdma_interrupt, | ||
750 | IRQF_SHARED, &svia_sht); | ||
703 | } | 751 | } |
704 | 752 | ||
705 | #ifdef CONFIG_PM_SLEEP | 753 | #ifdef CONFIG_PM_SLEEP |