Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fe06e5f9 authored by Tejun Heo's avatar Tejun Heo Committed by Jeff Garzik
Browse files

libata-sff: separate out BMDMA EH



Some of error handling logic in ata_sff_error_handler() and all of
ata_sff_post_internal_cmd() are for BMDMA.  Create
ata_bmdma_error_handler() and ata_bmdma_post_internal_cmd() and move
BMDMA part into those.

While at it, change DMA protocol check to ata_is_dma(), fix
post_internal_cmd to call ap->ops->bmdma_stop instead of directly
calling ata_bmdma_stop() and open code hardreset selection so that
ata_std_error_handler() doesn't have to know about sff hardreset.

As these two functions are BMDMA specific, there's no reason to check
for bmdma_addr before calling bmdma methods if the protocol of the
failed command is DMA.  sata_mv and pata_mpc52xx now don't need to set
.post_internal_cmd to ATA_OP_NULL and pata_icside and sata_qstor don't
need to set it to their bmdma_stop routines.

ata_sff_post_internal_cmd() becomes noop and is removed.

This fixes p3 described in clean-up-BMDMA-initialization patch.

Signed-off-by: default avatarTejun Heo <tj@kernel.org>
Signed-off-by: default avatarJeff Garzik <jgarzik@redhat.com>
parent c429137a
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -3684,7 +3684,7 @@ void ata_std_error_handler(struct ata_port *ap)
	ata_reset_fn_t hardreset = ops->hardreset;

	/* ignore built-in hardreset if SCR access is not available */
	if (ata_is_builtin_hardreset(hardreset) && !sata_scr_valid(&ap->link))
	if (hardreset == sata_std_hardreset && !sata_scr_valid(&ap->link))
		hardreset = NULL;

	ata_do_eh(ap, ops->prereset, ops->softreset, hardreset, ops->postreset);
+93 −66
Original line number Diff line number Diff line
@@ -56,7 +56,6 @@ const struct ata_port_operations ata_sff_port_ops = {
	.hardreset		= sata_sff_hardreset,
	.postreset		= ata_sff_postreset,
	.error_handler		= ata_sff_error_handler,
	.post_internal_cmd	= ata_sff_post_internal_cmd,

	.sff_dev_select		= ata_sff_dev_select,
	.sff_check_status	= ata_sff_check_status,
@@ -2361,7 +2360,7 @@ void ata_sff_drain_fifo(struct ata_queued_cmd *qc)
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 SFF controller
 *	@ap: port to handle error for
 *
 *	Stock error handler for SFF controller.  It can handle both
@@ -2378,64 +2377,32 @@ void ata_sff_error_handler(struct ata_port *ap)
	ata_reset_fn_t hardreset = ap->ops->hardreset;
	struct ata_queued_cmd *qc;
	unsigned long flags;
	bool thaw = false;

	qc = __ata_qc_from_tag(ap, ap->link.active_tag);
	if (qc && !(qc->flags & ATA_QCFLAG_FAILED))
		qc = NULL;

	/* reset PIO HSM and stop DMA engine */
	spin_lock_irqsave(ap->lock, flags);

	if (ap->ioaddr.bmdma_addr &&
	    qc && (qc->tf.protocol == ATA_PROT_DMA ||
		   qc->tf.protocol == ATAPI_PROT_DMA)) {
		u8 host_stat;

		host_stat = ap->ops->bmdma_status(ap);

		/* BMDMA controllers indicate host bus error by
		 * setting DMA_ERR bit and timing out.  As it wasn't
		 * really a timeout event, adjust error mask and
		 * cancel frozen state.
		 */
		if (qc->err_mask == AC_ERR_TIMEOUT
						&& (host_stat & ATA_DMA_ERR)) {
			qc->err_mask = AC_ERR_HOST_BUS;
			thaw = true;
		}

		ap->ops->bmdma_stop(qc);

		/* if we're gonna thaw, make sure IRQ is clear */
		if (thaw) {
			ap->ops->sff_check_status(ap);
			ap->ops->sff_irq_clear(ap);

			spin_unlock_irqrestore(ap->lock, flags);
			ata_eh_thaw_port(ap);
			spin_lock_irqsave(ap->lock, flags);
		}
	}

	/* 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
	/*
	 * 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->sff_drain_fifo)
		ap->ops->sff_drain_fifo(qc);

	spin_unlock_irqrestore(ap->lock, flags);

	/* PIO and DMA engines have been stopped, perform recovery */

	/* Ignore ata_sff_softreset if ctl isn't accessible and
	 * built-in hardresets if SCR access isn't available.
	 */
	/* ignore ata_sff_softreset if ctl isn't accessible */
	if (softreset == ata_sff_softreset && !ap->ioaddr.ctl_addr)
		softreset = NULL;
	if (ata_is_builtin_hardreset(hardreset) && !sata_scr_valid(&ap->link))

	/* ignore built-in hardresets if SCR access is not available */
	if ((hardreset == sata_std_hardreset ||
	     hardreset == sata_sff_hardreset) && !sata_scr_valid(&ap->link))
		hardreset = NULL;

	ata_do_eh(ap, ap->ops->prereset, softreset, hardreset,
@@ -2443,27 +2410,6 @@ void ata_sff_error_handler(struct ata_port *ap)
}
EXPORT_SYMBOL_GPL(ata_sff_error_handler);

/**
 *	ata_sff_post_internal_cmd - Stock post_internal_cmd for SFF controller
 *	@qc: internal command to clean up
 *
 *	LOCKING:
 *	Kernel thread context (may sleep)
 */
void ata_sff_post_internal_cmd(struct ata_queued_cmd *qc)
{
	struct ata_port *ap = qc->ap;
	unsigned long flags;

	spin_lock_irqsave(ap->lock, flags);

	if (ap->ioaddr.bmdma_addr)
		ap->ops->bmdma_stop(qc);

	spin_unlock_irqrestore(ap->lock, flags);
}
EXPORT_SYMBOL_GPL(ata_sff_post_internal_cmd);

/**
 *	ata_sff_std_ports - initialize ioaddr with standard port offsets.
 *	@ioaddr: IO address structure to be initialized
@@ -2811,6 +2757,9 @@ EXPORT_SYMBOL_GPL(ata_pci_sff_init_one);
const struct ata_port_operations ata_bmdma_port_ops = {
	.inherits		= &ata_sff_port_ops,

	.error_handler		= ata_bmdma_error_handler,
	.post_internal_cmd	= ata_bmdma_post_internal_cmd,

	.bmdma_setup		= ata_bmdma_setup,
	.bmdma_start		= ata_bmdma_start,
	.bmdma_stop		= ata_bmdma_stop,
@@ -2828,6 +2777,84 @@ const struct ata_port_operations ata_bmdma32_port_ops = {
};
EXPORT_SYMBOL_GPL(ata_bmdma32_port_ops);

/**
 *	ata_bmdma_error_handler - Stock error handler for BMDMA controller
 *	@ap: port to handle error for
 *
 *	Stock error handler for BMDMA controller.  It can handle both
 *	PATA and SATA controllers.  Most BMDMA controllers should be
 *	able to use this EH as-is or with some added handling before
 *	and after.
 *
 *	LOCKING:
 *	Kernel thread context (may sleep)
 */
void ata_bmdma_error_handler(struct ata_port *ap)
{
	struct ata_queued_cmd *qc;
	unsigned long flags;
	bool thaw = false;

	qc = __ata_qc_from_tag(ap, ap->link.active_tag);
	if (qc && !(qc->flags & ATA_QCFLAG_FAILED))
		qc = NULL;

	/* reset PIO HSM and stop DMA engine */
	spin_lock_irqsave(ap->lock, flags);

	if (qc && ata_is_dma(qc->tf.protocol)) {
		u8 host_stat;

		host_stat = ap->ops->bmdma_status(ap);

		/* BMDMA controllers indicate host bus error by
		 * setting DMA_ERR bit and timing out.  As it wasn't
		 * really a timeout event, adjust error mask and
		 * cancel frozen state.
		 */
		if (qc->err_mask == AC_ERR_TIMEOUT && (host_stat & ATA_DMA_ERR)) {
			qc->err_mask = AC_ERR_HOST_BUS;
			thaw = true;
		}

		ap->ops->bmdma_stop(qc);

		/* if we're gonna thaw, make sure IRQ is clear */
		if (thaw) {
			ap->ops->sff_check_status(ap);
			ap->ops->sff_irq_clear(ap);
		}
	}

	spin_unlock_irqrestore(ap->lock, flags);

	if (thaw)
		ata_eh_thaw_port(ap);

	ata_sff_error_handler(ap);
}
EXPORT_SYMBOL_GPL(ata_bmdma_error_handler);

/**
 *	ata_bmdma_post_internal_cmd - Stock post_internal_cmd for BMDMA
 *	@qc: internal command to clean up
 *
 *	LOCKING:
 *	Kernel thread context (may sleep)
 */
void ata_bmdma_post_internal_cmd(struct ata_queued_cmd *qc)
{
	struct ata_port *ap = qc->ap;
	unsigned long flags;

	if (ata_is_dma(qc->tf.protocol)) {
		spin_lock_irqsave(ap->lock, flags);
		ap->ops->bmdma_stop(qc);
		spin_unlock_irqrestore(ap->lock, flags);
	}
}
EXPORT_SYMBOL_GPL(ata_bmdma_post_internal_cmd);

/**
 *	ata_bmdma_setup - Set up PCI IDE BMDMA transaction
 *	@qc: Info associated with this ATA transaction.
+0 −11
Original line number Diff line number Diff line
@@ -38,17 +38,6 @@ struct ata_scsi_args {
	void			(*done)(struct scsi_cmnd *);
};

static inline int ata_is_builtin_hardreset(ata_reset_fn_t reset)
{
	if (reset == sata_std_hardreset)
		return 1;
#ifdef CONFIG_ATA_SFF
	if (reset == sata_sff_hardreset)
		return 1;
#endif
	return 0;
}

/* libata-core.c */
enum {
	/* flags for ata_dev_read_id() */
+0 −1
Original line number Diff line number Diff line
@@ -333,7 +333,6 @@ static struct ata_port_operations pata_icside_port_ops = {
	.cable_detect		= ata_cable_40wire,
	.set_dmamode		= pata_icside_set_dmamode,
	.postreset		= pata_icside_postreset,
	.post_internal_cmd	= pata_icside_bmdma_stop,

	.port_start		= ATA_OP_NULL,	/* don't need PRD table */
};
+0 −1
Original line number Diff line number Diff line
@@ -951,7 +951,6 @@ static struct ata_port_operations scc_pata_ops = {
	.prereset		= scc_pata_prereset,
	.softreset		= scc_softreset,
	.postreset		= scc_postreset,
	.post_internal_cmd	= scc_bmdma_stop,

	.sff_irq_clear		= scc_irq_clear,

Loading