Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 29484
b: refs/heads/master
c: d7bb4cc
h: refs/heads/master
v: v3
  • Loading branch information
Tejun Heo committed May 31, 2006
1 parent 578b5ea commit d885109
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 15 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: a9beec95352ff675f27d74c3cb97dc258d022497
refs/heads/master: d7bb4cc7575929a60b0a718daa1bce87bea9a9cc
107 changes: 93 additions & 14 deletions trunk/drivers/scsi/libata-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,11 @@

#include "libata.h"

/* debounce timing parameters in msecs { interval, duration, timeout } */
const unsigned long sata_deb_timing_boot[] = { 5, 100, 2000 };
const unsigned long sata_deb_timing_eh[] = { 25, 500, 2000 };
const unsigned long sata_deb_timing_before_fsrst[] = { 100, 2000, 5000 };

static unsigned int ata_dev_init_params(struct ata_device *dev,
u16 heads, u16 sectors);
static unsigned int ata_dev_set_xfermode(struct ata_device *dev);
Expand Down Expand Up @@ -2427,10 +2432,81 @@ void ata_bus_reset(struct ata_port *ap)
DPRINTK("EXIT\n");
}

static int sata_phy_resume(struct ata_port *ap)
/**
* sata_phy_debounce - debounce SATA phy status
* @ap: ATA port to debounce SATA phy status for
* @params: timing parameters { interval, duratinon, timeout } in msec
*
* Make sure SStatus of @ap reaches stable state, determined by
* holding the same value where DET is not 1 for @duration polled
* every @interval, before @timeout. Timeout constraints the
* beginning of the stable state. Because, after hot unplugging,
* DET gets stuck at 1 on some controllers, this functions waits
* until timeout then returns 0 if DET is stable at 1.
*
* LOCKING:
* Kernel thread context (may sleep)
*
* RETURNS:
* 0 on success, -errno on failure.
*/
int sata_phy_debounce(struct ata_port *ap, const unsigned long *params)
{
unsigned long timeout = jiffies + (HZ * 5);
u32 scontrol, sstatus;
unsigned long interval_msec = params[0];
unsigned long duration = params[1] * HZ / 1000;
unsigned long timeout = jiffies + params[2] * HZ / 1000;
unsigned long last_jiffies;
u32 last, cur;
int rc;

if ((rc = sata_scr_read(ap, SCR_STATUS, &cur)))
return rc;
cur &= 0xf;

last = cur;
last_jiffies = jiffies;

while (1) {
msleep(interval_msec);
if ((rc = sata_scr_read(ap, SCR_STATUS, &cur)))
return rc;
cur &= 0xf;

/* DET stable? */
if (cur == last) {
if (cur == 1 && time_before(jiffies, timeout))
continue;
if (time_after(jiffies, last_jiffies + duration))
return 0;
continue;
}

/* unstable, start over */
last = cur;
last_jiffies = jiffies;

/* check timeout */
if (time_after(jiffies, timeout))
return -EBUSY;
}
}

/**
* sata_phy_resume - resume SATA phy
* @ap: ATA port to resume SATA phy for
* @params: timing parameters { interval, duratinon, timeout } in msec
*
* Resume SATA phy of @ap and debounce it.
*
* LOCKING:
* Kernel thread context (may sleep)
*
* RETURNS:
* 0 on success, -errno on failure.
*/
int sata_phy_resume(struct ata_port *ap, const unsigned long *params)
{
u32 scontrol;
int rc;

if ((rc = sata_scr_read(ap, SCR_CONTROL, &scontrol)))
Expand All @@ -2441,16 +2517,12 @@ static int sata_phy_resume(struct ata_port *ap)
if ((rc = sata_scr_write(ap, SCR_CONTROL, scontrol)))
return rc;

/* Wait for phy to become ready, if necessary. */
do {
msleep(200);
if ((rc = sata_scr_read(ap, SCR_STATUS, &sstatus)))
return rc;
if ((sstatus & 0xf) != 1)
return 0;
} while (time_before(jiffies, timeout));
/* Some PHYs react badly if SStatus is pounded immediately
* after resuming. Delay 200ms before debouncing.
*/
msleep(200);

return -EBUSY;
return sata_phy_debounce(ap, params);
}

/**
Expand All @@ -2468,8 +2540,10 @@ static int sata_phy_resume(struct ata_port *ap)
*/
void ata_std_probeinit(struct ata_port *ap)
{
static const unsigned long deb_timing[] = { 5, 100, 5000 };

/* resume link */
sata_phy_resume(ap);
sata_phy_resume(ap, deb_timing);

/* wait for device */
if (ata_port_online(ap))
Expand Down Expand Up @@ -2585,7 +2659,7 @@ int sata_std_hardreset(struct ata_port *ap, unsigned int *class)
msleep(1);

/* bring phy back */
sata_phy_resume(ap);
sata_phy_resume(ap, sata_deb_timing_eh);

/* TODO: phy layer with polling, timeouts, etc. */
if (ata_port_offline(ap)) {
Expand Down Expand Up @@ -5718,6 +5792,9 @@ u32 ata_wait_register(void __iomem *reg, u32 mask, u32 val,
* Do not depend on ABI/API stability.
*/

EXPORT_SYMBOL_GPL(sata_deb_timing_boot);
EXPORT_SYMBOL_GPL(sata_deb_timing_eh);
EXPORT_SYMBOL_GPL(sata_deb_timing_before_fsrst);
EXPORT_SYMBOL_GPL(ata_std_bios_param);
EXPORT_SYMBOL_GPL(ata_std_ports);
EXPORT_SYMBOL_GPL(ata_device_add);
Expand Down Expand Up @@ -5757,6 +5834,8 @@ EXPORT_SYMBOL_GPL(ata_bmdma_error_handler);
EXPORT_SYMBOL_GPL(ata_bmdma_post_internal_cmd);
EXPORT_SYMBOL_GPL(ata_port_probe);
EXPORT_SYMBOL_GPL(sata_set_spd);
EXPORT_SYMBOL_GPL(sata_phy_debounce);
EXPORT_SYMBOL_GPL(sata_phy_resume);
EXPORT_SYMBOL_GPL(sata_phy_reset);
EXPORT_SYMBOL_GPL(__sata_phy_reset);
EXPORT_SYMBOL_GPL(ata_bus_reset);
Expand Down
6 changes: 6 additions & 0 deletions trunk/include/linux/libata.h
Original file line number Diff line number Diff line change
Expand Up @@ -607,11 +607,17 @@ struct ata_timing {

#define FIT(v,vmin,vmax) max_t(short,min_t(short,v,vmax),vmin)

extern const unsigned long sata_deb_timing_boot[];
extern const unsigned long sata_deb_timing_eh[];
extern const unsigned long sata_deb_timing_before_fsrst[];

extern void ata_port_probe(struct ata_port *);
extern void __sata_phy_reset(struct ata_port *ap);
extern void sata_phy_reset(struct ata_port *ap);
extern void ata_bus_reset(struct ata_port *ap);
extern int sata_set_spd(struct ata_port *ap);
extern int sata_phy_debounce(struct ata_port *ap, const unsigned long *param);
extern int sata_phy_resume(struct ata_port *ap, const unsigned long *param);
extern int ata_drive_probe_reset(struct ata_port *ap,
ata_probeinit_fn_t probeinit,
ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
Expand Down

0 comments on commit d885109

Please sign in to comment.