aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthew Wilcox <matthew@wil.cx>2006-03-28 11:03:44 -0500
committerJames Bottomley <jejb@mulgrave.il.steeleye.com>2006-04-13 11:13:25 -0400
commitb4e93a739ed1352664defd41d5e4f82afa29b928 (patch)
tree1799983732dd5dbedd59eb69661f11f49a7f1217
parentc2349df918cdfd47dfe6afaaeed9f504b83255d0 (diff)
[SCSI] Simplify error handling
Use wait_for_completion_timeout() instead of using a timer (as Christoph Hellwig did for aic7xxx). That lets me eliminate the sym_eh_wait structure; the struct completion, the old_done pointer and the to_do flag can be folded into the sym_ucmd (which overrides the scsi_pointer in scsi_cmnd). The sym_eh_done() function becomes much simpler as the timeout handling is done in sym_eh_handler() directly. The host_lock can be unlocked earlier, and I cache the host in a local variable to make accesses to it quicker. Signed-off-by: Matthew Wilcox <matthew@wil.cx> Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
-rw-r--r--drivers/scsi/sym53c8xx_2/sym_glue.c84
1 files changed, 22 insertions, 62 deletions
diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c
index a27dd66b6613..e48409e26e5f 100644
--- a/drivers/scsi/sym53c8xx_2/sym_glue.c
+++ b/drivers/scsi/sym53c8xx_2/sym_glue.c
@@ -137,24 +137,14 @@ static void sym2_setup_params(void)
137static struct scsi_transport_template *sym2_transport_template = NULL; 137static struct scsi_transport_template *sym2_transport_template = NULL;
138 138
139/* 139/*
140 * Used by the eh thread to wait for command completion.
141 * It is allocated on the eh thread stack.
142 */
143struct sym_eh_wait {
144 struct completion done;
145 struct timer_list timer;
146 void (*old_done)(struct scsi_cmnd *);
147 int to_do;
148 int timed_out;
149};
150
151/*
152 * Driver private area in the SCSI command structure. 140 * Driver private area in the SCSI command structure.
153 */ 141 */
154struct sym_ucmd { /* Override the SCSI pointer structure */ 142struct sym_ucmd { /* Override the SCSI pointer structure */
143 struct completion done;
144 void (*old_done)(struct scsi_cmnd *);
155 dma_addr_t data_mapping; 145 dma_addr_t data_mapping;
156 u_char data_mapped; 146 int to_do;
157 struct sym_eh_wait *eh_wait; 147 u_char data_mapped; /* corresponds to data_mapping above */
158}; 148};
159 149
160#define SYM_UCMD_PTR(cmd) ((struct sym_ucmd *)(&(cmd)->SCp)) 150#define SYM_UCMD_PTR(cmd) ((struct sym_ucmd *)(&(cmd)->SCp))
@@ -713,55 +703,35 @@ static void sym53c8xx_timer(unsigned long npref)
713#define SYM_EH_DO_WAIT 2 703#define SYM_EH_DO_WAIT 2
714 704
715/* 705/*
716 * Our general completion handler. 706 * scsi_done() alias when error recovery is in progress.
717 */ 707 */
718static void __sym_eh_done(struct scsi_cmnd *cmd, int timed_out) 708static void sym_eh_done(struct scsi_cmnd *cmd)
719{ 709{
720 struct sym_eh_wait *ep = SYM_UCMD_PTR(cmd)->eh_wait; 710 struct sym_ucmd *ucmd = SYM_UCMD_PTR(cmd);
721 if (!ep) 711 BUILD_BUG_ON(sizeof(struct scsi_pointer) < sizeof(struct sym_ucmd));
722 return;
723
724 /* Try to avoid a race here (not 100% safe) */
725 if (!timed_out) {
726 ep->timed_out = 0;
727 if (ep->to_do == SYM_EH_DO_WAIT && !del_timer(&ep->timer))
728 return;
729 }
730 712
731 /* Revert everything */ 713 cmd->scsi_done = ucmd->old_done;
732 SYM_UCMD_PTR(cmd)->eh_wait = NULL;
733 cmd->scsi_done = ep->old_done;
734 714
735 /* Wake up the eh thread if it wants to sleep */ 715 if (ucmd->to_do == SYM_EH_DO_WAIT)
736 if (ep->to_do == SYM_EH_DO_WAIT) 716 complete(&ucmd->done);
737 complete(&ep->done);
738} 717}
739 718
740/* 719/*
741 * scsi_done() alias when error recovery is in progress.
742 */
743static void sym_eh_done(struct scsi_cmnd *cmd) { __sym_eh_done(cmd, 0); }
744
745/*
746 * Some timeout handler to avoid waiting too long.
747 */
748static void sym_eh_timeout(u_long p) { __sym_eh_done((struct scsi_cmnd *)p, 1); }
749
750/*
751 * Generic method for our eh processing. 720 * Generic method for our eh processing.
752 * The 'op' argument tells what we have to do. 721 * The 'op' argument tells what we have to do.
753 */ 722 */
754static int sym_eh_handler(int op, char *opname, struct scsi_cmnd *cmd) 723static int sym_eh_handler(int op, char *opname, struct scsi_cmnd *cmd)
755{ 724{
756 struct sym_hcb *np = SYM_SOFTC_PTR(cmd); 725 struct sym_hcb *np = SYM_SOFTC_PTR(cmd);
726 struct sym_ucmd *ucmd = SYM_UCMD_PTR(cmd);
727 struct Scsi_Host *host = cmd->device->host;
757 SYM_QUEHEAD *qp; 728 SYM_QUEHEAD *qp;
758 int to_do = SYM_EH_DO_IGNORE; 729 int to_do = SYM_EH_DO_IGNORE;
759 int sts = -1; 730 int sts = -1;
760 struct sym_eh_wait eh, *ep = &eh;
761 731
762 dev_warn(&cmd->device->sdev_gendev, "%s operation started.\n", opname); 732 dev_warn(&cmd->device->sdev_gendev, "%s operation started.\n", opname);
763 733
764 spin_lock_irq(cmd->device->host->host_lock); 734 spin_lock_irq(host->host_lock);
765 /* This one is queued in some place -> to wait for completion */ 735 /* This one is queued in some place -> to wait for completion */
766 FOR_EACH_QUEUED_ELEMENT(&np->busy_ccbq, qp) { 736 FOR_EACH_QUEUED_ELEMENT(&np->busy_ccbq, qp) {
767 struct sym_ccb *cp = sym_que_entry(qp, struct sym_ccb, link_ccbq); 737 struct sym_ccb *cp = sym_que_entry(qp, struct sym_ccb, link_ccbq);
@@ -772,10 +742,9 @@ static int sym_eh_handler(int op, char *opname, struct scsi_cmnd *cmd)
772 } 742 }
773 743
774 if (to_do == SYM_EH_DO_WAIT) { 744 if (to_do == SYM_EH_DO_WAIT) {
775 init_completion(&ep->done); 745 init_completion(&ucmd->done);
776 ep->old_done = cmd->scsi_done; 746 ucmd->old_done = cmd->scsi_done;
777 cmd->scsi_done = sym_eh_done; 747 cmd->scsi_done = sym_eh_done;
778 SYM_UCMD_PTR(cmd)->eh_wait = ep;
779 } 748 }
780 749
781 /* Try to proceed the operation we have been asked for */ 750 /* Try to proceed the operation we have been asked for */
@@ -802,28 +771,19 @@ static int sym_eh_handler(int op, char *opname, struct scsi_cmnd *cmd)
802 771
803 /* On error, restore everything and cross fingers :) */ 772 /* On error, restore everything and cross fingers :) */
804 if (sts) { 773 if (sts) {
805 SYM_UCMD_PTR(cmd)->eh_wait = NULL; 774 cmd->scsi_done = ucmd->old_done;
806 cmd->scsi_done = ep->old_done;
807 to_do = SYM_EH_DO_IGNORE; 775 to_do = SYM_EH_DO_IGNORE;
808 } 776 }
809 777
810 ep->to_do = to_do; 778 ucmd->to_do = to_do;
779 spin_unlock_irq(host->host_lock);
811 780
812 /* Wait for completion with locks released, as required by kernel */
813 if (to_do == SYM_EH_DO_WAIT) { 781 if (to_do == SYM_EH_DO_WAIT) {
814 init_timer(&ep->timer); 782 if (!wait_for_completion_timeout(&ucmd->done, 5*HZ)) {
815 ep->timer.expires = jiffies + (5*HZ); 783 ucmd->to_do = SYM_EH_DO_IGNORE;
816 ep->timer.function = sym_eh_timeout;
817 ep->timer.data = (u_long)cmd;
818 ep->timed_out = 1; /* Be pessimistic for once :) */
819 add_timer(&ep->timer);
820 spin_unlock_irq(np->s.host->host_lock);
821 wait_for_completion(&ep->done);
822 spin_lock_irq(np->s.host->host_lock);
823 if (ep->timed_out)
824 sts = -2; 784 sts = -2;
785 }
825 } 786 }
826 spin_unlock_irq(cmd->device->host->host_lock);
827 dev_warn(&cmd->device->sdev_gendev, "%s operation %s.\n", opname, 787 dev_warn(&cmd->device->sdev_gendev, "%s operation %s.\n", opname,
828 sts==0 ? "complete" :sts==-2 ? "timed-out" : "failed"); 788 sts==0 ? "complete" :sts==-2 ? "timed-out" : "failed");
829 return sts ? SCSI_FAILED : SCSI_SUCCESS; 789 return sts ? SCSI_FAILED : SCSI_SUCCESS;