|
@@ -52,6 +52,7 @@ const struct ata_port_operations ata_sff_port_ops = {
|
|
.softreset = ata_sff_softreset,
|
|
.softreset = ata_sff_softreset,
|
|
.hardreset = sata_sff_hardreset,
|
|
.hardreset = sata_sff_hardreset,
|
|
.postreset = ata_sff_postreset,
|
|
.postreset = ata_sff_postreset,
|
|
|
|
+ .drain_fifo = ata_sff_drain_fifo,
|
|
.error_handler = ata_sff_error_handler,
|
|
.error_handler = ata_sff_error_handler,
|
|
.post_internal_cmd = ata_sff_post_internal_cmd,
|
|
.post_internal_cmd = ata_sff_post_internal_cmd,
|
|
|
|
|
|
@@ -2198,6 +2199,39 @@ void ata_sff_postreset(struct ata_link *link, unsigned int *classes)
|
|
}
|
|
}
|
|
EXPORT_SYMBOL_GPL(ata_sff_postreset);
|
|
EXPORT_SYMBOL_GPL(ata_sff_postreset);
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * ata_sff_drain_fifo - Stock FIFO drain logic for SFF controllers
|
|
|
|
+ * @qc: command
|
|
|
|
+ *
|
|
|
|
+ * Drain the FIFO and device of any stuck data following a command
|
|
|
|
+ * failing to complete. In some cases this is neccessary before a
|
|
|
|
+ * reset will recover the device.
|
|
|
|
+ *
|
|
|
|
+ */
|
|
|
|
+
|
|
|
|
+void ata_sff_drain_fifo(struct ata_queued_cmd *qc)
|
|
|
|
+{
|
|
|
|
+ int count;
|
|
|
|
+ struct ata_port *ap;
|
|
|
|
+
|
|
|
|
+ /* We only need to flush incoming data when a command was running */
|
|
|
|
+ if (qc == NULL || qc->dma_dir == DMA_TO_DEVICE)
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+ ap = qc->ap;
|
|
|
|
+ /* Drain up to 64K of data before we give up this recovery method */
|
|
|
|
+ for (count = 0; (ap->ops->sff_check_status(ap) & ATA_DRQ)
|
|
|
|
+ && count < 32768; count++)
|
|
|
|
+ ioread16(ap->ioaddr.data_addr);
|
|
|
|
+
|
|
|
|
+ /* Can become DEBUG later */
|
|
|
|
+ if (count)
|
|
|
|
+ ata_port_printk(ap, KERN_DEBUG,
|
|
|
|
+ "drained %d bytes to clear DRQ.\n", count);
|
|
|
|
+
|
|
|
|
+}
|
|
|
|
+EXPORT_SYMBOL_GPL(ata_sff_drain_fifo);
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* ata_sff_error_handler - Stock error handler for BMDMA controller
|
|
* ata_sff_error_handler - Stock error handler for BMDMA controller
|
|
* @ap: port to handle error for
|
|
* @ap: port to handle error for
|
|
@@ -2239,7 +2273,8 @@ void ata_sff_error_handler(struct ata_port *ap)
|
|
* really a timeout event, adjust error mask and
|
|
* really a timeout event, adjust error mask and
|
|
* cancel frozen state.
|
|
* cancel frozen state.
|
|
*/
|
|
*/
|
|
- if (qc->err_mask == AC_ERR_TIMEOUT && (host_stat & ATA_DMA_ERR)) {
|
|
|
|
|
|
+ if (qc->err_mask == AC_ERR_TIMEOUT
|
|
|
|
+ && (host_stat & ATA_DMA_ERR)) {
|
|
qc->err_mask = AC_ERR_HOST_BUS;
|
|
qc->err_mask = AC_ERR_HOST_BUS;
|
|
thaw = 1;
|
|
thaw = 1;
|
|
}
|
|
}
|
|
@@ -2250,6 +2285,13 @@ void ata_sff_error_handler(struct ata_port *ap)
|
|
ata_sff_sync(ap); /* FIXME: We don't need this */
|
|
ata_sff_sync(ap); /* FIXME: We don't need this */
|
|
ap->ops->sff_check_status(ap);
|
|
ap->ops->sff_check_status(ap);
|
|
ap->ops->sff_irq_clear(ap);
|
|
ap->ops->sff_irq_clear(ap);
|
|
|
|
+ /* We *MUST* do FIFO draining before we issue a reset as several
|
|
|
|
+ * devices helpfully clear their internal state and will lock solid
|
|
|
|
+ * if we touch the data port post reset. Pass qc in case anyone wants
|
|
|
|
+ * to do different PIO/DMA recovery or has per command fixups
|
|
|
|
+ */
|
|
|
|
+ if (ap->ops->drain_fifo)
|
|
|
|
+ ap->ops->drain_fifo(qc);
|
|
|
|
|
|
spin_unlock_irqrestore(ap->lock, flags);
|
|
spin_unlock_irqrestore(ap->lock, flags);
|
|
|
|
|
|
@@ -2959,4 +3001,3 @@ out:
|
|
EXPORT_SYMBOL_GPL(ata_pci_sff_init_one);
|
|
EXPORT_SYMBOL_GPL(ata_pci_sff_init_one);
|
|
|
|
|
|
#endif /* CONFIG_PCI */
|
|
#endif /* CONFIG_PCI */
|
|
-
|
|
|