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