Fix zero sg_dma_len() on 64-bit platform
PATCH 1/5 Fix zero sg_dma_len() on 64-bit platform
Hi Jeff,
When testing ATAPI PIO data transfer on the ppc64 platform, __atapi_pio_bytes() got zero whensg_dma_len() is used. I checked the <asm-ppc64/scatterlish.h>, the struct scatterlist is defined as:
struct scatterlist {
struct page *page;
unsigned int offset;
unsigned int length;
/* For TCE support */
u32 dma_address;
u32 dma_length;
};#define sg_dma_address(sg) ((sg)->dma_address)
#define sg_dma_len(sg) ((sg)->dma_length)
So, if the scatterlist is not DMA mapped, sg_dma_len() will return zero on ppc64.
The same problem should occur on the x86-64 platform.
On the i386 platform, sg_dma_len() returns sg->length, that's why the problem does not occur on an i386.
Changes:
- Use sg->length if the scatterlist is not DMA mapped (yet).
Attached please find the patch against the libata-2.6 tree for your review. Thanks.
Albert
---------------------------------------
drivers/scsi/libata-core.c +7 -6
@@ -2071,7 +2071,7 @@ sg = qc->sg; sg->page =virt_to_page (buf); sg->offset = (unsigned long ) buf & ~PAGE_MASK ; -sg_dma_len (sg) = buflen; + sg->length = buflen; } void ata_sg_init(struct ata_queued_cmd *qc, struct scatterlist *sg,
@@ -2101,11 +2101,12 @@dma_addr_t dma_address; dma_address =dma_map_single (ap->host_set->dev, qc->buf_virt, -sg_dma_len (sg), dir); + sg->length, dir);if (dma_mapping_error (dma_address))return -1 ;sg_dma_address (sg) = dma_address; +sg_dma_len (sg) = sg->length;DPRINTK ("mapped buffer of %d bytes for %s\n" ,sg_dma_len (sg), qc->tf.flags &ATA_TFLAG_WRITE ?"write" :"read" );
@@ -2310,7 +2311,7 @@ qc->cursect++; qc->cursg_ofs++; -if ((qc->cursg_ofs *ATA_SECT_SIZE ) ==sg_dma_len (&sg[qc->cursg])) { +if ((qc->cursg_ofs *ATA_SECT_SIZE ) == (&sg[qc->cursg])->length) { qc->cursg++; qc->cursg_ofs =0 ; }
@@ -2347,7 +2348,7 @@ page =nth_page (page, (offset >>PAGE_SHIFT )); offset %=PAGE_SIZE ; - count =min (sg_dma_len (sg) - qc->cursg_ofs, bytes); + count =min (sg->length - qc->cursg_ofs, bytes);/* don't cross page boundaries */ count =min (count, (unsigned int )PAGE_SIZE - offset);
@@ -2358,7 +2359,7 @@ qc->curbytes += count; qc->cursg_ofs += count; -if (qc->cursg_ofs ==sg_dma_len (sg)) { +if (qc->cursg_ofs == sg->length) { qc->cursg++; qc->cursg_ofs =0 ; }
@@ -2371,7 +2372,7 @@kunmap (page);if (bytes) { -if (qc->cursg_ofs <sg_dma_len (sg)) +if (qc->cursg_ofs < sg->length) goto next_page; goto next_sg; }
drivers/scsi/libata-core.c +7 -6
@@ -2071,7 +2071,7 @@ sg = qc->sg; sg->page =virt_to_page (buf); sg->offset = (unsigned long ) buf & ~PAGE_MASK ; -sg_dma_len (sg) = buflen; + sg->length = buflen; } void ata_sg_init(struct ata_queued_cmd *qc, struct scatterlist *sg,
@@ -2101,11 +2101,12 @@dma_addr_t dma_address; dma_address =dma_map_single (ap->host_set->dev, qc->buf_virt, -sg_dma_len (sg), dir); + sg->length, dir);if (dma_mapping_error (dma_address))return -1 ;sg_dma_address (sg) = dma_address; +sg_dma_len (sg) = sg->length;DPRINTK ("mapped buffer of %d bytes for %s\n" ,sg_dma_len (sg), qc->tf.flags &ATA_TFLAG_WRITE ?"write" :"read" );
@@ -2310,7 +2311,7 @@ qc->cursect++; qc->cursg_ofs++; -if ((qc->cursg_ofs *ATA_SECT_SIZE ) ==sg_dma_len (&sg[qc->cursg])) { +if ((qc->cursg_ofs *ATA_SECT_SIZE ) == (&sg[qc->cursg])->length) { qc->cursg++; qc->cursg_ofs =0 ; }
@@ -2347,7 +2348,7 @@ page =nth_page (page, (offset >>PAGE_SHIFT )); offset %=PAGE_SIZE ; - count =min (sg_dma_len (sg) - qc->cursg_ofs, bytes); + count =min (sg->length - qc->cursg_ofs, bytes);/* don't cross page boundaries */ count =min (count, (unsigned int )PAGE_SIZE - offset);
@@ -2358,7 +2359,7 @@ qc->curbytes += count; qc->cursg_ofs += count; -if (qc->cursg_ofs ==sg_dma_len (sg)) { +if (qc->cursg_ofs == sg->length) { qc->cursg++; qc->cursg_ofs =0 ; }
@@ -2371,7 +2372,7 @@kunmap (page);if (bytes) { -if (qc->cursg_ofs <sg_dma_len (sg)) +if (qc->cursg_ofs < sg->length) goto next_page; goto next_sg; }
Just FYI... I'll review and merge these patches tomorrow.
From a quick glance, they look sane, modulo the ATAPI padding comments earlier.
Jeff
Jeff Garzik
Appliedapplied to 'misc-fixes' branch of libata-dev.git.
Jeff