Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 29493
b: refs/heads/master
c: 084fe63
h: refs/heads/master
i:
  29491: d9fded3
v: v3
  • Loading branch information
Tejun Heo committed May 31, 2006
1 parent 56f3347 commit 1ca413c
Show file tree
Hide file tree
Showing 3 changed files with 116 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: 0ea035a3d1ad948096e205f08f350c03d5cea453
refs/heads/master: 084fe639b81c4d418a2cf714acb0475e3713cb73
123 changes: 102 additions & 21 deletions trunk/drivers/scsi/libata-eh.c
Original file line number Diff line number Diff line change
Expand Up @@ -932,10 +932,8 @@ static void ata_eh_analyze_serror(struct ata_port *ap)
err_mask |= AC_ERR_SYSTEM;
action |= ATA_EH_SOFTRESET;
}
if (serror & (SERR_PHYRDY_CHG | SERR_DEV_XCHG)) {
err_mask |= AC_ERR_ATA_BUS;
action |= ATA_EH_HARDRESET;
}
if (serror & (SERR_PHYRDY_CHG | SERR_DEV_XCHG))
ata_ehi_hotplugged(&ehc->i);

ehc->i.err_mask |= err_mask;
ehc->i.action |= action;
Expand Down Expand Up @@ -1487,11 +1485,12 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
return rc;
}

static int ata_eh_revalidate(struct ata_port *ap,
struct ata_device **r_failed_dev)
static int ata_eh_revalidate_and_attach(struct ata_port *ap,
struct ata_device **r_failed_dev)
{
struct ata_eh_context *ehc = &ap->eh_context;
struct ata_device *dev;
unsigned long flags;
int i, rc = 0;

DPRINTK("ENTER\n");
Expand All @@ -1513,6 +1512,23 @@ static int ata_eh_revalidate(struct ata_port *ap,
break;

ehc->i.action &= ~ATA_EH_REVALIDATE;
} else if (dev->class == ATA_DEV_UNKNOWN &&
ehc->tries[dev->devno] &&
ata_class_enabled(ehc->classes[dev->devno])) {
dev->class = ehc->classes[dev->devno];

rc = ata_dev_read_id(dev, &dev->class, 1, dev->id);
if (rc == 0)
rc = ata_dev_configure(dev, 1);

if (rc) {
dev->class = ATA_DEV_UNKNOWN;
break;
}

spin_lock_irqsave(&ap->host_set->lock, flags);
ap->flags |= ATA_FLAG_SCSI_HOTPLUG;
spin_unlock_irqrestore(&ap->host_set->lock, flags);
}
}

Expand All @@ -1533,6 +1549,36 @@ static int ata_port_nr_enabled(struct ata_port *ap)
return cnt;
}

static int ata_port_nr_vacant(struct ata_port *ap)
{
int i, cnt = 0;

for (i = 0; i < ATA_MAX_DEVICES; i++)
if (ap->device[i].class == ATA_DEV_UNKNOWN)
cnt++;
return cnt;
}

static int ata_eh_skip_recovery(struct ata_port *ap)
{
struct ata_eh_context *ehc = &ap->eh_context;
int i;

if (ap->flags & ATA_FLAG_FROZEN || ata_port_nr_enabled(ap))
return 0;

/* skip if class codes for all vacant slots are ATA_DEV_NONE */
for (i = 0; i < ATA_MAX_DEVICES; i++) {
struct ata_device *dev = &ap->device[i];

if (dev->class == ATA_DEV_UNKNOWN &&
ehc->classes[dev->devno] != ATA_DEV_NONE)
return 0;
}

return 1;
}

/**
* ata_eh_recover - recover host port after error
* @ap: host port to recover
Expand All @@ -1543,9 +1589,10 @@ static int ata_port_nr_enabled(struct ata_port *ap)
*
* This is the alpha and omega, eum and yang, heart and soul of
* libata exception handling. On entry, actions required to
* recover each devices are recorded in eh_context. This
* function executes all the operations with appropriate retrials
* and fallbacks to resurrect failed devices.
* recover the port and hotplug requests are recorded in
* eh_context. This function executes all the operations with
* appropriate retrials and fallbacks to resurrect failed
* devices, detach goners and greet newcomers.
*
* LOCKING:
* Kernel thread context (may sleep).
Expand All @@ -1568,22 +1615,38 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
dev = &ap->device[i];

ehc->tries[dev->devno] = ATA_EH_DEV_TRIES;

/* process hotplug request */
if (dev->flags & ATA_DFLAG_DETACH)
ata_eh_detach_dev(dev);

if (!ata_dev_enabled(dev) &&
((ehc->i.probe_mask & (1 << dev->devno)) &&
!(ehc->did_probe_mask & (1 << dev->devno)))) {
ata_eh_detach_dev(dev);
ata_dev_init(dev);
ehc->did_probe_mask |= (1 << dev->devno);
ehc->i.action |= ATA_EH_SOFTRESET;
}
}

retry:
down_xfermask = 0;
rc = 0;

/* skip EH if possible. */
if (!ata_port_nr_enabled(ap) && !(ap->flags & ATA_FLAG_FROZEN))
if (ata_eh_skip_recovery(ap))
ehc->i.action = 0;

for (i = 0; i < ATA_MAX_DEVICES; i++)
ehc->classes[i] = ATA_DEV_UNKNOWN;

/* reset */
if (ehc->i.action & ATA_EH_RESET_MASK) {
ata_eh_freeze_port(ap);

rc = ata_eh_reset(ap, 0, prereset, softreset, hardreset,
postreset);
rc = ata_eh_reset(ap, ata_port_nr_vacant(ap), prereset,
softreset, hardreset, postreset);
if (rc) {
ata_port_printk(ap, KERN_ERR,
"reset failed, giving up\n");
Expand All @@ -1593,8 +1656,8 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
ata_eh_thaw_port(ap);
}

/* revalidate existing devices */
rc = ata_eh_revalidate(ap, &dev);
/* revalidate existing devices and attach new ones */
rc = ata_eh_revalidate_and_attach(ap, &dev);
if (rc)
goto dev_fail;

Expand All @@ -1612,6 +1675,8 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
dev_fail:
switch (rc) {
case -ENODEV:
/* device missing, schedule probing */
ehc->i.probe_mask |= (1 << dev->devno);
case -EINVAL:
ehc->tries[dev->devno] = 0;
break;
Expand All @@ -1624,15 +1689,31 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
ehc->tries[dev->devno] = 0;
}

/* disable device if it has used up all its chances */
if (ata_dev_enabled(dev) && !ehc->tries[dev->devno])
if (ata_dev_enabled(dev) && !ehc->tries[dev->devno]) {
/* disable device if it has used up all its chances */
ata_dev_disable(dev);

/* soft didn't work? be haaaaard */
if (ehc->i.flags & ATA_EHI_DID_RESET)
ehc->i.action |= ATA_EH_HARDRESET;
else
ehc->i.action |= ATA_EH_SOFTRESET;
/* detach if offline */
if (ata_port_offline(ap))
ata_eh_detach_dev(dev);

/* probe if requested */
if ((ehc->i.probe_mask & (1 << dev->devno)) &&
!(ehc->did_probe_mask & (1 << dev->devno))) {
ata_eh_detach_dev(dev);
ata_dev_init(dev);

ehc->tries[dev->devno] = ATA_EH_DEV_TRIES;
ehc->did_probe_mask |= (1 << dev->devno);
ehc->i.action |= ATA_EH_SOFTRESET;
}
} else {
/* soft didn't work? be haaaaard */
if (ehc->i.flags & ATA_EHI_DID_RESET)
ehc->i.action |= ATA_EH_HARDRESET;
else
ehc->i.action |= ATA_EH_SOFTRESET;
}

if (ata_port_nr_enabled(ap)) {
ata_port_printk(ap, KERN_WARNING, "failed to recover some "
Expand Down
13 changes: 13 additions & 0 deletions trunk/include/linux/libata.h
Original file line number Diff line number Diff line change
Expand Up @@ -824,6 +824,19 @@ extern void ata_do_eh(struct ata_port *ap, ata_prereset_fn_t prereset,
(ehi)->desc_len = 0; \
} while (0)

static inline void ata_ehi_hotplugged(struct ata_eh_info *ehi)
{
if (ehi->flags & ATA_EHI_HOTPLUGGED)
return;

ehi->flags |= ATA_EHI_HOTPLUGGED;
ehi->hotplug_timestamp = jiffies;

ehi->err_mask |= AC_ERR_ATA_BUS;
ehi->action |= ATA_EH_SOFTRESET;
ehi->probe_mask |= (1 << ATA_MAX_DEVICES) - 1;
}

/*
* qc helpers
*/
Expand Down

0 comments on commit 1ca413c

Please sign in to comment.