Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=3f3debdbfb7713aa06c4370bab6bef277dfd7a37
Commit:     3f3debdbfb7713aa06c4370bab6bef277dfd7a37
Parent:     2254c2e0184c603f92fc9b81016ff4bb53da622d
Author:     Robert Hancock <[EMAIL PROTECTED]>
AuthorDate: Sun Nov 25 16:59:36 2007 -0600
Committer:  Jeff Garzik <[EMAIL PROTECTED]>
CommitDate: Tue Dec 4 14:01:18 2007 -0500

    sata_nv: don't use legacy DMA in ADMA mode (v3)
    
    We need to run any DMA command with result taskfile requested in ADMA mode
    when the port is in ADMA mode, otherwise it may try to use the legacy DMA 
engine
    in ADMA mode which is not allowed. Enforce this with BUG_ON() since data
    corruption could potentially result if this happened. Also, fail any 
attempt to
    try and issue NCQ commands with result taskfile requested, since the 
hardware
    doesn't allow this.
    
    Signed-off-by: Robert Hancock <[EMAIL PROTECTED]>
    Signed-off-by: Jeff Garzik <[EMAIL PROTECTED]>
---
 drivers/ata/sata_nv.c |   32 +++++++++++++++++++++++---------
 1 files changed, 23 insertions(+), 9 deletions(-)

diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c
index 44f9e5d..ed5dc7c 100644
--- a/drivers/ata/sata_nv.c
+++ b/drivers/ata/sata_nv.c
@@ -791,11 +791,13 @@ static int nv_adma_check_atapi_dma(struct ata_queued_cmd 
*qc)
 
 static void nv_adma_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
 {
-       /* Since commands where a result TF is requested are not
-          executed in ADMA mode, the only time this function will be called
-          in ADMA mode will be if a command fails. In this case we
-          don't care about going into register mode with ADMA commands
-          pending, as the commands will all shortly be aborted anyway. */
+       /* Other than when internal or pass-through commands are executed,
+          the only time this function will be called in ADMA mode will be
+          if a command fails. In the failure case we don't care about going
+          into register mode with ADMA commands pending, as the commands will
+          all shortly be aborted anyway. We assume that NCQ commands are not
+          issued via passthrough, which is the only way that switching into
+          ADMA mode could abort outstanding commands. */
        nv_adma_register_mode(ap);
 
        ata_tf_read(ap, tf);
@@ -1359,11 +1361,9 @@ static int nv_adma_use_reg_mode(struct ata_queued_cmd 
*qc)
        struct nv_adma_port_priv *pp = qc->ap->private_data;
 
        /* ADMA engine can only be used for non-ATAPI DMA commands,
-          or interrupt-driven no-data commands, where a result taskfile
-          is not required. */
+          or interrupt-driven no-data commands. */
        if ((pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE) ||
-          (qc->tf.flags & ATA_TFLAG_POLLING) ||
-          (qc->flags & ATA_QCFLAG_RESULT_TF))
+          (qc->tf.flags & ATA_TFLAG_POLLING))
                return 1;
 
        if ((qc->flags & ATA_QCFLAG_DMAMAP) ||
@@ -1381,6 +1381,8 @@ static void nv_adma_qc_prep(struct ata_queued_cmd *qc)
                       NV_CPB_CTL_IEN;
 
        if (nv_adma_use_reg_mode(qc)) {
+               BUG_ON(!(pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE) &&
+                       (qc->flags & ATA_QCFLAG_DMAMAP));
                nv_adma_register_mode(qc->ap);
                ata_qc_prep(qc);
                return;
@@ -1425,9 +1427,21 @@ static unsigned int nv_adma_qc_issue(struct 
ata_queued_cmd *qc)
 
        VPRINTK("ENTER\n");
 
+       /* We can't handle result taskfile with NCQ commands, since
+          retrieving the taskfile switches us out of ADMA mode and would abort
+          existing commands. */
+       if (unlikely(qc->tf.protocol == ATA_PROT_NCQ &&
+                    (qc->flags & ATA_QCFLAG_RESULT_TF))) {
+               ata_dev_printk(qc->dev, KERN_ERR,
+                       "NCQ w/ RESULT_TF not allowed\n");
+               return AC_ERR_SYSTEM;
+       }
+
        if (nv_adma_use_reg_mode(qc)) {
                /* use ATA register mode */
                VPRINTK("using ATA register mode: 0x%lx\n", qc->flags);
+               BUG_ON(!(pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE) &&
+                       (qc->flags & ATA_QCFLAG_DMAMAP));
                nv_adma_register_mode(qc->ap);
                return ata_qc_issue_prot(qc);
        } else
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to