diff options
Diffstat (limited to 'drivers/ata/libata-sff.c')
-rw-r--r-- | drivers/ata/libata-sff.c | 91 |
1 files changed, 88 insertions, 3 deletions
diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index f93dc029dfde..8332e97a9de3 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c | |||
@@ -52,6 +52,7 @@ const struct ata_port_operations ata_sff_port_ops = { | |||
52 | .softreset = ata_sff_softreset, | 52 | .softreset = ata_sff_softreset, |
53 | .hardreset = sata_sff_hardreset, | 53 | .hardreset = sata_sff_hardreset, |
54 | .postreset = ata_sff_postreset, | 54 | .postreset = ata_sff_postreset, |
55 | .drain_fifo = ata_sff_drain_fifo, | ||
55 | .error_handler = ata_sff_error_handler, | 56 | .error_handler = ata_sff_error_handler, |
56 | .post_internal_cmd = ata_sff_post_internal_cmd, | 57 | .post_internal_cmd = ata_sff_post_internal_cmd, |
57 | 58 | ||
@@ -64,6 +65,8 @@ const struct ata_port_operations ata_sff_port_ops = { | |||
64 | .sff_irq_on = ata_sff_irq_on, | 65 | .sff_irq_on = ata_sff_irq_on, |
65 | .sff_irq_clear = ata_sff_irq_clear, | 66 | .sff_irq_clear = ata_sff_irq_clear, |
66 | 67 | ||
68 | .lost_interrupt = ata_sff_lost_interrupt, | ||
69 | |||
67 | .port_start = ata_sff_port_start, | 70 | .port_start = ata_sff_port_start, |
68 | }; | 71 | }; |
69 | EXPORT_SYMBOL_GPL(ata_sff_port_ops); | 72 | EXPORT_SYMBOL_GPL(ata_sff_port_ops); |
@@ -1646,7 +1649,7 @@ EXPORT_SYMBOL_GPL(ata_sff_qc_fill_rtf); | |||
1646 | * RETURNS: | 1649 | * RETURNS: |
1647 | * One if interrupt was handled, zero if not (shared irq). | 1650 | * One if interrupt was handled, zero if not (shared irq). |
1648 | */ | 1651 | */ |
1649 | inline unsigned int ata_sff_host_intr(struct ata_port *ap, | 1652 | unsigned int ata_sff_host_intr(struct ata_port *ap, |
1650 | struct ata_queued_cmd *qc) | 1653 | struct ata_queued_cmd *qc) |
1651 | { | 1654 | { |
1652 | struct ata_eh_info *ehi = &ap->link.eh_info; | 1655 | struct ata_eh_info *ehi = &ap->link.eh_info; |
@@ -1775,6 +1778,48 @@ irqreturn_t ata_sff_interrupt(int irq, void *dev_instance) | |||
1775 | EXPORT_SYMBOL_GPL(ata_sff_interrupt); | 1778 | EXPORT_SYMBOL_GPL(ata_sff_interrupt); |
1776 | 1779 | ||
1777 | /** | 1780 | /** |
1781 | * ata_sff_lost_interrupt - Check for an apparent lost interrupt | ||
1782 | * @ap: port that appears to have timed out | ||
1783 | * | ||
1784 | * Called from the libata error handlers when the core code suspects | ||
1785 | * an interrupt has been lost. If it has complete anything we can and | ||
1786 | * then return. Interface must support altstatus for this faster | ||
1787 | * recovery to occur. | ||
1788 | * | ||
1789 | * Locking: | ||
1790 | * Caller holds host lock | ||
1791 | */ | ||
1792 | |||
1793 | void ata_sff_lost_interrupt(struct ata_port *ap) | ||
1794 | { | ||
1795 | u8 status; | ||
1796 | struct ata_queued_cmd *qc; | ||
1797 | |||
1798 | /* Only one outstanding command per SFF channel */ | ||
1799 | qc = ata_qc_from_tag(ap, ap->link.active_tag); | ||
1800 | /* Check we have a live one.. */ | ||
1801 | if (qc == NULL || !(qc->flags & ATA_QCFLAG_ACTIVE)) | ||
1802 | return; | ||
1803 | /* We cannot lose an interrupt on a polled command */ | ||
1804 | if (qc->tf.flags & ATA_TFLAG_POLLING) | ||
1805 | return; | ||
1806 | /* See if the controller thinks it is still busy - if so the command | ||
1807 | isn't a lost IRQ but is still in progress */ | ||
1808 | status = ata_sff_altstatus(ap); | ||
1809 | if (status & ATA_BUSY) | ||
1810 | return; | ||
1811 | |||
1812 | /* There was a command running, we are no longer busy and we have | ||
1813 | no interrupt. */ | ||
1814 | ata_port_printk(ap, KERN_WARNING, "lost interrupt (Status 0x%x)\n", | ||
1815 | status); | ||
1816 | /* Run the host interrupt logic as if the interrupt had not been | ||
1817 | lost */ | ||
1818 | ata_sff_host_intr(ap, qc); | ||
1819 | } | ||
1820 | EXPORT_SYMBOL_GPL(ata_sff_lost_interrupt); | ||
1821 | |||
1822 | /** | ||
1778 | * ata_sff_freeze - Freeze SFF controller port | 1823 | * ata_sff_freeze - Freeze SFF controller port |
1779 | * @ap: port to freeze | 1824 | * @ap: port to freeze |
1780 | * | 1825 | * |
@@ -2199,6 +2244,39 @@ void ata_sff_postreset(struct ata_link *link, unsigned int *classes) | |||
2199 | EXPORT_SYMBOL_GPL(ata_sff_postreset); | 2244 | EXPORT_SYMBOL_GPL(ata_sff_postreset); |
2200 | 2245 | ||
2201 | /** | 2246 | /** |
2247 | * ata_sff_drain_fifo - Stock FIFO drain logic for SFF controllers | ||
2248 | * @qc: command | ||
2249 | * | ||
2250 | * Drain the FIFO and device of any stuck data following a command | ||
2251 | * failing to complete. In some cases this is neccessary before a | ||
2252 | * reset will recover the device. | ||
2253 | * | ||
2254 | */ | ||
2255 | |||
2256 | void ata_sff_drain_fifo(struct ata_queued_cmd *qc) | ||
2257 | { | ||
2258 | int count; | ||
2259 | struct ata_port *ap; | ||
2260 | |||
2261 | /* We only need to flush incoming data when a command was running */ | ||
2262 | if (qc == NULL || qc->dma_dir == DMA_TO_DEVICE) | ||
2263 | return; | ||
2264 | |||
2265 | ap = qc->ap; | ||
2266 | /* Drain up to 64K of data before we give up this recovery method */ | ||
2267 | for (count = 0; (ap->ops->sff_check_status(ap) & ATA_DRQ) | ||
2268 | && count < 32768; count++) | ||
2269 | ioread16(ap->ioaddr.data_addr); | ||
2270 | |||
2271 | /* Can become DEBUG later */ | ||
2272 | if (count) | ||
2273 | ata_port_printk(ap, KERN_DEBUG, | ||
2274 | "drained %d bytes to clear DRQ.\n", count); | ||
2275 | |||
2276 | } | ||
2277 | EXPORT_SYMBOL_GPL(ata_sff_drain_fifo); | ||
2278 | |||
2279 | /** | ||
2202 | * ata_sff_error_handler - Stock error handler for BMDMA controller | 2280 | * ata_sff_error_handler - Stock error handler for BMDMA controller |
2203 | * @ap: port to handle error for | 2281 | * @ap: port to handle error for |
2204 | * | 2282 | * |
@@ -2239,7 +2317,8 @@ void ata_sff_error_handler(struct ata_port *ap) | |||
2239 | * really a timeout event, adjust error mask and | 2317 | * really a timeout event, adjust error mask and |
2240 | * cancel frozen state. | 2318 | * cancel frozen state. |
2241 | */ | 2319 | */ |
2242 | if (qc->err_mask == AC_ERR_TIMEOUT && (host_stat & ATA_DMA_ERR)) { | 2320 | if (qc->err_mask == AC_ERR_TIMEOUT |
2321 | && (host_stat & ATA_DMA_ERR)) { | ||
2243 | qc->err_mask = AC_ERR_HOST_BUS; | 2322 | qc->err_mask = AC_ERR_HOST_BUS; |
2244 | thaw = 1; | 2323 | thaw = 1; |
2245 | } | 2324 | } |
@@ -2250,6 +2329,13 @@ void ata_sff_error_handler(struct ata_port *ap) | |||
2250 | ata_sff_sync(ap); /* FIXME: We don't need this */ | 2329 | ata_sff_sync(ap); /* FIXME: We don't need this */ |
2251 | ap->ops->sff_check_status(ap); | 2330 | ap->ops->sff_check_status(ap); |
2252 | ap->ops->sff_irq_clear(ap); | 2331 | ap->ops->sff_irq_clear(ap); |
2332 | /* We *MUST* do FIFO draining before we issue a reset as several | ||
2333 | * devices helpfully clear their internal state and will lock solid | ||
2334 | * if we touch the data port post reset. Pass qc in case anyone wants | ||
2335 | * to do different PIO/DMA recovery or has per command fixups | ||
2336 | */ | ||
2337 | if (ap->ops->drain_fifo) | ||
2338 | ap->ops->drain_fifo(qc); | ||
2253 | 2339 | ||
2254 | spin_unlock_irqrestore(ap->lock, flags); | 2340 | spin_unlock_irqrestore(ap->lock, flags); |
2255 | 2341 | ||
@@ -2959,4 +3045,3 @@ out: | |||
2959 | EXPORT_SYMBOL_GPL(ata_pci_sff_init_one); | 3045 | EXPORT_SYMBOL_GPL(ata_pci_sff_init_one); |
2960 | 3046 | ||
2961 | #endif /* CONFIG_PCI */ | 3047 | #endif /* CONFIG_PCI */ |
2962 | |||