diff options
Diffstat (limited to 'drivers/scsi/sym53c8xx_2/sym_glue.c')
-rw-r--r-- | drivers/scsi/sym53c8xx_2/sym_glue.c | 205 |
1 files changed, 51 insertions, 154 deletions
diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c index 1fffd2b3c654..9c83b4d39a26 100644 --- a/drivers/scsi/sym53c8xx_2/sym_glue.c +++ b/drivers/scsi/sym53c8xx_2/sym_glue.c | |||
@@ -134,66 +134,17 @@ static void sym2_setup_params(void) | |||
134 | } | 134 | } |
135 | } | 135 | } |
136 | 136 | ||
137 | /* | ||
138 | * We used to try to deal with 64-bit BARs here, but don't any more. | ||
139 | * There are many parts of this driver which would need to be modified | ||
140 | * to handle a 64-bit base address, including scripts. I'm uncomfortable | ||
141 | * with making those changes when I have no way of testing it, so I'm | ||
142 | * just going to disable it. | ||
143 | * | ||
144 | * Note that some machines (eg HP rx8620 and Superdome) have bus addresses | ||
145 | * below 4GB and physical addresses above 4GB. These will continue to work. | ||
146 | */ | ||
147 | static int __devinit | ||
148 | pci_get_base_address(struct pci_dev *pdev, int index, unsigned long *basep) | ||
149 | { | ||
150 | u32 tmp; | ||
151 | unsigned long base; | ||
152 | #define PCI_BAR_OFFSET(index) (PCI_BASE_ADDRESS_0 + (index<<2)) | ||
153 | |||
154 | pci_read_config_dword(pdev, PCI_BAR_OFFSET(index++), &tmp); | ||
155 | base = tmp; | ||
156 | if ((tmp & 0x7) == PCI_BASE_ADDRESS_MEM_TYPE_64) { | ||
157 | pci_read_config_dword(pdev, PCI_BAR_OFFSET(index++), &tmp); | ||
158 | if (tmp > 0) { | ||
159 | dev_err(&pdev->dev, | ||
160 | "BAR %d is 64-bit, disabling\n", index - 1); | ||
161 | base = 0; | ||
162 | } | ||
163 | } | ||
164 | |||
165 | if ((base & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) { | ||
166 | base &= PCI_BASE_ADDRESS_IO_MASK; | ||
167 | } else { | ||
168 | base &= PCI_BASE_ADDRESS_MEM_MASK; | ||
169 | } | ||
170 | |||
171 | *basep = base; | ||
172 | return index; | ||
173 | #undef PCI_BAR_OFFSET | ||
174 | } | ||
175 | |||
176 | static struct scsi_transport_template *sym2_transport_template = NULL; | 137 | static struct scsi_transport_template *sym2_transport_template = NULL; |
177 | 138 | ||
178 | /* | 139 | /* |
179 | * Used by the eh thread to wait for command completion. | ||
180 | * It is allocated on the eh thread stack. | ||
181 | */ | ||
182 | struct sym_eh_wait { | ||
183 | struct completion done; | ||
184 | struct timer_list timer; | ||
185 | void (*old_done)(struct scsi_cmnd *); | ||
186 | int to_do; | ||
187 | int timed_out; | ||
188 | }; | ||
189 | |||
190 | /* | ||
191 | * Driver private area in the SCSI command structure. | 140 | * Driver private area in the SCSI command structure. |
192 | */ | 141 | */ |
193 | struct sym_ucmd { /* Override the SCSI pointer structure */ | 142 | struct sym_ucmd { /* Override the SCSI pointer structure */ |
194 | dma_addr_t data_mapping; | 143 | dma_addr_t data_mapping; |
195 | u_char data_mapped; | 144 | unsigned char data_mapped; |
196 | struct sym_eh_wait *eh_wait; | 145 | unsigned char to_do; /* For error handling */ |
146 | void (*old_done)(struct scsi_cmnd *); /* For error handling */ | ||
147 | struct completion *eh_done; /* For error handling */ | ||
197 | }; | 148 | }; |
198 | 149 | ||
199 | #define SYM_UCMD_PTR(cmd) ((struct sym_ucmd *)(&(cmd)->SCp)) | 150 | #define SYM_UCMD_PTR(cmd) ((struct sym_ucmd *)(&(cmd)->SCp)) |
@@ -514,8 +465,6 @@ static inline int sym_setup_cdb(struct sym_hcb *np, struct scsi_cmnd *cmd, struc | |||
514 | */ | 465 | */ |
515 | int sym_setup_data_and_start(struct sym_hcb *np, struct scsi_cmnd *cmd, struct sym_ccb *cp) | 466 | int sym_setup_data_and_start(struct sym_hcb *np, struct scsi_cmnd *cmd, struct sym_ccb *cp) |
516 | { | 467 | { |
517 | struct sym_tcb *tp = &np->target[cp->target]; | ||
518 | struct sym_lcb *lp = sym_lp(tp, cp->lun); | ||
519 | u32 lastp, goalp; | 468 | u32 lastp, goalp; |
520 | int dir; | 469 | int dir; |
521 | 470 | ||
@@ -596,7 +545,7 @@ int sym_setup_data_and_start(struct sym_hcb *np, struct scsi_cmnd *cmd, struct s | |||
596 | /* | 545 | /* |
597 | * activate this job. | 546 | * activate this job. |
598 | */ | 547 | */ |
599 | sym_start_next_ccbs(np, lp, 2); | 548 | sym_put_start_queue(np, cp); |
600 | return 0; | 549 | return 0; |
601 | 550 | ||
602 | out_abort: | 551 | out_abort: |
@@ -751,80 +700,54 @@ static void sym53c8xx_timer(unsigned long npref) | |||
751 | * What we will do regarding the involved SCSI command. | 700 | * What we will do regarding the involved SCSI command. |
752 | */ | 701 | */ |
753 | #define SYM_EH_DO_IGNORE 0 | 702 | #define SYM_EH_DO_IGNORE 0 |
754 | #define SYM_EH_DO_COMPLETE 1 | ||
755 | #define SYM_EH_DO_WAIT 2 | 703 | #define SYM_EH_DO_WAIT 2 |
756 | 704 | ||
757 | /* | 705 | /* |
758 | * Our general completion handler. | 706 | * scsi_done() alias when error recovery is in progress. |
759 | */ | 707 | */ |
760 | static void __sym_eh_done(struct scsi_cmnd *cmd, int timed_out) | 708 | static void sym_eh_done(struct scsi_cmnd *cmd) |
761 | { | 709 | { |
762 | struct sym_eh_wait *ep = SYM_UCMD_PTR(cmd)->eh_wait; | 710 | struct sym_ucmd *ucmd = SYM_UCMD_PTR(cmd); |
763 | if (!ep) | 711 | BUILD_BUG_ON(sizeof(struct scsi_pointer) < sizeof(struct sym_ucmd)); |
764 | return; | ||
765 | |||
766 | /* Try to avoid a race here (not 100% safe) */ | ||
767 | if (!timed_out) { | ||
768 | ep->timed_out = 0; | ||
769 | if (ep->to_do == SYM_EH_DO_WAIT && !del_timer(&ep->timer)) | ||
770 | return; | ||
771 | } | ||
772 | 712 | ||
773 | /* Revert everything */ | 713 | cmd->scsi_done = ucmd->old_done; |
774 | SYM_UCMD_PTR(cmd)->eh_wait = NULL; | ||
775 | cmd->scsi_done = ep->old_done; | ||
776 | 714 | ||
777 | /* Wake up the eh thread if it wants to sleep */ | 715 | if (ucmd->to_do == SYM_EH_DO_WAIT) |
778 | if (ep->to_do == SYM_EH_DO_WAIT) | 716 | complete(ucmd->eh_done); |
779 | complete(&ep->done); | ||
780 | } | 717 | } |
781 | 718 | ||
782 | /* | 719 | /* |
783 | * scsi_done() alias when error recovery is in progress. | ||
784 | */ | ||
785 | static void sym_eh_done(struct scsi_cmnd *cmd) { __sym_eh_done(cmd, 0); } | ||
786 | |||
787 | /* | ||
788 | * Some timeout handler to avoid waiting too long. | ||
789 | */ | ||
790 | static void sym_eh_timeout(u_long p) { __sym_eh_done((struct scsi_cmnd *)p, 1); } | ||
791 | |||
792 | /* | ||
793 | * Generic method for our eh processing. | 720 | * Generic method for our eh processing. |
794 | * The 'op' argument tells what we have to do. | 721 | * The 'op' argument tells what we have to do. |
795 | */ | 722 | */ |
796 | static int sym_eh_handler(int op, char *opname, struct scsi_cmnd *cmd) | 723 | static int sym_eh_handler(int op, char *opname, struct scsi_cmnd *cmd) |
797 | { | 724 | { |
798 | 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; | ||
799 | SYM_QUEHEAD *qp; | 728 | SYM_QUEHEAD *qp; |
800 | int to_do = SYM_EH_DO_IGNORE; | 729 | int to_do = SYM_EH_DO_IGNORE; |
801 | int sts = -1; | 730 | int sts = -1; |
802 | struct sym_eh_wait eh, *ep = &eh; | 731 | struct completion eh_done; |
803 | 732 | ||
804 | dev_warn(&cmd->device->sdev_gendev, "%s operation started.\n", opname); | 733 | dev_warn(&cmd->device->sdev_gendev, "%s operation started.\n", opname); |
805 | 734 | ||
735 | spin_lock_irq(host->host_lock); | ||
806 | /* This one is queued in some place -> to wait for completion */ | 736 | /* This one is queued in some place -> to wait for completion */ |
807 | FOR_EACH_QUEUED_ELEMENT(&np->busy_ccbq, qp) { | 737 | FOR_EACH_QUEUED_ELEMENT(&np->busy_ccbq, qp) { |
808 | struct sym_ccb *cp = sym_que_entry(qp, struct sym_ccb, link_ccbq); | 738 | struct sym_ccb *cp = sym_que_entry(qp, struct sym_ccb, link_ccbq); |
809 | if (cp->cmd == cmd) { | 739 | if (cp->cmd == cmd) { |
810 | to_do = SYM_EH_DO_WAIT; | 740 | to_do = SYM_EH_DO_WAIT; |
811 | goto prepare; | 741 | break; |
812 | } | 742 | } |
813 | } | 743 | } |
814 | 744 | ||
815 | prepare: | 745 | if (to_do == SYM_EH_DO_WAIT) { |
816 | /* Prepare stuff to either ignore, complete or wait for completion */ | 746 | init_completion(&eh_done); |
817 | switch(to_do) { | 747 | ucmd->old_done = cmd->scsi_done; |
818 | default: | 748 | ucmd->eh_done = &eh_done; |
819 | case SYM_EH_DO_IGNORE: | 749 | wmb(); |
820 | break; | ||
821 | case SYM_EH_DO_WAIT: | ||
822 | init_completion(&ep->done); | ||
823 | /* fall through */ | ||
824 | case SYM_EH_DO_COMPLETE: | ||
825 | ep->old_done = cmd->scsi_done; | ||
826 | cmd->scsi_done = sym_eh_done; | 750 | cmd->scsi_done = sym_eh_done; |
827 | SYM_UCMD_PTR(cmd)->eh_wait = ep; | ||
828 | } | 751 | } |
829 | 752 | ||
830 | /* Try to proceed the operation we have been asked for */ | 753 | /* Try to proceed the operation we have been asked for */ |
@@ -851,29 +774,19 @@ prepare: | |||
851 | 774 | ||
852 | /* On error, restore everything and cross fingers :) */ | 775 | /* On error, restore everything and cross fingers :) */ |
853 | if (sts) { | 776 | if (sts) { |
854 | SYM_UCMD_PTR(cmd)->eh_wait = NULL; | 777 | cmd->scsi_done = ucmd->old_done; |
855 | cmd->scsi_done = ep->old_done; | ||
856 | to_do = SYM_EH_DO_IGNORE; | 778 | to_do = SYM_EH_DO_IGNORE; |
857 | } | 779 | } |
858 | 780 | ||
859 | ep->to_do = to_do; | 781 | ucmd->to_do = to_do; |
860 | /* Complete the command with locks held as required by the driver */ | 782 | spin_unlock_irq(host->host_lock); |
861 | if (to_do == SYM_EH_DO_COMPLETE) | ||
862 | sym_xpt_done2(np, cmd, DID_ABORT); | ||
863 | 783 | ||
864 | /* Wait for completion with locks released, as required by kernel */ | ||
865 | if (to_do == SYM_EH_DO_WAIT) { | 784 | if (to_do == SYM_EH_DO_WAIT) { |
866 | init_timer(&ep->timer); | 785 | if (!wait_for_completion_timeout(&eh_done, 5*HZ)) { |
867 | ep->timer.expires = jiffies + (5*HZ); | 786 | ucmd->to_do = SYM_EH_DO_IGNORE; |
868 | ep->timer.function = sym_eh_timeout; | 787 | wmb(); |
869 | ep->timer.data = (u_long)cmd; | ||
870 | ep->timed_out = 1; /* Be pessimistic for once :) */ | ||
871 | add_timer(&ep->timer); | ||
872 | spin_unlock_irq(np->s.host->host_lock); | ||
873 | wait_for_completion(&ep->done); | ||
874 | spin_lock_irq(np->s.host->host_lock); | ||
875 | if (ep->timed_out) | ||
876 | sts = -2; | 788 | sts = -2; |
789 | } | ||
877 | } | 790 | } |
878 | dev_warn(&cmd->device->sdev_gendev, "%s operation %s.\n", opname, | 791 | dev_warn(&cmd->device->sdev_gendev, "%s operation %s.\n", opname, |
879 | sts==0 ? "complete" :sts==-2 ? "timed-out" : "failed"); | 792 | sts==0 ? "complete" :sts==-2 ? "timed-out" : "failed"); |
@@ -886,46 +799,22 @@ prepare: | |||
886 | */ | 799 | */ |
887 | static int sym53c8xx_eh_abort_handler(struct scsi_cmnd *cmd) | 800 | static int sym53c8xx_eh_abort_handler(struct scsi_cmnd *cmd) |
888 | { | 801 | { |
889 | int rc; | 802 | return sym_eh_handler(SYM_EH_ABORT, "ABORT", cmd); |
890 | |||
891 | spin_lock_irq(cmd->device->host->host_lock); | ||
892 | rc = sym_eh_handler(SYM_EH_ABORT, "ABORT", cmd); | ||
893 | spin_unlock_irq(cmd->device->host->host_lock); | ||
894 | |||
895 | return rc; | ||
896 | } | 803 | } |
897 | 804 | ||
898 | static int sym53c8xx_eh_device_reset_handler(struct scsi_cmnd *cmd) | 805 | static int sym53c8xx_eh_device_reset_handler(struct scsi_cmnd *cmd) |
899 | { | 806 | { |
900 | int rc; | 807 | return sym_eh_handler(SYM_EH_DEVICE_RESET, "DEVICE RESET", cmd); |
901 | |||
902 | spin_lock_irq(cmd->device->host->host_lock); | ||
903 | rc = sym_eh_handler(SYM_EH_DEVICE_RESET, "DEVICE RESET", cmd); | ||
904 | spin_unlock_irq(cmd->device->host->host_lock); | ||
905 | |||
906 | return rc; | ||
907 | } | 808 | } |
908 | 809 | ||
909 | static int sym53c8xx_eh_bus_reset_handler(struct scsi_cmnd *cmd) | 810 | static int sym53c8xx_eh_bus_reset_handler(struct scsi_cmnd *cmd) |
910 | { | 811 | { |
911 | int rc; | 812 | return sym_eh_handler(SYM_EH_BUS_RESET, "BUS RESET", cmd); |
912 | |||
913 | spin_lock_irq(cmd->device->host->host_lock); | ||
914 | rc = sym_eh_handler(SYM_EH_BUS_RESET, "BUS RESET", cmd); | ||
915 | spin_unlock_irq(cmd->device->host->host_lock); | ||
916 | |||
917 | return rc; | ||
918 | } | 813 | } |
919 | 814 | ||
920 | static int sym53c8xx_eh_host_reset_handler(struct scsi_cmnd *cmd) | 815 | static int sym53c8xx_eh_host_reset_handler(struct scsi_cmnd *cmd) |
921 | { | 816 | { |
922 | int rc; | 817 | return sym_eh_handler(SYM_EH_HOST_RESET, "HOST RESET", cmd); |
923 | |||
924 | spin_lock_irq(cmd->device->host->host_lock); | ||
925 | rc = sym_eh_handler(SYM_EH_HOST_RESET, "HOST RESET", cmd); | ||
926 | spin_unlock_irq(cmd->device->host->host_lock); | ||
927 | |||
928 | return rc; | ||
929 | } | 818 | } |
930 | 819 | ||
931 | /* | 820 | /* |
@@ -944,15 +833,12 @@ static void sym_tune_dev_queuing(struct sym_tcb *tp, int lun, u_short reqtags) | |||
944 | if (reqtags > lp->s.scdev_depth) | 833 | if (reqtags > lp->s.scdev_depth) |
945 | reqtags = lp->s.scdev_depth; | 834 | reqtags = lp->s.scdev_depth; |
946 | 835 | ||
947 | lp->started_limit = reqtags ? reqtags : 2; | ||
948 | lp->started_max = 1; | ||
949 | lp->s.reqtags = reqtags; | 836 | lp->s.reqtags = reqtags; |
950 | 837 | ||
951 | if (reqtags != oldtags) { | 838 | if (reqtags != oldtags) { |
952 | dev_info(&tp->starget->dev, | 839 | dev_info(&tp->starget->dev, |
953 | "tagged command queuing %s, command queue depth %d.\n", | 840 | "tagged command queuing %s, command queue depth %d.\n", |
954 | lp->s.reqtags ? "enabled" : "disabled", | 841 | lp->s.reqtags ? "enabled" : "disabled", reqtags); |
955 | lp->started_limit); | ||
956 | } | 842 | } |
957 | } | 843 | } |
958 | 844 | ||
@@ -1866,15 +1752,25 @@ static int __devinit sym_set_workarounds(struct sym_device *device) | |||
1866 | static void __devinit | 1752 | static void __devinit |
1867 | sym_init_device(struct pci_dev *pdev, struct sym_device *device) | 1753 | sym_init_device(struct pci_dev *pdev, struct sym_device *device) |
1868 | { | 1754 | { |
1869 | int i; | 1755 | int i = 2; |
1756 | struct pci_bus_region bus_addr; | ||
1870 | 1757 | ||
1871 | device->host_id = SYM_SETUP_HOST_ID; | 1758 | device->host_id = SYM_SETUP_HOST_ID; |
1872 | device->pdev = pdev; | 1759 | device->pdev = pdev; |
1873 | 1760 | ||
1874 | i = pci_get_base_address(pdev, 1, &device->mmio_base); | 1761 | pcibios_resource_to_bus(pdev, &bus_addr, &pdev->resource[1]); |
1875 | pci_get_base_address(pdev, i, &device->ram_base); | 1762 | device->mmio_base = bus_addr.start; |
1763 | |||
1764 | /* | ||
1765 | * If the BAR is 64-bit, resource 2 will be occupied by the | ||
1766 | * upper 32 bits | ||
1767 | */ | ||
1768 | if (!pdev->resource[i].flags) | ||
1769 | i++; | ||
1770 | pcibios_resource_to_bus(pdev, &bus_addr, &pdev->resource[i]); | ||
1771 | device->ram_base = bus_addr.start; | ||
1876 | 1772 | ||
1877 | #ifndef CONFIG_SCSI_SYM53C8XX_IOMAPPED | 1773 | #ifdef CONFIG_SCSI_SYM53C8XX_MMIO |
1878 | if (device->mmio_base) | 1774 | if (device->mmio_base) |
1879 | device->s.ioaddr = pci_iomap(pdev, 1, | 1775 | device->s.ioaddr = pci_iomap(pdev, 1, |
1880 | pci_resource_len(pdev, 1)); | 1776 | pci_resource_len(pdev, 1)); |
@@ -1978,7 +1874,8 @@ static struct scsi_host_template sym2_template = { | |||
1978 | .eh_bus_reset_handler = sym53c8xx_eh_bus_reset_handler, | 1874 | .eh_bus_reset_handler = sym53c8xx_eh_bus_reset_handler, |
1979 | .eh_host_reset_handler = sym53c8xx_eh_host_reset_handler, | 1875 | .eh_host_reset_handler = sym53c8xx_eh_host_reset_handler, |
1980 | .this_id = 7, | 1876 | .this_id = 7, |
1981 | .use_clustering = DISABLE_CLUSTERING, | 1877 | .use_clustering = ENABLE_CLUSTERING, |
1878 | .max_sectors = 0xFFFF, | ||
1982 | #ifdef SYM_LINUX_PROC_INFO_SUPPORT | 1879 | #ifdef SYM_LINUX_PROC_INFO_SUPPORT |
1983 | .proc_info = sym53c8xx_proc_info, | 1880 | .proc_info = sym53c8xx_proc_info, |
1984 | .proc_name = NAME53C8XX, | 1881 | .proc_name = NAME53C8XX, |