diff options
Diffstat (limited to 'drivers/scsi/libata-scsi.c')
-rw-r--r-- | drivers/scsi/libata-scsi.c | 44 |
1 files changed, 43 insertions, 1 deletions
diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c index b007bb409382..9d67c6768335 100644 --- a/drivers/scsi/libata-scsi.c +++ b/drivers/scsi/libata-scsi.c | |||
@@ -717,6 +717,47 @@ int ata_scsi_slave_config(struct scsi_device *sdev) | |||
717 | } | 717 | } |
718 | 718 | ||
719 | /** | 719 | /** |
720 | * ata_scsi_timed_out - SCSI layer time out callback | ||
721 | * @cmd: timed out SCSI command | ||
722 | * | ||
723 | * Handles SCSI layer timeout. We race with normal completion of | ||
724 | * the qc for @cmd. If the qc is already gone, we lose and let | ||
725 | * the scsi command finish (EH_HANDLED). Otherwise, the qc has | ||
726 | * timed out and EH should be invoked. Prevent ata_qc_complete() | ||
727 | * from finishing it by setting EH_SCHEDULED and return | ||
728 | * EH_NOT_HANDLED. | ||
729 | * | ||
730 | * LOCKING: | ||
731 | * Called from timer context | ||
732 | * | ||
733 | * RETURNS: | ||
734 | * EH_HANDLED or EH_NOT_HANDLED | ||
735 | */ | ||
736 | enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd) | ||
737 | { | ||
738 | struct Scsi_Host *host = cmd->device->host; | ||
739 | struct ata_port *ap = (struct ata_port *) &host->hostdata[0]; | ||
740 | unsigned long flags; | ||
741 | struct ata_queued_cmd *qc; | ||
742 | enum scsi_eh_timer_return ret = EH_HANDLED; | ||
743 | |||
744 | DPRINTK("ENTER\n"); | ||
745 | |||
746 | spin_lock_irqsave(&ap->host_set->lock, flags); | ||
747 | qc = ata_qc_from_tag(ap, ap->active_tag); | ||
748 | if (qc) { | ||
749 | assert(qc->scsicmd == cmd); | ||
750 | qc->flags |= ATA_QCFLAG_EH_SCHEDULED; | ||
751 | qc->err_mask |= AC_ERR_TIMEOUT; | ||
752 | ret = EH_NOT_HANDLED; | ||
753 | } | ||
754 | spin_unlock_irqrestore(&ap->host_set->lock, flags); | ||
755 | |||
756 | DPRINTK("EXIT, ret=%d\n", ret); | ||
757 | return ret; | ||
758 | } | ||
759 | |||
760 | /** | ||
720 | * ata_scsi_error - SCSI layer error handler callback | 761 | * ata_scsi_error - SCSI layer error handler callback |
721 | * @host: SCSI host on which error occurred | 762 | * @host: SCSI host on which error occurred |
722 | * | 763 | * |
@@ -741,6 +782,7 @@ int ata_scsi_error(struct Scsi_Host *host) | |||
741 | spin_lock_irqsave(&ap->host_set->lock, flags); | 782 | spin_lock_irqsave(&ap->host_set->lock, flags); |
742 | assert(!(ap->flags & ATA_FLAG_IN_EH)); | 783 | assert(!(ap->flags & ATA_FLAG_IN_EH)); |
743 | ap->flags |= ATA_FLAG_IN_EH; | 784 | ap->flags |= ATA_FLAG_IN_EH; |
785 | assert(ata_qc_from_tag(ap, ap->active_tag) != NULL); | ||
744 | spin_unlock_irqrestore(&ap->host_set->lock, flags); | 786 | spin_unlock_irqrestore(&ap->host_set->lock, flags); |
745 | 787 | ||
746 | ap->ops->eng_timeout(ap); | 788 | ap->ops->eng_timeout(ap); |
@@ -770,7 +812,7 @@ static void __ata_eh_qc_complete(struct ata_queued_cmd *qc) | |||
770 | 812 | ||
771 | spin_lock_irqsave(&ap->host_set->lock, flags); | 813 | spin_lock_irqsave(&ap->host_set->lock, flags); |
772 | qc->scsidone = ata_eh_scsidone; | 814 | qc->scsidone = ata_eh_scsidone; |
773 | ata_qc_complete(qc); | 815 | __ata_qc_complete(qc); |
774 | assert(!ata_tag_valid(qc->tag)); | 816 | assert(!ata_tag_valid(qc->tag)); |
775 | spin_unlock_irqrestore(&ap->host_set->lock, flags); | 817 | spin_unlock_irqrestore(&ap->host_set->lock, flags); |
776 | 818 | ||