Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit aa2731ad authored by Tejun Heo's avatar Tejun Heo Committed by Jeff Garzik
Browse files

libata: separate out ata_wait_ready() and implement ata_wait_after_reset()



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: default avatarTejun Heo <htejun@gmail.com>
parent 705e76be
Loading
Loading
Loading
Loading
+98 −0
Original line number Diff line number Diff line
@@ -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);
+12 −50
Original line number Diff line number Diff line
@@ -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);
}

/**
+2 −0
Original line number Diff line number Diff line
@@ -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);
+2 −0
Original line number Diff line number Diff line
@@ -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,