diff options
-rw-r--r-- | drivers/scsi/libata-eh.c | 33 | ||||
-rw-r--r-- | include/linux/libata.h | 4 |
2 files changed, 31 insertions, 6 deletions
diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c index 1dcb2c13ffa9..29f59345305d 100644 --- a/drivers/scsi/libata-eh.c +++ b/drivers/scsi/libata-eh.c | |||
@@ -764,12 +764,27 @@ static void ata_eh_about_to_do(struct ata_port *ap, struct ata_device *dev, | |||
764 | unsigned int action) | 764 | unsigned int action) |
765 | { | 765 | { |
766 | unsigned long flags; | 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 | spin_lock_irqsave(ap->lock, flags); | 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; | ||
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); | ||
771 | 786 | ||
772 | if (!(ap->eh_context.i.flags & ATA_EHI_QUIET)) | 787 | if (!(ehc->i.flags & ATA_EHI_QUIET)) |
773 | ap->pflags |= ATA_PFLAG_RECOVERED; | 788 | ap->pflags |= ATA_PFLAG_RECOVERED; |
774 | 789 | ||
775 | spin_unlock_irqrestore(ap->lock, flags); | 790 | spin_unlock_irqrestore(ap->lock, flags); |
@@ -790,6 +805,12 @@ static void ata_eh_about_to_do(struct ata_port *ap, struct ata_device *dev, | |||
790 | static void ata_eh_done(struct ata_port *ap, struct ata_device *dev, | 805 | static void ata_eh_done(struct ata_port *ap, struct ata_device *dev, |
791 | unsigned int action) | 806 | unsigned int action) |
792 | { | 807 | { |
808 | /* if reset is complete, clear all reset actions & reset modifier */ | ||
809 | if (action & ATA_EH_RESET_MASK) { | ||
810 | action |= ATA_EH_RESET_MASK; | ||
811 | ap->eh_context.i.flags &= ~ATA_EHI_RESET_MODIFIER_MASK; | ||
812 | } | ||
813 | |||
793 | ata_eh_clear_action(dev, &ap->eh_context.i, action); | 814 | ata_eh_clear_action(dev, &ap->eh_context.i, action); |
794 | } | 815 | } |
795 | 816 | ||
@@ -1478,6 +1499,9 @@ static int ata_eh_reset(struct ata_port *ap, int classify, | |||
1478 | ata_reset_fn_t reset; | 1499 | ata_reset_fn_t reset; |
1479 | int i, did_followup_srst, rc; | 1500 | int i, did_followup_srst, rc; |
1480 | 1501 | ||
1502 | /* about to reset */ | ||
1503 | ata_eh_about_to_do(ap, NULL, ehc->i.action & ATA_EH_RESET_MASK); | ||
1504 | |||
1481 | /* Determine which reset to use and record in ehc->i.action. | 1505 | /* Determine which reset to use and record in ehc->i.action. |
1482 | * prereset() may examine and modify it. | 1506 | * prereset() may examine and modify it. |
1483 | */ | 1507 | */ |
@@ -1526,8 +1550,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify, | |||
1526 | ata_port_printk(ap, KERN_INFO, "%s resetting port\n", | 1550 | ata_port_printk(ap, KERN_INFO, "%s resetting port\n", |
1527 | reset == softreset ? "soft" : "hard"); | 1551 | reset == softreset ? "soft" : "hard"); |
1528 | 1552 | ||
1529 | /* reset */ | 1553 | /* mark that this EH session started with reset */ |
1530 | ata_eh_about_to_do(ap, NULL, ATA_EH_RESET_MASK); | ||
1531 | ehc->i.flags |= ATA_EHI_DID_RESET; | 1554 | ehc->i.flags |= ATA_EHI_DID_RESET; |
1532 | 1555 | ||
1533 | rc = ata_do_reset(ap, reset, classes); | 1556 | rc = ata_do_reset(ap, reset, classes); |
@@ -1590,7 +1613,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify, | |||
1590 | postreset(ap, classes); | 1613 | postreset(ap, classes); |
1591 | 1614 | ||
1592 | /* reset successful, schedule revalidation */ | 1615 | /* reset successful, schedule revalidation */ |
1593 | ata_eh_done(ap, NULL, ATA_EH_RESET_MASK); | 1616 | ata_eh_done(ap, NULL, ehc->i.action & ATA_EH_RESET_MASK); |
1594 | ehc->i.action |= ATA_EH_REVALIDATE; | 1617 | ehc->i.action |= ATA_EH_REVALIDATE; |
1595 | } | 1618 | } |
1596 | 1619 | ||
diff --git a/include/linux/libata.h b/include/linux/libata.h index 6cc497a2b6da..66c3100c2b94 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h | |||
@@ -265,12 +265,14 @@ enum { | |||
265 | 265 | ||
266 | /* ata_eh_info->flags */ | 266 | /* ata_eh_info->flags */ |
267 | ATA_EHI_HOTPLUGGED = (1 << 0), /* could have been hotplugged */ | 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 | ATA_EHI_NO_AUTOPSY = (1 << 2), /* no autopsy */ | 269 | ATA_EHI_NO_AUTOPSY = (1 << 2), /* no autopsy */ |
270 | ATA_EHI_QUIET = (1 << 3), /* be quiet */ | 270 | ATA_EHI_QUIET = (1 << 3), /* be quiet */ |
271 | 271 | ||
272 | ATA_EHI_DID_RESET = (1 << 16), /* already reset this port */ | 272 | ATA_EHI_DID_RESET = (1 << 16), /* already reset this port */ |
273 | 273 | ||
274 | ATA_EHI_RESET_MODIFIER_MASK = ATA_EHI_RESUME_LINK, | ||
275 | |||
274 | /* max repeat if error condition is still set after ->error_handler */ | 276 | /* max repeat if error condition is still set after ->error_handler */ |
275 | ATA_EH_MAX_REPEAT = 5, | 277 | ATA_EH_MAX_REPEAT = 5, |
276 | 278 | ||