Skip to content

Commit ecef6a9

Browse files
Christoph Hellwigaxboe
authored andcommitted
libata: fix ata_pio_sector for CONFIG_HIGHMEM
Data transfers are not required to be block aligned in memory, so they span two pages. Fix this by splitting the call to >sff_data_xfer into two for that case. This has been broken since the initial libata import before the damn of git, but was uncovered by the legacy ide driver removal. Reported-by: kernel test robot <[email protected]> Signed-off-by: Christoph Hellwig <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jens Axboe <[email protected]>
1 parent f559665 commit ecef6a9

File tree

1 file changed

+27
-8
lines changed

1 file changed

+27
-8
lines changed

drivers/ata/libata-sff.c

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -637,6 +637,20 @@ unsigned int ata_sff_data_xfer32(struct ata_queued_cmd *qc, unsigned char *buf,
637637
}
638638
EXPORT_SYMBOL_GPL(ata_sff_data_xfer32);
639639

640+
static void ata_pio_xfer(struct ata_queued_cmd *qc, struct page *page,
641+
unsigned int offset, size_t xfer_size)
642+
{
643+
bool do_write = (qc->tf.flags & ATA_TFLAG_WRITE);
644+
unsigned char *buf;
645+
646+
buf = kmap_atomic(page);
647+
qc->ap->ops->sff_data_xfer(qc, buf + offset, xfer_size, do_write);
648+
kunmap_atomic(buf);
649+
650+
if (!do_write && !PageSlab(page))
651+
flush_dcache_page(page);
652+
}
653+
640654
/**
641655
* ata_pio_sector - Transfer a sector of data.
642656
* @qc: Command on going
@@ -648,11 +662,9 @@ EXPORT_SYMBOL_GPL(ata_sff_data_xfer32);
648662
*/
649663
static void ata_pio_sector(struct ata_queued_cmd *qc)
650664
{
651-
int do_write = (qc->tf.flags & ATA_TFLAG_WRITE);
652665
struct ata_port *ap = qc->ap;
653666
struct page *page;
654667
unsigned int offset;
655-
unsigned char *buf;
656668

657669
if (!qc->cursg) {
658670
qc->curbytes = qc->nbytes;
@@ -670,13 +682,20 @@ static void ata_pio_sector(struct ata_queued_cmd *qc)
670682

671683
DPRINTK("data %s\n", qc->tf.flags & ATA_TFLAG_WRITE ? "write" : "read");
672684

673-
/* do the actual data transfer */
674-
buf = kmap_atomic(page);
675-
ap->ops->sff_data_xfer(qc, buf + offset, qc->sect_size, do_write);
676-
kunmap_atomic(buf);
685+
/*
686+
* Split the transfer when it splits a page boundary. Note that the
687+
* split still has to be dword aligned like all ATA data transfers.
688+
*/
689+
WARN_ON_ONCE(offset % 4);
690+
if (offset + qc->sect_size > PAGE_SIZE) {
691+
unsigned int split_len = PAGE_SIZE - offset;
677692

678-
if (!do_write && !PageSlab(page))
679-
flush_dcache_page(page);
693+
ata_pio_xfer(qc, page, offset, split_len);
694+
ata_pio_xfer(qc, nth_page(page, 1), 0,
695+
qc->sect_size - split_len);
696+
} else {
697+
ata_pio_xfer(qc, page, offset, qc->sect_size);
698+
}
680699

681700
qc->curbytes += qc->sect_size;
682701
qc->cursg_ofs += qc->sect_size;

0 commit comments

Comments
 (0)