+void swap_buf_le16(u16 *buf, unsigned int buf_words)
+{
+#ifdef __BIG_ENDIAN
+ unsigned int i;
+
+ for (i = 0; i < buf_words; i++)
+ buf[i] = le16_to_cpu(buf[i]);
+#endif /* __BIG_ENDIAN */
+}
+
+static void ata_mmio_data_xfer(struct ata_port *ap, unsigned char *buf,
+ unsigned int buflen, int write_data)
+{
+ unsigned int i;
+ unsigned int words = buflen >> 1;
+ u16 *buf16 = (u16 *) buf;
+ void __iomem *mmio = (void __iomem *)ap->ioaddr.data_addr;
+
+ if (write_data) {
+ for (i = 0; i < words; i++)
+ writew(le16_to_cpu(buf16[i]), mmio);
+ } else {
+ for (i = 0; i < words; i++)
+ buf16[i] = cpu_to_le16(readw(mmio));
+ }
+}
+
+static void ata_pio_data_xfer(struct ata_port *ap, unsigned char *buf,
+ unsigned int buflen, int write_data)
+{
+ unsigned int dwords = buflen >> 1;
+
+ if (write_data)
+ outsw(ap->ioaddr.data_addr, buf, dwords);
+ else
+ insw(ap->ioaddr.data_addr, buf, dwords);
+}
+
+static void ata_data_xfer(struct ata_port *ap, unsigned char *buf,
+ unsigned int buflen, int do_write)
+{
+ if (ap->flags & ATA_FLAG_MMIO)
+ ata_mmio_data_xfer(ap, buf, buflen, do_write);
+ else
+ ata_pio_data_xfer(ap, buf, buflen, do_write);
+}
+
+static void ata_pio_sector(struct ata_queued_cmd *qc)
+{
+ int do_write = (qc->tf.flags & ATA_TFLAG_WRITE);
+ 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;
+ 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++;
+
+ if ((qc->cursg_ofs * ATA_SECT_SIZE) == sg_dma_len(&sg[qc->cursg])) {
+ qc->cursg++;
+ qc->cursg_ofs = 0;
+ }
+
+ DPRINTK("data %s\n", qc->tf.flags & ATA_TFLAG_WRITE ? "write" : "read");
+
+ /* do the actual data transfer */
+ do_write = (qc->tf.flags & ATA_TFLAG_WRITE);
+ ata_data_xfer(ap, buf, ATA_SECT_SIZE, do_write);
+
+ kunmap(page);
+}
+
+static void __atapi_pio_bytes(struct ata_queued_cmd *qc, unsigned int bytes)
+{
+ int do_write = (qc->tf.flags & ATA_TFLAG_WRITE);
+ struct scatterlist *sg = qc->sg;
+ struct ata_port *ap = qc->ap;
+ struct page *page;
+ unsigned char *buf;
+ 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);
+
+ /* don't cross page boundaries */
+ count = min(count, (unsigned int)PAGE_SIZE - offset);
+
+ buf = kmap(page) + offset;
+
+ bytes -= count;
+ qc->curbytes += count;
+ qc->cursg_ofs += count;
+
+ if (qc->cursg_ofs == sg_dma_len(sg)) {
+ qc->cursg++;
+ qc->cursg_ofs = 0;
+ }
+
+ DPRINTK("data %s\n", qc->tf.flags & ATA_TFLAG_WRITE ? "write" : "read");
+
+ /* do the actual data transfer */
+ ata_data_xfer(ap, buf, count, do_write);
+
+ kunmap(page);
+
+ 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)
+{
+ struct ata_port *ap = qc->ap;
+ struct ata_device *dev = qc->dev;
+ unsigned int ireason, bc_lo, bc_hi, bytes;
+ int i_write, do_write = (qc->tf.flags & ATA_TFLAG_WRITE) ? 1 : 0;
+
+ ap->ops->tf_read(ap, &qc->tf);
+ ireason = qc->tf.nsect;
+ bc_lo = qc->tf.lbam;
+ bc_hi = qc->tf.lbah;
+ bytes = (bc_hi << 8) | bc_lo;
+
+ /* shall be cleared to zero, indicating xfer of data */
+ if (ireason & (1 << 0))
+ goto err_out;
+
+ /* make sure transfer direction matches expected */
+ i_write = ((ireason & (1 << 1)) == 0) ? 1 : 0;
+ if (do_write != i_write)
+ goto err_out;
+
+ __atapi_pio_bytes(qc, bytes);
+
+ return;
+
+err_out:
+ printk(KERN_INFO "ata%u: dev %u: ATAPI check failed\n",
+ ap->id, dev->devno);
+ ap->pio_task_state = PIO_ST_ERR;
+}
+