Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 29485
b: refs/heads/master
c: f5914a4
h: refs/heads/master
i:
  29483: 578b5ea
v: v3
  • Loading branch information
Tejun Heo committed May 31, 2006
1 parent d885109 commit f63dd5c
Show file tree
Hide file tree
Showing 7 changed files with 166 additions and 22 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: d7bb4cc7575929a60b0a718daa1bce87bea9a9cc
refs/heads/master: f5914a461eb9703773226a0813f6ffcae10c0861
3 changes: 2 additions & 1 deletion trunk/drivers/scsi/ahci.c
Original file line number Diff line number Diff line change
Expand Up @@ -1026,7 +1026,8 @@ static void ahci_error_handler(struct ata_port *ap)
}

/* perform recovery */
ata_do_eh(ap, ahci_softreset, ahci_hardreset, ahci_postreset);
ata_do_eh(ap, ata_std_prereset, ahci_softreset, ahci_hardreset,
ahci_postreset);
}

static void ahci_post_internal_cmd(struct ata_queued_cmd *qc)
Expand Down
11 changes: 7 additions & 4 deletions trunk/drivers/scsi/libata-bmdma.c
Original file line number Diff line number Diff line change
Expand Up @@ -695,6 +695,7 @@ void ata_bmdma_thaw(struct ata_port *ap)
/**
* ata_bmdma_drive_eh - Perform EH with given methods for BMDMA controller
* @ap: port to handle error for
* @prereset: prereset method (can be NULL)
* @softreset: softreset method (can be NULL)
* @hardreset: hardreset method (can be NULL)
* @postreset: postreset method (can be NULL)
Expand All @@ -710,8 +711,9 @@ void ata_bmdma_thaw(struct ata_port *ap)
* LOCKING:
* Kernel thread context (may sleep)
*/
void ata_bmdma_drive_eh(struct ata_port *ap, ata_reset_fn_t softreset,
ata_reset_fn_t hardreset, ata_postreset_fn_t postreset)
void ata_bmdma_drive_eh(struct ata_port *ap, ata_prereset_fn_t prereset,
ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
ata_postreset_fn_t postreset)
{
struct ata_host_set *host_set = ap->host_set;
struct ata_eh_context *ehc = &ap->eh_context;
Expand Down Expand Up @@ -759,7 +761,7 @@ void ata_bmdma_drive_eh(struct ata_port *ap, ata_reset_fn_t softreset,
ata_eh_thaw_port(ap);

/* PIO and DMA engines have been stopped, perform recovery */
ata_do_eh(ap, softreset, hardreset, postreset);
ata_do_eh(ap, prereset, softreset, hardreset, postreset);
}

/**
Expand All @@ -779,7 +781,8 @@ void ata_bmdma_error_handler(struct ata_port *ap)
if (sata_scr_valid(ap))
hardreset = sata_std_hardreset;

ata_bmdma_drive_eh(ap, ata_std_softreset, hardreset, ata_std_postreset);
ata_bmdma_drive_eh(ap, ata_std_prereset, ata_std_softreset, hardreset,
ata_std_postreset);
}

/**
Expand Down
85 changes: 85 additions & 0 deletions trunk/drivers/scsi/libata-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -2525,6 +2525,90 @@ int sata_phy_resume(struct ata_port *ap, const unsigned long *params)
return sata_phy_debounce(ap, params);
}

static void ata_wait_spinup(struct ata_port *ap)
{
struct ata_eh_context *ehc = &ap->eh_context;
unsigned long end, secs;
int rc;

/* first, debounce phy if SATA */
if (ap->cbl == ATA_CBL_SATA) {
rc = sata_phy_debounce(ap, sata_deb_timing_eh);

/* if debounced successfully and offline, no need to wait */
if ((rc == 0 || rc == -EOPNOTSUPP) && ata_port_offline(ap))
return;
}

/* okay, let's give the drive time to spin up */
end = ehc->i.hotplug_timestamp + ATA_SPINUP_WAIT * HZ / 1000;
secs = ((end - jiffies) + HZ - 1) / HZ;

if (time_after(jiffies, end))
return;

if (secs > 5)
ata_port_printk(ap, KERN_INFO, "waiting for device to spin up "
"(%lu secs)\n", secs);

schedule_timeout_uninterruptible(end - jiffies);
}

/**
* ata_std_prereset - prepare for reset
* @ap: ATA port to be reset
*
* @ap is about to be reset. Initialize it.
*
* LOCKING:
* Kernel thread context (may sleep)
*
* RETURNS:
* 0 on success, -errno otherwise.
*/
int ata_std_prereset(struct ata_port *ap)
{
struct ata_eh_context *ehc = &ap->eh_context;
const unsigned long *timing;
int rc;

/* hotplug? */
if (ehc->i.flags & ATA_EHI_HOTPLUGGED) {
if (ap->flags & ATA_FLAG_HRST_TO_RESUME)
ehc->i.action |= ATA_EH_HARDRESET;
if (ap->flags & ATA_FLAG_SKIP_D2H_BSY)
ata_wait_spinup(ap);
}

/* if we're about to do hardreset, nothing more to do */
if (ehc->i.action & ATA_EH_HARDRESET)
return 0;

/* if SATA, resume phy */
if (ap->cbl == ATA_CBL_SATA) {
if (ap->flags & ATA_FLAG_LOADING)
timing = sata_deb_timing_boot;
else
timing = sata_deb_timing_eh;

rc = sata_phy_resume(ap, timing);
if (rc && rc != -EOPNOTSUPP) {
/* phy resume failed */
ata_port_printk(ap, KERN_WARNING, "failed to resume "
"link for reset (errno=%d)\n", rc);
return rc;
}
}

/* Wait for !BSY if the controller can wait for the first D2H
* Reg FIS and we don't know that no device is attached.
*/
if (!(ap->flags & ATA_FLAG_SKIP_D2H_BSY) && !ata_port_offline(ap))
ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);

return 0;
}

/**
* ata_std_probeinit - initialize probing
* @ap: port to be probed
Expand Down Expand Up @@ -5840,6 +5924,7 @@ EXPORT_SYMBOL_GPL(sata_phy_reset);
EXPORT_SYMBOL_GPL(__sata_phy_reset);
EXPORT_SYMBOL_GPL(ata_bus_reset);
EXPORT_SYMBOL_GPL(ata_std_probeinit);
EXPORT_SYMBOL_GPL(ata_std_prereset);
EXPORT_SYMBOL_GPL(ata_std_softreset);
EXPORT_SYMBOL_GPL(sata_std_hardreset);
EXPORT_SYMBOL_GPL(ata_std_postreset);
Expand Down
60 changes: 51 additions & 9 deletions trunk/drivers/scsi/libata-eh.c
Original file line number Diff line number Diff line change
Expand Up @@ -1318,20 +1318,58 @@ static void ata_eh_report(struct ata_port *ap)
}
}

static int ata_eh_reset(struct ata_port *ap, ata_reset_fn_t softreset,
static int ata_eh_reset(struct ata_port *ap,
ata_prereset_fn_t prereset, ata_reset_fn_t softreset,
ata_reset_fn_t hardreset, ata_postreset_fn_t postreset)
{
struct ata_eh_context *ehc = &ap->eh_context;
unsigned int classes[ATA_MAX_DEVICES];
int tries = ATA_EH_RESET_TRIES;
unsigned int action;
ata_reset_fn_t reset;
int i, rc;

/* Determine which reset to use and record in ehc->i.action.
* prereset() may examine and modify it.
*/
action = ehc->i.action;
ehc->i.action &= ~ATA_EH_RESET_MASK;
if (softreset && (!hardreset || (!sata_set_spd_needed(ap) &&
!(ehc->i.action & ATA_EH_HARDRESET))))
reset = softreset;
!(action & ATA_EH_HARDRESET))))
ehc->i.action |= ATA_EH_SOFTRESET;
else
ehc->i.action |= ATA_EH_HARDRESET;

if (prereset) {
rc = prereset(ap);
if (rc) {
ata_port_printk(ap, KERN_ERR,
"prereset failed (errno=%d)\n", rc);
return rc;
}
}

/* prereset() might have modified ehc->i.action */
if (ehc->i.action & ATA_EH_HARDRESET)
reset = hardreset;
else if (ehc->i.action & ATA_EH_SOFTRESET)
reset = softreset;
else {
/* prereset told us not to reset, bang classes and return */
for (i = 0; i < ATA_MAX_DEVICES; i++)
classes[i] = ATA_DEV_NONE;
return 0;
}

/* did prereset() screw up? if so, fix up to avoid oopsing */
if (!reset) {
ata_port_printk(ap, KERN_ERR, "BUG: prereset() requested "
"invalid reset type\n");
if (softreset)
reset = softreset;
else
reset = hardreset;
}

retry:
ata_port_printk(ap, KERN_INFO, "%s resetting port\n",
Expand Down Expand Up @@ -1424,6 +1462,7 @@ static int ata_port_nr_enabled(struct ata_port *ap)
/**
* ata_eh_recover - recover host port after error
* @ap: host port to recover
* @prereset: prereset method (can be NULL)
* @softreset: softreset method (can be NULL)
* @hardreset: hardreset method (can be NULL)
* @postreset: postreset method (can be NULL)
Expand All @@ -1440,8 +1479,8 @@ static int ata_port_nr_enabled(struct ata_port *ap)
* RETURNS:
* 0 on success, -errno on failure.
*/
static int ata_eh_recover(struct ata_port *ap, ata_reset_fn_t softreset,
ata_reset_fn_t hardreset,
static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
ata_postreset_fn_t postreset)
{
struct ata_eh_context *ehc = &ap->eh_context;
Expand Down Expand Up @@ -1469,7 +1508,8 @@ static int ata_eh_recover(struct ata_port *ap, ata_reset_fn_t softreset,
if (ehc->i.action & ATA_EH_RESET_MASK) {
ata_eh_freeze_port(ap);

rc = ata_eh_reset(ap, softreset, hardreset, postreset);
rc = ata_eh_reset(ap, prereset, softreset, hardreset,
postreset);
if (rc) {
ata_port_printk(ap, KERN_ERR,
"reset failed, giving up\n");
Expand Down Expand Up @@ -1586,6 +1626,7 @@ static void ata_eh_finish(struct ata_port *ap)
/**
* ata_do_eh - do standard error handling
* @ap: host port to handle error for
* @prereset: prereset method (can be NULL)
* @softreset: softreset method (can be NULL)
* @hardreset: hardreset method (can be NULL)
* @postreset: postreset method (can be NULL)
Expand All @@ -1595,11 +1636,12 @@ static void ata_eh_finish(struct ata_port *ap)
* LOCKING:
* Kernel thread context (may sleep).
*/
void ata_do_eh(struct ata_port *ap, ata_reset_fn_t softreset,
ata_reset_fn_t hardreset, ata_postreset_fn_t postreset)
void ata_do_eh(struct ata_port *ap, ata_prereset_fn_t prereset,
ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
ata_postreset_fn_t postreset)
{
ata_eh_autopsy(ap);
ata_eh_report(ap);
ata_eh_recover(ap, softreset, hardreset, postreset);
ata_eh_recover(ap, prereset, softreset, hardreset, postreset);
ata_eh_finish(ap);
}
3 changes: 2 additions & 1 deletion trunk/drivers/scsi/sata_sil24.c
Original file line number Diff line number Diff line change
Expand Up @@ -912,7 +912,8 @@ static void sil24_error_handler(struct ata_port *ap)
}

/* perform recovery */
ata_do_eh(ap, sil24_softreset, sil24_hardreset, ata_std_postreset);
ata_do_eh(ap, ata_std_prereset, sil24_softreset, sil24_hardreset,
ata_std_postreset);
}

static void sil24_post_internal_cmd(struct ata_queued_cmd *qc)
Expand Down
24 changes: 18 additions & 6 deletions trunk/include/linux/libata.h
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,15 @@ enum {
ATA_PROBE_MAX_TRIES = 3,
ATA_EH_RESET_TRIES = 3,
ATA_EH_DEV_TRIES = 3,

/* Drive spinup time (time from power-on to the first D2H FIS)
* in msecs - 8s currently. Failing to get ready in this time
* isn't critical. It will result in reset failure for
* controllers which can't wait for the first D2H FIS. libata
* will retry, so it just has to be long enough to spin up
* most devices.
*/
ATA_SPINUP_WAIT = 8000,
};

enum hsm_task_states {
Expand Down Expand Up @@ -294,9 +303,10 @@ struct ata_queued_cmd;

/* typedefs */
typedef void (*ata_qc_cb_t) (struct ata_queued_cmd *qc);
typedef void (*ata_probeinit_fn_t)(struct ata_port *);
typedef int (*ata_reset_fn_t)(struct ata_port *, unsigned int *);
typedef void (*ata_postreset_fn_t)(struct ata_port *ap, unsigned int *);
typedef void (*ata_probeinit_fn_t)(struct ata_port *ap);
typedef int (*ata_prereset_fn_t)(struct ata_port *ap);
typedef int (*ata_reset_fn_t)(struct ata_port *ap, unsigned int *classes);
typedef void (*ata_postreset_fn_t)(struct ata_port *ap, unsigned int *classes);

struct ata_ioports {
unsigned long cmd_addr;
Expand Down Expand Up @@ -623,6 +633,7 @@ extern int ata_drive_probe_reset(struct ata_port *ap,
ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
ata_postreset_fn_t postreset, unsigned int *classes);
extern void ata_std_probeinit(struct ata_port *ap);
extern int ata_std_prereset(struct ata_port *ap);
extern int ata_std_softreset(struct ata_port *ap, unsigned int *classes);
extern int sata_std_hardreset(struct ata_port *ap, unsigned int *class);
extern void ata_std_postreset(struct ata_port *ap, unsigned int *classes);
Expand Down Expand Up @@ -706,7 +717,7 @@ extern u8 ata_bmdma_status(struct ata_port *ap);
extern void ata_bmdma_irq_clear(struct ata_port *ap);
extern void ata_bmdma_freeze(struct ata_port *ap);
extern void ata_bmdma_thaw(struct ata_port *ap);
extern void ata_bmdma_drive_eh(struct ata_port *ap,
extern void ata_bmdma_drive_eh(struct ata_port *ap, ata_prereset_fn_t prereset,
ata_reset_fn_t softreset,
ata_reset_fn_t hardreset,
ata_postreset_fn_t postreset);
Expand Down Expand Up @@ -784,8 +795,9 @@ extern void ata_eh_thaw_port(struct ata_port *ap);
extern void ata_eh_qc_complete(struct ata_queued_cmd *qc);
extern void ata_eh_qc_retry(struct ata_queued_cmd *qc);

extern void ata_do_eh(struct ata_port *ap, ata_reset_fn_t softreset,
ata_reset_fn_t hardreset, ata_postreset_fn_t postreset);
extern void ata_do_eh(struct ata_port *ap, ata_prereset_fn_t prereset,
ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
ata_postreset_fn_t postreset);

/*
* printk helpers
Expand Down

0 comments on commit f63dd5c

Please sign in to comment.