Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=f2fb344beadf79f9d265c3fc60e8399bbf917a4d
Commit:     f2fb344beadf79f9d265c3fc60e8399bbf917a4d
Parent:     4dc5200d70a3e81510956c35fbb9fa3c15b440a5
Author:     Robert Hancock <[EMAIL PROTECTED]>
AuthorDate: Mon Mar 26 21:43:36 2007 -0800
Committer:  Jeff Garzik <[EMAIL PROTECTED]>
CommitDate: Sat Apr 28 14:16:00 2007 -0400

    sata_nv: don't read shadow registers when in ADMA mode
    
    Reading from the ATA shadow registers while we are in ADMA mode may cause
    undefined behavior.  Don't read the ATA status register when completing
    commands for this reason, it shouldn't be needed as the controller will
    notify us if the command failed.  Also, don't allow commands with result
    taskfile requested to execute in ADMA mode, since that requires accessing
    the shadow registers.  We also still need to override tf_read since libata
    will read the result taskfile on a command failure, and we need to go into
    port register mode before allowing this.
    
    Signed-off-by: Robert Hancock <[EMAIL PROTECTED]>
    Signed-off-by: Andrew Morton <[EMAIL PROTECTED]>
    Signed-off-by: Jeff Garzik <[EMAIL PROTECTED]>
---
 drivers/ata/sata_nv.c |   33 ++++++++++++++++++++-------------
 1 files changed, 20 insertions(+), 13 deletions(-)

diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c
index 9d9670a..8a9473b 100644
--- a/drivers/ata/sata_nv.c
+++ b/drivers/ata/sata_nv.c
@@ -260,6 +260,7 @@ static int nv_adma_port_resume(struct ata_port *ap);
 static void nv_adma_error_handler(struct ata_port *ap);
 static void nv_adma_host_stop(struct ata_host *host);
 static void nv_adma_post_internal_cmd(struct ata_queued_cmd *qc);
+static void nv_adma_tf_read(struct ata_port *ap, struct ata_taskfile *tf);
 
 enum nv_host_type
 {
@@ -435,7 +436,7 @@ static const struct ata_port_operations nv_ck804_ops = {
 static const struct ata_port_operations nv_adma_ops = {
        .port_disable           = ata_port_disable,
        .tf_load                = ata_tf_load,
-       .tf_read                = ata_tf_read,
+       .tf_read                = nv_adma_tf_read,
        .check_atapi_dma        = nv_adma_check_atapi_dma,
        .exec_command           = ata_exec_command,
        .check_status           = ata_check_status,
@@ -667,6 +668,18 @@ static int nv_adma_check_atapi_dma(struct ata_queued_cmd 
*qc)
        return !(pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE);
 }
 
+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. */
+       nv_adma_register_mode(ap);
+
+       ata_tf_read(ap, tf);
+}
+
 static unsigned int nv_adma_tf_to_cpb(struct ata_taskfile *tf, __le16 *cpb)
 {
        unsigned int idx = 0;
@@ -738,19 +751,11 @@ static int nv_adma_check_cpb(struct ata_port *ap, int 
cpb_num, int force_err)
                return 1;
        }
 
-       if (flags & NV_CPB_RESP_DONE) {
+       if (likely(flags & NV_CPB_RESP_DONE)) {
                struct ata_queued_cmd *qc = ata_qc_from_tag(ap, cpb_num);
                VPRINTK("CPB flags done, flags=0x%x\n", flags);
                if (likely(qc)) {
-                       /* Grab the ATA port status for non-NCQ commands.
-                          For NCQ commands the current status may have nothing 
to do with
-                          the command just completed. */
-                       if (qc->tf.protocol != ATA_PROT_NCQ) {
-                               u8 ata_status = readb(pp->ctl_block + 
(ATA_REG_STATUS * 4));
-                               qc->err_mask |= ac_err_mask(ata_status);
-                       }
-                       DPRINTK("Completing qc from tag %d with err_mask 
%u\n",cpb_num,
-                               qc->err_mask);
+                       DPRINTK("Completing qc from tag %d\n",cpb_num);
                        ata_qc_complete(qc);
                } else {
                        struct ata_eh_info *ehi = &ap->eh_info;
@@ -1167,9 +1172,11 @@ 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. */
+          or interrupt-driven no-data commands, where a result taskfile
+          is not required. */
        if((pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE) ||
-          (qc->tf.flags & ATA_TFLAG_POLLING))
+          (qc->tf.flags & ATA_TFLAG_POLLING) ||
+          (qc->flags & ATA_QCFLAG_RESULT_TF))
                return 1;
 
        if((qc->flags & ATA_QCFLAG_DMAMAP) ||
-
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