On Fri, 22 Apr 2005, Jens Axboe wrote: > On Thu, Apr 21 2005, Guennadi Liakhovetski wrote: > > +static void dc390_kunmap_atomic_sg(void *virt) > > +{ > > + kunmap_atomic(virt_to_page(virt), KM_BIO_SRC_IRQ); > > +} > > Please remember to test this with highmem debug. The above is buggy, > kunmap_atomic() takes the mapped pointer, not the page structure. Oops... Thanks. Sure, I'd like to test it - the problem been, I don't know how to get the damn thing to execute that place. I'll keep thinking about testing possibilities. So far on both my test machines with HDs, CD-ROM, tape and an external ZIP it didn't hit that path. Below is an updated patch. By highmem debug do you mean just enabling the respective option under kernel debugging or one still needs that patch from Andrea you mentioned earlier to test it on low mem machines? Thanks Guennadi --- Guennadi Liakhovetski Index: drivers/scsi/tmscsim.c =================================================================== RCS file: /usr/src/cvs/linux-2_6/drivers/scsi/tmscsim.c,v retrieving revision 1.1.1.8 diff -u -r1.1.1.8 tmscsim.c --- drivers/scsi/tmscsim.c 13 Jan 2005 21:10:01 -0000 1.1.1.8 +++ drivers/scsi/tmscsim.c 23 Apr 2005 09:04:34 -0000 @@ -461,6 +461,8 @@ return error; } +static int debug_kmap; + /* Remove pci mapping */ static void dc390_pci_unmap (struct dc390_srb* pSRB) { @@ -856,8 +858,8 @@ pSRB->pSegmentList++; psgl = pSRB->pSegmentList; - pSRB->SGBusAddr = cpu_to_le32(pci_dma_lo32(sg_dma_address(psgl))); - pSRB->SGToBeXferLen = cpu_to_le32(sg_dma_len(psgl)); + pSRB->SGBusAddr = sg_dma_address(psgl); + pSRB->SGToBeXferLen = sg_dma_len(psgl); } else pSRB->SGToBeXferLen = 0; @@ -882,10 +884,44 @@ } } + +/** + * dc390_kmap_atomic_sg - find and atomically map an sg-elemnt + * @sg: scatter-gather list + * @sg_count: number of segments in sg + * @offset: offset in bytes into sg, on return offset into mapped area + * @len: on return number of bytes mapped + * + * Returns virtual address of the start of the mapped page + */ +static void *dc390_kmap_atomic_sg(struct scatterlist *sg, int sg_count, size_t *offset, size_t *len) +{ + int i; + size_t sg_len = 0; + + for (i = 0; i < sg_count; i++) { + sg_len += sg[i].length; + if (sg_len > *offset) + break; + } + + BUG_ON(i == sg_count); + + *len = sg_len - *offset; + *offset = sg[i].offset + sg[i].length - *len; + + return kmap_atomic(sg[i].page, KM_BIO_SRC_IRQ); +} + +static void dc390_kunmap_atomic_sg(void *virt) +{ + kunmap_atomic(virt, KM_BIO_SRC_IRQ); +} + static void dc390_DataIn_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus) { - u8 sstatus, residual, bval; + u8 sstatus; struct scatterlist *psgl; u32 ResidCnt, i; unsigned long xferCnt; @@ -931,16 +967,17 @@ pSRB->pSegmentList++; psgl = pSRB->pSegmentList; - pSRB->SGBusAddr = cpu_to_le32(pci_dma_lo32(sg_dma_address(psgl))); - pSRB->SGToBeXferLen = cpu_to_le32(sg_dma_len(psgl)); + pSRB->SGBusAddr = sg_dma_address(psgl); + pSRB->SGToBeXferLen = sg_dma_len(psgl); } else pSRB->SGToBeXferLen = 0; } else /* phase changed */ { - residual = 0; - bval = DC390_read8 (Current_Fifo); + u8 residual = 0; + u8 bval = DC390_read8 (Current_Fifo); + while( bval & 0x1f ) { DEBUG1(printk (KERN_DEBUG "Check for residuals,")); @@ -988,10 +1025,24 @@ if( residual ) { + size_t count = 1; + unsigned long flags; + size_t offset = pSRB->TotalXferredLen; + struct scsi_cmnd *pcmd = pSRB->pcmd; + struct scatterlist *sg = pcmd->use_sg ? + (struct scatterlist *)pcmd->request_buffer : &pSRB->pSegmentx; + bval = DC390_read8 (ScsiFifo); /* get one residual byte */ - ptr = (u8 *) bus_to_virt( pSRB->SGBusAddr ); - *ptr = bval; - pSRB->SGBusAddr++; xferCnt++; + + local_irq_save(flags); + ptr = (u8*)dc390_kmap_atomic_sg(sg, pSRB->SGcount, &offset, &count); + + *(ptr + offset) = bval; + dc390_kunmap_atomic_sg(ptr); + local_irq_restore(flags); + + pSRB->SGBusAddr++; + xferCnt++; pSRB->TotalXferredLen++; pSRB->SGToBeXferLen--; } @@ -1212,32 +1263,31 @@ { struct scsi_cmnd *pcmd = pSRB->pcmd; struct scatterlist *psgl; + pSRB->TotalXferredLen = 0; pSRB->SGIndex = 0; if (pcmd->use_sg) { + unsigned long last_xfer; + pSRB->pSegmentList = (struct scatterlist *)pcmd->request_buffer; - psgl = pSRB->pSegmentList; - //dc390_pci_sync(pSRB); - while (pSRB->TotalXferredLen + (unsigned long) sg_dma_len(psgl) < pSRB->Saved_Ptr) - { - pSRB->TotalXferredLen += (unsigned long) sg_dma_len(psgl); - pSRB->SGIndex++; - if( pSRB->SGIndex < pSRB->SGcount ) - { - pSRB->pSegmentList++; - psgl = pSRB->pSegmentList; - pSRB->SGBusAddr = cpu_to_le32(pci_dma_lo32(sg_dma_address(psgl))); - pSRB->SGToBeXferLen = cpu_to_le32(sg_dma_len(psgl)); - } - else - pSRB->SGToBeXferLen = 0; + for (psgl = pSRB->pSegmentList; pSRB->TotalXferredLen + sg_dma_len(psgl) < pSRB->Saved_Ptr; psgl++) { + pSRB->TotalXferredLen += sg_dma_len(psgl); + pSRB->SGIndex++; } - pSRB->SGToBeXferLen -= (pSRB->Saved_Ptr - pSRB->TotalXferredLen); - pSRB->SGBusAddr += (pSRB->Saved_Ptr - pSRB->TotalXferredLen); - printk (KERN_INFO "DC390: Pointer restored. Segment %i, Total %li, Bus %08lx\n", - pSRB->SGIndex, pSRB->Saved_Ptr, pSRB->SGBusAddr); + BUG_ON(pSRB->SGIndex >= pSRB->SGcount); + + last_xfer = pSRB->Saved_Ptr - pSRB->TotalXferredLen; + + pSRB->pSegmentList += pSRB->SGIndex; + pSRB->SGBusAddr = sg_dma_address(psgl) + last_xfer; + pSRB->SGToBeXferLen = sg_dma_len(psgl) - last_xfer; + + //dc390_pci_sync(pSRB); + + DEBUG0(printk(KERN_INFO "DC390: Pointer restored. Segment %i, Total %li, Bus %08lx\n", + pSRB->SGIndex, pSRB->Saved_Ptr, pSRB->SGBusAddr)); } else if(pcmd->request_buffer) { //dc390_pci_sync(pSRB); @@ -1245,11 +1295,11 @@ pSRB->SGcount = 1; pSRB->pSegmentList = (struct scatterlist *) &pSRB->Segmentx; } else { - pSRB->SGcount = 0; - printk (KERN_INFO "DC390: RESTORE_PTR message for Transfer without Scatter-Gather ??\n"); + pSRB->SGcount = 0; + printk (KERN_INFO "DC390: RESTORE_PTR message for Transfer without Scatter-Gather ??\n"); } - pSRB->TotalXferredLen = pSRB->Saved_Ptr; + pSRB->TotalXferredLen = pSRB->Saved_Ptr; } @@ -1385,8 +1435,8 @@ if( !pSRB->SGToBeXferLen ) { psgl = pSRB->pSegmentList; - pSRB->SGBusAddr = cpu_to_le32(pci_dma_lo32(sg_dma_address(psgl))); - pSRB->SGToBeXferLen = cpu_to_le32(sg_dma_len(psgl)); + pSRB->SGBusAddr = sg_dma_address(psgl); + pSRB->SGToBeXferLen = sg_dma_len(psgl); DEBUG1(printk (KERN_DEBUG " DC390: Next SG segment.")); } lval = pSRB->SGToBeXferLen; @@ -1397,8 +1447,8 @@ lval >>= 8; DC390_write8 (CtcReg_High, (u8) lval); - DC390_write32 (DMA_XferCnt, pSRB->SGToBeXferLen); - DC390_write32 (DMA_XferAddr, pSRB->SGBusAddr); + DC390_write32 (DMA_XferCnt, cpu_to_le32(pSRB->SGToBeXferLen)); + DC390_write32 (DMA_XferAddr, cpu_to_le32((u32)pSRB->SGBusAddr)); //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD | ioDir); /* | DMA_INT; */ pSRB->SRBState = SRB_DATA_XFER; - : send the line "unsubscribe linux-scsi" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html