summaryrefslogtreecommitdiff
path: root/drivers/ata
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2010-05-10 21:41:39 +0200
committerJeff Garzik <jgarzik@redhat.com>2010-05-19 13:36:46 -0400
commitfe06e5f9b7c61dc567edace3f4909672067f7d7e (patch)
treeb2242169e8e3b32c63925ed9901fff9d49c26192 /drivers/ata
parentc429137a67b82788d24682153bb9c96501a9ef34 (diff)
downloadlinux-3.10-fe06e5f9b7c61dc567edace3f4909672067f7d7e.tar.gz
linux-3.10-fe06e5f9b7c61dc567edace3f4909672067f7d7e.tar.bz2
linux-3.10-fe06e5f9b7c61dc567edace3f4909672067f7d7e.zip
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: Tejun Heo <tj@kernel.org> Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
Diffstat (limited to 'drivers/ata')
-rw-r--r--drivers/ata/libata-eh.c2
-rw-r--r--drivers/ata/libata-sff.c159
-rw-r--r--drivers/ata/libata.h11
-rw-r--r--drivers/ata/pata_icside.c1
-rw-r--r--drivers/ata/pata_scc.c1
-rw-r--r--drivers/ata/sata_nv.c6
-rw-r--r--drivers/ata/sata_promise.c2
-rw-r--r--drivers/ata/sata_qstor.c3
-rw-r--r--drivers/ata/sata_sx4.c2
9 files changed, 100 insertions, 87 deletions
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index d6e67488174..f77a67303f8 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -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);
diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c
index e78ad76861f..aa378c04ed8 100644
--- a/drivers/ata/libata-sff.c
+++ b/drivers/ata/libata-sff.c
@@ -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,
@@ -2444,27 +2411,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,
@@ -2829,6 +2778,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.
*
diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h
index 002390cdc04..4b84ed60324 100644
--- a/drivers/ata/libata.h
+++ b/drivers/ata/libata.h
@@ -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() */
diff --git a/drivers/ata/pata_icside.c b/drivers/ata/pata_icside.c
index ee85a9ce0a1..b56e8f722d2 100644
--- a/drivers/ata/pata_icside.c
+++ b/drivers/ata/pata_icside.c
@@ -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 */
};
diff --git a/drivers/ata/pata_scc.c b/drivers/ata/pata_scc.c
index 70d549e28f0..93f690e51a7 100644
--- a/drivers/ata/pata_scc.c
+++ b/drivers/ata/pata_scc.c
@@ -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,
diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c
index a007b20c199..64e99824d8c 100644
--- a/drivers/ata/sata_nv.c
+++ b/drivers/ata/sata_nv.c
@@ -1131,7 +1131,7 @@ static void nv_adma_post_internal_cmd(struct ata_queued_cmd *qc)
struct nv_adma_port_priv *pp = qc->ap->private_data;
if (pp->flags & NV_ADMA_PORT_REGISTER_MODE)
- ata_sff_post_internal_cmd(qc);
+ ata_bmdma_post_internal_cmd(qc);
}
static int nv_adma_port_start(struct ata_port *ap)
@@ -1739,7 +1739,7 @@ static void nv_adma_error_handler(struct ata_port *ap)
readw(mmio + NV_ADMA_CTL); /* flush posted write */
}
- ata_sff_error_handler(ap);
+ ata_bmdma_error_handler(ap);
}
static void nv_swncq_qc_to_dq(struct ata_port *ap, struct ata_queued_cmd *qc)
@@ -1865,7 +1865,7 @@ static void nv_swncq_error_handler(struct ata_port *ap)
ehc->i.action |= ATA_EH_RESET;
}
- ata_sff_error_handler(ap);
+ ata_bmdma_error_handler(ap);
}
#ifdef CONFIG_PM
diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c
index e80628a7766..09a6179f5de 100644
--- a/drivers/ata/sata_promise.c
+++ b/drivers/ata/sata_promise.c
@@ -839,7 +839,7 @@ static void pdc_error_handler(struct ata_port *ap)
if (!(ap->pflags & ATA_PFLAG_FROZEN))
pdc_reset_port(ap);
- ata_std_error_handler(ap);
+ ata_sff_error_handler(ap);
}
static void pdc_post_internal_cmd(struct ata_queued_cmd *qc)
diff --git a/drivers/ata/sata_qstor.c b/drivers/ata/sata_qstor.c
index da84ea9e4fb..d3a22f2ae7b 100644
--- a/drivers/ata/sata_qstor.c
+++ b/drivers/ata/sata_qstor.c
@@ -147,7 +147,6 @@ static struct ata_port_operations qs_ata_ops = {
.prereset = qs_prereset,
.softreset = ATA_OP_NULL,
.error_handler = qs_error_handler,
- .post_internal_cmd = ATA_OP_NULL,
.lost_interrupt = ATA_OP_NULL,
.scr_read = qs_scr_read,
@@ -255,7 +254,7 @@ static int qs_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val)
static void qs_error_handler(struct ata_port *ap)
{
qs_enter_reg_mode(ap);
- ata_std_error_handler(ap);
+ ata_sff_error_handler(ap);
}
static int qs_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val)
diff --git a/drivers/ata/sata_sx4.c b/drivers/ata/sata_sx4.c
index a4e552a325b..bedd5188e5b 100644
--- a/drivers/ata/sata_sx4.c
+++ b/drivers/ata/sata_sx4.c
@@ -921,7 +921,7 @@ static void pdc_error_handler(struct ata_port *ap)
if (!(ap->pflags & ATA_PFLAG_FROZEN))
pdc_reset_port(ap);
- ata_std_error_handler(ap);
+ ata_sff_error_handler(ap);
}
static void pdc_post_internal_cmd(struct ata_queued_cmd *qc)