diff options
author | Tejun Heo <htejun@gmail.com> | 2006-01-22 23:09:37 -0500 |
---|---|---|
committer | Jeff Garzik <jgarzik@pobox.com> | 2006-01-26 22:36:28 -0500 |
commit | a72ec4ce6d3ae92e76baf5b2c65cc26e5e775e83 (patch) | |
tree | f5a177cc30c9b39d8ae7dcad29d03d27534b9f78 /drivers/scsi/libata-scsi.c | |
parent | 041c5fc33cb7ed4fe5322585a611fb6e29a05d3a (diff) |
[PATCH] libata: implement and apply ata_eh_qc_complete/retry()
Implement ata_eh_qc_complete/retry() using scsi_eh_finish_cmd() and
scsi_eh_flush_done_q(). This removes all eh scsicmd finish hacks from
low level drivers.
This change was first suggested by Jeff Garzik.
Signed-off-by: Tejun Heo <htejun@gmail.com>
Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
Diffstat (limited to 'drivers/scsi/libata-scsi.c')
-rw-r--r-- | drivers/scsi/libata-scsi.c | 59 |
1 files changed, 53 insertions, 6 deletions
diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c index 95e3c278dd43..ab6b53349d6f 100644 --- a/drivers/scsi/libata-scsi.c +++ b/drivers/scsi/libata-scsi.c | |||
@@ -738,17 +738,64 @@ int ata_scsi_error(struct Scsi_Host *host) | |||
738 | ap = (struct ata_port *) &host->hostdata[0]; | 738 | ap = (struct ata_port *) &host->hostdata[0]; |
739 | ap->ops->eng_timeout(ap); | 739 | ap->ops->eng_timeout(ap); |
740 | 740 | ||
741 | /* TODO: this is per-command; when queueing is supported | 741 | assert(host->host_failed == 0 && list_empty(&host->eh_cmd_q)); |
742 | * this code will either change or move to a more | 742 | |
743 | * appropriate place | 743 | scsi_eh_flush_done_q(&ap->eh_done_q); |
744 | */ | ||
745 | host->host_failed--; | ||
746 | INIT_LIST_HEAD(&host->eh_cmd_q); | ||
747 | 744 | ||
748 | DPRINTK("EXIT\n"); | 745 | DPRINTK("EXIT\n"); |
749 | return 0; | 746 | return 0; |
750 | } | 747 | } |
751 | 748 | ||
749 | static void ata_eh_scsidone(struct scsi_cmnd *scmd) | ||
750 | { | ||
751 | /* nada */ | ||
752 | } | ||
753 | |||
754 | static void __ata_eh_qc_complete(struct ata_queued_cmd *qc) | ||
755 | { | ||
756 | struct ata_port *ap = qc->ap; | ||
757 | struct scsi_cmnd *scmd = qc->scsicmd; | ||
758 | unsigned long flags; | ||
759 | |||
760 | spin_lock_irqsave(&ap->host_set->lock, flags); | ||
761 | qc->scsidone = ata_eh_scsidone; | ||
762 | ata_qc_complete(qc); | ||
763 | assert(!ata_tag_valid(qc->tag)); | ||
764 | spin_unlock_irqrestore(&ap->host_set->lock, flags); | ||
765 | |||
766 | scsi_eh_finish_cmd(scmd, &ap->eh_done_q); | ||
767 | } | ||
768 | |||
769 | /** | ||
770 | * ata_eh_qc_complete - Complete an active ATA command from EH | ||
771 | * @qc: Command to complete | ||
772 | * | ||
773 | * Indicate to the mid and upper layers that an ATA command has | ||
774 | * completed. To be used from EH. | ||
775 | */ | ||
776 | void ata_eh_qc_complete(struct ata_queued_cmd *qc) | ||
777 | { | ||
778 | struct scsi_cmnd *scmd = qc->scsicmd; | ||
779 | scmd->retries = scmd->allowed; | ||
780 | __ata_eh_qc_complete(qc); | ||
781 | } | ||
782 | |||
783 | /** | ||
784 | * ata_eh_qc_retry - Tell midlayer to retry an ATA command after EH | ||
785 | * @qc: Command to retry | ||
786 | * | ||
787 | * Indicate to the mid and upper layers that an ATA command | ||
788 | * should be retried. To be used from EH. | ||
789 | * | ||
790 | * SCSI midlayer limits the number of retries to scmd->allowed. | ||
791 | * This function might need to adjust scmd->retries for commands | ||
792 | * which get retried due to unrelated NCQ failures. | ||
793 | */ | ||
794 | void ata_eh_qc_retry(struct ata_queued_cmd *qc) | ||
795 | { | ||
796 | __ata_eh_qc_complete(qc); | ||
797 | } | ||
798 | |||
752 | /** | 799 | /** |
753 | * ata_scsi_start_stop_xlat - Translate SCSI START STOP UNIT command | 800 | * ata_scsi_start_stop_xlat - Translate SCSI START STOP UNIT command |
754 | * @qc: Storage for translated ATA taskfile | 801 | * @qc: Storage for translated ATA taskfile |