diff options
Diffstat (limited to 'drivers/scsi/sym53c8xx_2')
-rw-r--r-- | drivers/scsi/sym53c8xx_2/sym_glue.c | 60 |
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 | */ |
136 | struct sym_ucmd { /* Override the SCSI pointer structure */ | 136 | struct 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 | */ |
148 | void sym_xpt_done(struct sym_hcb *np, struct scsi_cmnd *cmd) | 146 | void 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 | */ | ||
597 | static 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; |