This patch adds NCQ support to the sata_mv driver.  Currently it does
not work:  FPDMA commands time out, and eventually EH falls back to
non-NCQ, which works.

My attention has turned to other things for moment.  Anybody interested
in sata_mv NCQ is encouraged to pick up where this left off, as this
patch, buggy or not, includes the changes that will be required to
enable command queueing in sata_mv.


commit 6bef64243c68bf637b5594a0a363d8105efedfa6
Author: Jeff Garzik <[EMAIL PROTECTED]>
Date:   Wed Jul 11 18:56:46 2007 -0400

    [libata mv-ncq] sata_mv: Add NCQ support
    
    Currently not working.
    
    Signed-off-by: Jeff Garzik <[EMAIL PROTECTED]>

 drivers/ata/sata_mv.c |   70 +++++++++++++++++++++++++++++++++++---------------
 1 file changed, 49 insertions(+), 21 deletions(-)

diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c
index 8ec5208..228f71a 100644
--- a/drivers/ata/sata_mv.c
+++ b/drivers/ata/sata_mv.c
@@ -29,8 +29,6 @@
   I distinctly remember a couple workarounds (one related to PCI-X)
   are still needed.
 
-  4) Add NCQ support (easy to intermediate, once new-EH support appears)
-
   5) Investigate problems with PCI Message Signalled Interrupts (MSI).
 
   6) Add port multiplier support (intermediate)
@@ -417,6 +415,7 @@ static void mv_error_handler(struct ata_port *ap);
 static void mv_post_int_cmd(struct ata_queued_cmd *qc);
 static void mv_eh_freeze(struct ata_port *ap);
 static void mv_eh_thaw(struct ata_port *ap);
+static void mv6_dev_config(struct ata_device *dev);
 static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
 
 static void mv5_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,
@@ -440,6 +439,8 @@ static void mv6_reset_flash(struct mv_host_priv *hpriv, 
void __iomem *mmio);
 static void mv_reset_pci_bus(struct pci_dev *pdev, void __iomem *mmio);
 static void mv_channel_reset(struct mv_host_priv *hpriv, void __iomem *mmio,
                             unsigned int port_no);
+static void mv_edma_cfg(struct ata_port *ap, struct mv_host_priv *hpriv,
+                       void __iomem *port_mmio);
 
 static struct scsi_host_template mv5_sht = {
        .module                 = THIS_MODULE,
@@ -464,7 +465,8 @@ static struct scsi_host_template mv6_sht = {
        .name                   = DRV_NAME,
        .ioctl                  = ata_scsi_ioctl,
        .queuecommand           = ata_scsi_queuecmd,
-       .can_queue              = ATA_DEF_QUEUE,
+       .change_queue_depth     = ata_scsi_change_queue_depth,
+       .can_queue              = MV_MAX_Q_DEPTH - 1,
        .this_id                = ATA_SHT_THIS_ID,
        .sg_tablesize           = MV_MAX_SG_CT,
        .cmd_per_lun            = ATA_SHT_CMD_PER_LUN,
@@ -510,6 +512,7 @@ static const struct ata_port_operations mv5_ops = {
 
 static const struct ata_port_operations mv6_ops = {
        .port_disable           = ata_port_disable,
+       .dev_config             = mv6_dev_config,
 
        .tf_load                = ata_tf_load,
        .tf_read                = ata_tf_read,
@@ -590,26 +593,29 @@ static const struct ata_port_info mv_port_info[] = {
                .port_ops       = &mv5_ops,
        },
        {  /* chip_604x */
-               .flags          = MV_COMMON_FLAGS | MV_6XXX_FLAGS,
+               .flags          = MV_COMMON_FLAGS | MV_6XXX_FLAGS |
+                                 ATA_FLAG_NCQ,
                .pio_mask       = 0x1f, /* pio0-4 */
                .udma_mask      = ATA_UDMA6,
                .port_ops       = &mv6_ops,
        },
        {  /* chip_608x */
                .flags          = MV_COMMON_FLAGS | MV_6XXX_FLAGS |
-                                 MV_FLAG_DUAL_HC,
+                                 MV_FLAG_DUAL_HC | ATA_FLAG_NCQ,
                .pio_mask       = 0x1f, /* pio0-4 */
                .udma_mask      = ATA_UDMA6,
                .port_ops       = &mv6_ops,
        },
        {  /* chip_6042 */
-               .flags          = MV_COMMON_FLAGS | MV_6XXX_FLAGS,
+               .flags          = MV_COMMON_FLAGS | MV_6XXX_FLAGS |
+                                 ATA_FLAG_NCQ,
                .pio_mask       = 0x1f, /* pio0-4 */
                .udma_mask      = ATA_UDMA6,
                .port_ops       = &mv_iie_ops,
        },
        {  /* chip_7042 */
-               .flags          = MV_COMMON_FLAGS | MV_6XXX_FLAGS,
+               .flags          = MV_COMMON_FLAGS | MV_6XXX_FLAGS |
+                                 ATA_FLAG_NCQ,
                .pio_mask       = 0x1f, /* pio0-4 */
                .udma_mask      = ATA_UDMA6,
                .port_ops       = &mv_iie_ops,
@@ -808,18 +814,23 @@ static void mv_set_edma_ptrs(void __iomem *port_mmio,
  *      LOCKING:
  *      Inherited from caller.
  */
-static void mv_start_dma(void __iomem *base, struct mv_host_priv *hpriv,
+static void mv_start_dma(struct ata_port *ap, void __iomem *base,
                         struct mv_port_priv *pp)
 {
        if (!(pp->pp_flags & MV_PP_FLAG_EDMA_EN)) {
+               struct mv_host_priv *hpriv = ap->host->private_data;
+
                /* clear EDMA event indicators, if any */
                writelfl(0, base + EDMA_ERR_IRQ_CAUSE_OFS);
 
+               mv_edma_cfg(ap, hpriv, base);
+
                mv_set_edma_ptrs(base, hpriv, pp);
 
                writelfl(EDMA_EN, base + EDMA_CMD_OFS);
                pp->pp_flags |= MV_PP_FLAG_EDMA_EN;
        }
+
        WARN_ON(!(EDMA_EN & readl(base + EDMA_CMD_OFS)));
 }
 
@@ -996,9 +1007,20 @@ static int mv_scr_write(struct ata_port *ap, unsigned int 
sc_reg_in, u32 val)
                return -EINVAL;
 }
 
+static void mv6_dev_config(struct ata_device *adev)
+{
+       /*
+        * We don't have hob_nsect when doing NCQ commands, on Gen-II.
+        * See mv_qc_prep() for more info.
+        */
+       if (adev->flags & ATA_DFLAG_NCQ)
+               adev->max_sectors = ATA_MAX_SECTORS;
+}
+
 static void mv_edma_cfg(struct ata_port *ap, struct mv_host_priv *hpriv,
                        void __iomem *port_mmio)
 {
+       struct ata_device *adev = &ap->device[0];       /* hardcode dev 0 */
        u32 cfg = readl(port_mmio + EDMA_CFG_OFS);
 
        /* set up non-NCQ EDMA configuration */
@@ -1013,6 +1035,14 @@ static void mv_edma_cfg(struct ata_port *ap, struct 
mv_host_priv *hpriv,
                cfg &= ~0x1f;           /* clear queue depth */
                cfg |= EDMA_CFG_RD_BRST_EXT | EDMA_CFG_WR_BUFF_LEN;
                cfg &= ~(EDMA_CFG_NCQ | EDMA_CFG_NCQ_GO_ON_ERR); /* clear NCQ */
+
+               if (adev->flags & ATA_DFLAG_NCQ) {
+                       unsigned int dev_depth =
+                               ata_id_queue_depth(adev->id) - 1;
+
+                       cfg |= EDMA_CFG_NCQ;
+                       cfg |= (dev_depth & 0x1f);
+               }
        }
 
        else if (IS_GEN_IIE(hpriv)) {
@@ -1023,6 +1053,9 @@ static void mv_edma_cfg(struct ata_port *ap, struct 
mv_host_priv *hpriv,
                cfg |= (1 << 17);       /* enab cut-through (dis stor&forwrd) */
                cfg &= ~(1 << 16);      /* dis FIS-based switching (for now) */
                cfg &= ~(EDMA_CFG_NCQ); /* clear NCQ */
+
+               if (adev->flags & ATA_DFLAG_NCQ)
+                       cfg |= EDMA_CFG_NCQ;
        }
 
        writelfl(cfg, port_mmio + EDMA_CFG_OFS);
@@ -1178,7 +1211,8 @@ static void mv_qc_prep(struct ata_queued_cmd *qc)
        u16 flags = 0;
        unsigned in_index;
 
-       if (qc->tf.protocol != ATA_PROT_DMA)
+       if ((qc->tf.protocol != ATA_PROT_DMA) &&
+           (qc->tf.protocol != ATA_PROT_NCQ))
                return;
 
        /* Fill in command request block
@@ -1215,13 +1249,11 @@ static void mv_qc_prep(struct ata_queued_cmd *qc)
        case ATA_CMD_WRITE_FUA_EXT:
                mv_crqb_pack_cmd(cw++, tf->hob_nsect, ATA_REG_NSECT, 0);
                break;
-#ifdef LIBATA_NCQ              /* FIXME: remove this line when NCQ added */
        case ATA_CMD_FPDMA_READ:
        case ATA_CMD_FPDMA_WRITE:
                mv_crqb_pack_cmd(cw++, tf->hob_feature, ATA_REG_FEATURE, 0);
                mv_crqb_pack_cmd(cw++, tf->feature, ATA_REG_FEATURE, 0);
                break;
-#endif                         /* FIXME: remove this line when NCQ added */
        default:
                /* The only other commands EDMA supports in non-queued and
                 * non-NCQ mode are: [RW] STREAM DMA and W DMA FUA EXT, none
@@ -1270,7 +1302,8 @@ static void mv_qc_prep_iie(struct ata_queued_cmd *qc)
        unsigned in_index;
        u32 flags = 0;
 
-       if (qc->tf.protocol != ATA_PROT_DMA)
+       if ((qc->tf.protocol != ATA_PROT_DMA) &&
+           (qc->tf.protocol != ATA_PROT_NCQ))
                return;
 
        /* Fill in Gen IIE command request block
@@ -1282,6 +1315,7 @@ static void mv_qc_prep_iie(struct ata_queued_cmd *qc)
        flags |= qc->tag << CRQB_TAG_SHIFT;
        flags |= qc->tag << CRQB_IOID_SHIFT;    /* "I/O Id" is -really-
                                                   what we use as our tag */
+       flags |= qc->tag << CRQB_HOSTQ_SHIFT;
 
        /* get current queue index from software */
        in_index = pp->req_idx & MV_MAX_Q_DEPTH_MASK;
@@ -1335,10 +1369,10 @@ static unsigned int mv_qc_issue(struct ata_queued_cmd 
*qc)
        struct ata_port *ap = qc->ap;
        void __iomem *port_mmio = mv_ap_base(ap);
        struct mv_port_priv *pp = ap->private_data;
-       struct mv_host_priv *hpriv = ap->host->private_data;
        u32 in_index;
 
-       if (qc->tf.protocol != ATA_PROT_DMA) {
+       if ((qc->tf.protocol != ATA_PROT_DMA) &&
+           (qc->tf.protocol != ATA_PROT_NCQ)) {
                /* We're about to send a non-EDMA capable command to the
                 * port.  Turn off EDMA so there won't be problems accessing
                 * shadow block, etc registers.
@@ -1347,13 +1381,7 @@ static unsigned int mv_qc_issue(struct ata_queued_cmd 
*qc)
                return ata_qc_issue_prot(qc);
        }
 
-       mv_start_dma(port_mmio, hpriv, pp);
-
-       in_index = pp->req_idx & MV_MAX_Q_DEPTH_MASK;
-
-       /* until we do queuing, the queue should be empty at this point */
-       WARN_ON(in_index != ((readl(port_mmio + EDMA_REQ_Q_OUT_PTR_OFS)
-               >> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK));
+       mv_start_dma(ap, port_mmio, pp);
 
        pp->req_idx++;
 
-
To unsubscribe from this list: send the line "unsubscribe linux-ide" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to