mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-29 23:24:11 +08:00
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: Tejun Heo <htejun@gmail.com>
This commit is contained in:
parent
705e76beb9
commit
aa2731ad9a
@ -3310,6 +3310,103 @@ int ata_do_set_mode(struct ata_link *link, struct ata_device **r_failed_dev)
|
|||||||
return rc;
|
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
|
* sata_link_debounce - debounce SATA phy status
|
||||||
* @link: ATA link to debounce SATA phy status for
|
* @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_port_probe);
|
||||||
EXPORT_SYMBOL_GPL(ata_dev_disable);
|
EXPORT_SYMBOL_GPL(ata_dev_disable);
|
||||||
EXPORT_SYMBOL_GPL(sata_set_spd);
|
EXPORT_SYMBOL_GPL(sata_set_spd);
|
||||||
|
EXPORT_SYMBOL_GPL(ata_wait_after_reset);
|
||||||
EXPORT_SYMBOL_GPL(sata_link_debounce);
|
EXPORT_SYMBOL_GPL(sata_link_debounce);
|
||||||
EXPORT_SYMBOL_GPL(sata_link_resume);
|
EXPORT_SYMBOL_GPL(sata_link_resume);
|
||||||
EXPORT_SYMBOL_GPL(ata_std_prereset);
|
EXPORT_SYMBOL_GPL(ata_std_prereset);
|
||||||
|
@ -308,6 +308,17 @@ int ata_sff_busy_sleep(struct ata_port *ap,
|
|||||||
return 0;
|
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
|
* ata_sff_wait_ready - sleep until BSY clears, or timeout
|
||||||
* @link: SFF link to wait ready status for
|
* @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)
|
int ata_sff_wait_ready(struct ata_link *link, unsigned long deadline)
|
||||||
{
|
{
|
||||||
struct ata_port *ap = link->ap;
|
return ata_wait_ready(link, deadline, ata_sff_check_ready);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -81,6 +81,8 @@ extern unsigned ata_exec_internal_sg(struct ata_device *dev,
|
|||||||
int dma_dir, struct scatterlist *sg,
|
int dma_dir, struct scatterlist *sg,
|
||||||
unsigned int n_elem, unsigned long timeout);
|
unsigned int n_elem, unsigned long timeout);
|
||||||
extern unsigned int ata_do_simple_cmd(struct ata_device *dev, u8 cmd);
|
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,
|
extern int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
|
||||||
unsigned int flags, u16 *id);
|
unsigned int flags, u16 *id);
|
||||||
extern int ata_dev_reread_id(struct ata_device *dev, unsigned int readid_flags);
|
extern int ata_dev_reread_id(struct ata_device *dev, unsigned int readid_flags);
|
||||||
|
@ -837,6 +837,8 @@ extern void sata_print_link_status(struct ata_link *link);
|
|||||||
extern void ata_port_probe(struct ata_port *);
|
extern void ata_port_probe(struct ata_port *);
|
||||||
extern int sata_set_spd(struct ata_link *link);
|
extern int sata_set_spd(struct ata_link *link);
|
||||||
extern int ata_std_prereset(struct ata_link *link, unsigned long deadline);
|
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,
|
extern int sata_link_debounce(struct ata_link *link,
|
||||||
const unsigned long *params, unsigned long deadline);
|
const unsigned long *params, unsigned long deadline);
|
||||||
extern int sata_link_resume(struct ata_link *link, const unsigned long *params,
|
extern int sata_link_resume(struct ata_link *link, const unsigned long *params,
|
||||||
|
Loading…
Reference in New Issue
Block a user