*/
#include <linux/kernel.h>
+#include <linux/gfp.h>
#include <linux/pci.h>
#include <linux/libata.h>
#include <linux/highmem.h>
.softreset = ata_sff_softreset,
.hardreset = sata_sff_hardreset,
.postreset = ata_sff_postreset,
+ .drain_fifo = ata_sff_drain_fifo,
.error_handler = ata_sff_error_handler,
.post_internal_cmd = ata_sff_post_internal_cmd,
.sff_irq_on = ata_sff_irq_on,
.sff_irq_clear = ata_sff_irq_clear,
+ .lost_interrupt = ata_sff_lost_interrupt,
+
.port_start = ata_sff_port_start,
};
EXPORT_SYMBOL_GPL(ata_sff_port_ops);
.inherits = &ata_bmdma_port_ops,
.sff_data_xfer = ata_sff_data_xfer32,
+ .port_start = ata_sff_port_start32,
};
EXPORT_SYMBOL_GPL(ata_bmdma32_port_ops);
else
iowrite16_rep(data_addr, buf, words);
- /* Transfer trailing 1 byte, if any. */
+ /* Transfer trailing byte, if any. */
if (unlikely(buflen & 0x01)) {
- __le16 align_buf[1] = { 0 };
- unsigned char *trailing_buf = buf + buflen - 1;
+ unsigned char pad[2];
+
+ /* Point buf to the tail of buffer */
+ buf += buflen - 1;
+ /*
+ * Use io*16_rep() accessors here as well to avoid pointlessly
+ * swapping bytes to and from on the big endian machines...
+ */
if (rw == READ) {
- align_buf[0] = cpu_to_le16(ioread16(data_addr));
- memcpy(trailing_buf, align_buf, 1);
+ ioread16_rep(data_addr, pad, 1);
+ *buf = pad[0];
} else {
- memcpy(align_buf, trailing_buf, 1);
- iowrite16(le16_to_cpu(align_buf[0]), data_addr);
+ pad[0] = *buf;
+ iowrite16_rep(data_addr, pad, 1);
}
words++;
}
unsigned int words = buflen >> 2;
int slop = buflen & 3;
+ if (!(ap->pflags & ATA_PFLAG_PIO32))
+ return ata_sff_data_xfer(dev, buf, buflen, rw);
+
/* Transfer multiple of 4 bytes */
if (rw == READ)
ioread32_rep(data_addr, buf, words);
else
iowrite32_rep(data_addr, buf, words);
+ /* Transfer trailing bytes, if any */
if (unlikely(slop)) {
- __le32 pad;
+ unsigned char pad[4];
+
+ /* Point buf to the tail of buffer */
+ buf += buflen - slop;
+
+ /*
+ * Use io*_rep() accessors here as well to avoid pointlessly
+ * swapping bytes to and from on the big endian machines...
+ */
if (rw == READ) {
- pad = cpu_to_le32(ioread32(ap->ioaddr.data_addr));
- memcpy(buf + buflen - slop, &pad, slop);
+ if (slop < 3)
+ ioread16_rep(data_addr, pad, 1);
+ else
+ ioread32_rep(data_addr, pad, 1);
+ memcpy(buf, pad, slop);
} else {
- memcpy(&pad, buf + buflen - slop, slop);
- iowrite32(le32_to_cpu(pad), ap->ioaddr.data_addr);
+ memcpy(pad, buf, slop);
+ if (slop < 3)
+ iowrite16_rep(data_addr, pad, 1);
+ else
+ iowrite32_rep(data_addr, pad, 1);
}
- words++;
}
- return words << 2;
+ return (buflen + 1) & ~1;
}
EXPORT_SYMBOL_GPL(ata_sff_data_xfer32);
do_write);
}
+ if (!do_write)
+ flush_dcache_page(page);
+
qc->curbytes += qc->sect_size;
qc->cursg_ofs += qc->sect_size;
* RETURNS:
* One if interrupt was handled, zero if not (shared irq).
*/
-inline unsigned int ata_sff_host_intr(struct ata_port *ap,
+unsigned int ata_sff_host_intr(struct ata_port *ap,
struct ata_queued_cmd *qc)
{
struct ata_eh_info *ehi = &ap->link.eh_info;
u8 status, host_stat = 0;
+ bool bmdma_stopped = false;
VPRINTK("ata%u: protocol %d task_state %d\n",
ap->print_id, qc->tf.protocol, ap->hsm_task_state);
/* before we do anything else, clear DMA-Start bit */
ap->ops->bmdma_stop(qc);
+ bmdma_stopped = true;
if (unlikely(host_stat & ATA_DMA_ERR)) {
/* error when transfering data to/from memory */
/* check main status, clearing INTRQ if needed */
status = ata_sff_irq_status(ap);
- if (status & ATA_BUSY)
- goto idle_irq;
+ if (status & ATA_BUSY) {
+ if (bmdma_stopped) {
+ /* BMDMA engine is already stopped, we're screwed */
+ qc->err_mask |= AC_ERR_HSM;
+ ap->hsm_task_state = HSM_ST_ERR;
+ } else
+ goto idle_irq;
+ }
/* ack bmdma irq events */
ap->ops->sff_irq_clear(ap);
irqreturn_t ata_sff_interrupt(int irq, void *dev_instance)
{
struct ata_host *host = dev_instance;
+ bool retried = false;
unsigned int i;
- unsigned int handled = 0;
+ unsigned int handled, idle, polling;
unsigned long flags;
/* TODO: make _irqsave conditional on x86 PCI IDE legacy mode */
spin_lock_irqsave(&host->lock, flags);
+retry:
+ handled = idle = polling = 0;
for (i = 0; i < host->n_ports; i++) {
- struct ata_port *ap;
+ struct ata_port *ap = host->ports[i];
+ struct ata_queued_cmd *qc;
- ap = host->ports[i];
- if (ap &&
- !(ap->flags & ATA_FLAG_DISABLED)) {
- struct ata_queued_cmd *qc;
+ if (unlikely(ap->flags & ATA_FLAG_DISABLED))
+ continue;
- qc = ata_qc_from_tag(ap, ap->link.active_tag);
- if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)) &&
- (qc->flags & ATA_QCFLAG_ACTIVE))
+ qc = ata_qc_from_tag(ap, ap->link.active_tag);
+ if (qc) {
+ if (!(qc->tf.flags & ATA_TFLAG_POLLING))
handled |= ata_sff_host_intr(ap, qc);
+ else
+ polling |= 1 << i;
+ } else
+ idle |= 1 << i;
+ }
+
+ /*
+ * If no port was expecting IRQ but the controller is actually
+ * asserting IRQ line, nobody cared will ensue. Check IRQ
+ * pending status if available and clear spurious IRQ.
+ */
+ if (!handled && !retried) {
+ bool retry = false;
+
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap = host->ports[i];
+
+ if (polling & (1 << i))
+ continue;
+
+ if (!ap->ops->sff_irq_check ||
+ !ap->ops->sff_irq_check(ap))
+ continue;
+
+ if (idle & (1 << i)) {
+ ap->ops->sff_check_status(ap);
+ ap->ops->sff_irq_clear(ap);
+ } else {
+ /* clear INTRQ and check if BUSY cleared */
+ if (!(ap->ops->sff_check_status(ap) & ATA_BUSY))
+ retry |= true;
+ /*
+ * With command in flight, we can't do
+ * sff_irq_clear() w/o racing with completion.
+ */
+ }
+ }
+
+ if (retry) {
+ retried = true;
+ goto retry;
}
}
EXPORT_SYMBOL_GPL(ata_sff_interrupt);
/**
+ * ata_sff_lost_interrupt - Check for an apparent lost interrupt
+ * @ap: port that appears to have timed out
+ *
+ * Called from the libata error handlers when the core code suspects
+ * an interrupt has been lost. If it has complete anything we can and
+ * then return. Interface must support altstatus for this faster
+ * recovery to occur.
+ *
+ * Locking:
+ * Caller holds host lock
+ */
+
+void ata_sff_lost_interrupt(struct ata_port *ap)
+{
+ u8 status;
+ struct ata_queued_cmd *qc;
+
+ /* Only one outstanding command per SFF channel */
+ qc = ata_qc_from_tag(ap, ap->link.active_tag);
+ /* Check we have a live one.. */
+ if (qc == NULL || !(qc->flags & ATA_QCFLAG_ACTIVE))
+ return;
+ /* We cannot lose an interrupt on a polled command */
+ if (qc->tf.flags & ATA_TFLAG_POLLING)
+ return;
+ /* See if the controller thinks it is still busy - if so the command
+ isn't a lost IRQ but is still in progress */
+ status = ata_sff_altstatus(ap);
+ if (status & ATA_BUSY)
+ return;
+
+ /* There was a command running, we are no longer busy and we have
+ no interrupt. */
+ ata_port_printk(ap, KERN_WARNING, "lost interrupt (Status 0x%x)\n",
+ status);
+ /* Run the host interrupt logic as if the interrupt had not been
+ lost */
+ ata_sff_host_intr(ap, qc);
+}
+EXPORT_SYMBOL_GPL(ata_sff_lost_interrupt);
+
+/**
* ata_sff_freeze - Freeze SFF controller port
* @ap: port to freeze
*
iowrite8(ap->ctl | ATA_SRST, ioaddr->ctl_addr);
udelay(20); /* FIXME: flush */
iowrite8(ap->ctl, ioaddr->ctl_addr);
+ ap->last_ctl = ap->ctl;
/* wait the port to become ready */
return ata_sff_wait_after_reset(&ap->link, devmask, deadline);
}
/* set up device control */
- if (ap->ioaddr.ctl_addr)
+ if (ap->ioaddr.ctl_addr) {
iowrite8(ap->ctl, ap->ioaddr.ctl_addr);
+ ap->last_ctl = ap->ctl;
+ }
}
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 necessary 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 < 65536; count += 2)
+ 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
* @ap: port to handle error for
*
* really a timeout event, adjust error mask and
* 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;
thaw = 1;
}
ata_sff_sync(ap); /* FIXME: We don't need this */
ap->ops->sff_check_status(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);
ap->hsm_task_state = HSM_ST_IDLE;
if (ap->ioaddr.bmdma_addr)
- ata_bmdma_stop(qc);
+ ap->ops->bmdma_stop(qc);
spin_unlock_irqrestore(ap->lock, flags);
}
EXPORT_SYMBOL_GPL(ata_sff_port_start);
/**
+ * ata_sff_port_start32 - Set port up for dma.
+ * @ap: Port to initialize
+ *
+ * Called just after data structures for each port are
+ * initialized. Allocates space for PRD table if the device
+ * is DMA capable SFF.
+ *
+ * May be used as the port_start() entry in ata_port_operations for
+ * devices that are capable of 32bit PIO.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+int ata_sff_port_start32(struct ata_port *ap)
+{
+ ap->pflags |= ATA_PFLAG_PIO32 | ATA_PFLAG_PIO32CHANGE;
+ if (ap->ioaddr.bmdma_addr)
+ return ata_port_start(ap);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ata_sff_port_start32);
+
+/**
* ata_sff_std_ports - initialize ioaddr with standard port offsets.
* @ioaddr: IO address structure to be initialized
*
if (ap->flags & (ATA_FLAG_SATA_RESET | ATA_FLAG_SRST)) {
/* set up device control for ATA_FLAG_SATA_RESET */
iowrite8(ap->ctl, ioaddr->ctl_addr);
+ ap->last_ctl = ap->ctl;
}
DPRINTK("EXIT\n");
* @ppi: array of port_info, must be enough for two ports
* @sht: scsi_host_template to use when registering the host
* @host_priv: host private_data
+ * @hflag: host flags
*
* This is a helper function which can be called from a driver's
* xxx_init_one() probe function if the hardware uses traditional
* Zero on success, negative on errno-based value on error.
*/
int ata_pci_sff_init_one(struct pci_dev *pdev,
- const struct ata_port_info * const *ppi,
- struct scsi_host_template *sht, void *host_priv)
+ const struct ata_port_info * const *ppi,
+ struct scsi_host_template *sht, void *host_priv, int hflag)
{
struct device *dev = &pdev->dev;
const struct ata_port_info *pi = NULL;
if (rc)
goto out;
host->private_data = host_priv;
+ host->flags |= hflag;
pci_set_master(pdev);
rc = ata_pci_sff_activate_host(host, ata_sff_interrupt, sht);
EXPORT_SYMBOL_GPL(ata_pci_sff_init_one);
#endif /* CONFIG_PCI */
-