aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ata/libata-eh.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/ata/libata-eh.c')
-rw-r--r--drivers/ata/libata-eh.c99
1 files changed, 97 insertions, 2 deletions
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index e7e2ba24ce66..ac6ceed4bb60 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -56,6 +56,7 @@ enum {
56 */ 56 */
57enum { 57enum {
58 ATA_EH_PRERESET_TIMEOUT = 10 * HZ, 58 ATA_EH_PRERESET_TIMEOUT = 10 * HZ,
59 ATA_EH_FASTDRAIN_INTERVAL = 3 * HZ,
59}; 60};
60 61
61/* The following table determines how we sequence resets. Each entry 62/* The following table determines how we sequence resets. Each entry
@@ -361,6 +362,9 @@ void ata_scsi_error(struct Scsi_Host *host)
361 repeat: 362 repeat:
362 /* invoke error handler */ 363 /* invoke error handler */
363 if (ap->ops->error_handler) { 364 if (ap->ops->error_handler) {
365 /* kill fast drain timer */
366 del_timer_sync(&ap->fastdrain_timer);
367
364 /* process port resume request */ 368 /* process port resume request */
365 ata_eh_handle_port_resume(ap); 369 ata_eh_handle_port_resume(ap);
366 370
@@ -576,6 +580,94 @@ void ata_eng_timeout(struct ata_port *ap)
576 DPRINTK("EXIT\n"); 580 DPRINTK("EXIT\n");
577} 581}
578 582
583static int ata_eh_nr_in_flight(struct ata_port *ap)
584{
585 unsigned int tag;
586 int nr = 0;
587
588 /* count only non-internal commands */
589 for (tag = 0; tag < ATA_MAX_QUEUE - 1; tag++)
590 if (ata_qc_from_tag(ap, tag))
591 nr++;
592
593 return nr;
594}
595
596void ata_eh_fastdrain_timerfn(unsigned long arg)
597{
598 struct ata_port *ap = (void *)arg;
599 unsigned long flags;
600 int cnt;
601
602 spin_lock_irqsave(ap->lock, flags);
603
604 cnt = ata_eh_nr_in_flight(ap);
605
606 /* are we done? */
607 if (!cnt)
608 goto out_unlock;
609
610 if (cnt == ap->fastdrain_cnt) {
611 unsigned int tag;
612
613 /* No progress during the last interval, tag all
614 * in-flight qcs as timed out and freeze the port.
615 */
616 for (tag = 0; tag < ATA_MAX_QUEUE - 1; tag++) {
617 struct ata_queued_cmd *qc = ata_qc_from_tag(ap, tag);
618 if (qc)
619 qc->err_mask |= AC_ERR_TIMEOUT;
620 }
621
622 ata_port_freeze(ap);
623 } else {
624 /* some qcs have finished, give it another chance */
625 ap->fastdrain_cnt = cnt;
626 ap->fastdrain_timer.expires =
627 jiffies + ATA_EH_FASTDRAIN_INTERVAL;
628 add_timer(&ap->fastdrain_timer);
629 }
630
631 out_unlock:
632 spin_unlock_irqrestore(ap->lock, flags);
633}
634
635/**
636 * ata_eh_set_pending - set ATA_PFLAG_EH_PENDING and activate fast drain
637 * @ap: target ATA port
638 * @fastdrain: activate fast drain
639 *
640 * Set ATA_PFLAG_EH_PENDING and activate fast drain if @fastdrain
641 * is non-zero and EH wasn't pending before. Fast drain ensures
642 * that EH kicks in in timely manner.
643 *
644 * LOCKING:
645 * spin_lock_irqsave(host lock)
646 */
647static void ata_eh_set_pending(struct ata_port *ap, int fastdrain)
648{
649 int cnt;
650
651 /* already scheduled? */
652 if (ap->pflags & ATA_PFLAG_EH_PENDING)
653 return;
654
655 ap->pflags |= ATA_PFLAG_EH_PENDING;
656
657 if (!fastdrain)
658 return;
659
660 /* do we have in-flight qcs? */
661 cnt = ata_eh_nr_in_flight(ap);
662 if (!cnt)
663 return;
664
665 /* activate fast drain */
666 ap->fastdrain_cnt = cnt;
667 ap->fastdrain_timer.expires = jiffies + ATA_EH_FASTDRAIN_INTERVAL;
668 add_timer(&ap->fastdrain_timer);
669}
670
579/** 671/**
580 * ata_qc_schedule_eh - schedule qc for error handling 672 * ata_qc_schedule_eh - schedule qc for error handling
581 * @qc: command to schedule error handling for 673 * @qc: command to schedule error handling for
@@ -593,7 +685,7 @@ void ata_qc_schedule_eh(struct ata_queued_cmd *qc)
593 WARN_ON(!ap->ops->error_handler); 685 WARN_ON(!ap->ops->error_handler);
594 686
595 qc->flags |= ATA_QCFLAG_FAILED; 687 qc->flags |= ATA_QCFLAG_FAILED;
596 qc->ap->pflags |= ATA_PFLAG_EH_PENDING; 688 ata_eh_set_pending(ap, 1);
597 689
598 /* The following will fail if timeout has already expired. 690 /* The following will fail if timeout has already expired.
599 * ata_scsi_error() takes care of such scmds on EH entry. 691 * ata_scsi_error() takes care of such scmds on EH entry.
@@ -620,7 +712,7 @@ void ata_port_schedule_eh(struct ata_port *ap)
620 if (ap->pflags & ATA_PFLAG_INITIALIZING) 712 if (ap->pflags & ATA_PFLAG_INITIALIZING)
621 return; 713 return;
622 714
623 ap->pflags |= ATA_PFLAG_EH_PENDING; 715 ata_eh_set_pending(ap, 1);
624 scsi_schedule_eh(ap->scsi_host); 716 scsi_schedule_eh(ap->scsi_host);
625 717
626 DPRINTK("port EH scheduled\n"); 718 DPRINTK("port EH scheduled\n");
@@ -644,6 +736,9 @@ int ata_port_abort(struct ata_port *ap)
644 736
645 WARN_ON(!ap->ops->error_handler); 737 WARN_ON(!ap->ops->error_handler);
646 738
739 /* we're gonna abort all commands, no need for fast drain */
740 ata_eh_set_pending(ap, 0);
741
647 for (tag = 0; tag < ATA_MAX_QUEUE; tag++) { 742 for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
648 struct ata_queued_cmd *qc = ata_qc_from_tag(ap, tag); 743 struct ata_queued_cmd *qc = ata_qc_from_tag(ap, tag);
649 744