libata: convert to chained sg
[pandora-kernel.git] / drivers / ata / sata_nv.c
index 35b2df2..a0f98fd 100644 (file)
@@ -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);
@@ -1334,21 +1336,18 @@ static void nv_adma_fill_aprd(struct ata_queued_cmd *qc,
 static void nv_adma_fill_sg(struct ata_queued_cmd *qc, struct nv_adma_cpb *cpb)
 {
        struct nv_adma_port_priv *pp = qc->ap->private_data;
-       unsigned int idx;
        struct nv_adma_prd *aprd;
        struct scatterlist *sg;
+       unsigned int si;
 
        VPRINTK("ENTER\n");
 
-       idx = 0;
-
-       ata_for_each_sg(sg, qc) {
-               aprd = (idx < 5) ? &cpb->aprd[idx] :
-                              &pp->aprd[NV_ADMA_SGTBL_LEN * qc->tag + (idx-5)];
-               nv_adma_fill_aprd(qc, sg, idx, aprd);
-               idx++;
+       for_each_sg(qc->sg, sg, qc->n_elem, si) {
+               aprd = (si < 5) ? &cpb->aprd[si] :
+                              &pp->aprd[NV_ADMA_SGTBL_LEN * qc->tag + (si-5)];
+               nv_adma_fill_aprd(qc, sg, si, aprd);
        }
-       if (idx > 5)
+       if (si > 5)
                cpb->next_aprd = cpu_to_le64(((u64)(pp->aprd_dma + NV_ADMA_SGTBL_SZ * qc->tag)));
        else
                cpb->next_aprd = cpu_to_le64(0);
@@ -1359,11 +1358,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 +1378,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 +1424,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
@@ -1629,7 +1640,7 @@ static int nv_hardreset(struct ata_link *link, unsigned int *class,
 
        /* SATA hardreset fails to retrieve proper device signature on
         * some controllers.  Don't classify on hardreset.  For more
-        * info, see http://bugme.osdl.org/show_bug.cgi?id=3352
+        * info, see http://bugzilla.kernel.org/show_bug.cgi?id=3352
         */
        return sata_std_hardreset(link, &dummy, deadline);
 }
@@ -1981,17 +1992,14 @@ static void nv_swncq_fill_sg(struct ata_queued_cmd *qc)
 {
        struct ata_port *ap = qc->ap;
        struct scatterlist *sg;
-       unsigned int idx;
        struct nv_swncq_port_priv *pp = ap->private_data;
        struct ata_prd *prd;
-
-       WARN_ON(qc->__sg == NULL);
-       WARN_ON(qc->n_elem == 0 && qc->pad_len == 0);
+       unsigned int si, idx;
 
        prd = pp->prd + ATA_MAX_PRD * qc->tag;
 
        idx = 0;
-       ata_for_each_sg(sg, qc) {
+       for_each_sg(qc->sg, sg, qc->n_elem, si) {
                u32 addr, offset;
                u32 sg_len, len;
 
@@ -2013,8 +2021,7 @@ static void nv_swncq_fill_sg(struct ata_queued_cmd *qc)
                }
        }
 
-       if (idx)
-               prd[idx - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT);
+       prd[idx - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT);
 }
 
 static unsigned int nv_swncq_issue_atacmd(struct ata_port *ap,