diff options
Diffstat (limited to 'drivers/scsi/libata-eh.c')
-rw-r--r-- | drivers/scsi/libata-eh.c | 185 |
1 files changed, 184 insertions, 1 deletions
diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c index 1e9e73d13485..b9df49a36214 100644 --- a/drivers/scsi/libata-eh.c +++ b/drivers/scsi/libata-eh.c | |||
@@ -1610,7 +1610,7 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap, | |||
1610 | dev = &ap->device[i]; | 1610 | dev = &ap->device[i]; |
1611 | action = ata_eh_dev_action(dev); | 1611 | action = ata_eh_dev_action(dev); |
1612 | 1612 | ||
1613 | if (action & ATA_EH_REVALIDATE && ata_dev_enabled(dev)) { | 1613 | if (action & ATA_EH_REVALIDATE && ata_dev_ready(dev)) { |
1614 | if (ata_port_offline(ap)) { | 1614 | if (ata_port_offline(ap)) { |
1615 | rc = -EIO; | 1615 | rc = -EIO; |
1616 | break; | 1616 | break; |
@@ -1653,6 +1653,164 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap, | |||
1653 | return rc; | 1653 | return rc; |
1654 | } | 1654 | } |
1655 | 1655 | ||
1656 | /** | ||
1657 | * ata_eh_suspend - handle suspend EH action | ||
1658 | * @ap: target host port | ||
1659 | * @r_failed_dev: result parameter to indicate failing device | ||
1660 | * | ||
1661 | * Handle suspend EH action. Disk devices are spinned down and | ||
1662 | * other types of devices are just marked suspended. Once | ||
1663 | * suspended, no EH action to the device is allowed until it is | ||
1664 | * resumed. | ||
1665 | * | ||
1666 | * LOCKING: | ||
1667 | * Kernel thread context (may sleep). | ||
1668 | * | ||
1669 | * RETURNS: | ||
1670 | * 0 on success, -errno otherwise | ||
1671 | */ | ||
1672 | static int ata_eh_suspend(struct ata_port *ap, struct ata_device **r_failed_dev) | ||
1673 | { | ||
1674 | struct ata_device *dev; | ||
1675 | int i, rc = 0; | ||
1676 | |||
1677 | DPRINTK("ENTER\n"); | ||
1678 | |||
1679 | for (i = 0; i < ATA_MAX_DEVICES; i++) { | ||
1680 | unsigned long flags; | ||
1681 | unsigned int action, err_mask; | ||
1682 | |||
1683 | dev = &ap->device[i]; | ||
1684 | action = ata_eh_dev_action(dev); | ||
1685 | |||
1686 | if (!ata_dev_enabled(dev) || !(action & ATA_EH_SUSPEND)) | ||
1687 | continue; | ||
1688 | |||
1689 | WARN_ON(dev->flags & ATA_DFLAG_SUSPENDED); | ||
1690 | |||
1691 | ata_eh_about_to_do(ap, dev, ATA_EH_SUSPEND); | ||
1692 | |||
1693 | if (dev->class == ATA_DEV_ATA && !(action & ATA_EH_PM_FREEZE)) { | ||
1694 | /* flush cache */ | ||
1695 | rc = ata_flush_cache(dev); | ||
1696 | if (rc) | ||
1697 | break; | ||
1698 | |||
1699 | /* spin down */ | ||
1700 | err_mask = ata_do_simple_cmd(dev, ATA_CMD_STANDBYNOW1); | ||
1701 | if (err_mask) { | ||
1702 | ata_dev_printk(dev, KERN_ERR, "failed to " | ||
1703 | "spin down (err_mask=0x%x)\n", | ||
1704 | err_mask); | ||
1705 | rc = -EIO; | ||
1706 | break; | ||
1707 | } | ||
1708 | } | ||
1709 | |||
1710 | spin_lock_irqsave(ap->lock, flags); | ||
1711 | dev->flags |= ATA_DFLAG_SUSPENDED; | ||
1712 | spin_unlock_irqrestore(ap->lock, flags); | ||
1713 | |||
1714 | ata_eh_done(ap, dev, ATA_EH_SUSPEND); | ||
1715 | } | ||
1716 | |||
1717 | if (rc) | ||
1718 | *r_failed_dev = dev; | ||
1719 | |||
1720 | DPRINTK("EXIT\n"); | ||
1721 | return 0; | ||
1722 | } | ||
1723 | |||
1724 | /** | ||
1725 | * ata_eh_prep_resume - prep for resume EH action | ||
1726 | * @ap: target host port | ||
1727 | * | ||
1728 | * Clear SUSPENDED in preparation for scheduled resume actions. | ||
1729 | * This allows other parts of EH to access the devices being | ||
1730 | * resumed. | ||
1731 | * | ||
1732 | * LOCKING: | ||
1733 | * Kernel thread context (may sleep). | ||
1734 | */ | ||
1735 | static void ata_eh_prep_resume(struct ata_port *ap) | ||
1736 | { | ||
1737 | struct ata_device *dev; | ||
1738 | unsigned long flags; | ||
1739 | int i; | ||
1740 | |||
1741 | DPRINTK("ENTER\n"); | ||
1742 | |||
1743 | for (i = 0; i < ATA_MAX_DEVICES; i++) { | ||
1744 | unsigned int action; | ||
1745 | |||
1746 | dev = &ap->device[i]; | ||
1747 | action = ata_eh_dev_action(dev); | ||
1748 | |||
1749 | if (!ata_dev_enabled(dev) || !(action & ATA_EH_RESUME)) | ||
1750 | continue; | ||
1751 | |||
1752 | spin_lock_irqsave(ap->lock, flags); | ||
1753 | dev->flags &= ~ATA_DFLAG_SUSPENDED; | ||
1754 | spin_unlock_irqrestore(ap->lock, flags); | ||
1755 | } | ||
1756 | |||
1757 | DPRINTK("EXIT\n"); | ||
1758 | } | ||
1759 | |||
1760 | /** | ||
1761 | * ata_eh_resume - handle resume EH action | ||
1762 | * @ap: target host port | ||
1763 | * @r_failed_dev: result parameter to indicate failing device | ||
1764 | * | ||
1765 | * Handle resume EH action. Target devices are already reset and | ||
1766 | * revalidated. Spinning up is the only operation left. | ||
1767 | * | ||
1768 | * LOCKING: | ||
1769 | * Kernel thread context (may sleep). | ||
1770 | * | ||
1771 | * RETURNS: | ||
1772 | * 0 on success, -errno otherwise | ||
1773 | */ | ||
1774 | static int ata_eh_resume(struct ata_port *ap, struct ata_device **r_failed_dev) | ||
1775 | { | ||
1776 | struct ata_device *dev; | ||
1777 | int i, rc = 0; | ||
1778 | |||
1779 | DPRINTK("ENTER\n"); | ||
1780 | |||
1781 | for (i = 0; i < ATA_MAX_DEVICES; i++) { | ||
1782 | unsigned int action, err_mask; | ||
1783 | |||
1784 | dev = &ap->device[i]; | ||
1785 | action = ata_eh_dev_action(dev); | ||
1786 | |||
1787 | if (!ata_dev_enabled(dev) || !(action & ATA_EH_RESUME)) | ||
1788 | continue; | ||
1789 | |||
1790 | ata_eh_about_to_do(ap, dev, ATA_EH_RESUME); | ||
1791 | |||
1792 | if (dev->class == ATA_DEV_ATA && !(action & ATA_EH_PM_FREEZE)) { | ||
1793 | err_mask = ata_do_simple_cmd(dev, | ||
1794 | ATA_CMD_IDLEIMMEDIATE); | ||
1795 | if (err_mask) { | ||
1796 | ata_dev_printk(dev, KERN_ERR, "failed to " | ||
1797 | "spin up (err_mask=0x%x)\n", | ||
1798 | err_mask); | ||
1799 | rc = -EIO; | ||
1800 | break; | ||
1801 | } | ||
1802 | } | ||
1803 | |||
1804 | ata_eh_done(ap, dev, ATA_EH_RESUME); | ||
1805 | } | ||
1806 | |||
1807 | if (rc) | ||
1808 | *r_failed_dev = dev; | ||
1809 | |||
1810 | DPRINTK("EXIT\n"); | ||
1811 | return 0; | ||
1812 | } | ||
1813 | |||
1656 | static int ata_port_nr_enabled(struct ata_port *ap) | 1814 | static int ata_port_nr_enabled(struct ata_port *ap) |
1657 | { | 1815 | { |
1658 | int i, cnt = 0; | 1816 | int i, cnt = 0; |
@@ -1678,6 +1836,18 @@ static int ata_eh_skip_recovery(struct ata_port *ap) | |||
1678 | struct ata_eh_context *ehc = &ap->eh_context; | 1836 | struct ata_eh_context *ehc = &ap->eh_context; |
1679 | int i; | 1837 | int i; |
1680 | 1838 | ||
1839 | /* skip if all possible devices are suspended */ | ||
1840 | for (i = 0; i < ata_port_max_devices(ap); i++) { | ||
1841 | struct ata_device *dev = &ap->device[i]; | ||
1842 | |||
1843 | if (ata_dev_absent(dev) || ata_dev_ready(dev)) | ||
1844 | break; | ||
1845 | } | ||
1846 | |||
1847 | if (i == ata_port_max_devices(ap)) | ||
1848 | return 1; | ||
1849 | |||
1850 | /* always thaw frozen port and recover failed devices */ | ||
1681 | if (ap->pflags & ATA_PFLAG_FROZEN || ata_port_nr_enabled(ap)) | 1851 | if (ap->pflags & ATA_PFLAG_FROZEN || ata_port_nr_enabled(ap)) |
1682 | return 0; | 1852 | return 0; |
1683 | 1853 | ||
@@ -1752,6 +1922,9 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, | |||
1752 | if (ap->pflags & ATA_PFLAG_UNLOADING) | 1922 | if (ap->pflags & ATA_PFLAG_UNLOADING) |
1753 | goto out; | 1923 | goto out; |
1754 | 1924 | ||
1925 | /* prep for resume */ | ||
1926 | ata_eh_prep_resume(ap); | ||
1927 | |||
1755 | /* skip EH if possible. */ | 1928 | /* skip EH if possible. */ |
1756 | if (ata_eh_skip_recovery(ap)) | 1929 | if (ata_eh_skip_recovery(ap)) |
1757 | ehc->i.action = 0; | 1930 | ehc->i.action = 0; |
@@ -1779,6 +1952,11 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, | |||
1779 | if (rc) | 1952 | if (rc) |
1780 | goto dev_fail; | 1953 | goto dev_fail; |
1781 | 1954 | ||
1955 | /* resume devices */ | ||
1956 | rc = ata_eh_resume(ap, &dev); | ||
1957 | if (rc) | ||
1958 | goto dev_fail; | ||
1959 | |||
1782 | /* configure transfer mode if the port has been reset */ | 1960 | /* configure transfer mode if the port has been reset */ |
1783 | if (ehc->i.flags & ATA_EHI_DID_RESET) { | 1961 | if (ehc->i.flags & ATA_EHI_DID_RESET) { |
1784 | rc = ata_set_mode(ap, &dev); | 1962 | rc = ata_set_mode(ap, &dev); |
@@ -1788,6 +1966,11 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, | |||
1788 | } | 1966 | } |
1789 | } | 1967 | } |
1790 | 1968 | ||
1969 | /* suspend devices */ | ||
1970 | rc = ata_eh_suspend(ap, &dev); | ||
1971 | if (rc) | ||
1972 | goto dev_fail; | ||
1973 | |||
1791 | goto out; | 1974 | goto out; |
1792 | 1975 | ||
1793 | dev_fail: | 1976 | dev_fail: |