07_libata_convert-ahci-to-new-eh.patch

        This patch converts ahci driver to use new NCQ helpers.

Signed-off-by: Tejun Heo <[EMAIL PROTECTED]>

 ahci.c |  363 ++++++++++-------------------------------------------------------
 1 files changed, 58 insertions(+), 305 deletions(-)

Index: work/drivers/scsi/ahci.c
===================================================================
--- work.orig/drivers/scsi/ahci.c       2005-07-07 22:08:34.000000000 +0900
+++ work/drivers/scsi/ahci.c    2005-07-07 22:08:36.000000000 +0900
@@ -171,7 +171,6 @@ struct ahci_port_priv {
        dma_addr_t              cmd_tbl_dma;
        void                    *rx_fis;
        dma_addr_t              rx_fis_dma;
-       u32                     sactive;
 };
 
 static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg);
@@ -181,7 +180,7 @@ static int ahci_qc_issue(struct ata_queu
 static irqreturn_t ahci_interrupt (int irq, void *dev_instance, struct pt_regs 
*regs);
 static void ahci_phy_reset(struct ata_port *ap);
 static void ahci_irq_clear(struct ata_port *ap);
-static void ahci_eng_timeout(struct ata_port *ap);
+static void ahci_error_handler(struct ata_port *ap);
 static int ahci_port_start(struct ata_port *ap);
 static void ahci_port_stop(struct ata_port *ap);
 static void ahci_host_stop(struct ata_host_set *host_set);
@@ -227,7 +226,7 @@ static struct ata_port_operations ahci_o
        .qc_prep                = ahci_qc_prep,
        .qc_issue               = ahci_qc_issue,
 
-       .eng_timeout            = ahci_eng_timeout,
+       .error_handler          = ahci_error_handler,
 
        .irq_handler            = ahci_interrupt,
        .irq_clear              = ahci_irq_clear,
@@ -427,6 +426,47 @@ static void ahci_scr_write (struct ata_p
        writel(val, (void *) ap->ioaddr.scr_addr + (sc_reg * 4));
 }
 
+static void ahci_stop_dma(struct ata_port *ap)
+{
+       void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr;
+       u32 tmp;
+       int work;
+
+       /* stop DMA */
+       tmp = readl(port_mmio + PORT_CMD);
+       tmp &= ~PORT_CMD_START;
+       writel(tmp, port_mmio + PORT_CMD);
+
+       /* wait for engine to stop. */
+       work = 500;
+       while (work-- > 0) {
+               tmp = readl(port_mmio + PORT_CMD);
+               if ((tmp & PORT_CMD_LIST_ON) == 0)
+                       break;
+               msleep(1);
+       }
+}
+
+static void ahci_start_dma(struct ata_port *ap)
+{
+       void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr;
+       u32 tmp;
+
+       /* clear SATA phy error, if any */
+       tmp = readl(port_mmio + PORT_SCR_ERR);
+       writel(tmp, port_mmio + PORT_SCR_ERR);
+
+       /* clear status */
+       tmp = readl(port_mmio + PORT_IRQ_STAT);
+       writel(tmp, port_mmio + PORT_IRQ_STAT);
+
+       /* re-start DMA */
+       tmp = readl(port_mmio + PORT_CMD);
+       tmp |= PORT_CMD_START;
+       writel(tmp, port_mmio + PORT_CMD);
+       readl(port_mmio + PORT_CMD); /* flush */
+}
+
 static void ahci_phy_reset(struct ata_port *ap)
 {
        void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr;
@@ -549,290 +589,22 @@ static void ahci_qc_prep(struct ata_queu
        ahci_fill_sg(qc, offset);
 }
 
-/*
- * Return 1 if COMRESET was done
- */
-static int ahci_intr_error(struct ata_port *ap, u32 irq_stat)
-{
-       void *mmio = ap->host_set->mmio_base;
-       void *port_mmio = ahci_port_base(mmio, ap->port_no);
-       u32 tmp;
-       int work, reset = 0;
-
-       /* stop DMA */
-       tmp = readl(port_mmio + PORT_CMD);
-       tmp &= ~PORT_CMD_START;
-       writel(tmp, port_mmio + PORT_CMD);
-
-       /* wait for engine to stop.  TODO: this could be
-        * as long as 500 msec
-        */
-       work = 1000;
-       while (work-- > 0) {
-               tmp = readl(port_mmio + PORT_CMD);
-               if ((tmp & PORT_CMD_LIST_ON) == 0)
-                       break;
-               udelay(10);
-       }
-
-       /* clear SATA phy error, if any */
-       tmp = readl(port_mmio + PORT_SCR_ERR);
-       writel(tmp, port_mmio + PORT_SCR_ERR);
-
-       /* clear status */
-       tmp = readl(port_mmio + PORT_IRQ_STAT);
-       writel(tmp, port_mmio + PORT_IRQ_STAT);
-
-       /* if DRQ/BSY is set, device needs to be reset.
-        * if so, issue COMRESET
-        */
-       tmp = readl(port_mmio + PORT_TFDATA);
-       if (tmp & (ATA_BUSY | ATA_DRQ)) {
-               printk(KERN_WARNING "ata%u: stat=%x, issuing COMRESET\n", 
ap->id, tmp);
-               writel(0x301, port_mmio + PORT_SCR_CTL);
-               readl(port_mmio + PORT_SCR_CTL); /* flush */
-               udelay(10);
-               writel(0x300, port_mmio + PORT_SCR_CTL);
-               readl(port_mmio + PORT_SCR_CTL); /* flush */
-               reset = 1;
-       }
-
-       /* re-start DMA */
-       tmp = readl(port_mmio + PORT_CMD);
-       tmp |= PORT_CMD_START;
-       writel(tmp, port_mmio + PORT_CMD);
-       readl(port_mmio + PORT_CMD); /* flush */
-
-       printk(KERN_WARNING "ata%u: error occurred, port reset\n", ap->id);
-       return reset;
-}
-
-static void ahci_complete_requests(struct ata_port *ap, u32 tag_mask, int err)
-{
-       while (tag_mask) {
-               struct ata_queued_cmd *qc;
-               int tag = ffs(tag_mask) - 1;
-
-               tag_mask &= ~(1 << tag);
-               qc = ata_qc_from_tag(ap, tag);
-               if (qc)
-                       ata_qc_complete(qc, err);
-               else
-                       printk(KERN_ERR "ahci: missing tag %d\n", tag);
-       }
-}
-
-static void dump_log_page(unsigned char *p)
-{
-       int i;
-
-       printk("LOG 0x10: nq=%d, tag=%d\n", p[0] >> 7, p[0] & 0x1f);
-
-       for (i = 2; i < 14; i++)
-               printk("%d:%d ", i, p[i]);
-
-       printk("\n");
-}
-
-/*
- * TODO: needs to use READ_LOG_EXT/page=10h to retrieve error information
- */
-extern void ata_qc_free(struct ata_queued_cmd *qc);
-static void ahci_ncq_timeout(struct ata_port *ap)
+static void ahci_error_handler(struct ata_port *ap)
 {
-       struct ahci_port_priv *pp = ap->private_data;
-       void *mmio = ap->host_set->mmio_base;
-       void *port_mmio = ahci_port_base(mmio, ap->port_no);
-       struct ata_queued_cmd *qc;
-       unsigned long flags;
-       char *buffer;
-       u32 sactive;
-       int reset;
-
-       printk(KERN_WARNING "ata%u: ncq interrupt error (Q=%d)\n", ap->id, 
ap->queue_depth);
-
-       spin_lock_irqsave(&ap->host_set->lock, flags);
-
-       sactive = readl(port_mmio + PORT_SCR_ACT);
-
-       printk(KERN_WARNING "ata%u: SActive 0x%x (0x%x)\n", ap->id, sactive, 
pp->sactive);
-       reset = ahci_intr_error(ap, readl(port_mmio + PORT_IRQ_STAT));
-
-       spin_unlock_irqrestore(&ap->host_set->lock, flags);
-
-       /*
-        * if COMRESET was done, we don't have to issue a log page read
-        */
-       if (reset)
-               goto done;
-
-       buffer = kmalloc(512, GFP_KERNEL);
-       if (!buffer) {
-               printk(KERN_ERR "ata%u: unable to allocate memory for error\n", 
ap->id);
-               goto done;
-       }
-
-       if (ata_read_log_page(ap, 0, READ_LOG_SATA_NCQ_PAGE, buffer, 1)) {
-               printk(KERN_ERR "ata%u: unable to read log page\n", ap->id);
-               goto out;
-       }
-
-       dump_log_page(buffer);
-
-       /*
-        * if NQ is cleared, bottom 5 bits contain the tag of the errored
-        * command
-        */
-       if ((buffer[0] & (1 << 7)) == 0) {
-               int tag = buffer[0] & 0x1f;
-
-               qc = ata_qc_from_tag(ap, tag);
-               if (qc)
-                       ata_qc_complete(qc, ATA_ERR);
-       }
-
        /*
-        * requeue the remaining commands
+        * Bring controller to known state.  libata layer will take
+        * care of the drive.
         */
-       while (pp->sactive) {
-               int tag = ffs(pp->sactive) - 1;
-
-               pp->sactive &= ~(1 << tag);
-               qc = ata_qc_from_tag(ap, tag);
-               if (qc) {
-                       if (qc->scsicmd)
-                               ata_qc_free(qc);
-                       else
-                               ata_qc_complete(qc, ATA_ERR);
-               } else
-                       printk(KERN_ERR "ata%u: missing tag %d\n", ap->id, tag);
-       }
-
-out:
-       kfree(buffer);
-done:
-       ata_scsi_unblock_requests(ap);
-}
-
-static void ahci_nonncq_timeout(struct ata_port *ap)
-{
-       void *mmio = ap->host_set->mmio_base;
-       void *port_mmio = ahci_port_base(mmio, ap->port_no);
-       struct ata_queued_cmd *qc;
-
-       DPRINTK("ENTER\n");
-
-       ahci_intr_error(ap, readl(port_mmio + PORT_IRQ_STAT));
-
-       qc = ata_qc_from_tag(ap, ap->active_tag);
-       if (!qc) {
-               printk(KERN_ERR "ata%u: BUG: timeout without command\n",
-                      ap->id);
-       } else {
-               /* hack alert!  We cannot use the supplied completion
-                * function from inside the ->eh_strategy_handler() thread.
-                * libata is the only user of ->eh_strategy_handler() in
-                * any kernel, so the default scsi_done() assumes it is
-                * not being called from the SCSI EH.
-                */
-               qc->scsidone = scsi_finish_command;
-               ata_qc_complete(qc, ATA_ERR);
-       }
-}
-
-static void ahci_eng_timeout(struct ata_port *ap)
-{
-       struct ahci_port_priv *pp = ap->private_data;
-
-       if (pp->sactive)
-               ahci_ncq_timeout(ap);
-       else
-               ahci_nonncq_timeout(ap);
-}
-
-static int ahci_ncq_intr(struct ata_port *ap, u32 status)
-{
-       struct ahci_port_priv *pp = ap->private_data;
-       void *mmio = ap->host_set->mmio_base;
-       void *port_mmio = ahci_port_base(mmio, ap->port_no);
-
-       if (!pp->sactive)
-               return 0;
-
-       if (status & PORT_IRQ_SDB_FIS) {
-               u8 *sdb = pp->rx_fis + RX_FIS_SDB_REG;
-               u32 sactive, mask;
-
-               if (unlikely(sdb[2] & ATA_ERR)) {
-                       printk("SDB fis, stat %x, err %x\n", sdb[2], sdb[3]);
-                       return 1;
-               }
-
-               /*
-                * SActive will have the bits cleared for completed commands
-                */
-               sactive = readl(port_mmio + PORT_SCR_ACT);
-               mask = pp->sactive & ~sactive;
-               if (mask) {
-                       ahci_complete_requests(ap, mask, 0);
-                       pp->sactive = sactive;
-                       return 1;
-               } else
-                       printk(KERN_INFO "ata%u: SDB with no bits cleared\n", 
ap->id);
-       } else if (status & PORT_IRQ_D2H_REG_FIS) {
-               u8 *d2h = pp->rx_fis + RX_FIS_D2H_REG;
-
-               /*
-                * pre-BSY clear error, let timeout error handling take care
-                * of it when it kicks in
-                */
-               if (d2h[2] & ATA_ERR) {
-                       VPRINTK("D2H fis, err %x\n", d2h[2]);
-                       return 1;
-               }
-
-               printk("D2H fis\n");
-       } else
-               printk(KERN_WARNING "ata%u: unhandled FIS, stat %x\n", ap->id, 
status);
-
-       return 0;
-}
-
-static void ahci_ncq_intr_error(struct ata_port *ap, u32 status)
-{
-       struct ahci_port_priv *pp = ap->private_data;
-       struct ata_queued_cmd *qc;
-       struct ata_taskfile tf;
-       int tag;
-
-       printk(KERN_ERR "ata%u: NCQ err status 0x%x\n", ap->id, status);
+       ahci_stop_dma(ap);
+       ahci_start_dma(ap);
 
-       if (status & PORT_IRQ_D2H_REG_FIS) {
-               ahci_tf_read(ap, &tf);
-               tag = tf.nsect >> 3;
-
-               qc = ata_qc_from_tag(ap, tag);
-               if (qc) {
-                       printk(KERN_ERR "ata%u: ending bad tag %d\n", ap->id, 
tag);
-                       pp->sactive &= ~(1 << tag);
-                       ata_qc_complete(qc, ATA_ERR);
-               } else
-                       printk(KERN_ERR "ata%u: error on tag %d, but not 
present\n", ap->id, tag);
-       }
-
-       /*
-        * let command timeout deal with error handling
-        */
-       ata_scsi_block_requests(ap);
+       ata_ncq_recover(ap, 0);
 }
 
 static inline int ahci_host_intr(struct ata_port *ap)
 {
-       struct ahci_port_priv *pp = ap->private_data;
-       void *mmio = ap->host_set->mmio_base;
-       void *port_mmio = ahci_port_base(mmio, ap->port_no);
-       struct ata_queued_cmd *qc;
-       u32 status, serr, ci;
+       void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr;
+       u32 status, serr;
 
        serr = readl(port_mmio + PORT_SCR_ERR);
        writel(serr, port_mmio + PORT_SCR_ERR);
@@ -840,29 +612,13 @@ static inline int ahci_host_intr(struct 
        status = readl(port_mmio + PORT_IRQ_STAT);
        writel(status, port_mmio + PORT_IRQ_STAT);
 
-       if (status & PORT_IRQ_FATAL) {
-               printk("ata%u: irq error %x %x, tag %d\n", ap->id, serr, 
status, ap->active_tag);
-               if (pp->sactive)
-                       ahci_ncq_intr_error(ap, status);
-               else
-                       ahci_intr_error(ap, status);
-
-               return 1;
-       }
-
-       if (ahci_ncq_intr(ap, status))
-               return 1;
-
-       ci = readl(port_mmio + PORT_CMD_ISSUE);
-
-       if ((ci & (1 << ap->active_tag)) == 0) {
-               VPRINTK("NON-NCQ interrupt\n");
-
-               qc = ata_qc_from_tag(ap, ap->active_tag);
-               if (qc && (qc->flags & ATA_QCFLAG_ACTIVE) &&
-                   !(qc->flags & ATA_QCFLAG_NCQ))
-                       ata_qc_complete(qc, 0);
-       }
+       if (!(status & PORT_IRQ_FATAL)) {
+               void *cmd_issue = port_mmio + PORT_CMD_ISSUE;
+               if (ap->sactive ||
+                   (readl(cmd_issue) & (1 << ap->active_tag)) == 0)
+                       ata_ncq_complete(ap);
+       } else
+               ata_ncq_error(ap);
 
        return 1;
 }
@@ -919,12 +675,9 @@ static irqreturn_t ahci_interrupt (int i
 static int ahci_qc_issue(struct ata_queued_cmd *qc)
 {
        struct ata_port *ap = qc->ap;
-       struct ahci_port_priv *pp = ap->private_data;
        void *port_mmio = (void *) ap->ioaddr.cmd_addr;
 
        if (qc->flags & ATA_QCFLAG_NCQ) {
-               pp->sactive |= (1 << qc->tag);
-
                writel(1 << qc->tag, port_mmio + PORT_SCR_ACT);
                readl(port_mmio + PORT_SCR_ACT);
        }

-
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