libata: separate out ata_wait_ready() and implement ata_wait_after_reset()
authorTejun Heo <htejun@gmail.com>
Mon, 7 Apr 2008 13:47:19 +0000 (22:47 +0900)
committerJeff Garzik <jgarzik@redhat.com>
Thu, 17 Apr 2008 19:44:22 +0000 (15:44 -0400)
Factor out waiting logic (which is common to all ATA controllers) from
ata_sff_wait_ready() into ata_wait_ready().  ata_wait_ready() takes
@check_ready function pointer and uses it to poll for readiness.  This
allows non-SFF controllers to use ata_wait_ready() to wait for link
readiness.

This patch also implements ata_wait_after_reset() - generic version of
ata_sff_wait_after_reset() - using ata_wait_ready().

ata_sff_wait_ready() is reimplemented using ata_wait_ready() and
ata_sff_check_ready().  Functionality remains the same.

Signed-off-by: Tejun Heo <htejun@gmail.com>
drivers/ata/libata-core.c
drivers/ata/libata-sff.c
drivers/ata/libata.h
include/linux/libata.h

index eaead76..3bad6f1 100644 (file)
@@ -3310,6 +3310,103 @@ int ata_do_set_mode(struct ata_link *link, struct ata_device **r_failed_dev)
        return rc;
 }
 
+/**
+ *     ata_wait_ready - wait for link to become ready
+ *     @link: link to be waited on
+ *     @deadline: deadline jiffies for the operation
+ *     @check_ready: callback to check link readiness
+ *
+ *     Wait for @link to become ready.  @check_ready should return
+ *     positive number if @link is ready, 0 if it isn't, -ENODEV if
+ *     link doesn't seem to be occupied, other errno for other error
+ *     conditions.
+ *
+ *     Transient -ENODEV conditions are allowed for
+ *     ATA_TMOUT_FF_WAIT.
+ *
+ *     LOCKING:
+ *     EH context.
+ *
+ *     RETURNS:
+ *     0 if @linke is ready before @deadline; otherwise, -errno.
+ */
+int ata_wait_ready(struct ata_link *link, unsigned long deadline,
+                  int (*check_ready)(struct ata_link *link))
+{
+       unsigned long start = jiffies;
+       unsigned long nodev_deadline = start + ATA_TMOUT_FF_WAIT;
+       int warned = 0;
+
+       if (time_after(nodev_deadline, deadline))
+               nodev_deadline = deadline;
+
+       while (1) {
+               unsigned long now = jiffies;
+               int ready, tmp;
+
+               ready = tmp = check_ready(link);
+               if (ready > 0)
+                       return 0;
+
+               /* -ENODEV could be transient.  Ignore -ENODEV if link
+                * is online.  Also, some SATA devices take a long
+                * time to clear 0xff after reset.  For example,
+                * HHD424020F7SV00 iVDR needs >= 800ms while Quantum
+                * GoVault needs even more than that.  Wait for
+                * ATA_TMOUT_FF_WAIT on -ENODEV if link isn't offline.
+                *
+                * Note that some PATA controllers (pata_ali) explode
+                * if status register is read more than once when
+                * there's no device attached.
+                */
+               if (ready == -ENODEV) {
+                       if (ata_link_online(link))
+                               ready = 0;
+                       else if ((link->ap->flags & ATA_FLAG_SATA) &&
+                                !ata_link_offline(link) &&
+                                time_before(now, nodev_deadline))
+                               ready = 0;
+               }
+
+               if (ready)
+                       return ready;
+               if (time_after(now, deadline))
+                       return -EBUSY;
+
+               if (!warned && time_after(now, start + 5 * HZ) &&
+                   (deadline - now > 3 * HZ)) {
+                       ata_link_printk(link, KERN_WARNING,
+                               "link is slow to respond, please be patient "
+                               "(ready=%d)\n", tmp);
+                       warned = 1;
+               }
+
+               msleep(50);
+       }
+}
+
+/**
+ *     ata_wait_after_reset - wait for link to become ready after reset
+ *     @link: link to be waited on
+ *     @deadline: deadline jiffies for the operation
+ *     @check_ready: callback to check link readiness
+ *
+ *     Wait for @link to become ready after reset.
+ *
+ *     LOCKING:
+ *     EH context.
+ *
+ *     RETURNS:
+ *     0 if @linke is ready before @deadline; otherwise, -errno.
+ */
+extern int ata_wait_after_reset(struct ata_link *link, unsigned long deadline,
+                               int (*check_ready)(struct ata_link *link))
+{
+       msleep(ATA_WAIT_AFTER_RESET_MSECS);
+
+       return ata_wait_ready(link, deadline, check_ready);
+}
+
 /**
  *     sata_link_debounce - debounce SATA phy status
  *     @link: ATA link to debounce SATA phy status for
@@ -6075,6 +6172,7 @@ EXPORT_SYMBOL_GPL(ata_noop_qc_prep);
 EXPORT_SYMBOL_GPL(ata_port_probe);
 EXPORT_SYMBOL_GPL(ata_dev_disable);
 EXPORT_SYMBOL_GPL(sata_set_spd);
+EXPORT_SYMBOL_GPL(ata_wait_after_reset);
 EXPORT_SYMBOL_GPL(sata_link_debounce);
 EXPORT_SYMBOL_GPL(sata_link_resume);
 EXPORT_SYMBOL_GPL(ata_std_prereset);
index 6e8de3c..78912c5 100644 (file)
@@ -308,6 +308,17 @@ int ata_sff_busy_sleep(struct ata_port *ap,
        return 0;
 }
 
+static int ata_sff_check_ready(struct ata_link *link)
+{
+       u8 status = link->ap->ops->sff_check_status(link->ap);
+
+       if (!(status & ATA_BUSY))
+               return 1;
+       if (status == 0xff)
+               return -ENODEV;
+       return 0;
+}
+
 /**
  *     ata_sff_wait_ready - sleep until BSY clears, or timeout
  *     @link: SFF link to wait ready status for
@@ -324,56 +335,7 @@ int ata_sff_busy_sleep(struct ata_port *ap,
  */
 int ata_sff_wait_ready(struct ata_link *link, unsigned long deadline)
 {
-       struct ata_port *ap = link->ap;
-       unsigned long start = jiffies;
-       unsigned long nodev_deadline = start + ATA_TMOUT_FF_WAIT;
-       int warned = 0;
-
-       if (time_after(nodev_deadline, deadline))
-               nodev_deadline = deadline;
-
-       while (1) {
-               u8 status = ap->ops->sff_check_status(ap);
-               unsigned long now = jiffies;
-
-               if (!(status & ATA_BUSY))
-                       return 0;
-
-               /* No device status could be transient.  Ignore it if
-                * link is online.  Also, some SATA devices take a
-                * long time to clear 0xff after reset.  For example,
-                * HHD424020F7SV00 iVDR needs >= 800ms while Quantum
-                * GoVault needs even more than that.  Wait for
-                * ATA_TMOUT_FF_WAIT on -ENODEV if link isn't offline.
-                *
-                * Note that some PATA controllers (pata_ali) explode
-                * if status register is read more than once when
-                * there's no device attached.
-                */
-               if (status == 0xff) {
-                       if (ata_link_online(link))
-                               status = ATA_BUSY;
-                       else if ((link->ap->flags & ATA_FLAG_SATA) &&
-                                !ata_link_offline(link) &&
-                                time_before(now, nodev_deadline))
-                               status = ATA_BUSY;
-                       if (status == 0xff)
-                               return -ENODEV;
-               }
-
-               if (time_after(now, deadline))
-                       return -EBUSY;
-
-               if (!warned && time_after(now, start + 5 * HZ) &&
-                   (deadline - now > 3 * HZ)) {
-                       ata_link_printk(link, KERN_WARNING,
-                               "link is slow to respond, please be patient "
-                               "(Status 0x%x)\n", status);
-                       warned = 1;
-               }
-
-               msleep(50);
-       }
+       return ata_wait_ready(link, deadline, ata_sff_check_ready);
 }
 
 /**
index 11b5f67..08af43e 100644 (file)
@@ -81,6 +81,8 @@ extern unsigned ata_exec_internal_sg(struct ata_device *dev,
                                     int dma_dir, struct scatterlist *sg,
                                     unsigned int n_elem, unsigned long timeout);
 extern unsigned int ata_do_simple_cmd(struct ata_device *dev, u8 cmd);
+extern int ata_wait_ready(struct ata_link *link, unsigned long deadline,
+                         int (*check_ready)(struct ata_link *link));
 extern int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
                           unsigned int flags, u16 *id);
 extern int ata_dev_reread_id(struct ata_device *dev, unsigned int readid_flags);
index da55602..4bbf252 100644 (file)
@@ -837,6 +837,8 @@ extern void sata_print_link_status(struct ata_link *link);
 extern void ata_port_probe(struct ata_port *);
 extern int sata_set_spd(struct ata_link *link);
 extern int ata_std_prereset(struct ata_link *link, unsigned long deadline);
+extern int ata_wait_after_reset(struct ata_link *link, unsigned long deadline,
+                               int (*check_ready)(struct ata_link *link));
 extern int sata_link_debounce(struct ata_link *link,
                        const unsigned long *params, unsigned long deadline);
 extern int sata_link_resume(struct ata_link *link, const unsigned long *params,