aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/sym53c8xx_2/sym_glue.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/sym53c8xx_2/sym_glue.c')
-rw-r--r--drivers/scsi/sym53c8xx_2/sym_glue.c60
1 files changed, 18 insertions, 42 deletions
diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c
index b5e7c6478653..4de0692f5c4f 100644
--- a/drivers/scsi/sym53c8xx_2/sym_glue.c
+++ b/drivers/scsi/sym53c8xx_2/sym_glue.c
@@ -134,8 +134,6 @@ static struct scsi_transport_template *sym2_transport_template = NULL;
134 * Driver private area in the SCSI command structure. 134 * Driver private area in the SCSI command structure.
135 */ 135 */
136struct sym_ucmd { /* Override the SCSI pointer structure */ 136struct sym_ucmd { /* Override the SCSI pointer structure */
137 unsigned char to_do; /* For error handling */
138 void (*old_done)(struct scsi_cmnd *); /* For error handling */
139 struct completion *eh_done; /* For error handling */ 137 struct completion *eh_done; /* For error handling */
140}; 138};
141 139
@@ -147,6 +145,12 @@ struct sym_ucmd { /* Override the SCSI pointer structure */
147 */ 145 */
148void sym_xpt_done(struct sym_hcb *np, struct scsi_cmnd *cmd) 146void sym_xpt_done(struct sym_hcb *np, struct scsi_cmnd *cmd)
149{ 147{
148 struct sym_ucmd *ucmd = SYM_UCMD_PTR(cmd);
149 BUILD_BUG_ON(sizeof(struct scsi_pointer) < sizeof(struct sym_ucmd));
150
151 if (ucmd->eh_done)
152 complete(ucmd->eh_done);
153
150 scsi_dma_unmap(cmd); 154 scsi_dma_unmap(cmd);
151 cmd->scsi_done(cmd); 155 cmd->scsi_done(cmd);
152} 156}
@@ -586,26 +590,6 @@ static void sym53c8xx_timer(unsigned long npref)
586#define SYM_EH_HOST_RESET 3 590#define SYM_EH_HOST_RESET 3
587 591
588/* 592/*
589 * What we will do regarding the involved SCSI command.
590 */
591#define SYM_EH_DO_IGNORE 0
592#define SYM_EH_DO_WAIT 2
593
594/*
595 * scsi_done() alias when error recovery is in progress.
596 */
597static void sym_eh_done(struct scsi_cmnd *cmd)
598{
599 struct sym_ucmd *ucmd = SYM_UCMD_PTR(cmd);
600 BUILD_BUG_ON(sizeof(struct scsi_pointer) < sizeof(struct sym_ucmd));
601
602 cmd->scsi_done = ucmd->old_done;
603
604 if (ucmd->to_do == SYM_EH_DO_WAIT)
605 complete(ucmd->eh_done);
606}
607
608/*
609 * Generic method for our eh processing. 593 * Generic method for our eh processing.
610 * The 'op' argument tells what we have to do. 594 * The 'op' argument tells what we have to do.
611 */ 595 */
@@ -615,7 +599,7 @@ static int sym_eh_handler(int op, char *opname, struct scsi_cmnd *cmd)
615 struct sym_ucmd *ucmd = SYM_UCMD_PTR(cmd); 599 struct sym_ucmd *ucmd = SYM_UCMD_PTR(cmd);
616 struct Scsi_Host *host = cmd->device->host; 600 struct Scsi_Host *host = cmd->device->host;
617 SYM_QUEHEAD *qp; 601 SYM_QUEHEAD *qp;
618 int to_do = SYM_EH_DO_IGNORE; 602 int cmd_queued = 0;
619 int sts = -1; 603 int sts = -1;
620 struct completion eh_done; 604 struct completion eh_done;
621 605
@@ -626,19 +610,11 @@ static int sym_eh_handler(int op, char *opname, struct scsi_cmnd *cmd)
626 FOR_EACH_QUEUED_ELEMENT(&np->busy_ccbq, qp) { 610 FOR_EACH_QUEUED_ELEMENT(&np->busy_ccbq, qp) {
627 struct sym_ccb *cp = sym_que_entry(qp, struct sym_ccb, link_ccbq); 611 struct sym_ccb *cp = sym_que_entry(qp, struct sym_ccb, link_ccbq);
628 if (cp->cmd == cmd) { 612 if (cp->cmd == cmd) {
629 to_do = SYM_EH_DO_WAIT; 613 cmd_queued = 1;
630 break; 614 break;
631 } 615 }
632 } 616 }
633 617
634 if (to_do == SYM_EH_DO_WAIT) {
635 init_completion(&eh_done);
636 ucmd->old_done = cmd->scsi_done;
637 ucmd->eh_done = &eh_done;
638 wmb();
639 cmd->scsi_done = sym_eh_done;
640 }
641
642 /* Try to proceed the operation we have been asked for */ 618 /* Try to proceed the operation we have been asked for */
643 sts = -1; 619 sts = -1;
644 switch(op) { 620 switch(op) {
@@ -662,21 +638,21 @@ static int sym_eh_handler(int op, char *opname, struct scsi_cmnd *cmd)
662 } 638 }
663 639
664 /* On error, restore everything and cross fingers :) */ 640 /* On error, restore everything and cross fingers :) */
665 if (sts) { 641 if (sts)
666 cmd->scsi_done = ucmd->old_done; 642 cmd_queued = 0;
667 to_do = SYM_EH_DO_IGNORE;
668 }
669
670 ucmd->to_do = to_do;
671 spin_unlock_irq(host->host_lock);
672 643
673 if (to_do == SYM_EH_DO_WAIT) { 644 if (cmd_queued) {
645 init_completion(&eh_done);
646 ucmd->eh_done = &eh_done;
647 spin_unlock_irq(host->host_lock);
674 if (!wait_for_completion_timeout(&eh_done, 5*HZ)) { 648 if (!wait_for_completion_timeout(&eh_done, 5*HZ)) {
675 ucmd->to_do = SYM_EH_DO_IGNORE; 649 ucmd->eh_done = NULL;
676 wmb();
677 sts = -2; 650 sts = -2;
678 } 651 }
652 } else {
653 spin_unlock_irq(host->host_lock);
679 } 654 }
655
680 dev_warn(&cmd->device->sdev_gendev, "%s operation %s.\n", opname, 656 dev_warn(&cmd->device->sdev_gendev, "%s operation %s.\n", opname,
681 sts==0 ? "complete" :sts==-2 ? "timed-out" : "failed"); 657 sts==0 ? "complete" :sts==-2 ? "timed-out" : "failed");
682 return sts ? SCSI_FAILED : SCSI_SUCCESS; 658 return sts ? SCSI_FAILED : SCSI_SUCCESS;