diff options
Diffstat (limited to 'drivers/scsi/tmscsim.c')
-rw-r--r-- | drivers/scsi/tmscsim.c | 124 |
1 files changed, 66 insertions, 58 deletions
diff --git a/drivers/scsi/tmscsim.c b/drivers/scsi/tmscsim.c index 12d8fea3de93..e7b85e832eb5 100644 --- a/drivers/scsi/tmscsim.c +++ b/drivers/scsi/tmscsim.c | |||
@@ -351,6 +351,27 @@ static u8 dc390_clock_speed[] = {100,80,67,57,50, 40, 31, 20}; | |||
351 | * (DCBs, SRBs, Queueing) | 351 | * (DCBs, SRBs, Queueing) |
352 | * | 352 | * |
353 | **********************************************************************/ | 353 | **********************************************************************/ |
354 | static void inline dc390_start_segment(struct dc390_srb* pSRB) | ||
355 | { | ||
356 | struct scatterlist *psgl = pSRB->pSegmentList; | ||
357 | |||
358 | /* start new sg segment */ | ||
359 | pSRB->SGBusAddr = sg_dma_address(psgl); | ||
360 | pSRB->SGToBeXferLen = sg_dma_len(psgl); | ||
361 | } | ||
362 | |||
363 | static unsigned long inline dc390_advance_segment(struct dc390_srb* pSRB, u32 residue) | ||
364 | { | ||
365 | unsigned long xfer = pSRB->SGToBeXferLen - residue; | ||
366 | |||
367 | /* xfer more bytes transferred */ | ||
368 | pSRB->SGBusAddr += xfer; | ||
369 | pSRB->TotalXferredLen += xfer; | ||
370 | pSRB->SGToBeXferLen = residue; | ||
371 | |||
372 | return xfer; | ||
373 | } | ||
374 | |||
354 | static struct dc390_dcb __inline__ *dc390_findDCB ( struct dc390_acb* pACB, u8 id, u8 lun) | 375 | static struct dc390_dcb __inline__ *dc390_findDCB ( struct dc390_acb* pACB, u8 id, u8 lun) |
355 | { | 376 | { |
356 | struct dc390_dcb* pDCB = pACB->pLinkDCB; if (!pDCB) return NULL; | 377 | struct dc390_dcb* pDCB = pACB->pLinkDCB; if (!pDCB) return NULL; |
@@ -741,11 +762,10 @@ static irqreturn_t do_DC390_Interrupt(int irq, void *dev_id) | |||
741 | } | 762 | } |
742 | 763 | ||
743 | static void | 764 | static void |
744 | dc390_DataOut_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus) | 765 | dc390_DataOut_0(struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus) |
745 | { | 766 | { |
746 | u8 sstatus; | 767 | u8 sstatus; |
747 | struct scatterlist *psgl; | 768 | u32 ResidCnt; |
748 | u32 ResidCnt, xferCnt; | ||
749 | u8 dstate = 0; | 769 | u8 dstate = 0; |
750 | 770 | ||
751 | sstatus = *psstatus; | 771 | sstatus = *psstatus; |
@@ -776,25 +796,20 @@ dc390_DataOut_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus) | |||
776 | if( pSRB->SGIndex < pSRB->SGcount ) | 796 | if( pSRB->SGIndex < pSRB->SGcount ) |
777 | { | 797 | { |
778 | pSRB->pSegmentList++; | 798 | pSRB->pSegmentList++; |
779 | psgl = pSRB->pSegmentList; | ||
780 | 799 | ||
781 | pSRB->SGBusAddr = sg_dma_address(psgl); | 800 | dc390_start_segment(pSRB); |
782 | pSRB->SGToBeXferLen = sg_dma_len(psgl); | ||
783 | } | 801 | } |
784 | else | 802 | else |
785 | pSRB->SGToBeXferLen = 0; | 803 | pSRB->SGToBeXferLen = 0; |
786 | } | 804 | } |
787 | else | 805 | else |
788 | { | 806 | { |
789 | ResidCnt = (u32) DC390_read8 (Current_Fifo) & 0x1f; | 807 | ResidCnt = ((u32) DC390_read8 (Current_Fifo) & 0x1f) + |
790 | ResidCnt |= (u32) DC390_read8 (CtcReg_High) << 16; | 808 | (((u32) DC390_read8 (CtcReg_High) << 16) | |
791 | ResidCnt |= (u32) DC390_read8 (CtcReg_Mid) << 8; | 809 | ((u32) DC390_read8 (CtcReg_Mid) << 8) | |
792 | ResidCnt += (u32) DC390_read8 (CtcReg_Low); | 810 | (u32) DC390_read8 (CtcReg_Low)); |
793 | 811 | ||
794 | xferCnt = pSRB->SGToBeXferLen - ResidCnt; | 812 | dc390_advance_segment(pSRB, ResidCnt); |
795 | pSRB->SGBusAddr += xferCnt; | ||
796 | pSRB->TotalXferredLen += xferCnt; | ||
797 | pSRB->SGToBeXferLen = ResidCnt; | ||
798 | } | 813 | } |
799 | } | 814 | } |
800 | if ((*psstatus & 7) != SCSI_DATA_OUT) | 815 | if ((*psstatus & 7) != SCSI_DATA_OUT) |
@@ -805,13 +820,11 @@ dc390_DataOut_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus) | |||
805 | } | 820 | } |
806 | 821 | ||
807 | static void | 822 | static void |
808 | dc390_DataIn_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus) | 823 | dc390_DataIn_0(struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus) |
809 | { | 824 | { |
810 | u8 sstatus, residual, bval; | 825 | u8 sstatus, residual, bval; |
811 | struct scatterlist *psgl; | 826 | u32 ResidCnt, i; |
812 | u32 ResidCnt, i; | ||
813 | unsigned long xferCnt; | 827 | unsigned long xferCnt; |
814 | u8 *ptr; | ||
815 | 828 | ||
816 | sstatus = *psstatus; | 829 | sstatus = *psstatus; |
817 | 830 | ||
@@ -851,10 +864,8 @@ dc390_DataIn_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus) | |||
851 | if( pSRB->SGIndex < pSRB->SGcount ) | 864 | if( pSRB->SGIndex < pSRB->SGcount ) |
852 | { | 865 | { |
853 | pSRB->pSegmentList++; | 866 | pSRB->pSegmentList++; |
854 | psgl = pSRB->pSegmentList; | ||
855 | 867 | ||
856 | pSRB->SGBusAddr = sg_dma_address(psgl); | 868 | dc390_start_segment(pSRB); |
857 | pSRB->SGToBeXferLen = sg_dma_len(psgl); | ||
858 | } | 869 | } |
859 | else | 870 | else |
860 | pSRB->SGToBeXferLen = 0; | 871 | pSRB->SGToBeXferLen = 0; |
@@ -894,41 +905,38 @@ din_1: | |||
894 | /* It seems a DMA Blast abort isn't that bad ... */ | 905 | /* It seems a DMA Blast abort isn't that bad ... */ |
895 | if (!i) printk (KERN_ERR "DC390: DMA Blast aborted unfinished!\n"); | 906 | if (!i) printk (KERN_ERR "DC390: DMA Blast aborted unfinished!\n"); |
896 | //DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD); | 907 | //DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD); |
897 | dc390_laststatus &= ~0xff000000; dc390_laststatus |= bval << 24; | 908 | dc390_laststatus &= ~0xff000000; |
909 | dc390_laststatus |= bval << 24; | ||
898 | 910 | ||
899 | DEBUG1(printk (KERN_DEBUG "Blast: Read %i times DMA_Status %02x", 0xa000-i, bval)); | 911 | DEBUG1(printk (KERN_DEBUG "Blast: Read %i times DMA_Status %02x", 0xa000-i, bval)); |
900 | ResidCnt = (u32) DC390_read8 (CtcReg_High); | 912 | ResidCnt = (((u32) DC390_read8 (CtcReg_High) << 16) | |
901 | ResidCnt <<= 8; | 913 | ((u32) DC390_read8 (CtcReg_Mid) << 8)) | |
902 | ResidCnt |= (u32) DC390_read8 (CtcReg_Mid); | 914 | (u32) DC390_read8 (CtcReg_Low); |
903 | ResidCnt <<= 8; | 915 | |
904 | ResidCnt |= (u32) DC390_read8 (CtcReg_Low); | 916 | xferCnt = dc390_advance_segment(pSRB, ResidCnt); |
905 | 917 | ||
906 | xferCnt = pSRB->SGToBeXferLen - ResidCnt; | 918 | if (residual) { |
907 | pSRB->SGBusAddr += xferCnt; | 919 | size_t count = 1; |
908 | pSRB->TotalXferredLen += xferCnt; | 920 | size_t offset = pSRB->SGBusAddr - sg_dma_address(pSRB->pSegmentList); |
909 | pSRB->SGToBeXferLen = ResidCnt; | 921 | unsigned long flags; |
910 | 922 | u8 *ptr; | |
911 | if( residual ) | 923 | |
912 | { | ||
913 | static int feedback_requested; | ||
914 | bval = DC390_read8 (ScsiFifo); /* get one residual byte */ | 924 | bval = DC390_read8 (ScsiFifo); /* get one residual byte */ |
915 | 925 | ||
916 | if (!feedback_requested) { | 926 | local_irq_save(flags); |
917 | feedback_requested = 1; | 927 | ptr = scsi_kmap_atomic_sg(pSRB->pSegmentList, pSRB->SGcount, &offset, &count); |
918 | printk(KERN_WARNING "%s: Please, contact <linux-scsi@vger.kernel.org> " | 928 | if (likely(ptr)) { |
919 | "to help improve support for your system.\n", __FILE__); | 929 | *(ptr + offset) = bval; |
930 | scsi_kunmap_atomic_sg(ptr); | ||
920 | } | 931 | } |
932 | local_irq_restore(flags); | ||
933 | WARN_ON(!ptr); | ||
921 | 934 | ||
922 | ptr = (u8 *) bus_to_virt( pSRB->SGBusAddr ); | 935 | /* 1 more byte read */ |
923 | *ptr = bval; | 936 | xferCnt += dc390_advance_segment(pSRB, pSRB->SGToBeXferLen - 1); |
924 | pSRB->SGBusAddr++; | ||
925 | xferCnt++; | ||
926 | pSRB->TotalXferredLen++; | ||
927 | pSRB->SGToBeXferLen--; | ||
928 | } | 937 | } |
929 | DEBUG1(printk (KERN_DEBUG "Xfered: %lu, Total: %lu, Remaining: %lu\n", xferCnt,\ | 938 | DEBUG1(printk (KERN_DEBUG "Xfered: %lu, Total: %lu, Remaining: %lu\n", xferCnt,\ |
930 | pSRB->TotalXferredLen, pSRB->SGToBeXferLen)); | 939 | pSRB->TotalXferredLen, pSRB->SGToBeXferLen)); |
931 | |||
932 | } | 940 | } |
933 | } | 941 | } |
934 | if ((*psstatus & 7) != SCSI_DATA_IN) | 942 | if ((*psstatus & 7) != SCSI_DATA_IN) |
@@ -1137,7 +1145,7 @@ dc390_MsgIn_set_sync (struct dc390_acb* pACB, struct dc390_srb* pSRB) | |||
1137 | 1145 | ||
1138 | 1146 | ||
1139 | /* handle RESTORE_PTR */ | 1147 | /* handle RESTORE_PTR */ |
1140 | /* I presume, this command is already mapped, so, have to remap. */ | 1148 | /* This doesn't look very healthy... to-be-fixed */ |
1141 | static void | 1149 | static void |
1142 | dc390_restore_ptr (struct dc390_acb* pACB, struct dc390_srb* pSRB) | 1150 | dc390_restore_ptr (struct dc390_acb* pACB, struct dc390_srb* pSRB) |
1143 | { | 1151 | { |
@@ -1146,6 +1154,7 @@ dc390_restore_ptr (struct dc390_acb* pACB, struct dc390_srb* pSRB) | |||
1146 | pSRB->TotalXferredLen = 0; | 1154 | pSRB->TotalXferredLen = 0; |
1147 | pSRB->SGIndex = 0; | 1155 | pSRB->SGIndex = 0; |
1148 | if (pcmd->use_sg) { | 1156 | if (pcmd->use_sg) { |
1157 | size_t saved; | ||
1149 | pSRB->pSegmentList = (struct scatterlist *)pcmd->request_buffer; | 1158 | pSRB->pSegmentList = (struct scatterlist *)pcmd->request_buffer; |
1150 | psgl = pSRB->pSegmentList; | 1159 | psgl = pSRB->pSegmentList; |
1151 | //dc390_pci_sync(pSRB); | 1160 | //dc390_pci_sync(pSRB); |
@@ -1157,15 +1166,16 @@ dc390_restore_ptr (struct dc390_acb* pACB, struct dc390_srb* pSRB) | |||
1157 | if( pSRB->SGIndex < pSRB->SGcount ) | 1166 | if( pSRB->SGIndex < pSRB->SGcount ) |
1158 | { | 1167 | { |
1159 | pSRB->pSegmentList++; | 1168 | pSRB->pSegmentList++; |
1160 | psgl = pSRB->pSegmentList; | 1169 | |
1161 | pSRB->SGBusAddr = sg_dma_address(psgl); | 1170 | dc390_start_segment(pSRB); |
1162 | pSRB->SGToBeXferLen = sg_dma_len(psgl); | ||
1163 | } | 1171 | } |
1164 | else | 1172 | else |
1165 | pSRB->SGToBeXferLen = 0; | 1173 | pSRB->SGToBeXferLen = 0; |
1166 | } | 1174 | } |
1167 | pSRB->SGToBeXferLen -= pSRB->Saved_Ptr - pSRB->TotalXferredLen; | 1175 | |
1168 | pSRB->SGBusAddr += pSRB->Saved_Ptr - pSRB->TotalXferredLen; | 1176 | saved = pSRB->Saved_Ptr - pSRB->TotalXferredLen; |
1177 | pSRB->SGToBeXferLen -= saved; | ||
1178 | pSRB->SGBusAddr += saved; | ||
1169 | printk (KERN_INFO "DC390: Pointer restored. Segment %i, Total %li, Bus %08lx\n", | 1179 | printk (KERN_INFO "DC390: Pointer restored. Segment %i, Total %li, Bus %08lx\n", |
1170 | pSRB->SGIndex, pSRB->Saved_Ptr, pSRB->SGBusAddr); | 1180 | pSRB->SGIndex, pSRB->Saved_Ptr, pSRB->SGBusAddr); |
1171 | 1181 | ||
@@ -1286,7 +1296,6 @@ dc390_MsgIn_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus) | |||
1286 | static void | 1296 | static void |
1287 | dc390_DataIO_Comm( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 ioDir) | 1297 | dc390_DataIO_Comm( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 ioDir) |
1288 | { | 1298 | { |
1289 | struct scatterlist *psgl; | ||
1290 | unsigned long lval; | 1299 | unsigned long lval; |
1291 | struct dc390_dcb* pDCB = pACB->pActiveDCB; | 1300 | struct dc390_dcb* pDCB = pACB->pActiveDCB; |
1292 | 1301 | ||
@@ -1315,9 +1324,8 @@ dc390_DataIO_Comm( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 ioDir) | |||
1315 | DC390_write8 (DMA_Cmd, DMA_IDLE_CMD | ioDir); | 1324 | DC390_write8 (DMA_Cmd, DMA_IDLE_CMD | ioDir); |
1316 | if( !pSRB->SGToBeXferLen ) | 1325 | if( !pSRB->SGToBeXferLen ) |
1317 | { | 1326 | { |
1318 | psgl = pSRB->pSegmentList; | 1327 | dc390_start_segment(pSRB); |
1319 | pSRB->SGBusAddr = sg_dma_address(psgl); | 1328 | |
1320 | pSRB->SGToBeXferLen = sg_dma_len(psgl); | ||
1321 | DEBUG1(printk (KERN_DEBUG " DC390: Next SG segment.")); | 1329 | DEBUG1(printk (KERN_DEBUG " DC390: Next SG segment.")); |
1322 | } | 1330 | } |
1323 | lval = pSRB->SGToBeXferLen; | 1331 | lval = pSRB->SGToBeXferLen; |