[PATCH] The redefinition of ahci_start_engine() and ahci_stop_engine()
authorzhao, forrest <forrest.zhao@intel.com>
Thu, 13 Jul 2006 05:38:32 +0000 (13:38 +0800)
committerJeff Garzik <jeff@garzik.org>
Wed, 19 Jul 2006 20:45:42 +0000 (16:45 -0400)
- Make ahci_start_engine() and ahci_stop_engine() more consistent with
  AHCI spec 1.1
- Change their input parameter from ap to port_mmio
- Update the existing users of ahci_start_engine() and ahci_stop_engine()

Signed-off-by: Forrest Zhao <forrest.zhao@intel.com>
Signed-off-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: Jens Axboe <axboe@suse.de>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
drivers/scsi/ahci.c

index 77e7202..f1516ca 100644 (file)
@@ -205,6 +205,8 @@ static irqreturn_t ahci_interrupt (int irq, void *dev_instance, struct pt_regs *
 static void ahci_irq_clear(struct ata_port *ap);
 static int ahci_port_start(struct ata_port *ap);
 static void ahci_port_stop(struct ata_port *ap);
+static int ahci_start_engine(void __iomem *port_mmio);
+static int ahci_stop_engine(void __iomem *port_mmio);
 static void ahci_tf_read(struct ata_port *ap, struct ata_taskfile *tf);
 static void ahci_qc_prep(struct ata_queued_cmd *qc);
 static u8 ahci_check_status(struct ata_port *ap);
@@ -508,41 +510,64 @@ static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg_in,
        writel(val, (void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4));
 }
 
-static int ahci_stop_engine(struct ata_port *ap)
+static int ahci_stop_engine(void __iomem *port_mmio)
 {
-       void __iomem *mmio = ap->host_set->mmio_base;
-       void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
-       int work;
        u32 tmp;
 
        tmp = readl(port_mmio + PORT_CMD);
+
+       /* Check if the HBA is idle */
+       if ((tmp & (PORT_CMD_START | PORT_CMD_LIST_ON)) == 0)
+               return 0;
+
+       /* Setting HBA to idle */
        tmp &= ~PORT_CMD_START;
        writel(tmp, port_mmio + PORT_CMD);
 
-       /* wait for engine to stop.  TODO: this could be
+       /* wait for engine to stop. 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)
-                       return 0;
-               udelay(10);
-       }
+       tmp = ata_wait_register(port_mmio + PORT_CMD,
+                               PORT_CMD_LIST_ON, PORT_CMD_LIST_ON, 1, 500);
+       if(tmp & PORT_CMD_LIST_ON)
+               return -EIO;
 
-       return -EIO;
+       return 0;
 }
 
-static void ahci_start_engine(struct ata_port *ap)
+static int ahci_start_engine(void __iomem *port_mmio)
 {
-       void __iomem *mmio = ap->host_set->mmio_base;
-       void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
        u32 tmp;
 
+       /*
+        * Get current status
+        */
        tmp = readl(port_mmio + PORT_CMD);
+
+       /*
+        * AHCI rev 1.1 section 10.3.1:
+        * Software shall not set PxCMD.ST to '1' until it verifies
+        * that PxCMD.CR is '0' and has set PxCMD.FRE to '1'
+        */
+       if ((tmp & PORT_CMD_FIS_RX) == 0)
+               return -EPERM;
+
+       /*
+        * wait for engine to become idle.
+        */
+       tmp = ata_wait_register(port_mmio + PORT_CMD,
+                               PORT_CMD_LIST_ON, PORT_CMD_LIST_ON, 1,500);
+       if(tmp & PORT_CMD_LIST_ON)
+               return -EBUSY;
+
+       /*
+        * Start DMA
+        */
        tmp |= PORT_CMD_START;
        writel(tmp, port_mmio + PORT_CMD);
        readl(port_mmio + PORT_CMD); /* flush */
+
+       return 0;
 }
 
 static unsigned int ahci_dev_classify(struct ata_port *ap)
@@ -626,7 +651,7 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class)
        }
 
        /* prepare for SRST (AHCI-1.1 10.4.1) */
-       rc = ahci_stop_engine(ap);
+       rc = ahci_stop_engine(port_mmio);
        if (rc) {
                reason = "failed to stop engine";
                goto fail_restart;
@@ -647,7 +672,7 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class)
        }
 
        /* restart engine */
-       ahci_start_engine(ap);
+       ahci_start_engine(port_mmio);
 
        ata_tf_init(ap->device, &tf);
        fis = pp->cmd_tbl;
@@ -706,7 +731,7 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class)
        return 0;
 
  fail_restart:
-       ahci_start_engine(ap);
+       ahci_start_engine(port_mmio);
  fail:
        ata_port_printk(ap, KERN_ERR, "softreset failed (%s)\n", reason);
        return rc;
@@ -717,11 +742,13 @@ static int ahci_hardreset(struct ata_port *ap, unsigned int *class)
        struct ahci_port_priv *pp = ap->private_data;
        u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
        struct ata_taskfile tf;
+       void __iomem *mmio = ap->host_set->mmio_base;
+       void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
        int rc;
 
        DPRINTK("ENTER\n");
 
-       ahci_stop_engine(ap);
+       ahci_stop_engine(port_mmio);
 
        /* clear D2H reception area to properly wait for D2H FIS */
        ata_tf_init(ap->device, &tf);
@@ -730,7 +757,7 @@ static int ahci_hardreset(struct ata_port *ap, unsigned int *class)
 
        rc = sata_std_hardreset(ap, class);
 
-       ahci_start_engine(ap);
+       ahci_start_engine(port_mmio);
 
        if (rc == 0 && ata_port_online(ap))
                *class = ahci_dev_classify(ap);
@@ -1052,10 +1079,13 @@ static void ahci_thaw(struct ata_port *ap)
 
 static void ahci_error_handler(struct ata_port *ap)
 {
+       void __iomem *mmio = ap->host_set->mmio_base;
+       void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
+
        if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
                /* restart engine */
-               ahci_stop_engine(ap);
-               ahci_start_engine(ap);
+               ahci_stop_engine(port_mmio);
+               ahci_start_engine(port_mmio);
        }
 
        /* perform recovery */
@@ -1066,14 +1096,16 @@ static void ahci_error_handler(struct ata_port *ap)
 static void ahci_post_internal_cmd(struct ata_queued_cmd *qc)
 {
        struct ata_port *ap = qc->ap;
+       void __iomem *mmio = ap->host_set->mmio_base;
+       void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
 
        if (qc->flags & ATA_QCFLAG_FAILED)
                qc->err_mask |= AC_ERR_OTHER;
 
        if (qc->err_mask) {
                /* make DMA engine forget about the failed command */
-               ahci_stop_engine(ap);
-               ahci_start_engine(ap);
+               ahci_stop_engine(port_mmio);
+               ahci_start_engine(port_mmio);
        }
 }