Skip to content

Commit

Permalink
[PATCH] libata: improve EH action and EHI flag handling
Browse files Browse the repository at this point in the history
Update ata_eh_about_to_do() and ata_eh_done() to improve EH action and
EHI flag handling.

* There are two types of EHI flags - one which expires on successful
  EH and the other which expires on a successful reset.  Make this
  distinction clear.

* Unlike other EH actions, reset actions are represented by two EH
  action masks and a EHI modifier.  Implement correct about_to_do/done
  semantics for resets.  That is, prior to reset, related EH info is
  sucked in from ehi and cleared, and after reset is complete, related
  EH info in ehc is cleared.

These changes improve consistency and remove unnecessary EH actions
caused by stale EH action masks and EHI flags.

Signed-off-by: Tejun Heo <htejun@gmail.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
  • Loading branch information
Tejun Heo authored and Jeff Garzik committed Jul 19, 2006
1 parent 7c8c2cf commit 13abf50
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 6 deletions.
33 changes: 28 additions & 5 deletions drivers/scsi/libata-eh.c
Original file line number Diff line number Diff line change
Expand Up @@ -764,12 +764,27 @@ static void ata_eh_about_to_do(struct ata_port *ap, struct ata_device *dev,
unsigned int action)
{
unsigned long flags;
struct ata_eh_info *ehi = &ap->eh_info;
struct ata_eh_context *ehc = &ap->eh_context;

spin_lock_irqsave(ap->lock, flags);

ata_eh_clear_action(dev, &ap->eh_info, action);
/* Reset is represented by combination of actions and EHI
* flags. Suck in all related bits before clearing eh_info to
* avoid losing requested action.
*/
if (action & ATA_EH_RESET_MASK) {
ehc->i.action |= ehi->action & ATA_EH_RESET_MASK;
ehc->i.flags |= ehi->flags & ATA_EHI_RESET_MODIFIER_MASK;

/* make sure all reset actions are cleared & clear EHI flags */
action |= ATA_EH_RESET_MASK;
ehi->flags &= ~ATA_EHI_RESET_MODIFIER_MASK;
}

ata_eh_clear_action(dev, ehi, action);

if (!(ap->eh_context.i.flags & ATA_EHI_QUIET))
if (!(ehc->i.flags & ATA_EHI_QUIET))
ap->pflags |= ATA_PFLAG_RECOVERED;

spin_unlock_irqrestore(ap->lock, flags);
Expand All @@ -790,6 +805,12 @@ static void ata_eh_about_to_do(struct ata_port *ap, struct ata_device *dev,
static void ata_eh_done(struct ata_port *ap, struct ata_device *dev,
unsigned int action)
{
/* if reset is complete, clear all reset actions & reset modifier */
if (action & ATA_EH_RESET_MASK) {
action |= ATA_EH_RESET_MASK;
ap->eh_context.i.flags &= ~ATA_EHI_RESET_MODIFIER_MASK;
}

ata_eh_clear_action(dev, &ap->eh_context.i, action);
}

Expand Down Expand Up @@ -1478,6 +1499,9 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
ata_reset_fn_t reset;
int i, did_followup_srst, rc;

/* about to reset */
ata_eh_about_to_do(ap, NULL, ehc->i.action & ATA_EH_RESET_MASK);

/* Determine which reset to use and record in ehc->i.action.
* prereset() may examine and modify it.
*/
Expand Down Expand Up @@ -1526,8 +1550,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
ata_port_printk(ap, KERN_INFO, "%s resetting port\n",
reset == softreset ? "soft" : "hard");

/* reset */
ata_eh_about_to_do(ap, NULL, ATA_EH_RESET_MASK);
/* mark that this EH session started with reset */
ehc->i.flags |= ATA_EHI_DID_RESET;

rc = ata_do_reset(ap, reset, classes);
Expand Down Expand Up @@ -1590,7 +1613,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
postreset(ap, classes);

/* reset successful, schedule revalidation */
ata_eh_done(ap, NULL, ATA_EH_RESET_MASK);
ata_eh_done(ap, NULL, ehc->i.action & ATA_EH_RESET_MASK);
ehc->i.action |= ATA_EH_REVALIDATE;
}

Expand Down
4 changes: 3 additions & 1 deletion include/linux/libata.h
Original file line number Diff line number Diff line change
Expand Up @@ -265,12 +265,14 @@ enum {

/* ata_eh_info->flags */
ATA_EHI_HOTPLUGGED = (1 << 0), /* could have been hotplugged */
ATA_EHI_RESUME_LINK = (1 << 1), /* need to resume link */
ATA_EHI_RESUME_LINK = (1 << 1), /* resume link (reset modifier) */
ATA_EHI_NO_AUTOPSY = (1 << 2), /* no autopsy */
ATA_EHI_QUIET = (1 << 3), /* be quiet */

ATA_EHI_DID_RESET = (1 << 16), /* already reset this port */

ATA_EHI_RESET_MODIFIER_MASK = ATA_EHI_RESUME_LINK,

/* max repeat if error condition is still set after ->error_handler */
ATA_EH_MAX_REPEAT = 5,

Expand Down

0 comments on commit 13abf50

Please sign in to comment.