[PATCH] libata: improve EH action and EHI flag handling

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>

authored by Tejun Heo and committed by Jeff Garzik 13abf50d 7c8c2cff

+31 -6
+28 -5
drivers/scsi/libata-eh.c
··· 764 764 unsigned int action) 765 765 { 766 766 unsigned long flags; 767 + struct ata_eh_info *ehi = &ap->eh_info; 768 + struct ata_eh_context *ehc = &ap->eh_context; 767 769 768 770 spin_lock_irqsave(ap->lock, flags); 769 771 770 - ata_eh_clear_action(dev, &ap->eh_info, action); 772 + /* Reset is represented by combination of actions and EHI 773 + * flags. Suck in all related bits before clearing eh_info to 774 + * avoid losing requested action. 775 + */ 776 + if (action & ATA_EH_RESET_MASK) { 777 + ehc->i.action |= ehi->action & ATA_EH_RESET_MASK; 778 + ehc->i.flags |= ehi->flags & ATA_EHI_RESET_MODIFIER_MASK; 771 779 772 - if (!(ap->eh_context.i.flags & ATA_EHI_QUIET)) 780 + /* make sure all reset actions are cleared & clear EHI flags */ 781 + action |= ATA_EH_RESET_MASK; 782 + ehi->flags &= ~ATA_EHI_RESET_MODIFIER_MASK; 783 + } 784 + 785 + ata_eh_clear_action(dev, ehi, action); 786 + 787 + if (!(ehc->i.flags & ATA_EHI_QUIET)) 773 788 ap->pflags |= ATA_PFLAG_RECOVERED; 774 789 775 790 spin_unlock_irqrestore(ap->lock, flags); ··· 805 790 static void ata_eh_done(struct ata_port *ap, struct ata_device *dev, 806 791 unsigned int action) 807 792 { 793 + /* if reset is complete, clear all reset actions & reset modifier */ 794 + if (action & ATA_EH_RESET_MASK) { 795 + action |= ATA_EH_RESET_MASK; 796 + ap->eh_context.i.flags &= ~ATA_EHI_RESET_MODIFIER_MASK; 797 + } 798 + 808 799 ata_eh_clear_action(dev, &ap->eh_context.i, action); 809 800 } 810 801 ··· 1499 1478 ata_reset_fn_t reset; 1500 1479 int i, did_followup_srst, rc; 1501 1480 1481 + /* about to reset */ 1482 + ata_eh_about_to_do(ap, NULL, ehc->i.action & ATA_EH_RESET_MASK); 1483 + 1502 1484 /* Determine which reset to use and record in ehc->i.action. 1503 1485 * prereset() may examine and modify it. 1504 1486 */ ··· 1550 1526 ata_port_printk(ap, KERN_INFO, "%s resetting port\n", 1551 1527 reset == softreset ? "soft" : "hard"); 1552 1528 1553 - /* reset */ 1554 - ata_eh_about_to_do(ap, NULL, ATA_EH_RESET_MASK); 1529 + /* mark that this EH session started with reset */ 1555 1530 ehc->i.flags |= ATA_EHI_DID_RESET; 1556 1531 1557 1532 rc = ata_do_reset(ap, reset, classes); ··· 1613 1590 postreset(ap, classes); 1614 1591 1615 1592 /* reset successful, schedule revalidation */ 1616 - ata_eh_done(ap, NULL, ATA_EH_RESET_MASK); 1593 + ata_eh_done(ap, NULL, ehc->i.action & ATA_EH_RESET_MASK); 1617 1594 ehc->i.action |= ATA_EH_REVALIDATE; 1618 1595 } 1619 1596
+3 -1
include/linux/libata.h
··· 265 265 266 266 /* ata_eh_info->flags */ 267 267 ATA_EHI_HOTPLUGGED = (1 << 0), /* could have been hotplugged */ 268 - ATA_EHI_RESUME_LINK = (1 << 1), /* need to resume link */ 268 + ATA_EHI_RESUME_LINK = (1 << 1), /* resume link (reset modifier) */ 269 269 ATA_EHI_NO_AUTOPSY = (1 << 2), /* no autopsy */ 270 270 ATA_EHI_QUIET = (1 << 3), /* be quiet */ 271 271 272 272 ATA_EHI_DID_RESET = (1 << 16), /* already reset this port */ 273 + 274 + ATA_EHI_RESET_MODIFIER_MASK = ATA_EHI_RESUME_LINK, 273 275 274 276 /* max repeat if error condition is still set after ->error_handler */ 275 277 ATA_EH_MAX_REPEAT = 5,