summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBartlomiej Zolnierkiewicz <bzolnier@elka.pw.edu.pl>2004-11-01 21:50:59 -0500
committerJeff Garzik <jgarzik@pobox.com>2004-11-01 21:50:59 -0500
commita66bce337aa6b1258a9d176fbff6a98cce2ee970 (patch)
tree63e7d9cc9a4b2c749a483ecd04d555814dfb82f9
parentf2ddba8c1911c3f440cb3e989a364d5d16c119dd (diff)
[PATCH] libata PIO bugfix
Untested but based on working IDE fix. We need to kmap()/kunmap() the current page not the first page of the scatterlist segment. Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com> Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
-rw-r--r--drivers/scsi/libata-core.c30
1 files changed, 25 insertions, 5 deletions
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index 3746cb21f980..ec87710cb363 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -2169,14 +2169,20 @@ static void ata_pio_sector(struct ata_queued_cmd *qc)
struct scatterlist *sg = qc->sg;
struct ata_port *ap = qc->ap;
struct page *page;
+ unsigned int offset;
unsigned char *buf;
if (qc->cursect == (qc->nsect - 1))
ap->pio_task_state = PIO_ST_LAST;
page = sg[qc->cursg].page;
- buf = kmap(page) +
- sg[qc->cursg].offset + (qc->cursg_ofs * ATA_SECT_SIZE);
+ offset = sg[qc->cursg].offset + qc->cursg_ofs * ATA_SECT_SIZE;
+
+ /* get the current page and offset */
+ page = nth_page(page, (offset >> PAGE_SHIFT));
+ offset %= PAGE_SIZE;
+
+ buf = kmap(page) + offset;
qc->cursect++;
qc->cursg_ofs++;
@@ -2202,17 +2208,28 @@ static void __atapi_pio_bytes(struct ata_queued_cmd *qc, unsigned int bytes)
struct ata_port *ap = qc->ap;
struct page *page;
unsigned char *buf;
- unsigned int count;
+ unsigned int offset, count;
if (qc->curbytes == qc->nbytes - bytes)
ap->pio_task_state = PIO_ST_LAST;
next_sg:
sg = &qc->sg[qc->cursg];
+
+next_page:
page = sg->page;
+ offset = sg->offset + qc->cursg_ofs;
+
+ /* get the current page and offset */
+ page = nth_page(page, (offset >> PAGE_SHIFT));
+ offset %= PAGE_SIZE;
count = min(sg_dma_len(sg) - qc->cursg_ofs, bytes);
- buf = kmap(page) + sg->offset + qc->cursg_ofs;
+
+ /* don't cross page boundaries */
+ count = min(count, (unsigned int)PAGE_SIZE - offset);
+
+ buf = kmap(page) + offset;
bytes -= count;
qc->curbytes += count;
@@ -2230,8 +2247,11 @@ next_sg:
kunmap(page);
- if (bytes)
+ if (bytes) {
+ if (qc->cursg_ofs < sg_dma_len(sg))
+ goto next_page;
goto next_sg;
+ }
}
static void atapi_pio_bytes(struct ata_queued_cmd *qc)