Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 96950
b: refs/heads/master
c: f046519
h: refs/heads/master
v: v3
  • Loading branch information
Tejun Heo authored and Jeff Garzik committed May 19, 2008
1 parent 48559ab commit f95edac
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 24 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: dc98c32cbe80750ae2d9d9fbdae305d38f005de7
refs/heads/master: f046519fc85a8fdf6a058b4ac9d897cdee6f3e52
21 changes: 8 additions & 13 deletions trunk/drivers/ata/libata-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -3490,22 +3490,11 @@ int sata_link_resume(struct ata_link *link, const unsigned long *params,
if ((rc = sata_link_debounce(link, params, deadline)))
return rc;

/* Clear SError. PMP and some host PHYs require this to
* operate and clearing should be done before checking PHY
* online status to avoid race condition (hotplugging between
* link resume and status check).
*/
/* clear SError, some PHYs require this even for SRST to work */
if (!(rc = sata_scr_read(link, SCR_ERROR, &serror)))
rc = sata_scr_write(link, SCR_ERROR, serror);
if (rc == 0 || rc == -EINVAL) {
unsigned long flags;

spin_lock_irqsave(link->ap->lock, flags);
link->eh_info.serror = 0;
spin_unlock_irqrestore(link->ap->lock, flags);
rc = 0;
}
return rc;
return rc != -EINVAL ? rc : 0;
}

/**
Expand Down Expand Up @@ -3704,8 +3693,14 @@ int sata_std_hardreset(struct ata_link *link, unsigned int *class,
*/
void ata_std_postreset(struct ata_link *link, unsigned int *classes)
{
u32 serror;

DPRINTK("ENTER\n");

/* reset complete, clear SError */
if (!sata_scr_read(link, SCR_ERROR, &serror))
sata_scr_write(link, SCR_ERROR, serror);

/* print link status */
sata_print_link_status(link);

Expand Down
52 changes: 42 additions & 10 deletions trunk/drivers/ata/libata-eh.c
Original file line number Diff line number Diff line change
Expand Up @@ -2047,19 +2047,11 @@ static int ata_do_reset(struct ata_link *link, ata_reset_fn_t reset,
unsigned int *classes, unsigned long deadline)
{
struct ata_device *dev;
int rc;

ata_link_for_each_dev(dev, link)
classes[dev->devno] = ATA_DEV_UNKNOWN;

rc = reset(link, classes, deadline);

/* convert all ATA_DEV_UNKNOWN to ATA_DEV_NONE */
ata_link_for_each_dev(dev, link)
if (classes[dev->devno] == ATA_DEV_UNKNOWN)
classes[dev->devno] = ATA_DEV_NONE;

return rc;
return reset(link, classes, deadline);
}

static int ata_eh_followup_srst_needed(struct ata_link *link,
Expand Down Expand Up @@ -2096,7 +2088,7 @@ int ata_eh_reset(struct ata_link *link, int classify,
ata_reset_fn_t reset;
unsigned long flags;
u32 sstatus;
int rc;
int nr_known, rc;

/*
* Prepare to reset
Expand Down Expand Up @@ -2245,9 +2237,49 @@ int ata_eh_reset(struct ata_link *link, int classify,
if (ata_is_host_link(link))
ata_eh_thaw_port(ap);

/* postreset() should clear hardware SError. Although SError
* is cleared during link resume, clearing SError here is
* necessary as some PHYs raise hotplug events after SRST.
* This introduces race condition where hotplug occurs between
* reset and here. This race is mediated by cross checking
* link onlineness and classification result later.
*/
if (postreset)
postreset(link, classes);

/* clear cached SError */
spin_lock_irqsave(link->ap->lock, flags);
link->eh_info.serror = 0;
spin_unlock_irqrestore(link->ap->lock, flags);

/* Make sure onlineness and classification result correspond.
* Hotplug could have happened during reset and some
* controllers fail to wait while a drive is spinning up after
* being hotplugged causing misdetection. By cross checking
* link onlineness and classification result, those conditions
* can be reliably detected and retried.
*/
nr_known = 0;
ata_link_for_each_dev(dev, link) {
/* convert all ATA_DEV_UNKNOWN to ATA_DEV_NONE */
if (classes[dev->devno] == ATA_DEV_UNKNOWN)
classes[dev->devno] = ATA_DEV_NONE;
else
nr_known++;
}

if (classify && !nr_known && ata_link_online(link)) {
if (try < max_tries) {
ata_link_printk(link, KERN_WARNING, "link online but "
"device misclassified, retrying\n");
rc = -EAGAIN;
goto fail;
}
ata_link_printk(link, KERN_WARNING,
"link online but device misclassified, "
"device detection might fail\n");
}

/* reset successful, schedule revalidation */
ata_eh_done(link, NULL, ATA_EH_RESET);
ehc->i.action |= ATA_EH_REVALIDATE;
Expand Down

0 comments on commit f95edac

Please sign in to comment.